Skip to main content

Home Assistant における ePaper パネル

note

この文書は AI によって翻訳されています。内容に不正確な点や改善すべき点がございましたら、文書下部のコメント欄または以下の Issue ページにてご報告ください。
https://github.com/Seeed-Studio/wiki-documents/issues


ハードウェア概要

概要

XIAO ESP32C3 搭載の 7.5 インチ E-Ink ディスプレイは、Home Assistant データを表示するためのコンパクトで省エネルギーなソリューションです。シームレスな統合と鮮明なビジュアルを備え、スマートホームに最適です。また、Arduino にも対応しており、簡単にカスタマイズ可能です。低消費電力で、どのような光環境でも優れた視認性を提供します。この多用途なディスプレイでスマートホームのセットアップを簡素化しましょう。

特徴

  1. 省エネルギー型 E-Ink スクリーン: 低消費電力で、直射日光下でも優れた視認性を提供します。
  2. シームレスな統合: Home Assistant や Arduino と簡単に統合でき、カスタマイズが可能です。
  3. コンパクトなデザイン: スマートホームアプリケーションに最適なコンパクトサイズ。
  4. ユーザーフレンドリーなセットアップ: 初心者から上級者まで簡単に設定して使用できます。
  5. 耐久性と信頼性: 高品質なコンポーネントで構築され、長期間の使用に耐えます。

仕様

項目説明
MCUXIAO ESP32 C3
ディスプレイ7.5 インチ ePaper ディスプレイ
解像度800x480
バッテリー2000mAh
寸法178x131x19mm
重量218g
動作温度-40°C ~ 85°C
動作電圧3.3V ~ 5V

ソフトウェア概要

Home Assistant での使用方法

ステップ 1. ESPHome のインストール

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

設定 -> アドオン -> ADD-ON STORE に移動します。

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

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

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

ESPHome に移動し、NEW DEVICE をクリックします。

好きな名前をデバイスに付けて、NEXT をクリックします。

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

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

これは非常に基本的な例で、ディスプレイに「Hello World!」を表示します。

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

ESPHome をインストールし、新しいデバイスを追加した後、以下のコードをコピーして captive_portal 部分に貼り付けます。

コードをコピーするにはここをクリックしてください。

# 表示する文字のフォントを定義
font:
- file: "gfonts://Inter@700"
id: font1
size: 24

# SPI インターフェースを定義
spi:
clk_pin: GPIO8
mosi_pin: GPIO10

display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin: GPIO4
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
it.print(0, 0, id(font1), "Hello World!");

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

tip

Home Assistant ホスト (Raspberry PI/Green/Yellow など) が遠くにある場合、この方法をお勧めします。手元のコンピュータでインストールできます。

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

ファームウェアを ePaper パネルにアップロードするためのウェブサイトを開きます。

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

工場出荷時のフォーマットを選択します。

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

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

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

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

ステップ4. 基本的な使用法

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: GPIO4
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 部分に貼り付けます。以下の画像を参考にしてください。

コードをコピーするにはここをクリック
# 情報を表示するためのフォントを定義
font:
- file: "gfonts://Inter@700"
id: myFont
size: 24

# HA から情報を取得(文字列形式)
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

# HA から情報を取得(浮動小数点形式)
sensor:
- platform: homeassistant
entity_id: weather.forecast_home
id: myPressure
attribute: "pressure"
internal: true

# SPI を介して情報を表示
spi:
clk_pin: GPIO8
mosi_pin: GPIO10

display:
- platform: waveshare_epaper
cs_pin: GPIO3
dc_pin: GPIO5
busy_pin: GPIO4
reset_pin: GPIO2
model: 7.50inv2
update_interval: 30s
lambda: |-
// ログに情報を出力
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);
// eペーパー画面に情報を表示
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 を検索してクリックします。INSTALLSTART をクリックします。

次に、新しいフォルダを作成し、fonts と名付けます。このファイルをダウンロードして fonts フォルダに配置します。

ESPHome ファイルに戻り、以下のコードをコピーして captive_portal 部分に貼り付けます。

