Home AssistantでESPHomeと連携

Home Assistantの紹介
Home Assistantは、スマートホームデバイスを単一の統合インターフェースから制御・監視できる強力なオープンソースホームオートメーションプラットフォームです。スマートホームの中央ハブとして機能し、ルーチンの自動化、センサーの監視、より知的な生活空間の構築を可能にします。

なぜHome Assistantなのか?
-
ローカル制御: 多くのクラウドベースソリューションとは異なり、Home Assistantはネットワーク上でローカルに動作するため、データのプライバシーが保護され、インターネット接続がなくても自動化が機能します。
-
豊富なデバイスサポート: Home Assistantは数千種類の異なるスマートホームデバイスやサービスと統合でき、高い汎用性と将来性を提供します。
-
強力な自動化: 時間、デバイス状態、センサー読み取り値など、さまざまなトリガーに応答する高度な自動化ルールを作成できます。
-
カスタマイズ可能なダッシュボード: 最も重要な情報を表示する独自のユーザーインターフェースを設計できます。
Home AssistantでE-Paperディスプレイを使う理由
XIAO 7.5" ePaper PanelがHome Assistantの優れたコンパニオンである理由はいくつかあります:
-
省エネルギー: e-paperディスプレイはコンテンツを更新する時のみ電力を消費するため、天気予報、カレンダーイベント、システムステータスなどの持続的な情報表示に最適です。
-
優れた視認性: LCDスクリーンとは異なり、e-paperディスプレイは直射日光を含むあらゆる照明条件下で読みやすく、壁掛けホームコントロールパネルに理想的です。
-
長いバッテリー寿命: ディープスリープモードと組み合わせることで、一目で価値ある情報を提供しながら、単一のバッテリー充電で数ヶ月間動作できます。
-
柔軟な統合: ESPHomeを通じて、ディスプレイはHome Assistantとシームレスに統合され、スマートホームシステムからのあらゆるデータをエレガントで常時表示可能な形式で表示できます。
これらの利点により、XIAO 7.5" ePaper PanelはHome Assistantセットアップ用の省エネルギーで常時オンの情報ディスプレイを作成するのに理想的な選択肢となります。
ESPHome統合
ESPHomeは、ESP8266/ESP32デバイス専用に設計されたオープンソースファームウェア作成ツールです。シンプルなYAML設定ファイルを使用してカスタムファームウェアを作成し、デバイスにフラッシュできます。XIAO 7.5" ePaper Panelにとって、ESPHomeはデバイスとHome Assistant間の通信を可能にする重要なミドルウェアとして機能します。
このシステムは、YAML設定をESPデバイス上で動作する完全機能のファームウェアに変換することで動作します。このファームウェアは、ネットワークへの接続、Home Assistantとの通信、ePaperディスプレイの制御といった複雑なタスクをすべて処理します。Home Assistantと組み合わせることで、ESPHomeは高度なホームオートメーションディスプレイとコントロールを作成するための堅牢なプラットフォームを提供します。
セットアップ方法とこの多機能ディスプレイを最大限に活用する方法を探ってみましょう。
はじめに
この記事のチュートリアル内容を始める前に、以下のハードウェアを準備していただく必要があります。
必要な材料
XIAO 7.5" ePaper Panel | Home Assistant Green |
---|---|
![]() | ![]() |
Home Assistant Green は、あなたの家を自動化する最も簡単でプライバシーに重点を置いた方法です。簡単なセットアップを提供し、すべてのスマートデバイスを1つのシステムで制御でき、すべてのデータはデフォルトでローカルに保存されます。このボードは繁栄している Home Assistant エコシステムの恩恵を受け、オープンソースによって毎月改善されます。
このチュートリアルでは Home Assistant Green を Home Assistant ホストとして使用することをお勧めしますが、Supervisor を搭載した任意の Home Assistant ホストを使用することもできます。
Seeed Studio 製品の一部に Home Assistant をインストールする方法も書いていますので、参考にしてください。
- ODYSSEY-X86 で Home Assistant を始める
- reTerminal で Home Assistant を始める
- LinkStar H68K/reRouter CM4 で Home Assistant を始める
Seeed Studio 製品を使用していない場合は、公式 Home Assistant ウェブサイトで他の製品に Home Assistant をインストールする方法を確認して学習することもできます。
ステップ 1. ESPHome をインストール
すでに ESPHome をインストールしている場合は、このステップをスキップできます。
設定 -> アドオン -> アドオンストア に移動します


