メインコンテンツまでスキップ

ESPHome クックブック: TRMNL 7.5" (OG) DIY Kit

まずメインの ESPHome ガイドを読んでください

このページは TRMNL DIY Kit 専用の ESPHome クックブックです。共通の手順 ― 書き込み方法の選択、汎用 YAML スケルトン、Home Assistant への接続 ― は Work with ESPHome にまとまっています。Seeed の ePaper で ESPHome を使うのが初めての場合は、先にそちらへ一通り目を通してください。TRMNL クラウドダッシュボード(YAML 不要のプラグイン方式)ワークフローを探している場合は、Work with TRMNL を参照してください。


Home Assistant の概要

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

なぜ Home Assistant なのか?

  • ローカル制御: 多くのクラウドベースのソリューションとは異なり、Home Assistant はローカルネットワーク上で動作するため、データはプライベートに保たれ、インターネット接続がなくても自動化が機能します。

  • 幅広いデバイス対応: Home Assistant は何千ものスマートホームデバイスやサービスと連携できるため、非常に汎用性が高く、将来性もあります。

  • 強力な自動化機能: 時刻、デバイスの状態、センサー値など、さまざまなトリガーに応じて動作する高度な自動化ルールを作成できます。

  • カスタマイズ可能なダッシュボード: 自分にとって重要な情報を表示する、独自のユーザーインターフェースをデザインできます。

なぜ TRMNL 7.5inch(OG) DIY Kit と Home Assistant を組み合わせるのか?

TRMNL 7.5inch(OG) DIY Kit は、次のような理由から Home Assistant の優れたパートナーとなります。

  1. 省エネルギー: 電子ペーパーディスプレイはコンテンツを更新するときにのみ電力を消費するため、天気予報、カレンダーイベント、システムステータスなどの常時表示したい情報に最適です。

  2. 高い視認性: LCD 画面とは異なり、電子ペーパーは直射日光下を含むあらゆる照明条件で読みやすく、壁掛け型のホームコントロールパネルに理想的です。

  3. 長いバッテリー寿命: ディープスリープモードと組み合わせることで、バッテリー 1 回の充電で数か月間動作しつつ、一目で分かる有用な情報を提供できます。

  4. 柔軟な統合: ESPHome を介してディスプレイは Home Assistant とシームレスに連携し、スマートホームシステムのあらゆるデータを、常に表示されるエレガントな形式で表示できます。

これらの利点により、TRMNL 7.5inch(OG) DIY Kit は、Home Assistant 環境向けに省エネルギーで常時オンの情報ディスプレイを構築するための理想的な選択肢となります。

ESPHome との連携

ESPHome は、ESP8266/ESP32 デバイス向けに特化したオープンソースのファームウェア作成ツールです。シンプルな YAML 設定ファイルを使ってカスタムファームウェアを作成し、それをデバイスに書き込むことができます。TRMNL 7.5inch(OG) DIY Kit においては、ESPHome がデバイスと Home Assistant 間の通信を可能にする重要なミドルウェアとして機能します。

このシステムは、YAML 設定を ESP デバイス上で動作するフル機能のファームウェアへと変換することで動作します。このファームウェアが、ネットワークへの接続、Home Assistant との通信、ePaper ディスプレイの制御といった複雑な処理をすべて担います。Home Assistant と組み合わせることで、ESPHome は高度なホームオートメーション用ディスプレイやコントローラを構築するための堅牢なプラットフォームを提供します。

それでは、この多用途なディスプレイのセットアップ方法と活用方法を見ていきましょう。

はじめに

本記事のチュートリアル内容に入る前に、以下のハードウェアを用意しておく必要があります。

必要なもの

TRMNL 7.5inch(OG) DIY KitHome Assistant Green

Home Assistant Green は、最も簡単かつプライバシー重視で自宅を自動化できる方法です。セットアップは手軽で、すべてのスマートデバイスを 1 つのシステムから制御でき、データはデフォルトでローカルに保存されます。このボードは活発な Home Assistant エコシステムの恩恵を受けており、オープンソースによって毎月改善されていきます。

