Dans un tutoriel précédent, je vous expliquais comment créer un capteur de température Zigbee à base d’ESP32C6 et comment l’intégrer dans Home Assistant.
Dans ce nouveau tutoriel, je vous guide pour intégrer un écran à encre électronique (e-paper) Seeed Studio reTerminal E1002 dans Home Assistant, afin d’y afficher les données issues de ce capteur.
Nous utiliserons le framework ESPHome, qui facilite grandement l’intégration de l’écran reTerminal dans Home Assistant via une configuration simple en YAML. Cette configuration permet de décrire précisément les périphériques connectés au microcontrôleur ESP32-S3 (écran, boutons, buzzer, LED, etc.), ainsi que les actions à exécuter localement. ESPHome compile ensuite ce fichier YAML pour générer un firmware qui sera téléversé sur le reTerminal.
Présentation du reTerminal
Le reTerminal E1002 est un appareil prêt à l’emploi doté d’un boîtier métallique robuste abritant un écran e-paper couleur de 7.3″ d’une résolution de 800×480. Il est équipé d’un microcontrôleur ESP32-S3 et il intègre 3 boutons, un buzzer, une LED de status (en plus de la LED d’alimentation), un capteur de température et de pression, un microphone et un lecteur de carte MicroSD. Il est alimenté par une batterie interne de 2000 mAh offrant jusqu’à 3 mois d’autonomie.
Les caractéristiques détaillées du reTerminal E1002 ainsi que son guide de démarrage rapide sont disponibles sur le wiki de Seeed Studio et la version avancée du wiki.





Mise à jour du firmware du reTerminal
Il est recommandé d’installer le dernier firmware disponible dès la première mise en service de votre appareil. Après avoir créé votre compte utilisateur sur le site sensecraft.seeed.cc, connectez votre reTerminal à un port USB de votre ordinateur, puis utilisez l’outil Device Flasher pour flasher le firmware le plus récent.

Dans ce tutoriel, SenseCraft HMI ne sera pas utilisé : il n’est donc pas nécessaire de suivre la procédure affichée sur l’écran du reTerminal, ni de se connecter au point d’accès Wi-Fi qu’il diffuse. L’objectif ici est de faire fonctionner le reTerminal avec Home Assistant, en le configurant directement via le framework ESPHome.
Configuration du reTerminal avec ESPHome
Installer le module complémentaire ESPHome Device Builder sur votre serveur Home Assistant puis le démarrer.

Dans le module ESPHome Builder, ajoutez le reTerminal comme nouvel appareil de type ESP32-S3. Étant donné que le reTerminal n’est pas encore configuré pour rejoindre le réseau Wi-Fi et que Home Assistant fonctionne en HTTP (et non HTTPS), le téléversement direct du firmware n’est pas possible depuis ESPHome Builder. Utilisez alors l’option Manual Download pour récupérer le firmware compilé au format Factory format (Previously Modern).




Note: l’installation des outils et la compilation du firmware peuvent être relativement longues si Home Assistant est hébergé sur un Raspberry Pi, notamment sur les modèles moins puissants. Il n’est pas rare d’attendre plusieurs minutes pour chaque compilation.
Téléversez ensuite ce fichier .bin sur le reTerminal à l’aide de l’outil en ligne ESPHome. Après ce premier flashage, le reTerminal rejoindra votre réseau Wi-Fi. Par la suite, il sera possible d’effectuer les futures mises à jour du firmware directement depuis Home Assistant via le Wi-Fi, sans nécessiter de connexion filaire.



Hello World!
Nous allons maintenant créer un exemple pour vous permettre de comprendre le principe de ESPHome et la configuration du reTerminal. Dans cet exemple, nous allons simplement afficher le message Hello World! sur l’écran du reTerminal.
Dans le module ESPHome Builder, cliquer sur Edit afin de pouvoir modifier la configuration YAML pour que le reTerminal affiche notre message.


