Le module "Séjour". *** EN COURS DE FINALISATION ***



Mon séjour comporte 3 fenêtres et une porte fenêtre équipés de volets électriques branchés avec des interrupteurs provisoires, du provisoire qui dure depuis au moins 15 ans ! Le module aura pour rôle principal de s'occuper des volets plus quelques autres fonctions annexes.

Voici donc toutes les fonctions que j'ai imaginé pour ce module avec quelques détails techniques pour chacun d'entre eux.
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é : si les relais de montée et de descente sont activés en même temps une seule sortie est alimentée. 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 !

Les relais sont alimentés entre 5 v (JD-Vcc) et masse grâce à un transistor commandé par un optocoupleur. La broche de commande arrive sur la cathode d'un optocoupleur (Avec une LED en série). L'anode est reliée à la ligne Vcc. Un shunt permet de relier JD-Vcc et Vcc, dans ce cas on alimente en 5 v mais il faut que les GPIO de commande acceptent 5 v. Donc bien retenir que c'est un niveau bas qui active le relais.
L'ESP fonctionne en 3,3 v : j'ai donc retiré le shunt et j'alimente la carte avec du 3,3 v et du 5 v. 3 pins reçoivent : GND, Vcc (3,3 v) et JD-Vcc (5 v).

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.
esphome:
  name: sejour
  friendly_name: Séjour
  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
                  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
    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
                  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
    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
    on_press: 
      then:
        - display.page.show_next: ecran
        - component.update: ecran
  # Détecteur d'ouverture fenêtre'
  - platform: gpio
    id: contact_fenetre
    name: "contact_fenetre"
    icon: mdi:door-closed
    pin:
      number: GPIO34
      inverted: true
  # Détecteur d'ouverture porte'
  - platform: gpio
    id: contact_porte
    name: "contact_porte"
    icon: mdi:door-closed
    pin:
      number: GPIO35
      inverted: true
  # 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
    id: ecran
    update_interval: 2min
    pages:
      - id: page_interieur
        lambda: |-
          it.printf(64, 0, id(arial20), TextAlign::TOP_CENTER, "Intérieur");
          it.printf(64, 30, id(arial30), TextAlign::TOP_CENTER, "%.1f °", id(temperature_sejour).state);
      - id: page_exterieur
        lambda: |-
          it.printf(64, 0, id(arial20), TextAlign::TOP_CENTER, "Extérieur");
          it.printf(64, 30, id(arial30), TextAlign::TOP_CENTER, "%.1f °", id(temperature_rue).state);
          
      - id: page_piscine
        lambda: |-
          it.printf(64, 0, id(arial20), TextAlign::TOP_CENTER, "Piscine");
          it.printf(64, 30, id(arial30), TextAlign::TOP_CENTER, "%.1f °", id(temperature_piscine).state);

font:
  - file: "fonts/arialbd.ttf"
    id: arial20
    size: 20
    glyphs: [EIPceéinrstux]
  - file: "fonts/arialbd.ttf"
    id: arial30
    size: 30
    glyphs: [0123456789. °-]

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:
      - 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;
      - if:
          condition:
            lambda: 'return id(groupement) == 1 || id(groupement) == 5 || id(groupement) == 6;'
          then:
            - switch.turn_on: led_1
          else:
            - switch.turn_off: led_1
      - if:
          condition:
            lambda: 'return id(groupement) == 2 || id(groupement) == 6;'
          then:
            - switch.turn_on: led_2
          else:
            - switch.turn_off: led_2
      - if:
          condition:
            lambda: 'return id(groupement) == 3 || id(groupement) == 5 || id(groupement) == 6;'
          then:
            - switch.turn_on: led_3
          else:
            - switch.turn_off: led_3
      - if:
          condition:
            lambda: 'return id(groupement) == 4 || id(groupement) == 5 || id(groupement) == 6;'
          then:
            - switch.turn_on: led_4
          else:
            - switch.turn_off: led_4
      - delay: 30s
      - script.execute:
          id: stop_relais
      - delay: 60s
      - 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;
  - id: stop_relais
    mode: restart
    then:
      - lambda: 
          id(flag_stop) = false;
      - 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:
      number: GPIO16
      inverted: true
  - platform: gpio
    id: relais_D1
    name: relais_D1
    pin:
      number: GPIO17
      inverted: true
  - platform: gpio
    id: relais_M2
    name: relais_M2
    pin:
      number: GPIO18
      inverted: true
  - platform: gpio
    id: relais_D2
    name: relais_D2
    pin:
      number: GPIO19
      inverted: true
  - platform: gpio
    id: relais_M3
    name: relais_M3
    pin:
      number: GPIO21
      inverted: true
  - platform: gpio
    id: relais_D3
    name: relais_D3
    pin:
      number: GPIO22
      inverted: true
  - platform: gpio
    id: relais_M4
    name: relais_M4
    pin:
      number: GPIO23
      inverted: true
  - platform: gpio
    id: relais_D4
    name: relais_D4
    pin:
      number: GPIO25
      inverted: true
  # 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