Skip to main content

ESPHome Cookbook:TRMNL 7.5" (OG) DIY Kit

请先阅读主 ESPHome 指南

本页是针对 TRMNL DIY Kit 的 ESPHome cookbook。通用的基础内容——选择刷写路径、通用 YAML 模板、连接 Home Assistant——都在 Work with ESPHome 中。如果你是第一次在 Seeed 电子纸上使用 ESPHome,建议先快速浏览那一页。若你在寻找的是TRMNL 云端仪表盘工作流(无需 YAML、基于插件),请查看 Work with TRMNL。


Home Assistant 简介​

Home Assistant 是一个功能强大的开源家庭自动化平台,可让你通过一个统一的界面控制和监控智能家居设备。它充当智能家居的中央枢纽,使你能够自动化日常流程、监控传感器,并打造更智能的居住空间。

为什么选择 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. 超长续航:配合深度睡眠模式,显示屏在单次电池充电后即可运行数月,同时仍能一眼提供有价值的信息。

  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 通信以及控制电子纸显示屏等所有复杂任务。结合 Home Assistant,ESPHome 为创建复杂的家庭自动化显示与控制界面提供了一个强大的平台。

下面我们来看看如何进行设置,并充分发挥这块多功能显示屏的潜力。

入门指南​

在开始阅读本教程的具体内容之前,你需要准备好以下硬件。

所需材料​

TRMNL 7.5inch(OG) DIY KitHome Assistant Green

Home Assistant Green 是自动化家庭的最简单、最注重隐私的方式。它提供了极其简便的安装流程,并允许你通过一个系统控制所有智能设备,且所有数据默认都本地存储。该主板受益于蓬勃发展的 Home Assistant 生态系统,并将通过开源社区在每个月持续改进。

我们推荐在本教程中使用 Home Assistant Green 作为 Home Assistant 主机,当然你也可以使用任何带 Supervisor 的 Home Assistant 主机。

安装 Home Assistant

我们也为部分 Seeed Studio 产品编写了 Home Assistant 的安装教程,请参考以下内容。

如果你没有使用 Seeed Studio 的产品,也可以在 Home Assistant 官方网站上查看并学习其他产品的 Home Assistant 安装方法。

设备安装​

步骤 1. 将显示屏连接到驱动板
将 FPC 线缆与 XIAO 电子纸显示板上的连接器对齐,然后扣上卡扣以确保连接牢固。

tip

FPC 线缆的金属面应朝上,否则将不会显示任何内容。

请按照下面的安装教程操作,很多人都会装错。

步骤 2. 连接电池
将电池线缆连接到驱动板上的 JST 接口,确保极性正确(红线接 +,黑线接 -)。

步骤 3. 外壳组装(可选)

tip

请注意,屏幕的软排线非常脆弱,操作时务必小心。如果损坏,整个屏幕将无法工作。

从 Resource part 打印开源外壳部件,并将组件装入其中。

首先,组装驱动板和电池。

测试 TRMNL 套件是否工作正常。

将屏幕插入外壳,并让 FPC 线缆能够伸出。

连接 FPC 延长线并组装整个外壳。

L 型外壳的组装方式也非常相似。

tip

如果你的 TRMNL 套件离路由器较远,可以将天线移到外壳外面,这样性能会更好。

步骤 1. 安装 ESPHome​

如果你已经安装了 ESPHome,可以跳过此步骤。

进入 Settings -> Add-ons -> ADD-ON STORE

搜索 ESPHome 并点击它。然后点击 INSTALL 和 START。

tip

如果你在插件商店中找不到 ESPHome,请确保你使用的是支持插件的 Home Assistant 安装方式(例如 Home Assistant OS 或 supervised 安装)。对于其他安装类型(例如 Home Assistant Container),你可能需要使用 Docker 独立运行 ESPHome Device Builder。更多详情请参阅 官方 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 将代码安装到设备上,你会看到如下图所示的画面。