L’écran du reTerminal E1002 de Seeed Studio est une dalle E Ink® Spectra™ 6 couleur de 7,3 pouces avec une résolution de 800×480 pixels. Comme vous pouvez le voir sur le schéma du reTerminal, l’ESP32-S3 communique avec l’écran au travers d’un bus SPI via les broches suivantes :
- SPI Clock (CLK) : GPIO 7
- Master In Slave Out (MISO) : GPIO8 (non utilisé par l’écran mais uniquement par le lecteur de carte microSD qui est sur le même bus SPI)
- Master Out Slave In (MOSI) : GPIO9
- Chip Select (CS) : GPIO10
- Data/Command (DC) : GPIO11
- Reset (RST) : GPIO12
Voici la configuration qui affiche le message « Hello Worlds! » en bleu, avec la police Google Inter 700 et une taille de 36 points. Vous pouvez utiliser cet exemple en copiant le code ci-dessous et en le collant juste après la ligne captive_portal dans votre fichier YAML.
captive_portal:
# define font to display words
font:
- file: "gfonts://Inter@700"
id: myFont
size: 36
# define SPI interface
spi:
clk_pin: GPIO7
mosi_pin: GPIO9
display:
- platform: epaper_spi
id: epaper_display
model: 7.3in-spectra-e6
cs_pin: GPIO10
dc_pin: GPIO11
reset_pin:
number: GPIO12
inverted: false
busy_pin:
number: GPIO13
inverted: true
update_interval: 300s
lambda: |-
const auto BLUE = Color(0, 0, 255, 0);
it.print(0, 0, id(myFont), BLUE, "Hello World!"); Sur un écran e-paper, il est essentiel de rafraîchir régulièrement (au moins une fois par jour) l’affichage afin d’éviter les effets de rémanence caractéristiques de cette technologie. Dans la configuration ci-dessus, l’affichage est rafraîchi toutes les 300 secondes (5 minutes) via la configuration update_interval: 300s
Il suffit ensuite de cliquer sur Install et de choisir l’option Wirelessly pour téléverser le firmware correspondant à cette configuration YAML dans le reTerminal via votre réseau Wi-Fi (qui a été configuré lors du premier téléversement via ESPHome).

Après compilation et téléversement, le reTerminal affiche bien le message Hello World! en bleu sur son écran.

Capteur de température et d’humidité interne au reTerminal
Le reTerminal possède un capteur interne de température et d’humidité STH40.
L’ESP32-S3 communique avec ce capteur au travers d’un bus I2C. Son adresse I2C est 0x44, et le bus I2C utilise les broches suivantes :
- Serial Data (SDA) : GPIO19
- Serial Clock (SCL) : GPIO20
Voici la configuration YAML qui permet de récupérer la température et l’humidité depuis ce capteur et de l’afficher sur l’écran, à copier juste après la ligne captive_portal dans votre fichier YAML :
captive_portal:
# define I2C interface
i2c:
sda: GPIO19
scl: GPIO20
scan: false
# temperature and humidity sensor
sensor:
- platform: sht4x
temperature:
name: "Temperature"
id: sht4x_temperature
humidity:
name: "Humidity"
id: sht4x_humidity
on_value:
then:
- component.update: epaper_display
address: 0x44
update_interval: 60s
# define font to display words
font:
- file: "gfonts://Inter@700"
id: myFont
size: 36
# define SPI interface
spi:
clk_pin: GPIO7
mosi_pin: GPIO9
display:
- platform: epaper_spi
id: epaper_display
model: 7.3in-spectra-e6
cs_pin: GPIO10
dc_pin: GPIO11
reset_pin:
number: GPIO12
inverted: false
busy_pin:
number: GPIO13
inverted: true
update_interval: never
lambda: |-
const auto BLUE = Color(0, 0, 255, 0);
it.printf(10, 10, id(myFont), BLUE, "Temperature: %.1f°C", id(sht4x_temperature).state);
it.printf(10, 40, id(myFont), BLUE, "Humidity: %.1f%%", id(sht4x_humidity).state); Il est préférable de rafraîchir l’écran qu’une fois la lecture du capteur finalisée. Pour cela, j’utilise le paramètre on_value dans la configuration du capteur SHT4X. Ce paramètre permet de déclencher le rafraîchissement de l’écran à chaque nouvelle valeur reçue du capteur. Par conséquent, le paramètre update_interval de l’écran est configuré sur never afin d’éviter un rafraîchissement automatique indépendant des données du capteur.
Le reTerminal affichera sur son écran la température et l’humidité mesurées par son capteur interne toutes les 60 secondes.