本チュートリアルでは Home Assistant ホストとして Home Assistant Green の使用を推奨しますが、Supervisor を備えた任意の Home Assistant ホストを使用することもできます。

Home Assistant をインストールする

Seeed Studio 製品のいくつかについては、Home Assistant のインストール方法も記載していますので、そちらも参照してください。

Seeed Studio 製品を使用していない場合は、Home Assistant 公式サイトで他の製品向けの Home Assistant のインストール方法を確認して学ぶこともできます。

機器の組み立て

Step 1. ディスプレイをドライバボードに接続する
FPC ケーブルを XIAO ePaper Display Board 上のコネクタに合わせ、ラッチを固定してしっかり接続されていることを確認します。

ヒント

FPC ケーブルの金属面は上向きにする必要があります。向きが逆だと、何も表示されません。

多くの方が間違える箇所なので、必ず以下の取り付けチュートリアルに従ってください。

Step 2. バッテリーを取り付ける
バッテリーケーブルをドライバボード上の JST コネクタに接続し、極性が正しいことを確認します(赤い線を +、黒い線を - へ)。

Step 3. ケースの組み立て(オプション)

ヒント

画面のフレキシブルケーブルは非常に繊細です。作業時は十分注意してください。損傷すると、画面全体が動作しなくなります。

Resource part からオープンソースのケース部品を印刷し、その中に各コンポーネントを組み込みます。

まず、ドライバボードとバッテリーを組み立てます。

TRMNL キットが正常に動作するかテストします。

画面をケースに差し込み、FPC ケーブルを外に出せるようにします。

FPC 延長ケーブルを接続し、ケース全体を組み立てます。

L 字型ケースもほとんど同じ手順です。

ヒント

TRMNL キットがルーターから遠い場合は、アンテナをケースの外に出すこともできます。その方が性能が向上します。

すでに ESPHome をインストールしている場合は、この手順をスキップできます。

Settings -> Add-ons -> ADD-ON STORE に移動します。

ESPHome を検索してクリックします。INSTALLSTART をクリックします。

ヒント

アドオンストアで ESPHome が見つからない場合は、アドオンをサポートする Home Assistant インストール(Home Assistant OS や supervised インストールなど)を使用していることを確認してください。その他のインストールタイプ(Home Assistant Container など)の場合は、ESPHome Device Builder を Docker を使って単独で実行する必要があるかもしれません。詳しくは 公式 ESPHome ドキュメント を参照してください。

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

ステップ 2. 新しいデバイスを追加する

ESPHome を開き、NEW DEVICE をクリックします。

デバイスに好きな名前を付け、チップタイプとして ESP32-S3 を選択し、SKIP をクリックします。

新しいデバイスを作成したら、EDIT をクリックします。

デフォルトで生成されたコード内では、esp32 のフレームワークが esp-idf になっている場合がありますが、これを arduino に変更する必要があります。

ステップ 3. ファームウェアをインストールする

これはとても基本的なサンプルで、ディスプレイに "Hello World!" を表示します。

主な目的は、デバイスにファームウェアをインストールするさまざまな方法を紹介することです。

ここで、以下のコードをコピーして、下図のように captive_portal の後に貼り付けます。

# define font to display words
font:
- file: "gfonts://Inter@700"
id: font1
size: 24

# define SPI interface
spi:
clk_pin: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
update_interval: 30s
lambda: |-
it.print(0, 0, id(font1), "Hello World!");

INSTALL をクリックしてコードをデバイスにインストールすると、次の画像のように表示されます。

ヒント

Home Assistant ホスト(Raspberry PI/Green/Yellow など)が手元から離れた場所にある場合は、この方法をお勧めします。手元のコンピュータを使ってインストールできます。

まず、Manual download をクリックして、コンパイル済みファームウェアをダウンロードする必要があります。