ESPHome を検索してクリックします。インストール と 開始 をクリックします。
アドオンストアで ESPHome が見つからない場合は、アドオンをサポートする Home Assistant インストール(Home Assistant OS や監視付きインストールなど)を使用していることを確認してください。他のインストールタイプ(Home Assistant Container など)の場合は、Docker を使用して ESPHome Device Builder を独立して実行する必要がある場合があります。詳細については、公式 ESPHome ドキュメントを参照してください。

その後、ESPHome Builder がサイドバーに表示されます。

ステップ 2. 新しいデバイスを追加
ESPHome に移動し、新しいデバイス をクリックします。

お好みのデバイス名を付けて、次へ をクリックします。



新しいデバイスを作成した後、編集 をクリックします。

ステップ 3. ファームウェアをインストール
これは非常に基本的な例で、ディスプレイに「Hello World!」を表示します。
主な目的は、デバイスにファームウェアをインストールするさまざまな方法を示すことです。
ESPHome をインストールして新しいデバイスを追加した後、以下のコードをコピーして、下図のように captive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
# define font to display words
font:
- file: "gfonts://Inter@700"
id: font1
size: 24
# define SPI interface
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
it.print(0, 0, id(font1), "Hello World!");

INSTALLをクリックしてコードをデバイスにインストールすると、以下の画像が表示されます。
- ブラウザ経由でインストール
- ホスト経由でインストール
- Wi-Fi経由でインストール
Home Assistantホスト(Raspberry PI/Green/Yellow等)が遠くにある場合は、この方法をお勧めします。手元にあるコンピューターでインストールできます。
まず、Manual downloadをクリックしてコンパイル済みファームウェアをダウンロードする必要があります。

このウェブサイトを開いて、ファームウェアをePaperパネルにアップロードします。

ESPHomeに戻ってファームウェアをダウンロードします。

Factory formatを選択します。

USBケーブルを使用してePaperパネルをコンピューターに接続し、CONNECTをクリックします。

usbmodemxxx(WindowsではCOMxxx)を選択してconnectをクリックします。問題が発生しましたか?こちらをクリック。

INSTALLをクリックして、先ほどダウンロードしたファームウェアを選択します。

しばらく待つと、ディスプレイに「Hello world!」が表示されます~


Home Assistantホスト(Raspberry PI/Green/Yellow等)が近くにある場合は、より簡単なこの方法をお勧めします。
デバイスにコードをインストールする前に、USBケーブルを使用してこのデバイスをHome Assistantを実行しているRaspberry PiまたはHA Green(Yellow)等に接続する必要があります。
画像に従ってオプションをクリックし、デバイスにコードをインストールします。デバイスがディープスリープモードの時にポートが見つからない?


しばらく待つと、以下の画像のようなフィードバックが表示されます。これはコードが正常に実行されていることを意味します。


これは最も簡単な方法ですが、初回プログラムインストール時は左側の方法を使用してePaper Panelにプログラムをアップロードする必要があります。その後はwifi経由でアップロードできます。また、この方法が機能するためには、YAMLの設定に適切に設定されたota
とapi
セクションが有効な暗号化キーと共に含まれていることを確認してください。
この方法では、ePaperパネルを何にも接続する必要がなく、オンラインであることを確認するだけです。
オプションをクリックすると、ファームウェアが自動的にePaper panelにインストールされます。

しばらく待つと、以下の画像のようなフィードバックが表示されます。失敗した場合は、信号が弱いことが原因の可能性があります。デバイスをルーターに近づけてください。問題が発生しましたか?こちらをクリック。


基本的な使用方法
1. 図形の表示
この例では、ディスプレイに図形を表示します。
ESPHomeをインストールして新しいデバイスを追加した後、以下のコードをコピーして、以下の画像のようにcaptive_portal部分に貼り付けることができます。
コードをコピーするにはここをクリック。
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO3
dc_pin: GPIO5
reset_pin: GPIO2
busy_pin:
number: GPIO4
inverted: true
update_interval: 5min
lambda: |-
it.rectangle(10, 10, 100, 50);
it.rectangle(150, 10, 50, 50);
it.circle(250, 35, 25);
it.filled_rectangle(10, 80, 100, 50);
it.filled_rectangle(150, 80, 50, 50);
it.filled_circle(250, 105, 25);

