Deep sleep, l'activer toutes les X heures et 3 minutes sous esphome

Bonjour,
je cherche à activer le deep_ sleep tous les x heures et 3 minutes. Je ne trouve pas de solution sur le net, je fais appelle à la communauté.
Pour le moment, j’ai le sleep duration sur 60min. Mais si je redémarre l’esp32 à 10h30 par exemple, il se réveillera à 11h30. Je voudrais qu’il se réveille a 11h03, puis 12h03 … .

deep_sleep:
  id: deep_sleep_1
  run_duration: 2min
  sleep_duration: 60min
  wakeup_pin: GPIO3 # Bouton vert
  wakeup_pin_mode: INVERT_WAKEUP

J’ai tenté avec ChatGPT, mais comme d’habitude, il ne sert à rien :rofl:
voici le code qu’il m’a proposé :

deep_sleep:
  id: deep_sleep_1
  run_duration: 2min
  sleep_duration: 60min # valeur par défaut, sera ajustée par l'automatisation
  wakeup_pin: GPIO3          # Bouton vert
  wakeup_pin_mode: INVERT_WAKEUP

# Automatisation : réveil toutes les heures à HH:03
interval:
  - interval: 10s
    then:
      - if:
          condition:
            lambda: |-
              auto t = id(ha_time).now();
              // Vérifie si l'heure est valide et qu'on est à HH:03 (±10 secondes)
              return t.is_valid() && t.minute == 3 && t.second < 10;
          then:
            - deep_sleep.enter:
                id: deep_sleep_1
                sleep_duration: 60min

Ma configuration

ESPHome 2025.8.2


Salut

Je vais peut-être te dire une bêtise, j’ai lu sur un site que tu pouvais réveiller ESP avec un input_button.

Donc je me dit qu’avec un automatisme tu dois pouvoir le réveiller comme tu veux.

Le lien du sujet:

Cest peut-être une fausse piste, Vois ce que tu peux en faire.

Salut,
j’avais vu ce site, mais je cherche à faire une automatisation directement dans l’esp32 et évite une automatisation sur HA.

Ce que tu cherches à faire c’est un réveil toutes les X heures suivi d’un offset de 3 minutes.
Le sleep_duration te permet de fixer ton nombre d’heures mais je ne pense pas qu’il existe un moyen simple d’instaurer un offset.

Je vais regarder dans la doc d’ESPHome mais j’imagine que tu as déjà jeté un oeil.

1 « J'aime »

Oui, j’ai regardé dans la doc, mais j’ai peu être mal lu ou mal compris :sweat_smile:

je pense à cet exemple avec un template:

# Sleep duration is also templatable
on_...:
  then:
    - deep_sleep.enter:
        id: deep_sleep_1
        sleep_duration: !lambda "return 20 * 60 * 1000;"

j’utilise l’heure de HA :

time:
  - platform: homeassistant
    id: ha_time

Faire un lamba basé sur l’heure et indiquer le sleep_duration. Mais je suis une quiche en lambda…

Salut,
en utilisant globals et l’ automation on_boot

globals:
  - id: sleep_interval_hours
    type: int
    restore_value: no
    initial_value: '1'  # Toutes les 1 heure
  - id: target_minute
    type: int
    restore_value: no
    initial_value: '3'  # À la minute 03