次に示す Web サイトを開き、ここから ePaper パネルにファームウェアをアップロードします。

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

Factory フォーマットを選択します。

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

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

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

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

基本的な使い方

1. 形状を表示する

このサンプルでは、ディスプレイに図形を表示します。

以下のコードをコピーして、次の画像のように captive_portal の部分に貼り付けることができます。

spi:
clk_pin: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
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 にデバイスが表示されるようになります。

その後、SUBMITFINISH をクリックします。

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: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
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 から 天気気温気圧 を取得し、それらをディスプレイに表示することです。

ヒント

もし Home Assistant に天気関連のコンポーネントがない場合は、インテグレーション内から Open-Meteo というインテグレーションをダウンロードできます。

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

3. アイコンを表示する

この例では、ディスプレイにアイコンを表示します。

まず、ファイルエディタのアドオンをインストールする必要があります。Studio Code Server を検索してクリックします。INSTALLSTART をクリックします。

そして次にfonts という名前の新しいフォルダを作成し、このファイルをダウンロードして fonts フォルダに入れます

以下のコードをコピーして、下図のように 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: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
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 フォルダに画像を入れます。試してみるために画像をダウンロードするには、下のボタンをクリックできます。

以下のコードをコピーして、下図のように 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: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
update_interval: 30s
lambda: |-
it.image(0, 0, id(myImage));

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

デモ 1. Home Assistant ダッシュボードをスクリーンショットとして取得する

この例では、ディスプレイに HA のスクリーンショットを表示します。

まず、スクリーンショット用のアドオン Puppet をインストールする必要があります。インストールするにはここをクリック。

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

次のステップでトークンを作成し、ここに貼り付けます。

Security page の一番下までスクロールしてトークンを作成し、それをコピーして 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

また、HA の To-do lists ページなど、他のページのスクリーンショットを撮ることもできます:

http://192.168.1.191:10000/todo?viewport=800x480&eink=2&invert

このリンクをブラウザに入力すると、スクリーンショットの効果を確認できます。

以下のコードをコピーして、esp32 の後に貼り付けてください:

# Enable PSRAM support since online_image requires more than the available RAM capacity
psram:
mode: octal
speed: 80MHz

以下のコードをコピーして、下図のように 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: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
id: main_display
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
update_interval: never
lambda: |-
it.image(0, 0, id(dashboard_image));

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

デモ 2. ディープスリープモード

ヒント

ディープスリープモード中は、デバイスに直接コードをアップロードすることはできません。ダウンロードモードに入る必要があります。Q3 にジャンプするにはここをクリックしてください。

このサンプルでは、ディープスリープモードを使用して電力を節約する方法を示します。情報は 6 時間ごとに更新されます。

以下のコードをコピーして、下図のように 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: GPIO7
mosi_pin: GPIO9

display:
- platform: waveshare_epaper
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
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. 総合的なサンプル

ヒント

よりよく理解していただくために、まず上記の基本的な使い方を実行することを強くお勧めします。

このサンプルでは、TRMNL 7.5 インチ電子ペーパー DIY キット向けの包括的な ESPHome 設定を示します。YAML コードは複数の機能を統合し、Home Assistant とシームレスに連携するスマートでインタラクティブなディスプレイパネルを構築します。

目的と機能:

  • この設定により、デバイスは Wi-Fi と Home Assistant に接続でき、簡単に管理できるよう API と OTA アップデートの両方をサポートします。

  • 物理ボタンで切り替え可能な 2 つのページに、さまざまな種類の情報を表示するように電子ペーパーディスプレイを設定します。

  • デバイスはバッテリー電圧を読み取り、バッテリー残量を計算し、それに対応するバッテリーアイコンと値を表示します。

  • 天気の状態と気温を Home Assistant から取得し、適切なアイコンと単位とともに表示します。

  • 現在の時刻と日付も Home Assistant と同期して表示されます。