以下のような画像のフィードバックが表示されたら、コードが正常に実行されていることを意味します。
こちらをクリックして、より多くの使用方法を確認することもできます。

2. HAの情報をディスプレイに表示する
この例では、HAの情報をディスプレイに表示します。
まず最初に、このデバイスをHAに追加する必要があります。そうしないと、HAから情報を取得できません。
HAにデバイスが表示されない場合は、上記のデモを最初に実行する必要があります。上記のデモを実行した後、HAでデバイスを確認できます。


そして、SUBMITとFINISHをクリックします。


ESPHomeをインストールして新しいデバイスを追加した後、以下のコードをコピーして、以下に示すようにcaptive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
# Define font to show info
font:
- file: "gfonts://Inter@700"
id: myFont
size: 24
# Get info from HA, as string format
text_sensor:
- platform: homeassistant
entity_id: weather.forecast_home
id: myWeather
internal: true
- platform: homeassistant
entity_id: weather.forecast_home
id: myTemperature
attribute: "temperature"
internal: true
# Get info from HA, as float format
sensor:
- platform: homeassistant
entity_id: weather.forecast_home
id: myPressure
attribute: "pressure"
internal: true
# Display info via SPI
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
//print info in log
ESP_LOGD("epaper", "weather: %s", id(myWeather).state.c_str());
ESP_LOGD("epaper", "temperature: %s", id(myTemperature).state.c_str());
ESP_LOGD("epaper", "pressure: %.1f", id(myPressure).state);
//display info in epaper screen
it.printf(100, 100, id(myFont), "%s", id(myWeather).state.c_str());
it.printf(100, 150, id(myFont), "%s", id(myTemperature).state.c_str());
it.printf(100, 200, id(myFont), "%.1f", id(myPressure).state);
これらのコードをあなたのデバイスにインストールしてください。

このコードの機能は、HAから天気、温度、気圧を取得してディスプレイに表示することです。

以下の画像のようなフィードバックが表示されたら、コードが正常に動作していることを意味します。


3. アイコンを表示する
この例では、ディスプレイにアイコンを表示します。
まず、File Editorアドオンをインストールする必要があります。Studio Code Serverを検索してクリックしてください。INSTALLをクリックしてSTARTしてください。


そして次に、fontsという新しいフォルダを作成し、このファイルをダウンロードしてfontsフォルダに入れてください。

ESPHomeをインストールして新しいデバイスを追加した後、以下のコードをコピーして、以下に示すようにcaptive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
font:
- file: 'fonts/materialdesignicons-webfont.ttf' #here is the directory to save ttf file
id: font_mdi_large
size: 200 # big size icon
glyphs: &mdi-weather-glyphs
- "\U000F0595" # weather cloudy
- "\U000F0592" # weather hail
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medium # small size icon
size: 40
glyphs: *mdi-weather-glyphs
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
it.printf(100, 200, id(font_mdi_medium), TextAlign::CENTER, "\U000F0595");
it.printf(400, 200, id(font_mdi_large), TextAlign::CENTER, "\U000F0592");

以下のような画像のフィードバックが表示されたら、コードが正常に実行されていることを意味します。

他のアイコンを使用したい場合は、以下のボタンをクリックしてさらに探索できます。
使用したいアイコンを選択してください。

コードをコピーして、以下の画像のように captive_portal 部分に貼り付けてください。


4. 画像を表示する
この例では、お好みの画像をディスプレイに表示する方法を示します。
前の例と同様に、Studio Code Server をインストールし、画像を保存するために image という新しいフォルダを作成する必要があります。
そして、image フォルダに画像を入れてください。以下のボタンをクリックして画像をダウンロードして試すことができます。

ESPHome をインストールして新しいデバイスを追加した後、以下のコードをコピーして、以下に示すように captive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
image:
- file: /config/esphome/image/wifi.jpg # the path where you save the image, png or jpg format
id: myImage
type: BINARY
resize: 800x480 # how big you want to show, the biggest size should be as same as ePaper Penal pixel(800x480)
invert_alpha: true # invert color
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
it.image(0, 0, id(myImage));

以下のような画像のフィードバックが表示されたら、コードが正常に実行されていることを意味します。

デモ 1. Home Assistant ダッシュボードのスクリーンショットを撮る
この例では、ディスプレイにHAのスクリーンショットを表示します。
まず、スクリーンショット用のアドオン Puppet をインストールする必要があります。こちらをクリックしてインストールしてください。