コードをコピーするにはここをクリック
font:
- file: 'fonts/materialdesignicons-webfont.ttf' # ttf ファイルを保存するディレクトリ
id: font_mdi_large
size: 200 # 大きなサイズのアイコン
glyphs: &mdi-weather-glyphs
- "\U000F0595" # 曇りの天気
- "\U000F0592" # 雹の天気
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medium # 小さなサイズのアイコン
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: GPIO4
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. 画像を表示する

この例では、ディスプレイに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(私のアドレス)

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リスト ページのスクリーンショットも取得できます:

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

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

その後、以下のコードをコピーして 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 #このリンクをスクリーンショットリンクに変更してください
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: GPIO4
reset_pin: GPIO2
model: 7.50inv2
update_interval: never
lambda: |-
it.image(0, 0, id(dashboard_image));

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

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

この例では、ディープスリープモードを使用して電力を節約する方法を示します。情報は6時間ごとに更新されます。2000mAhのバッテリーで約3か月間動作可能です。

以下のコードをコピーして、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: GPIO4
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ずつ増加します。

ステップ5:総合的な例

この例では、HA(Home Assistant)から天気情報とカレンダー情報を取得し、それらをディスプレイに表示する方法を紹介します。さらに、ディープスリープモードを使用して電力を節約します。情報は6時間ごとに更新され、2000mAhのバッテリーで約3か月間動作可能です。

まず、HAに天気コンポーネントがあるかどうかを確認する必要があります。通常、HAをインストールすると自動的に1つ追加されます。

また、開発者ツール → ステータス(STATES) に移動して、HAに天気情報があるかどうかを確認することもできます。以下は、後で取得する情報の一例です。

次に、HAにカレンダーコンポーネントをインストールする必要があります。

設定 → デバイスとサービス → 統合 → 統合を追加 に進んでください。

ローカルカレンダー(Local Calendar) を選択し、送信(SUBMIT) ボタンをクリックしてください。

その後、「構成済み(Configured)」の部分とサイドバーにローカルカレンダーが表示されるようになります。

サイドバーの「カレンダー(Calendar)」をクリックし、新しく3つのカレンダーを作成してください。名前は calenderepaper_eventnew_calendar にします。別の名前を使用しても構いませんが、後でコード内で同じ名前を使用するようにしてください。

コードをコピーするにはこちらをクリックしてください。

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.calender
attribute: "message"
- platform: homeassistant
id: ha_calendar_start_time_1
entity_id: calendar.calender
attribute: "start_time"
- platform: homeassistant
id: ha_calendar_end_time_1
entity_id: calendar.calender
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_calender
attribute: "message"
- platform: homeassistant
id: ha_calendar_start_time_3
entity_id: calendar.new_calender
attribute: "start_time"
- platform: homeassistant
id: ha_calendar_end_time_3
entity_id: calendar.new_calender
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: GPIO4
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: なぜデータが表示されないのですか?

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

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

この場合、設定 -> デバイスとサービス -> 統合に移動して、デバイスを追加(ADD)する必要があります。

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

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

  1. まず、デバイスがオンになっていることを確認し、基板の背面にあるBootボタンを押します。

  2. Resetボタンを1回クリックしてからBootボタンを離します。

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

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

Q4: バッテリーはどのくらい持ちますか?

tip

充電時にはバッテリーボタンをオンにすることを忘れないでください。そうしないと、バッテリーは充電されません。

テストの結果、6時間ごとに画面をリフレッシュすると、ディープスリープモードでバッテリーは約3か月持続します。

Q5: ePaperパネルがコンピュータに接続できませんか?

数回抜き差ししてみるか、プロンプトに従ってドライバーをインストールしてください。

Q6: Wi-Fi経由でのプログラムアップロードが失敗しましたか?

この場合、ePaperパネルがオフラインまたはディープスリープモードになっています。オンラインにするか、スリープを解除してください。

リソース

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

弊社製品をお選びいただきありがとうございます!お客様が弊社製品をスムーズにご利用いただけるよう、さまざまなサポートを提供しております。異なる好みやニーズに対応するため、複数のコミュニケーションチャネルをご用意しています。

Loading Comments...