on_boot:
  priority: -100
  then:
    - delay: 15s  # Attente de la synchro HA
    - lambda: |-
        auto time = id(ha_time).now();
        if (!time.is_valid()) {
          ESP_LOGI("custom", "Heure invalide (pas de synchro HA). Deep sleep 60 min par défaut.");
          id(deep_sleep_1).set_sleep_duration(60 * 60 * 1000ULL);
          id(deep_sleep_1)->begin_sleep();
          return;
        }

        int now_seconds = time.hour * 3600 + time.minute * 60 + time.second;

        int h = time.hour;
        int m = time.minute;
        int interval = id(sleep_interval_hours);
        int target_min = id(target_minute);

        int next_target_hour = (h / interval) * interval;
        if (m >= target_min) {
          next_target_hour += interval;
        }
        if (next_target_hour >= 24) next_target_hour -= 24;

        int target_seconds = next_target_hour * 3600 + target_min * 60;
        int sleep_seconds = target_seconds - now_seconds;
        if (sleep_seconds <= 60) sleep_seconds += interval * 3600;

        ESP_LOGI("custom", "Il est %02d:%02d:%02d", h, m, time.second);
        ESP_LOGI("custom", "Prochain réveil prévu à %02d:%02d (dans %d sec)", next_target_hour, target_min, sleep_seconds);

        id(deep_sleep_1).set_sleep_duration(sleep_seconds * 1000ULL);
        id(deep_sleep_1)->begin_sleep();

OK, mais je dois mettre quoi dans sleep_duration: ?
je vire la ligne ?

je remplace par mon id du deep_sleep ?

sans sleep_duration ici défini dynamiquement

deep_sleep_ctrl tu peut le modifier par ton id: deep_sleep_1

deep_sleep:
  id: deep_sleep_ctrl
  run_duration: 2min
  wakeup_pin: GPIO3
  wakeup_pin_mode: INVERT_WAKEUP
1 « J'aime »

Ok, merci.
Je teste ça :wink:

1 « J'aime »

@hackdiy , j’ai cette erreur à la compilation :

xxxx.yaml: In lambda function:
xxxx.yaml:18:23: error: 'class esphome::deep_sleep::DeepSleepComponent' has no member named 'start'
xxxx.yaml:43:21: error: 'class esphome::deep_sleep::DeepSleepComponent' has no member named 'start'
*** [.pioenvs\xxxx\src\main.cpp.o] Error 1

le code :

esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
  on_boot:
    - priority: -100
      then:
        - delay: 15s  # Attente de la synchro HA
        - lambda: |-
            auto time = id(ha_time).now();
            if (!time.is_valid()) {
              ESP_LOGI("custom", "Heure invalide (pas de synchro HA). Deep sleep 60 min par défaut.");
              id(deep_sleep_1).set_sleep_duration(60 * 60 * 1000ULL);
              id(deep_sleep_1).start();
              return;
            }
      
            int now_seconds = time.hour * 3600 + time.minute * 60 + time.second;
      
            int h = time.hour;
            int m = time.minute;
            int interval = id(sleep_interval_hours);
            int target_min = id(target_minute);
      
            int next_target_hour = (h / interval) * interval;
            if (m >= target_min) {
              next_target_hour += interval;
            }
            if (next_target_hour >= 24) next_target_hour -= 24;
      
            int target_seconds = next_target_hour * 3600 + target_min * 60;
            int sleep_seconds = target_seconds - now_seconds;
            if (sleep_seconds <= 60) sleep_seconds += interval * 3600;
      
            ESP_LOGI("custom", "Il est %02d:%02d:%02d", h, m, time.second);
            ESP_LOGI("custom", "Prochain réveil prévu à %02d:%02d (dans %d sec)", next_target_hour, target_min, sleep_seconds);
      
            id(deep_sleep_1).set_sleep_duration(sleep_seconds * 1000ULL);
            id(deep_sleep_1).start();

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf
  flash_size: 32MB

deep_sleep:
  id: deep_sleep_1
  run_duration: 2min
  #sleep_duration: 58min 
  wakeup_pin: GPIO3  # Bouton vert
  wakeup_pin_mode: INVERT_WAKEUP

tente de remplace les 2 lignes

id(deep_sleep_1).start();

par :

id(deep_sleep_1)->begin_sleep();
1 « J'aime »

la compilation est passée. Je vois que maintenant l’esp se met en sommeil directement au boot.
Je vais attendre voir à 18h03 si mon écran ce rafraichi.
Il me faudrais qu’au boot , l’esp reste allumé 2 min puis passe en sommeil avec l’heure programmé toutes les X heure 03 minutes.