このサンプルは、センサーの読み取り値、Home Assistant のデータ、ユーザー入力を組み合わせて、ESPHome と TRMNL 7.5 インチ電子ペーパーキットを使用した多機能で常時表示のスマートディスプレイを構築する方法を紹介します。

完全なコードをプレビューするにはここをクリック
esphome:
name: obdy
friendly_name: obdy
on_boot:
priority: 600
then:
- output.turn_on: bsp_battery_enable
- delay: 200ms
- component.update: battery_voltage
- component.update: battery_level

esp32:
board: esp32-s3-devkitc-1
framework:
type: arduino

# Enable PSRAM support since online_image requires more than the available RAM capacity
psram:
mode: octal
speed: 80MHz

# Enable logging
logger:

# Enable Home Assistant API
api:
encryption:
key: "j0V30kuJ6Zdij9SU6Ee+7ruwid+7SQOxtinjld2PRc0="

ota:
- platform: esphome
password: "db786195ae6f9748f5b57ea9bd1d4161"

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Obdy Fallback Hotspot"
password: "IOfapF7hXq55"

captive_portal:

# Deep-sleep, wake by GPIO4
# deep_sleep:
# id: deep_sleep_1
# run_duration: 1min
# sleep_duration: 60min
# wakeup_pin: GPIO4
# wakeup_pin_mode: INVERT_WAKEUP

spi:
clk_pin: GPIO7
mosi_pin: GPIO9

# Fonts
font:
- file: "gfonts://Inter@700"
id: small_font
size: 24
- file: "gfonts://Inter@700"
id: mid_font
size: 36
- file: "gfonts://Inter@700"
id: big_font
size: 180
- file: "gfonts://Inter@700"
id: time_font
size: 96 # for the big time display
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_bat_icon
size: 24
glyphs:
- "\U000F007A" # mdi-battery-10
- "\U000F007B" # mdi-battery-20
- "\U000F007C" # mdi-battery-30
- "\U000F007D" # mdi-battery-40
- "\U000F007E" # mdi-battery-50
- "\U000F007F" # mdi-battery-60
- "\U000F0080" # mdi-battery-70
- "\U000F0081" # mdi-battery-80
- "\U000F0082" # mdi-battery-90
- "\U000F0079" # mdi-battery
- file: "fonts/materialdesignicons-webfont.ttf" # <-- 替换成你的字体文件路径
id: weather_icon_font
size: 100
glyphs:
- "\U000F0599" # weather-sunny
- "\U000F0595" # weather-partly-cloudy
- "\U000F0F2F" # weather-cloudy
- "\U000F0597" # weather-rainy
- "\U000F0598" # weather-snowy
- "\U000F059B" # weather-windy
- "\U000F0594" # weather-fog
- "\U000F0596" # weather-lightning

globals:
- id: page_index
type: int
restore_value: true
initial_value: '0'
- id: battery_glyph
type: std::string
restore_value: no
initial_value: "\"\\U000F0079\"" # default full battery

sensor:
- platform: adc
pin: GPIO1
name: "Battery Voltage"
id: battery_voltage
update_interval: 60s
attenuation: 12db
filters:
- multiply: 2.0
- platform: template
name: "Battery Level"
id: battery_level
unit_of_measurement: "%"
icon: "mdi:battery"
device_class: battery
state_class: measurement
lambda: 'return id(battery_voltage).state;'
update_interval: 60s
on_value:
then:
- lambda: |-
int pct = int(x);
if (pct <= 10) id(battery_glyph) = "\U000F007A";
else if (pct <= 20) id(battery_glyph) = "\U000F007B";
else if (pct <= 30) id(battery_glyph) = "\U000F007C";
else if (pct <= 40) id(battery_glyph) = "\U000F007D";
else if (pct <= 50) id(battery_glyph) = "\U000F007E";
else if (pct <= 60) id(battery_glyph) = "\U000F007F";
else if (pct <= 70) id(battery_glyph) = "\U000F0080";
else if (pct <= 80) id(battery_glyph) = "\U000F0081";
else if (pct <= 90) id(battery_glyph) = "\U000F0082";
else id(battery_glyph) = "\U000F0079";
filters:
- calibrate_linear:
- 4.15 -> 100.0
- 3.96 -> 90.0
- 3.91 -> 80.0
- 3.85 -> 70.0
- 3.80 -> 60.0
- 3.75 -> 50.0
- 3.68 -> 40.0
- 3.58 -> 30.0
- 3.49 -> 20.0
- 3.41 -> 10.0
- 3.30 -> 5.0
- 3.27 -> 0.0
- clamp:
min_value: 0
max_value: 100