Grâce à ESPHome, il est possible d’afficher les données issues du reTerminal dans Home Assistant.



Affichage des données d’un capteur externe sur l’écran du reTerminal
Il est parfaitement possible d’afficher n’importe quelle entité de Home Assistant sur l’écran du reTerminal. Comme mentionné au début de ce tutoriel, nous allons afficher sur l’écran du reTerminal, la température et l’humidité mesurée par le capteur Zigbee externe à base d’ESP32-C6 que j’ai conçu dans mon tutoriel précédent.
La température et l’humidité mesurées par ce capteur externe correspondent aux entité d’ID suivantes dans Home Assistant :
- sensor.tutoduino_esp32c6tempsensor_temperature
- sensor.tutoduino_esp32c6tempsensor_humidite

Voici le code à copier juste après la ligne captive_portal dans votre fichier YAML :
captive_portal:
# define I2C interface
i2c:
sda: GPIO19
scl: GPIO20
scan: false
sensor:
# internal temperature and humidity sensor
- platform: sht4x
temperature:
name: "Temperature"
id: sht4x_temperature
humidity:
name: "Humidity"
id: sht4x_humidity
on_value:
then:
- component.update: epaper_display
address: 0x44
update_interval: 60s
# external EP32C6 sensor
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_temperature
entity_id: sensor.tutoduino_esp32c6tempsensor_temperature
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_humidite
entity_id: sensor.tutoduino_esp32c6tempsensor_humidite
# define font to display words
font:
- file: "gfonts://Inter@700"
id: myFont
size: 36
- file: "gfonts://Inter@700"
id: myFontLarge
size: 50
- file: "gfonts://Inter@700"
id: myFontVeryLarge
size: 70
# define SPI interface
spi:
clk_pin: GPIO7
mosi_pin: GPIO9
display:
- platform: epaper_spi
id: epaper_display
model: 7.3in-spectra-e6
cs_pin: GPIO10
dc_pin: GPIO11
reset_pin:
number: GPIO12
inverted: false
busy_pin:
number: GPIO13
inverted: true
update_interval: never
lambda: |-
const auto BLUE = Color(0, 0, 255, 0);
const auto GREEN = Color(0, 255, 0, 0);
const auto BLACK = Color(0, 0, 0, 0);
it.line(400, 0, 400, 480, BLACK);
it.printf(130, 15, id(myFont), BLACK, "INDOOR");
it.printf(510, 15, id(myFont), BLACK, "OUTDOOR");
if (isnan(id(sht4x_temperature).state)) {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "--.-°C");
} else {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "%.1f°C", id(sht4x_temperature).state);
}
if (isnan(id(sht4x_humidity).state)) {
it.printf(120, 250, id(myFontLarge), BLUE, "--.-%%");
} else {
it.printf(120, 250, id(myFontLarge), BLUE, "%.1f%%", id(sht4x_humidity).state);
}
if (isnan(id(tutoduino_esp32c6tempsensor_temperature).state)) {
it.printf(500, 120, id(myFontVeryLarge), GREEN, "--.-°C");
} else {
it.printf(500, 120, id(myFontVeryLarge), GREEN, "%.1f°C", id(tutoduino_esp32c6tempsensor_temperature).state);
}
if (isnan(id(tutoduino_esp32c6tempsensor_humidite).state)) {
it.printf(540, 250, id(myFontLarge), GREEN, "--.-%%");
} else {
it.printf(540, 250, id(myFontLarge), GREEN, "%.1f%%", id(tutoduino_esp32c6tempsensor_humidite).state);
}Cette configuration affiche les données du capteur interne au reTerminal dans la partie INDOOR et les données issues du capteur externe dans la partie OUTDOOR.

