Voici donc toutes les fonctions que j'ai imaginé pour ce module avec quelques détails techniques pour chacun d'entre eux.
-
Le fonctionnement des volets.
3 touches à effleurement (Merci l'ESP32)
- Sélection du ou des volets à actionner; cycliquement : 1, 2, 3, 4, 1+3+4, 1+2+3+4 (2 étant la porte-fenêtre)
- Montée : appui bref lance ou arrête le mouvement et appui long arrête le mouvement au relâchement.
- Descente : appui bref lance ou arrête le mouvement et appui long arrête le mouvement au relâchement.
4 LEDs indiquent la sélection de volet à manoeuvrer.
Dit comme ça on peux penser à une usine à gaz mais en fait c'est super intuitif.
8 relais pour commnder tout ça.
-
Un mini écran pour indiquer les températures : extérieur, séjour, piscine.
Une touche à effleurement permet de faire défiler les différentes températures.
-
Un détecteur de présence; pour éventuellement déclencher Alarmo.
-
Une boucle avec en série les 3 contacts des fenêtres et une autre boucle avec le contact de la porte-fenêtre.
C'est aussi pour Alarmo.
-
Un capteur Dallas DS18B20 pour la température intérieure.
Je vais brancher tout ça sur un ESP32-WROOM-32D installé sur un «devkit» de 30 pins. Un petit module 220v Hi-link délivrera du 5v avec une puissance de 5w.
La carte devkit, alimentée en 5v possède un régulateur fournissant du 3,3v.
La carte 8 relais vient de chez Ali. mais je l'ais bien modifié pour ajouter une sécurité : les relais de montée et de descente d'un même volet ne peuvent
pas être actionnés en même temps. J'ai aussi remodelé les connnecteurs : un connecteur 3 fils pour chaque moteur. Il faut 2 relais pour chaque volet.

Au repos le relais 1 envoie le jus sur le relais 2 qui en s'activant alimente B. En activant le relais 1 on alimente A mais on n'alimente plus le relais 2. CQFD

Les borniers sont des modèles débrochables. Le résultat est presque propre !
Le schéma est très simple puisque tous les capteurs et relais sont déportés et connectés grâce à des fiches RJ.
Les fichiers KiCad et PDF sont disponibles sous licence

Les fonctionnalités qui permettent à plusieurs modules ESPhome d'interagir nécessitent de valider une autorisation dans HA sous Appareil --> Options
Reste à écrire le fichier YAML de l'appareil dans ESPHome builder; quelques comentaires avant de plonger dans le code.
- globals:
- Un flag d'arrêt de manoeuvre
- Une variable indiquants la sélection de volet à manoeuvrer
- Un flag d'activation du système
- esp32_touch --> Bouton sensiifs. Les valeurs de "threshold" seront à ajuster sur l'appareil fini.
-
binary_sensor:
- Les 4 boutons sensitifs
- Les 2 boucles d'ouverture des huisseries
- Le détecteur de présence
-
display: et font:
L'affichage des températures
-
i2c: et one_wireC
Les interfaces de l'écran et du capteur de température.
-
script:
Ils regroupent l'essentiel de la logique du bidule !
-
sensor: --> dallas_temp
La température intérieure
sensor: --> temperature_piscine
La température provenant d'un autre module
sensor: --> temperature_rue
La température provenant d'un autre module
-
switch: --> Les 8 relais de commande des volets et les 4 LEDs
esphome:
name: sejour-e7a318
friendly_name: Sejour
min_version: 2025.9.0
esp32:
variant: esp32
framework:
type: esp-idf
logger:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Sejour Hotspot"
captive_portal:
api:
globals:
- id: flag_stop
type: bool
initial_value: "false"
- id: groupement
type: int
initial_value: "6"
- id: systeme_actif
type: bool
initial_value: "false"
esp32_touch:
# Dans l'ordre alphabétique des composants
binary_sensor:
# Bouton sélection
- platform: esp32_touch
id: bouton_select
name: "bouton_select"
pin: GPIO12
threshold: 300
filters:
- delayed_on: 20ms
- delayed_off: 20ms
on_press:
then:
- if:
condition:
lambda: 'return ! id(systeme_actif);'
then:
- script.execute:
id: allume_led
else:
- if:
condition:
lambda: 'return id(groupement) == 6;'
then:
- lambda:
id(groupement) = 1;
else:
- lambda:
id(groupement) = id(groupement) + 1;
- script.execute:
id: allume_led
# Bouton monte
- platform: esp32_touch
id: bouton_monte
name: "bouton_monte"
pin: GPIO13
threshold: 300
filters:
- delayed_on: 20ms
- delayed_off: 20ms
on_press:
then:
- if:
condition:
lambda: 'return ! id(systeme_actif);'
then:
- script.execute:
id: allume_led
else:
- if:
condition:
lambda: 'return id(flag_stop);'
then:
- script.execute:
id: stop_relais
- lambda:
id(flag_stop) = false;
else:
- script.execute:
id: monter
- lambda:
id(flag_stop) = true;
- script.execute:
id: bouton_press
on_release:
then:
- if:
condition:
lambda: 'return ! id(flag_stop);'
then:
- script.execute:
id: stop_relais
- lambda:
id(flag_stop) = false;
on_click:
min_length: 50ms
max_length: 400ms
then:
- script.stop:
id: bouton_press
# Bouton descend
- platform: esp32_touch
id: bouton_descend
name: "bouton_descend"
pin: GPIO14
threshold: 300
filters:
- delayed_on: 20ms
- delayed_off: 20ms
on_press:
then:
- if:
condition:
lambda: 'return ! id(systeme_actif);'
then:
- script.execute:
id: allume_led
else:
- if:
condition:
lambda: 'return id(flag_stop);'
then:
- script.execute:
id: stop_relais
- lambda:
id(flag_stop) = false;
else:
- script.execute:
id: descendre
- lambda:
id(flag_stop) = true;
- script.execute:
id: bouton_press
on_release:
then:
- if:
condition:
lambda: 'return ! id(flag_stop);'
then:
- script.execute:
id: stop_relais
- lambda:
id(flag_stop) = false;
on_click:
min_length: 50ms
max_length: 400ms
then:
- script.stop:
id: bouton_press
# Bouton thermomètre
- platform: esp32_touch
id: bouton_thermo
name: "bouton_thermo"
pin: GPIO15
threshold: 300
filters:
- delayed_on: 20ms
- delayed_off: 20ms
# Détecteur d'ouverture fenêtre'
- platform: gpio
id: contact_fenetre
name: "contact_fenetre"
icon: mdi:door-closed
pin: GPIO34
# Détecteur d'ouverture porte'
- platform: gpio
id: contact_porte
name: "contact_porte"
icon: mdi:door-closed
pin: GPIO35
# Détecteur de présence
- platform: gpio
id: presence_sejour
name: "presence_sejour"
device_class: "motion"
pin: GPIO36
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
address: 0x3C
lambda: |-
it.printf(0, 0, id(lucida), "Intérieur : %.1f °", id(temperature_sejour).state);
it.printf(0, 20, id(lucida), "Extérieur : %.1f °", id(temperature_rue).state);
it.printf(0, 40, id(lucida), "Piscine : %.1f °", id(temperature_piscine).state);
font:
- file: "fonts/lucon.ttf"
id: lucida
size: 12
glyphsets:
- GF_Latin_Core
i2c:
- id: bus_display
sda: GPIO26
scl: GPIO27
one_wire:
- platform: gpio
pin: GPIO32
script:
- id: bouton_press
then:
- delay: 600ms
- lambda:
id(flag_stop) = false;
- id: monter
then:
- script.execute:
id: allume_led
- if:
condition:
lambda: 'return id(groupement) == 1 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_D1
- switch.turn_on: relais_M1
- if:
condition:
lambda: 'return id(groupement) == 2 || id(groupement) == 6;'
then:
- switch.turn_off: relais_D2
- switch.turn_on: relais_M2
- if:
condition:
lambda: 'return id(groupement) == 3 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_D3
- switch.turn_on: relais_M3
- if:
condition:
lambda: 'return id(groupement) == 4 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_D4
- switch.turn_on: relais_M4
- id: descendre
then:
- logger.log: "***** Début descendre *****"
- script.execute:
id: allume_led
- if:
condition:
lambda: 'return id(groupement) == 1 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_M1
- switch.turn_on: relais_D1
- if:
condition:
lambda: 'return id(groupement) == 2 || id(groupement) == 6;'
then:
- switch.turn_off: relais_M2
- switch.turn_on: relais_D2
- if:
condition:
lambda: 'return id(groupement) == 3 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_M3
- switch.turn_on: relais_D3
- if:
condition:
lambda: 'return id(groupement) == 4 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_off: relais_M4
- switch.turn_on: relais_D4
- id: allume_led
mode: restart
then:
- lambda:
id(systeme_actif) = true;
- switch.turn_off: led_1
- switch.turn_off: led_2
- switch.turn_off: led_3
- switch.turn_off: led_4
- if:
condition:
lambda: 'return id(groupement) == 1 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_on: led_1
- if:
condition:
lambda: 'return id(groupement) == 2 || id(groupement) == 6;'
then:
- switch.turn_on: led_2
- if:
condition:
lambda: 'return id(groupement) == 3 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_on: led_3
- if:
condition:
lambda: 'return id(groupement) == 4 || id(groupement) == 5 || id(groupement) == 6;'
then:
- switch.turn_on: led_4
- delay: 60s
- script.execute:
id: stop_relais
- switch.turn_off: led_1
- switch.turn_off: led_2
- switch.turn_off: led_3
- switch.turn_off: led_4
- lambda:
id(systeme_actif) = false;
- lambda:
id(flag_stop) = false;
- id: stop_relais
mode: restart
then:
- switch.turn_off: relais_M1
- switch.turn_off: relais_D1
- switch.turn_off: relais_M2
- switch.turn_off: relais_D2
- switch.turn_off: relais_M3
- switch.turn_off: relais_D3
- switch.turn_off: relais_M4
- switch.turn_off: relais_D4
sensor:
# Capteur local Dallas DS18
- platform: dallas_temp
id: temperature_sejour
name: Temperature séjour
update_interval: 10min
# Récupérer température de la piscine
- platform: homeassistant
id: temperature_piscine
entity_id: sensor.thermometre_piscine_temperature
internal: true
unit_of_measurement: "°C"
# Récupérer température extérieure
- platform: homeassistant
id: temperature_rue
entity_id: sensor.portier_temperature_rue
internal: true
unit_of_measurement: "°C"
switch:
# 8 relais des volets
- platform: gpio
id: relais_M1
name: relais_M1
pin: GPIO16
- platform: gpio
id: relais_D1
name: relais_D1
pin: GPIO17
- platform: gpio
id: relais_M2
name: relais_M2
pin: GPIO18
- platform: gpio
id: relais_D2
name: relais_D2
pin: GPIO19
- platform: gpio
id: relais_M3
name: relais_M3
pin: GPIO21
- platform: gpio
id: relais_D3
name: relais_D3
pin: GPIO22
- platform: gpio
id: relais_M4
name: relais_M4
pin: GPIO23
- platform: gpio
id: relais_D4
name: relais_D4
pin: GPIO25
# 4 LEDs d'indication de volet actif
- platform: gpio
id: led_1
name: led_1
pin: GPIO1
- platform: gpio
id: led_2
name: led_2
pin: GPIO2
- platform: gpio
id: led_3
name: led_3
pin: GPIO3
- platform: gpio
id: led_4
name: led_4
pin: GPIO4
Le dessin du C.I.
Le C.I. terminé.
Les pièces 3D et le montage