output:
- platform: gpio
pin: GPIO6
id: bsp_battery_enable

binary_sensor:
- platform: gpio # Next page KEY1
pin:
number: GPIO2
mode: INPUT_PULLUP
inverted: true
id: key1
name: "Key1"
on_press:
then:
- lambda: |-
id(page_index) = (id(page_index) + 1) % 2;
id(epaper_display).update();

- platform: gpio # Prev page KEY2
pin:
number: GPIO3
mode: INPUT_PULLUP
inverted: true
id: key2
name: "Key2"
on_press:
then:
- lambda: |-
id(page_index) = (id(page_index) - 1 + 2) % 2;
id(epaper_display).update();

# - platform: gpio
# pin:
# number: GPIO5 # KEY3
# mode: INPUT_PULLUP
# inverted: true
# id: key2
# name: "Key2"
# on_press:
# then:

# Home Assistant time
time:
- platform: homeassistant
id: ha_time

text_sensor:
- platform: homeassistant
entity_id: weather.home
id: myWeather
- platform: homeassistant
entity_id: weather.home
id: temp
attribute: "temperature"

display:
- platform: waveshare_epaper
id: epaper_display
model: 7.50inv2
cs_pin: GPIO44
dc_pin: GPIO10
reset_pin: GPIO38
busy_pin:
number: GPIO4
inverted: true
update_interval: never
lambda: |-
// ---------- PAGE 0 ----------
if (id(page_index) == 0) {
// Screen dimension constants for easy adjustment
const int scr_w = 800;
const int scr_h = 480;
const int center_x = scr_w / 2; // Center X-coordinate of the screen (400)

// --- Top-right: Battery Info ---
// Display the battery icon using an icon font
it.printf(scr_w - 130, 13, id(font_bat_icon), "%s", id(battery_glyph).c_str());
// Display the battery percentage text
it.printf(scr_w - 100, 10, id(small_font), "%.0f%%", id(battery_level).state);

// --- Draw the vertical separator line ---
// Draw a vertical line in the middle to separate left and right areas
it.filled_rectangle(center_x, 100, 2, 280);

// ==================================================
// LEFT AREA: WEATHER INFO
// ==================================================
// Calculate the center X-coordinate of the left area for alignment
const int left_center_x = center_x / 2; // 200

// 1. Display the title "Weather" at the top of the left area
it.printf(left_center_x, 110, id(mid_font), TextAlign::TOP_CENTER, "Weather");

// 2. Get the weather condition and select the corresponding icon
std::string weather_condition = id(myWeather).state;
std::string weather_icon = "\U000F0599"; // Default icon (sunny), as a fallback for unknown states

if (weather_condition == "partlycloudy") {
weather_icon = "\U000F0595"; // weather-partly-cloudy
} else if (weather_condition == "cloudy") {
weather_icon = "\U000F0F2F"; // weather-cloudy
} else if (weather_condition == "rainy") {
weather_icon = "\U000F0597"; // weather-rainy
} else if (weather_condition == "snowy") {
weather_icon = "\U000F0598"; // weather-snowy
} else if (weather_condition == "windy") {
weather_icon = "\U000F059B"; // weather-windy
} else if (weather_condition == "fog") {
weather_icon = "\U000F0594"; // weather-fog
} else if (weather_condition == "lightning") {
weather_icon = "\U000F0596"; // weather-lightning
}
// Display the weather icon in the center of the left area
it.printf(left_center_x, 240, id(weather_icon_font), TextAlign::CENTER, "%s", weather_icon.c_str());

// 3. Display the weather condition text below the icon
it.printf(left_center_x, 400, id(mid_font), TextAlign::BOTTOM_CENTER, "%s", weather_condition.c_str());


// ==================================================
// RIGHT AREA: TEMPERATURE INFO
// ==================================================
// Calculate the center X-coordinate of the right area for alignment
const int right_center_x = center_x + (center_x / 2); // 600

// 1. Display the title "Temperature" at the top of the right area
it.printf(right_center_x, 110, id(mid_font), TextAlign::TOP_CENTER, "Temperature");

// 3. Display the temperature reading below the icon, with one decimal place
float temp_c = stof(id(temp).state);
double temp_f = temp_c * 9.0 / 5.0 + 32.0;
it.printf(right_center_x, 250, id(mid_font), TextAlign::CENTER, "%.0f°F", temp_f);
it.printf(right_center_x, 380, id(mid_font), TextAlign::CENTER, "%.1f°C", temp_c);
}
// ---------- PAGE 1 ----------
else{
// Battery top-right
it.printf(670, 13, id(font_bat_icon), "%s", id(battery_glyph).c_str());
it.printf(700, 10, id(small_font), "%.0f%%", id(battery_level).state);

auto now = id(ha_time).now();
struct tm timeinfo = now.to_c_tm();

// centering time HH:MM
char timeStr[6];
strftime(timeStr, sizeof(timeStr), "%H:%M", &timeinfo);
it.printf(400, 180, id(time_font), TextAlign::CENTER, timeStr);

// Date: Day of week
const char *weekday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
const char *wday = weekday[timeinfo.tm_wday];

// Date: month - day
char dateStr[12];
strftime(dateStr, sizeof(dateStr), "%b %d", &timeinfo); // e.g. Jun 15

// Day of the week + date below the time
it.printf(400, 280, id(mid_font), TextAlign::CENTER, "%s, %s", wday, dateStr);
}