バージョンは 1.11.4以上 である必要があることにご注意ください。インストール後、Configuration ページ に移動します。このアドオン用のaccess_tokenを作成する必要があります。

次のステップでトークンを作成し、ここに貼り付けてください。

Security ページ の下部に移動してトークンを作成し、それをコピーして Puppet アドオンに貼り付けます。

Puppet アドオンを 再起動 することを忘れないでください。

アドオンを開始すると、ポート10000で新しいサーバーが起動します。リクエストしたパスのスクリーンショットが返されます。必要なビューポートサイズを指定する必要があります。
例えば、デフォルトダッシュボードの1000px x 1000pxのスクリーンショットを取得するには、以下を取得します:
# http://192.168.1.191:10000/lovelace/0?viewport=1000x1000(My address)
http://homeassistant.local:10000/lovelace/0?viewport=1000x1000
E Ink®ディスプレイのカラーパレットを削減するには、einkパラメータを追加できます。この値は使用する色数(黒を含む)を表します。例えば、2色のE Ink®ディスプレイの場合:
http://homeassistant.local:10000/lovelace/0?viewport=1000x1000&eink=2
eink=2を使用している場合、invertパラメータを追加することで色を反転させることもできます:
http://homeassistant.local:10000/lovelace/0?viewport=1000x1000&eink=2&invert
Besides, you can also screenshot other page, for example To-do lists page in HA:
http://192.168.1.191:10000/todo?viewport=800x480&eink=2&invert
ブラウザでこのリンクを入力することで、スクリーンショットの効果を確認できます。

ESPHomeをインストールして新しいデバイスを追加した後、以下のコードをコピーして、下図のようにcaptive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
http_request:
verify_ssl: false
timeout: 10s
watchdog_timeout: 15s
online_image:
- id: dashboard_image
format: PNG
type: BINARY
buffer_size: 30000
url: http://192.168.1.191:10000/todo?viewport=800x480&eink=2&invert #change this link to your screenshot link
update_interval: 30s
on_download_finished:
- delay: 0ms
- component.update: main_display
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
id: main_display
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: never
lambda: |-
it.image(0, 0, id(dashboard_image));

以下の画像のようなフィードバックが表示されたら、コードが正常に実行されていることを意味します。

Demo2. ディープスリープモード
ディープスリープモード中は、デバイスに直接コードをアップロードできません。ダウンロードモードに入る必要があります。こちらをクリックしてQ3に移動してください。
この例では、ディープスリープモードを使用して電力を節約する方法を示します。6時間ごとに情報を更新します。2000mAhのバッテリーで約3ヶ月持続できます。
ESPHomeをインストールして新しいデバイスを追加した後、以下のコードをコピーして、下図のようにcaptive_portal
の後に貼り付けることができます。
完全なコードをプレビューするにはここをクリック
globals:
- id: sleep_counter
type: int
restore_value: yes # key parameter, to use RTC storage
initial_value: '0'
# Here is deep sleep part
deep_sleep:
id: deep_sleep_1
run_duration: 30s # Device wake up and run 30s (enough to display)
sleep_duration: 3min # deep sleep for 3min
interval:
- interval: 29s # run this command before the end of run_duration
then:
- logger.log: "Entering deep sleep now..."
font:
- file: "gfonts://Inter@700"
id: font1
size: 24
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 3min
lambda: |-
id(sleep_counter) += 1;
ESP_LOGD("main", "Wakeup count: %d", id(sleep_counter));
it.printf(100, 100, id(font1), "Wakeup count: %d", id(sleep_counter));

カウンターが表示されます。起動するたびに1つずつ増加します。

デモ 3. 総合的な例
より良く理解するために、まず上記の基本的な使用方法を実行することを強く推奨します。
この例では、HAから天気情報とカレンダー情報を取得し、ディスプレイに表示する方法を示します。さらに、電力を節約するためにディープスリープモードを使用します。6時間ごとに情報を更新します。2000mAhのバッテリーで約3ヶ月持続できます。
まず、HAに天気コンポーネントがあるかどうかを確認する必要があります。通常、HAをインストールすると天気コンポーネントも含まれています。

また、Developer Tools -> STATESに移動して、HAに天気情報があるかどうかを確認することもできます。これが後で取得する情報です。