Affichage de la charge des batteries
Mon capteur externe à base d’ESP32-C6 et le reTerminal étant tous les deux alimentés par batterie, il est utile de pouvoir afficher leur niveau sur l’écran.
Pour récupérer le niveau de batterie du reTerminal, il faut activer la mesure de la tension de la batterie en configurant le GPIO21 (VBAT ENABLE). La lecture s’effectue ensuite sur le GPIO1 (VBAT ADC), qui est relié en interne à la batterie via un circuit de mesure. En lisant la valeur analogique (tension) sur ce GPIO1, il est possible d’obtenir une estimation précise du niveau de charge de la batterie.
Concernant le niveau de la batterie du capteur externe, elle est simplement récupérée via l’entité Home Assistant sensor.tutoduino_esp32c6tempsensor_batterie.
Voici la configuration qui permet de récupérer le niveau de la batterie du reTerminal ainsi que celle du capteur de température externe.
esphome:
name: reterminal
friendly_name: reTerminal
on_boot:
priority: 600
then:
- output.turn_on: bsp_battery_enable
- delay: 500ms
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "XXXX"
ota:
- platform: esphome
password: "XXXX"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Reterminal Fallback Hotspot"
password: "XXXX"
captive_portal:
output:
- platform: gpio
pin: GPIO21
id: bsp_battery_enable
# define I2C interface
i2c:
sda: GPIO19
scl: GPIO20
scan: false
sensor:
# internal temperature and humidity sensor
- platform: sht4x
temperature:
name: "Temperature"
id: sht4x_temperature
humidity:
name: "Humidity"
id: sht4x_humidity
address: 0x44
update_interval: 60s
# external EP32C6 sensor
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_temperature
entity_id: sensor.tutoduino_esp32c6tempsensor_temperature
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_humidite
entity_id: sensor.tutoduino_esp32c6tempsensor_humidite
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_batterie
entity_id: sensor.tutoduino_esp32c6tempsensor_batterie
# ADC for battery voltage measurement
- platform: adc
pin: GPIO1
name: "Battery Voltage"
id: battery_voltage
on_value:
then:
- component.update: battery_level
update_interval: 60s
attenuation: 12db
filters:
- multiply: 2.0 # Voltage divider compensation
# Template to display battery level in %
- 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: never
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
# define font to display words
font:
- file: "gfonts://Inter@700"
id: mySmallFont
size: 15
- file: "gfonts://Inter@700"
id: myFont
size: 36
- file: "gfonts://Inter@700"
id: myFontLarge
size: 50
- file: "gfonts://Inter@700"
id: myFontVeryLarge
size: 70
- file: 'fonts/MaterialDesignIconsDesktop.ttf'
id: font_mdi_large
size: 50
glyphs:
- "\U000F050F" # thermometer
- "\U000F058E" # humidity
- file: 'fonts/MaterialDesignIconsDesktop.ttf'
id: font_bat_icon
size: 50
glyphs:
- "\U000F0079" # mdi-battery
# define SPI interface
spi:
clk_pin: GPIO7
mosi_pin: GPIO9
display:
- platform: epaper_spi
id: epaper_display
model: 7.3in-spectra-e6
cs_pin: GPIO10
dc_pin: GPIO11
reset_pin:
number: GPIO12
inverted: false
busy_pin:
number: GPIO13
inverted: true
update_interval: 60s
lambda: |-
const auto BLUE = Color(0, 0, 255, 0);
const auto GREEN = Color(0, 255, 0, 0);
const auto BLACK = Color(0, 0, 0, 0);
const auto RED = Color(255, 0, 0, 0);
it.line(400, 0, 400, 480, BLACK);
it.printf(130, 15, id(myFont), BLACK, "INDOOR");
it.printf(510, 15, id(myFont), BLACK, "OUTDOOR");
it.printf(60, 165, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F050F");
if (isnan(id(sht4x_temperature).state)) {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "--.-°C");
} else {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "%.1f°C", id(sht4x_temperature).state);
}
it.printf(60, 283, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F058E");
if (isnan(id(sht4x_humidity).state)) {
it.printf(90, 250, id(myFontLarge), BLUE, "--.-%%");
} else {
it.printf(90, 250, id(myFontLarge), BLUE, "%.1f%%", id(sht4x_humidity).state);
}
it.printf(60, 390, id(font_bat_icon), BLACK, TextAlign::CENTER, "\U000F0079");
if (isnan(id(battery_level).state)) {
it.printf(90, 360, id(myFontLarge), BLUE, "--%%");
} else {
it.printf(90, 360, id(myFontLarge), BLUE, "%2.0f%%", id(battery_level).state);
}
it.printf(470, 165 , id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F050F");
if (isnan(id(tutoduino_esp32c6tempsensor_temperature).state)) {
it.printf(500, 120, id(myFontVeryLarge), BLUE, "--.-°C");
} else {
it.printf(500, 120, id(myFontVeryLarge), BLUE, "%.1f°C", id(tutoduino_esp32c6tempsensor_temperature).state);
}
it.printf(470, 283, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F058E");
if (isnan(id(tutoduino_esp32c6tempsensor_humidite).state)) {
it.printf(500, 250, id(myFontLarge), BLUE, "--.-%%");
} else {
it.printf(500, 250, id(myFontLarge), BLUE, "%.1f%%", id(tutoduino_esp32c6tempsensor_humidite).state);
}
it.printf(470, 390, id(font_bat_icon), BLACK, TextAlign::CENTER, "\U000F0079");
if (isnan(id(tutoduino_esp32c6tempsensor_batterie).state)) {
it.printf(500, 360, id(myFontLarge), BLUE, "--%%");
} else {
it.printf(500, 360, id(myFontLarge), BLUE, "%2.0f%%", id(tutoduino_esp32c6tempsensor_batterie).state);
}Ajout des icônes
Pour ajouter les icônes de thermomètre, d’hygromètre et de batterie, il faut créer le répertoire fonts dans le répertoire esphome (avec le module complémentaire File editor) et y ajouter le fichier de font suivant : MaterialDesignIconsDesktop.ttf

Voici le rendu des icônes sur l’écran du reTerminal E1002, mais n’hésitez pas à les adapter à vos besoins.

Mode veille
Afin d’économiser la batterie du reTerminal entre 2 rafraîchissements de son écran, il est possible de mettre son microcontrôleur ESP32-S3 en veille profonde. C’est très simple avec ESPHome, il suffit de configurer la durée de la veille profonde via le paramètre sleep_duration ainsi que la durée d’activité en sortie de veille via le paramètre run_duration dans la configuration deep_sleep.
Afin de pouvoir réveiller le microcontrôleur lorsqu’il est en veille profonde, il est possible de configurer un événement (temporisation, changement d’état d’une broche…). Ici je configure l’appui sur le bouton vert du reTerminal (GPIO3) comme événement qui le fera sortir du mode veille.
# Deep sleep configuration to save power
deep_sleep:
id: deep_sleep_1
run_duration: 30s # Active time after wake-up
sleep_duration: 10min # Sleep duration between wake-ups
wakeup_pin: GPIO3 # External pin to wake up device
wakeup_pin_mode: INVERT_WAKEUP # Inverted wake-up logicEn sortie du mode veille profonde, le microcontrôleur redémarre comme si il venait d’être allumé. C’est un point important car cela impacte fortement la façon dont il faut lire les capteurs et rafraîchir l’écran avant de retourner en mode veille. Il faut être attentif car plusieurs problèmes potentiels se présentent :
- Le capteur interne SHT4X n’est pas encore prêt au démarrage et ne retourne pas de donnée et ainsi retourne nan (not a number).
- Le Wi-Fi n’est pas encore initialisé au démarrage et les données du serveur Home Assistant ne sont pas disponibles au démarrage et ainsi retournent nan.
Lorsque la lecture des capteurs est cyclique (update_interval: 60s) cela ne pose pas de problème, car ces données sont bien disponibles lors du second cycle (après 60 secondes). Mais il va falloir gérer le cas d’une lecture unique au démarrage du reTerminal et que l’affichage soit correct dès le démarrage.
Pour cela, nous allons effectuer les actions suivantes :
1/ Lecture du capteur interne STH4X et de la tension de la batterie lors du démarrage (on_boot) :
on_boot:
priority: 600
then:
# Turn on the GPIO output that powers the battery measurement circuit
- output.turn_on: bsp_battery_enable
# Wait a short delay to allow power stabilization
- delay: 500ms
# Manually update battery sensors (voltage and percentage)
- component.update: battery_voltage
- component.update: battery_level
# Manually read the internal temperature/humidity sensor
- component.update: sht4x_component2/ Pas de mise à jour automatique de la lecture du capteur interne et de la tension de la batterie, puisque ils sont lus au démarrage, ni de rafraississement automatique de l’écran.
update_interval: never # Do not update automatically (manual read only)3/ Rafraississement de l’écran uniquement lorque la valeur des capteurs Home Assistant est disponible (et donc le Wi-Fi opérationnel) :
# Home Assistant sensors (external data)
- platform: homeassistant
id: tutoduino_esp32c6tempsensor_temperature
entity_id: sensor.tutoduino_esp32c6tempsensor_temperature
on_value:
then:
# Refresh the e-paper display whenever this sensor updates
- component.update: epaper_display Voici le code complet avec une mise en veille profonde pendant 10 minutes du reTerminal entre chaque mise à jour des capteur et du rafraississement de son écran.
# ESPHome configuration for the "reterminal2" device
esphome:
name: "reterminal2" # Device name for ESPHome
friendly_name: "reterminal2" # User-friendly name for the device
on_boot:
priority: 600
then:
# Turn on the GPIO output that powers the battery measurement circuit
- output.turn_on: bsp_battery_enable
# Wait a short delay to allow power stabilization
- delay: 500ms
# Manually update battery sensors (voltage and percentage)
- component.update: battery_voltage
- component.update: battery_level
# Manually read the internal temperature/humidity sensor
- component.update: sht4x_component
# ESP32 board configuration
esp32:
board: esp32-s3-devkitc-1 # Board model
framework: # Framework settings
type: esp-idf # Use ESP-IDF framework
# Enable logging for debugging
logger:
# Home Assistant API configuration
api:
encryption: # Encryption settings for secure communication
key: "xxx=" # Encryption key
# Over-The-Air (OTA) update configuration
ota:
- platform: esphome # Use ESPHome OTA platform
password: "xxx" # OTA update password
# Wi-Fi configuration
wifi:
ssid: !secret wifi_ssid # Wi-Fi SSID (from secrets)
password: !secret wifi_password # Wi-Fi password (from secrets)
ap: # Fallback Access Point (hotspot) if Wi-Fi fails
ssid: "Re Fallback Hotspot" # Hotspot SSID
password: "xxx" # Hotspot password
captive_portal: # Enable captive portal for AP mode
# GPIO output configuration
output:
- platform: gpio # GPIO platform
pin: GPIO21 # GPIO pin number
id: bsp_battery_enable # ID for this output
# I2C bus configuration (for SHT4x sensor)
i2c:
sda: GPIO19 # I2C SDA pin
scl: GPIO20 # I2C SCL pin
scan: false # Disable automatic I2C scanning for faster boot
# Sensor configurations
sensor:
# Internal SHT4x temperature/humidity sensor
- platform: sht4x # Sensor platform
id: sht4x_component # ID for the component
temperature: # Temperature sensor
name: "Temperature" # Sensor name
id: sht4x_temperature # ID for temperature sensor
humidity: # Humidity sensor
name: "Humidity" # Sensor name
id: sht4x_humidity # ID for humidity sensor
address: 0x44 # I2C address
update_interval: never # Disable automatic updates (manual read only)
# Home Assistant sensors (external data)
- platform: homeassistant # Home Assistant sensor platform
id: tutoduino_esp32c6tempsensor_temperature # ID for this sensor
entity_id: sensor.tutoduino_esp32c6tempsensor_temperature # Home Assistant entity ID
on_value: # Action to perform when value updates
then: # List of actions
- component.update: epaper_display # Update e-paper display on value change
- platform: homeassistant # Home Assistant sensor platform
id: tutoduino_esp32c6tempsensor_humidite # ID for this sensor
entity_id: sensor.tutoduino_esp32c6tempsensor_humidite # Home Assistant entity ID
- platform: homeassistant # Home Assistant sensor platform
id: tutoduino_esp32c6tempsensor_batterie # ID for this sensor
entity_id: sensor.tutoduino_esp32c6tempsensor_batterie # Home Assistant entity ID
# ADC (analog) battery voltage measurement
- platform: adc # ADC platform
pin: GPIO1 # GPIO pin for ADC
name: "Battery Voltage" # Sensor name
id: battery_voltage # ID for this sensor
attenuation: 12db # Attenuation level
update_interval: never # Disable automatic updates (manual read only)
filters: # Data processing filters
- multiply: 2.0 # Compensate for voltage divider ratio
# Template battery level (%) derived from measured voltage
- platform: template # Template sensor platform
name: "Battery Level" # Sensor name
id: battery_level # ID for this sensor
unit_of_measurement: "%" # Unit of measurement
icon: "mdi:battery" # Icon for display
device_class: battery # Device class
state_class: measurement # State class
update_interval: never # Disable automatic updates (manual read only)
lambda: 'return id(battery_voltage).state;' # Lambda function to get voltage
filters: # Data processing filters
# Voltage-to-percentage calibration curve
- calibrate_linear: # Linear calibration
- 4.15 -> 100.0 # Voltage to percentage mapping
- 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: # Clamp values to valid range
min_value: 0 # Minimum value
max_value: 100 # Maximum value
# Deep sleep configuration to save power
deep_sleep:
id: deep_sleep_1 # ID for deep sleep component
run_duration: 30s # Time to stay awake after wake-up
sleep_duration: 10min # Time to sleep between wake-ups
wakeup_pin: GPIO3 # GPIO pin to wake up device
wakeup_pin_mode: INVERT_WAKEUP # Inverted wake-up logic
# SPI bus configuration (for the e-paper display)
spi:
clk_pin: GPIO7 # SPI CLK pin
mosi_pin: GPIO9 # SPI MOSI pin
# Font definitions for the display
font:
- file: "gfonts://Inter@700" # Google Fonts URL
id: mySmallFont # ID for this font
size: 15 # Font size
- file: "gfonts://Inter@700" # Google Fonts URL
id: myFont # ID for this font
size: 36 # Font size
- file: "gfonts://Inter@700" # Google Fonts URL
id: myFontLarge # ID for this font
size: 50 # Font size
- file: "gfonts://Inter@700" # Google Fonts URL
id: myFontVeryLarge # ID for this font
size: 70 # Font size
- file: 'fonts/MaterialDesignIconsDesktop.ttf' # Icon font file
id: font_mdi_large # ID for this font
size: 50 # Font size
glyphs: # Specific glyphs to include
- "\U000F050F" # Thermometer icon
- "\U000F058E" # Humidity icon
- file: 'fonts/MaterialDesignIconsDesktop.ttf' # Icon font file
id: font_bat_icon # ID for this font
size: 50 # Font size
glyphs: # Specific glyphs to include
- "\U000F0079" # Battery icon
# E-paper display configuration
display:
- platform: epaper_spi
id: epaper_display
model: 7.3in-spectra-e6
cs_pin: GPIO10 # SPI CS pin
dc_pin: GPIO11 # DC pin
reset_pin: # Reset pin configuration
number: GPIO12 # GPIO pin number
inverted: false # Inversion setting
busy_pin: # Busy pin configuration
number: GPIO13 # GPIO pin number
inverted: true # Inversion setting
update_interval: never # Disable automatic updates
# Lambda function for drawing on the display
lambda: |-
const auto BLUE = Color(0, 0, 255, 0); # Define color constants
const auto GREEN = Color(0, 255, 0, 0);
const auto BLACK = Color(0, 0, 0, 0);
const auto RED = Color(255, 0, 0, 0);
it.line(400, 0, 400, 480, BLACK); # Draw a vertical line to separate sections
it.printf(130, 15, id(myFont), BLACK, "INDOOR"); # Print "INDOOR" label
it.printf(510, 15, id(myFont), BLACK, "OUTDOOR"); # Print "OUTDOOR" label
# Draw indoor temperature icon and value
it.printf(60, 165, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F050F");
if (isnan(id(sht4x_temperature).state)) {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "--.-°C"); # Placeholder if no data
} else {
it.printf(90, 120, id(myFontVeryLarge), BLUE, "%.1f°C", id(sht4x_temperature).state); # Display temperature
}
# Draw indoor humidity icon and value
it.printf(60, 283, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F058E");
if (isnan(id(sht4x_humidity).state)) {
it.printf(90, 250, id(myFontLarge), BLUE, "--.-%%"); # Placeholder if no data
} else {
it.printf(90, 250, id(myFontLarge), BLUE, "%.1f%%", id(sht4x_humidity).state); # Display humidity
}
# Draw battery level icon and value
it.printf(60, 390, id(font_bat_icon), BLACK, TextAlign::CENTER, "\U000F0079");
if (isnan(id(battery_level).state)) {
it.printf(90, 360, id(myFontLarge), BLUE, "--%%"); # Placeholder if no data
} else {
it.printf(90, 360, id(myFontLarge), BLUE, "%2.0f%%", id(battery_level).state); # Display battery level
}
# Draw outdoor temperature icon and value
it.printf(470, 165 , id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F050F");
if (isnan(id(tutoduino_esp32c6tempsensor_temperature).state)) {
it.printf(500, 120, id(myFontVeryLarge), BLUE, "--.-°C"); # Placeholder if no data
} else {
it.printf(500, 120, id(myFontVeryLarge), BLUE, "%.1f°C", id(tutoduino_esp32c6tempsensor_temperature).state); # Display temperature
}
# Draw outdoor humidity icon and value
it.printf(470, 283, id(font_mdi_large), BLACK, TextAlign::CENTER, "\U000F058E");
if (isnan(id(tutoduino_esp32c6tempsensor_humidite).state)) {
it.printf(500, 250, id(myFontLarge), BLUE, "--.-%%"); # Placeholder if no data
} else {
it.printf(500, 250, id(myFontLarge), BLUE, "%.1f%%", id(tutoduino_esp32c6tempsensor_humidite).state); # Display humidity
}
# Draw outdoor battery level icon and value
it.printf(470, 390, id(font_bat_icon), BLACK, TextAlign::CENTER, "\U000F0079");
if (isnan(id(tutoduino_esp32c6tempsensor_batterie).state)) {
it.printf(500, 360, id(myFontLarge), BLUE, "--%%"); # Placeholder if no data
} else {
it.printf(500, 360, id(myFontLarge), BLUE, "%2.0f%%", id(tutoduino_esp32c6tempsensor_batterie).state); # Display battery level
}