次の画像のようなフィードバックが表示されたら、コードは正常に実行されています。

FAQ

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

この場合、Settings -> Devices & Services -> Integrations に移動してデバイスをRECONGFIGUREする必要があります。ePaper Penal が見つかりませんか?HA を再起動してみてください。

Q2: なぜ Home Assistant でこれらのデータを取得できないのですか?

この場合、Settings -> Devices & Services -> Integrations に移動して、デバイスを HA にADDする必要があります。

Q3: デバイスがディープスリープモードのときに、新しいプログラムをどのようにアップロードできますか?

デバイスがディープスリープモードのときは、新しいプログラムを直接アップロードすることはできません。

  1. まず、デバイスの電源が入っていることを確認します。その後、XIAO ESP32-S3 Plus の USB-C ポートの横にある Boot ボタンを押し続けます。

  2. Boot ボタンを押し続けたまま、Reset ボタンを 1 回押し、その後 Boot ボタンを離します。

  3. その後、バッテリースイッチをオフにし、電源ケーブルを抜きます。

  4. 最後に、ケーブルを再接続して新しいプログラムをアップロードします。

Q4: TRMNL 7.5inch(OG) DIY Kit がコンピュータに接続できませんか?

何度か抜き差ししてみるか、表示される指示に従ってドライバをインストールしてみてください。

Q5: Wi-Fi 経由でのプログラムアップロードに失敗しますか?

この場合、epaper penal がオフラインであるか、ディープスリープモードになっています。オンラインにするか、スリープを解除してください。

技術サポート & 製品ディスカッション

当社の製品をお選びいただきありがとうございます。私たちは、製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに合わせて選べる、複数のコミュニケーションチャネルをご用意しています。

Loading Comments...