次に、HAにカレンダーコンポーネントをインストールする必要があります。
Settings -> Devices & Services -> Integrations -> Add Integrationに移動します


Local Calendarを選択し、SUBMITボタンをクリックします。


その後、ConfiguredセクションとサイドバーにLocal Calendarが表示されます。

サイドバーのCalendarをクリックし、calendar、epaper_event、new_calendarという名前の3つの新しいカレンダーを作成します。他の名前を使用することもできますが、後でコード内で同じ名前を使用してください。


コードをコピーする前に、wifi.jpg、アイコンttfファイルとフォントttfファイルをimageフォルダとfontsフォルダに配置してください。
完全なコードをプレビューするにはここをクリック
esphome:
name: dashboard
friendly_name: dashboard
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "jBgx0v+Y9eKiQmYTk0SCnHgtDowNDZqgFU26Z2VTYzM="
ota:
- platform: esphome
password: "9f78b53ef216c5d689f7408bb1ebe728"
# -------------------------------------- Keep your code above, change your code below --------------------------------------
globals:
- id: wifi_status
type: int
restore_value: no
initial_value: "0"
- id: first_update_done
type: bool
restore_value: no
initial_value: "false"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
on_connect:
then:
- lambda: |-
id(wifi_status) = 1;
on_disconnect:
then:
- lambda: |-
id(wifi_status) = 0;
captive_portal:
# Here is deep sleep part
deep_sleep:
id: deep_sleep_1
run_duration: 1min # Device wake up and run 60s (enough to pull data and update)
sleep_duration: 60min # deep sleep for 1h
script:
- id: update_display
then:
- component.update: my_display
interval:
# Condition: wifi connected && data retrieved && first time
- interval: 10s # Check every second
then:
- if:
condition:
and:
- wifi.connected:
- lambda: "return !id(ha_calendar_event_1).state.empty();"
- lambda: "return !id(first_update_done);"
then:
- lambda: |-
ESP_LOGD("Display", "Updating Display...");
- script.execute: update_display # Refresh immediately
- lambda: "id(first_update_done) = true;"
- interval: 59s # run this command before 1s of run_duration end
then:
- logger.log: "Entering deep sleep now..."
image:
- file: image/wifi.jpg
type: BINARY
id: esphome_logo
resize: 400x240
invert_alpha: true
# Connect to Home Assistant to get time
time:
- platform: homeassistant
id: homeassistant_time
text_sensor:
- platform: homeassistant
id: ha_calendar_event_1
entity_id: calendar.calendar
attribute: "message"
- platform: homeassistant
id: ha_calendar_start_time_1
entity_id: calendar.calendar
attribute: "start_time"
- platform: homeassistant
id: ha_calendar_end_time_1
entity_id: calendar.calendar
attribute: "end_time"
- platform: homeassistant
id: ha_calendar_event_2
entity_id: calendar.epaper_event
attribute: "message"
- platform: homeassistant
id: ha_calendar_start_time_2
entity_id: calendar.epaper_event
attribute: "start_time"
- platform: homeassistant
id: ha_calendar_end_time_2
entity_id: calendar.epaper_event
attribute: "end_time"
- platform: homeassistant
id: ha_calendar_event_3
entity_id: calendar.new_calendar
attribute: "message"
- platform: homeassistant
id: ha_calendar_start_time_3
entity_id: calendar.new_calendar
attribute: "start_time"
- platform: homeassistant
id: ha_calendar_end_time_3
entity_id: calendar.new_calendar
attribute: "end_time"
- platform: homeassistant
entity_id: weather.forecast_home
id: myWeather
- platform: homeassistant
entity_id: weather.forecast_home
id: temp
attribute: "temperature"
- platform: homeassistant
entity_id: weather.forecast_home
id: humi
attribute: "humidity"
- platform: homeassistant
entity_id: weather.forecast_home
id: press
attribute: "pressure"
- platform: homeassistant
entity_id: weather.forecast_home
id: wind
attribute: "wind_speed"
font:
- file: "fonts/Montserrat-Black.ttf"
id: web_font
size: 20
- file: "fonts/Montserrat-Black.ttf"
id: data_font
size: 30
- file: "fonts/Montserrat-Black.ttf"
id: sensor_font
size: 22
- file: "gfonts://Inter@700" #
id: font1
size: 24
- file: 'fonts/materialdesignicons-webfont.ttf' # Directory to save ttf file
id: font_mdi_large
size: 200
glyphs: &mdi-weather-glyphs # https://pictogrammers.com/library/mdi/
- "\U000F050F" # Thermometer
- "\U000F058E" # Humidity
- "\U000F059D" # Wind speed
- "\U000F0D60" # Atmospheric pressure
- "\U000F0590" # Cloudy weather
- "\U000F0596" # Rainy weather
- "\U000F0598" # Snowy weather
- "\U000F0599" # Sunny weather
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_weather # Copy the above icon and change the size to 40
size: 200
glyphs: *mdi-weather-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: img_font_sensor # Copy the above icon and change the size to 40
size: 70
glyphs: *mdi-weather-glyphs
spi:
clk_pin: GPIO8
mosi_pin: GPIO10
display:
- platform: waveshare_epaper
id: my_display
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin:
number: GPIO4
inverted: true
reset_pin: GPIO2
model: 7.50inv2
update_interval: 50s
lambda: |-
if(id(wifi_status) == 0){
it.image(180, 0, id(esphome_logo));
it.print(230, 300, id(data_font), "WI-FI CONNECTING");
}else{
// Draw weather images here
std::string weather_string = id(myWeather).state.c_str();
if(weather_string == "rainy" || weather_string == "lightning" || weather_string == "pouring"){
// Draw rainy weather image
it.printf(120, 85, id(font_weather), TextAlign::CENTER, "\U000F0596");
}else if(weather_string == "snowy"){
// Draw snowy weather image
it.printf(120, 85, id(font_weather), TextAlign::CENTER, "\U000F0598");
}else if(weather_string == "sunny" || weather_string == "windy"){
// Draw sunny weather image
it.printf(120, 85, id(font_weather), TextAlign::CENTER, "\U000F0599");
}else{
// Draw cloudy weather image
it.printf(120, 85, id(font_weather), TextAlign::CENTER, "\U000F0590");
}
auto time_now = id(homeassistant_time).now();
// Month conversion
const char* months[] = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
const char* month_str = months[time_now.month - 1]; // Month index starts from 0
// Get the day
int day = time_now.day_of_month;
// Draw the date
it.printf(250, 110, id(data_font), "%s %d", month_str, day);
// Get the day of the week
const char* days[] = {"Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
const char* day_of_week = days[time_now.day_of_week];
it.printf(250, 70, id(data_font), "%s", day_of_week);
int x = 20, y = 180, w = 180, h = 120, r = 10, thickness = 4;
// Draw four borders
it.filled_rectangle(x + r, y, w - 2 * r, thickness); // Top border
it.filled_rectangle(x + r, y + h - thickness, w - 2 * r, thickness); // Bottom border
it.filled_rectangle(x, y + r, thickness, h - 2 * r); // Left border
it.filled_rectangle(x + w - thickness, y + r, thickness, h - 2 * r); // Right border
// Draw four rounded corners
it.filled_circle(x + r, y + r, r); // Top-left corner
it.filled_circle(x + w - r, y + r, r); // Top-right corner
it.filled_circle(x + r, y + h - r, r); // Bottom-left corner
it.filled_circle(x + w - r, y + h - r, r); // Bottom-right corner
// Fill the inside with black to form a border
it.filled_rectangle(x + thickness, y + thickness, w - 2 * thickness, h - 2 * thickness, COLOR_OFF);
// Temperature
it.printf(x+10, y+10, id(sensor_font), "Temperature");
it.printf(x+45, y+75, id(img_font_sensor), TextAlign::CENTER, "\U000F050F");
// Get temperature data
it.printf(x+75,y+65, id(data_font), "%s°F", id(temp).state.c_str());
x = 220;
y = 180;
// Draw four borders
it.filled_rectangle(x + r, y, w - 2 * r, thickness); // Top border
it.filled_rectangle(x + r, y + h - thickness, w - 2 * r, thickness); // Bottom border
it.filled_rectangle(x, y + r, thickness, h - 2 * r); // Left border
it.filled_rectangle(x + w - thickness, y + r, thickness, h - 2 * r); // Right border
// Draw four rounded corners
it.filled_circle(x + r, y + r, r); // Top-left corner
it.filled_circle(x + w - r, y + r, r); // Top-right corner
it.filled_circle(x + r, y + h - r, r); // Bottom-left corner
it.filled_circle(x + w - r, y + h - r, r); // Bottom-right corner
// Fill the inside with black to form a border
it.filled_rectangle(x + thickness, y + thickness, w - 2 * thickness, h - 2 * thickness, COLOR_OFF);
// Humidity
it.printf(x+10, y+10, id(sensor_font), "Humidity");
it.printf(x+45, y+75, id(img_font_sensor), TextAlign::CENTER, "\U000F058E");
// Get humidity data
it.printf(x+75,y+65, id(data_font), "%s%%", id(humi).state.c_str());
x = 20;
y = 320;
// Draw four borders
it.filled_rectangle(x + r, y, w - 2 * r, thickness); // Top border
it.filled_rectangle(x + r, y + h - thickness, w - 2 * r, thickness); // Bottom border
it.filled_rectangle(x, y + r, thickness, h - 2 * r); // Left border
it.filled_rectangle(x + w - thickness, y + r, thickness, h - 2 * r); // Right border
// Draw four rounded corners
it.filled_circle(x + r, y + r, r); // Top-left corner
it.filled_circle(x + w - r, y + r, r); // Top-right corner
it.filled_circle(x + r, y + h - r, r); // Bottom-left corner
it.filled_circle(x + w - r, y + h - r, r); // Bottom-right corner
// Fill the inside with black to form a border
it.filled_rectangle(x + thickness, y + thickness, w - 2 * thickness, h - 2 * thickness, COLOR_OFF);
// Air Pressure
it.printf(x+10, y+10, id(sensor_font), "Air Pressure");
it.printf(x+45, y+75, id(img_font_sensor), TextAlign::CENTER, "\U000F0D60");
// Get atmospheric pressure data
it.printf(x+85,y+50, id(data_font), "%s", id(press).state.c_str());
it.printf(x+85,y+78, id(sensor_font), "inHg");
x = 220;
y = 320;
// Draw four borders
it.filled_rectangle(x + r, y, w - 2 * r, thickness); // Top border
it.filled_rectangle(x + r, y + h - thickness, w - 2 * r, thickness); // Bottom border
it.filled_rectangle(x, y + r, thickness, h - 2 * r); // Left border
it.filled_rectangle(x + w - thickness, y + r, thickness, h - 2 * r); // Right border
// Draw four rounded corners
it.filled_circle(x + r, y + r, r); // Top-left corner
it.filled_circle(x + w - r, y + r, r); // Top-right corner
it.filled_circle(x + r, y + h - r, r); // Bottom-left corner
it.filled_circle(x + w - r, y + h - r, r); // Bottom-right corner
// Fill the inside with black to form a border
it.filled_rectangle(x + thickness, y + thickness, w - 2 * thickness, h - 2 * thickness, COLOR_OFF);
// Wind Speed
it.printf(x+10, y+10, id(sensor_font), "Wind Speed");
it.printf(x+45, y+75, id(img_font_sensor), TextAlign::CENTER, "\U000F059D");
// Get wind speed data
it.printf(x+85,y+50, id(data_font), "%s", id(wind).state.c_str());
it.printf(x+85,y+78, id(sensor_font), "mph");
// Draw a vertical line
it.filled_rectangle(430, 30, 5, 430);
// Right section
it.printf(540, 40, id(data_font), "Calendar");
// Define event structure
struct Event {
std::string message;
std::string start_time;
std::string end_time;
time_t start_timestamp;
};
// Parse time string to time_t (UNIX timestamp)
auto parse_time = [](const std::string &time_str) -> time_t {
struct tm timeinfo = {};
if (strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &timeinfo) == nullptr) {
return 0; // Invalid time
}
return mktime(&timeinfo);
};
// Create event list
std::vector<Event> events = {
{id(ha_calendar_event_1).state, id(ha_calendar_start_time_1).state, id(ha_calendar_end_time_1).state, parse_time(id(ha_calendar_start_time_1).state)},
{id(ha_calendar_event_2).state, id(ha_calendar_start_time_2).state, id(ha_calendar_end_time_2).state, parse_time(id(ha_calendar_start_time_2).state)},
{id(ha_calendar_event_3).state, id(ha_calendar_start_time_3).state, id(ha_calendar_end_time_3).state, parse_time(id(ha_calendar_start_time_3).state)}
};
ESP_LOGD("myCalendar", "Start Time: %s -> %ld", id(ha_calendar_start_time_1).state.c_str(), parse_time(id(ha_calendar_start_time_1).state));
ESP_LOGD("myCalendar", "Start Time: %s -> %ld", id(ha_calendar_start_time_2).state.c_str(), parse_time(id(ha_calendar_start_time_2).state));
ESP_LOGD("myCalendar", "Start Time: %s -> %ld", id(ha_calendar_start_time_3).state.c_str(), parse_time(id(ha_calendar_start_time_3).state));
// Filter invalid events (start_timestamp == 0)
events.erase(std::remove_if(events.begin(), events.end(), [](const Event &e) { return e.start_timestamp == 0; }), events.end());
// Sort by `start_timestamp` (earliest to latest)
std::sort(events.begin(), events.end(), [](const Event &a, const Event &b) {
return a.start_timestamp < b.start_timestamp;
});
// Define a function to format time
auto format_time = [](std::string time_str) -> std::string {
struct tm timeinfo;
if (strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &timeinfo) == nullptr) {
return "Invalid";
}
char buffer[10];
strftime(buffer, sizeof(buffer), "%I:%M%p", &timeinfo); // Convert to 12-hour format
return std::string(buffer);
};
// Parse date
auto format_date = [](const std::string &time_str) -> std::string {
struct tm timeinfo = {};
if (strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &timeinfo) == nullptr) {
return "Invalid";
}
char buffer[6]; // Need to store "MM-DD\0"
strftime(buffer, sizeof(buffer), "%m-%d", &timeinfo);
return std::string(buffer);
};
// Draw events
int even_x_start_offset = 460;
int even_y_start_offset = 80;
for (const auto &event : events) {
if(even_y_start_offset >= 420){
break;
}
// Format time
std::string formatted_date = format_date(event.start_time);
std::string formatted_start_time = format_time(event.start_time);
std::string formatted_end_time = format_time(event.end_time);
// Combine time range string
std::string time_range = formatted_start_time + " - " + formatted_end_time;
time_range = formatted_date + " " + time_range;
if(formatted_start_time == "Invalid" || formatted_end_time == "Invalid"){
time_range.clear();
}
// Display time range, e.g., "10:00AM - 11:00AM"
it.printf(even_x_start_offset, even_y_start_offset, id(sensor_font), "%s", time_range.c_str());
even_y_start_offset += 30;
// Display event name
it.printf(even_x_start_offset, even_y_start_offset, id(sensor_font), "%s", event.message.c_str());
even_y_start_offset += 40;
}
}
以下の画像のようなフィードバックが表示された場合、コードが正常に実行されていることを意味します。