1 « J'aime »

oui regarde les logs série tu devrais voir les logs du type :

Il est 17:50:05
Prochain réveil prévu à 18:03 (dans xxxx sec)

Logiquement ton ESP se réveille à HH:03 toutes les heures , même si tu le démarres à une heure aléatoire. Exécute son run_duration pendant 2 minutes, puis se met en deep sleep jusqu’à la prochaine heure HH:03 .

1 « J'aime »

Ok, ça aurait été mieux qu’il puisse actualiser les informations au boot avant de passer en sommeil. Parce que là, je suis obligé d’attendre HH:03 pour voir les changements que j’y apporte.
Au pire, j’enlève le code. Je finalise mes configurations et le remets.

soit tu y ajouter un délai fixe avant , risque de surcoso de la batterie , ou alors commente begin_sleep() pour travailler tranquille , vérifie dans les logs si HA envoie bien l’heure ha_time une fois OK → remets le deep sleep.

1 « J'aime »

Bon du coup ca fonctionne, je les mis en priority 600 a la fin de met execution. Comme j’ai le temps d’avoir les sensor actualisé, puis actualisé l’écran et passer en sommeil.
Chez pas si c’est la meilleure solution, mais ça fonctionne.

[19:25:34][I][custom:046]: Il est 19:25:34
[19:25:34][I][custom:047]: Prochain réveil prévu à 20:03 (dans 2246 sec)
[19:25:34][I][deep_sleep:061]: Beginning sleep
[19:25:34][I][deep_sleep:063]: Sleeping for 2246000000us
esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
  on_boot:
    - priority: 600
      then:
        - output.turn_on: bsp_sd_enable
        - output.turn_on: bsp_battery_enable
        - delay: 200ms
        - component.update: battery_voltage
        - component.update: battery_level
        - delay: 40s 
        - component.update: epaper_display
        - delay: 10s
        - lambda: |-
            auto time = id(ha_time).now();
            if (!time.is_valid()) {
              ESP_LOGI("custom", "Heure invalide (pas de synchro HA). Deep sleep 60 min par défaut.");
              id(deep_sleep_1).set_sleep_duration(60 * 60 * 1000ULL);
              id(deep_sleep_1)->begin_sleep();
              return;
            }
      
            int now_seconds = time.hour * 3600 + time.minute * 60 + time.second;
      
            int h = time.hour;
            int m = time.minute;
            int interval = id(sleep_interval_hours);
            int target_min = id(target_minute);
      
            int next_target_hour = (h / interval) * interval;
            if (m >= target_min) {
              next_target_hour += interval;
            }
            if (next_target_hour >= 24) next_target_hour -= 24;
      
            int target_seconds = next_target_hour * 3600 + target_min * 60;
            int sleep_seconds = target_seconds - now_seconds;
            if (sleep_seconds <= 60) sleep_seconds += interval * 3600;
      
            ESP_LOGI("custom", "Il est %02d:%02d:%02d", h, m, time.second);
            ESP_LOGI("custom", "Prochain réveil prévu à %02d:%02d (dans %d sec)", next_target_hour, target_min, sleep_seconds);
      
            id(deep_sleep_1).set_sleep_duration(sleep_seconds * 1000ULL);
            id(deep_sleep_1)->begin_sleep();


external_components:
  - source:
      type: git
      url: https://github.com/lublak/esphome
      ref: dev
    components: [ waveshare_epaper ]

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf
  flash_size: 32MB

psram:
  mode: octal

deep_sleep:
  id: deep_sleep_1
  run_duration: 2min
  #sleep_duration: 58min 
  wakeup_pin: GPIO3  # Bouton vert
  wakeup_pin_mode: INVERT_WAKEUP

1 « J'aime »