tip

如果你的 Home Assistant 主机(Raspberry PI/Green/Yellow 等)离你比较远,我们推荐使用这种方式。你可以使用手边的电脑来安装。

首先,你需要点击 Manual download 下载编译好的固件。

打开这个网站,我们将在这里把固件上传到 ePaper 面板。

回到 ESPHome 下载固件。

选择 Factory 格式。

使用 USB 线 将 ePaper 面板连接到你的电脑,然后点击 CONNECT。

选择 usbmodemxxx(Windows 为 COMxxx)并点击连接。遇到问题?点击这里。

点击 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 中看到该设备。

然后,点击 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: 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 获取天气、温度和气压,并将它们显示在屏幕上。

tip

如果你发现你的 Home Assistant 中没有与天气相关的组件,可以在集成中下载一个名为 Open-Meteo 的集成。

当你看到如下图所示的反馈时,说明代码已成功运行。

3. 显示图标​

本示例将在屏幕上显示图标。

首先,我们需要安装一个文件编辑器附加组件。搜索 Studio Code Server 并点击它。点击 INSTALL 和 START。

接着然后,创建一个名为 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。

请参照下一步创建一个 token 并粘贴到这里。

进入Security page页面底部创建一个 token,然后将其复制并粘贴到 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. 深度睡眠模式​

tip

在深度睡眠模式下,你无法直接向设备上传代码。你需要进入下载模式。点击此处跳转到 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));

你会看到一个计数器。每次设备唤醒时,它都会加一。

示例 3. 综合示例​

tip

为了让你更好地理解,我们强烈建议你先运行上面的基础用法示例。

本示例展示了适用于 TRMNL 7.5 英寸电子纸 DIY 套件的完整 ESPHome 配置。该 YAML 代码集成了多种功能,用于创建一个与 Home Assistant 无缝协作的智能交互式显示面板。

目的与功能:

  • 该配置使设备能够连接到 Wi-Fi 和 Home Assistant,并支持 API 和 OTA 更新,便于管理。

  • 它将电子纸显示屏设置为通过物理按键控制的两个可切换页面,用于显示不同类型的信息。

  • 设备读取电池电压,计算电池电量百分比,并显示相应的电池图标和数值。

  • 从 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);
}

当你看到如下图所示的反馈时,表示代码已成功运行。

常见问题​

Q1:为什么没有数据?​

在这种情况下,你需要前往 Settings -> Devices & Services -> Integrations 来**重新配置(RECONGFIGURE)**设备。还没有找到你的 ePaper Penal?尝试重启 HA。

Q2:为什么我在 Home Assistant 中获取不到这些数据?​

在这种情况下,你需要前往 Settings -> Devices & Services -> Integrations,将你的设备**添加(ADD)**到 HA 中。

Q3:设备处于深度睡眠模式时,如何上传新程序?​

当设备处于深度睡眠模式时,你无法直接上传新程序。

  1. 首先,确保设备已开启。然后,按住位于 XIAO ESP32-S3 Plus 上 USB-C 接口旁边的 Boot 按钮。

  2. 在按住 Boot 按钮的同时,按一下 Reset 按钮,然后松开 Boot 按钮。

  3. 之后,关闭电池开关并拔掉电源线。

  4. 最后,重新插上电源线并上传新程序。

Q4:TRMNL 7.5inch(OG) DIY Kit 无法连接到你的电脑?​

尝试多次拔插,或者根据提示安装驱动程序。

Q5:通过 Wi-Fi 上传程序失败?​

在这种情况下,你的 epaper penal 处于离线或深度睡眠模式。请让它重新上线或将其唤醒。

技术支持与产品讨论​

感谢你选择我们的产品!我们将为你提供多种支持,以确保你在使用我们产品的过程中尽可能顺利。我们提供多种沟通渠道,以满足不同的偏好和需求。

Loading Comments...