FAQ
Q1: なぜデータが表示されないのですか?

この場合、設定 -> デバイスとサービス -> 統合に移動してデバイスを再設定する必要があります。ePaper パネルが見つからない場合は、HAを再起動してみてください。

Q2: なぜHome Assistantでこれらのデータを取得できないのですか?
この場合、設定 -> デバイスとサービス -> 統合に移動してデバイスをHAに追加する必要があります。

Q3: デバイスがディープスリープモードの時に新しいプログラムをアップロードするにはどうすればよいですか?


デバイスがディープスリープモードの時は、直接新しいプログラムをアップロードすることはできません。
-
まず、デバイスの電源が入っていることを確認し、ボードの裏面にあるBootボタンを押します。
-
Resetボタンを1回クリックし、Bootボタンを離します。
-
その後、バッテリースイッチをオフにし、電源ケーブルを抜きます。
-
最後に、ケーブルを再接続して新しいプログラムをアップロードします。
Q4: バッテリーはどのくらい持続しますか?
充電時はバッテリーボタンをオンにすることを忘れないでください。そうしないと、バッテリーが充電されません。
テストの結果、6時間ごとに画面を更新し、ディープスリープモードでバッテリーは約3ヶ月持続します。
Q5: ePaper パネルがコンピューターに接続できませんか?

何度か抜き差しを試すか、プロンプトに従ってドライバーをインストールしてください。
Q6: Wi-Fiプログラムのアップロードが失敗しましたか?

この場合、epaperパネルがオフラインまたはディープスリープモードになっています。オンラインにするか、起動してください。
リソース
- [STP]: 3Dモデル筐体
- [PDF]: ePaperドライバーボード回路図PDF
技術サポート & 製品ディスカッション
弊社製品をお選びいただき、ありがとうございます!お客様の製品体験が可能な限りスムーズになるよう、さまざまなサポートを提供いたします。異なる好みやニーズに対応するため、複数のコミュニケーションチャンネルをご用意しています。