Top, super boulot ! :clap: et tu as trouvé une solution propre et efficace en utilisant priority: 600 , ce qui fait que ton bloc on_boot s’exécute tout à la fin de l’initialisation , après que les capteurs et les entités HA soient synchronisées . :bullseye:

Franchement, oui, dans ton cas. Bien joué ! :ok_hand:

1 « J'aime »

Salut @hackdiy,
j’ai trouvé un bug, à partir de 23h03, il ne se réveille plus. Il y a un problème pour 00h03. Après ça fonctionne très bien toute la journée, mais le passage à minuit non.

        - lambda: |-
            auto time = id(ha_time).now();
            if (!time.is_valid()) {
              ESP_LOGI("custom", "Heure invalide (pas de synchro HA). Deep sleep 60 min par défaut.");
              id(deep_sleep_1).set_sleep_duration(60 * 60 * 1000ULL);
              //id(deep_sleep_1)->begin_sleep();
              id(deep_sleep_1).begin_sleep(true);
              return;
            }
      
            int now_seconds = time.hour * 3600 + time.minute * 60 + time.second;
      
            int h = time.hour;
            int m = time.minute;
            int interval = id(sleep_interval_hours);
            int target_min = id(target_minute);
      
            int next_target_hour = (h / interval) * interval;
            if (m >= target_min) {
              next_target_hour += interval;
            }
            if (next_target_hour >= 24) next_target_hour -= 24;
      
            int target_seconds = next_target_hour * 3600 + target_min * 60;
            int sleep_seconds = target_seconds - now_seconds;
            if (sleep_seconds <= 60) sleep_seconds += interval * 3600;
      
            ESP_LOGI("custom", "Il est %02d:%02d:%02d", h, m, time.second);
            ESP_LOGI("custom", "Prochain réveil prévu à %02d:%02d (dans %d sec)", next_target_hour, target_min, sleep_seconds);
      
            id(deep_sleep_1).set_sleep_duration(sleep_seconds * 1000ULL);
            //id(deep_sleep_1)->begin_sleep();
            id(deep_sleep_1).begin_sleep(true);

Tu saurais résoudre ça ?

je pense que ça vient du problème next_target_hour devient 0, donc target_seconds = 180, mais now_seconds est ~83 000 (23h10).
Résultat : sleep_seconds est négatif tu ajoutes un intervalle, mais le calcul tombe à côté , et ne fait pas le saut au lendemain correctement.

Essaye en modifiant cette partie

      - lambda: |-
          auto time = id(ha_time).now();
          if (!time.is_valid()) {
            ESP_LOGI("custom", "Heure invalide (pas de synchro NTP). Deep sleep 60 min par défaut.");
            id(deep_sleep_1).set_sleep_duration(60 * 60 * 1000ULL);
            id(deep_sleep_1).begin_sleep(true);
            return;
          }

          int now_seconds = time.hour * 3600 + time.minute * 60 + time.second;

          int h = time.hour;
          int m = time.minute;
          int interval = id(sleep_interval_hours);
          int target_min = id(target_minute);

          // Calcul de la prochaine heure cible
          int next_target_hour = (h / interval) * interval;
          if (m >= target_min) {
            next_target_hour += interval;
          }
          if (next_target_hour >= 24) next_target_hour -= 24;

          int target_seconds = next_target_hour * 3600 + target_min * 60;
          if (target_seconds <= now_seconds) {
            target_seconds += 24 * 3600;  // bascule au jour suivant
          }

          int sleep_seconds = target_seconds - now_seconds;

          ESP_LOGI("custom", "Il est %02d:%02d:%02d", h, m, time.second);
          ESP_LOGI("custom", "Prochain réveil prévu à %02d:%02d (dans %d sec)", 
                   next_target_hour, target_min, sleep_seconds);

          id(deep_sleep_1).set_sleep_duration((uint64_t)sleep_seconds * 1000ULL);
          id(deep_sleep_1).begin_sleep(true);
1 « J'aime »

@hackdiy le chat GPT du forum :sweat_smile: