Guides · 18 min de lecture

ESP32 Deep Sleep : réveil, consommation en µA et autonomie 18650

ESP32 deep sleep pas à pas : consommation en µA de chaque mode, réveil par timer, bouton, PIR et tactile (ext0/ext1), mémoire RTC et autonomie avec une 18650.

Le deep sleep de l'ESP32 (sommeil profond) est le mode d'énergie dans lequel l'ESP32 coupe ses cœurs, sa radio Wi-Fi et Bluetooth et sa mémoire principale pour ne garder que la petite partie RTC. Dans ce mode, la consommation de la puce passe de 240 mA pendant une émission Wi-Fi à environ 10 µA, soit vingt-quatre mille fois moins. La carte se réveille à la fin du délai que tu as fixé, quand on appuie sur un bouton, quand un capteur PIR détecte un mouvement ou quand on touche une broche ; elle fait son travail en quelques secondes puis se rendort. C'est ainsi que des stations météo, des capteurs de jardin, des alarmes de porte et des enregistreurs à distance tiennent des mois au lieu de quelques jours avec une seule batterie 18650.

Dans ce guide, tu découvriras les modes de sommeil de l'ESP32 et leurs consommations réelles, tu apprendras à réveiller la carte avec un timer, un bouton, un capteur PIR (ext0 et ext1) ou un toucher, à conserver des compteurs et des mesures dans la mémoire RTC qui survit au sommeil, tu comprendras pourquoi les cartes de développement consomment encore des milliampères en dormant et tu calculeras pas à pas combien de mois tient une seule 18650. Les sketches Arduino sont écrits pour la version 3.1 ou ultérieure du cœur Arduino ESP32 ; à la fin, tu verras comment faire la même chose en MicroPython.

Carte de développement ESP32 (DevKit)
Carte de développement ESP32 : le module sous capot métallique consomme environ 10 µA en sommeil profond, mais le régulateur, la LED d'alimentation et la puce USB-série de la carte font grimper ce chiffre jusqu'aux milliampères.

Qu'est-ce que le deep sleep de l'ESP32 et comment fonctionne-t-il ?

L'ESP32 contient deux mondes séparés. Le premier est la partie principale, avec les cœurs, 520 Ko de RAM et la radio Wi-Fi et Bluetooth. Le second est la partie RTC, avec son propre petit timer, 8 Ko de mémoire RTC FAST et 8 Ko de RTC SLOW, les broches RTC GPIO et un coprocesseur ultra basse consommation appelé ULP. En sommeil profond, la partie principale est entièrement coupée et seule la partie RTC continue de tourner. Au moment du réveil, la puce redémarre en réalité : le bootloader s'exécute, le programme est rechargé depuis la flash et setup() reprend depuis le début. C'est pourquoi un programme en deep sleep fait tout son travail dans setup() et que loop() ne s'exécute jamais. Les variables normales sont remises à zéro à chaque réveil ; seules celles que tu places en mémoire RTC sont conservées.

Modes de sommeil de l'ESP32 et consommation (µA)

ModeQu'est-ce qui reste actif ?Courant (puce ESP32)
Actif : émission Wi-Fi (802.11b, 19,5 dBm)CPU et radio240 mA
Actif : réception et écoute Wi-FiCPU et radio95–100 mA
Modem sleep, 240 MHzLe CPU tourne, radio coupée30–68 mA
Modem sleep, 80 MHzLe CPU tourne plus lentement, radio coupée20–31 mA
Sommeil léger (light sleep)CPU en pause, RAM conservée0,8 mA
Sommeil profond avec ULPPartie RTC et coprocesseur ULP150 µA
Sommeil profond (deep sleep)Timer RTC et mémoire RTC10 µA
HibernationSeulement le timer RTC et quelques broches RTC5 µA
Éteint (broche EN à LOW)Rien1 µA

Ces valeurs viennent de la fiche technique de l'ESP32 publiée par Espressif et ne concernent que la puce. Deux points du tableau méritent ton attention. D'abord, en sommeil léger le programme reprend à la ligne où il s'était arrêté et tout le contenu de la RAM est conservé, mais la consommation est quatre-vingts fois plus élevée qu'en sommeil profond ; ce mode convient aux pauses de quelques secondes. En sommeil profond, le programme redémarre, mais la consommation descend à quelques microampères : c'est le bon choix pour des attentes de plusieurs minutes ou heures. Ensuite, aucun des deux modes ne garde la connexion Wi-Fi ou Bluetooth ; il faut se reconnecter à chaque réveil. Les puces plus récentes sont un peu différentes : l'ESP32-C3 consomme environ 5 µA en sommeil profond et l'ESP32-S3 environ 7–8 µA.

Si tu veux consommer encore moins, tu peux aussi couper les périphériques RTC et la mémoire RTC. Avec esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF) et la même ligne pour ESP_PD_DOMAIN_RTC_SLOW_MEM et ESP_PD_DOMAIN_RTC_FAST_MEM, la puce s'approche du mode hibernation et consomme environ 5 µA. Dans ce cas, les variables en mémoire RTC sont perdues et seuls le timer ou ext1 peuvent réveiller la carte. Dans la plupart des projets, la différence entre 10 µA et 5 µA est négligeable face au reste de la carte ; règle d'abord les problèmes de la section suivante.

Pourquoi les cartes de développement consomment-elles des milliampères en deep sleep ?

Quand tu téléverses ton sketch et branches un multimètre, tu vois souvent 5–15 mA au lieu de 10 µA. Le problème ne vient pas de la puce, mais des composants annexes de la carte. La plupart des cartes DevKit et NodeMCU-32S bon marché utilisent un régulateur AMS1117 pour passer de 5 V à 3,3 V, et ce régulateur consomme à lui seul environ 5 mA typiques même sans charge. Il faut y ajouter la LED d'alimentation toujours allumée et la puce USB-série (CP2102 ou CH340) qui dialogue avec l'ordinateur. Ensemble, ils tournent généralement autour de 8 mA et vident environ 190 mAh par jour même quand l'ESP32 dort : une 18650 de 3000 mAh tient à peine deux semaines avec une telle carte. Pour mesurer le courant, place le multimètre en série entre la batterie et le circuit et passe sur le calibre µA pendant le sommeil ; tous les détails sont dans le guide comment utiliser un multimètre.

Source de consommationCourant en sommeilSolution
Module ESP32 (sommeil profond)≈10 µADéjà bas, rien à faire
Régulateur AMS11175 mA typiques (au repos)Utilise un MCP1700 (1,6 µA au repos) ou un HT7333 (environ 4 µA)
LED d'alimentation1–3 mADessoude la LED ou sa résistance
Puce USB-série (CP2102, CH340)Variable selon la carte, peut atteindre le mAUtilise une carte sans puce USB ou un module nu
Pont diviseur de batterie 100 kΩ + 100 kΩ21 µA (à 4,2 V)Utilise 1 MΩ + 1 MΩ ou active le pont avec un MOSFET seulement pendant la mesure
Capteurs alimentés en permanenceDu µA au mA selon le capteurAlimente le capteur via une GPIO ou un MOSFET seulement pendant la mesure
Ne branche jamais une batterie lithium-ion comme la 18650 directement sur la broche 3V3 : une cellule Li-ion pleine est à 4,2 V, alors que l'ESP32 accepte au maximum 3,6 V. La brancher sur VIN n'est pas une bonne solution non plus, car l'AMS1117 fait chuter environ 1 V et sa sortie passe sous 3 V dès que la batterie est à moitié vide. La bonne méthode consiste à alimenter la broche 3V3 via un LDO 3,3 V à faible courant de repos et faible chute de tension. Les petits LDO comme le MCP1700 et le HT7333 ne fournissent que 250 mA : ajoute au moins 470 µF sur leur sortie pour absorber les pics de courant du Wi-Fi. Les cellules LiFePO4, qui ne dépassent pas 3,6 V même pleines, peuvent être branchées directement sur 3V3, sans régulateur.

Ton premier sketch deep sleep : réveil par timer

  1. Dans le gestionnaire de cartes de l'Arduino IDE, installe le paquet esp32 by Espressif Systems (version 3.1 ou ultérieure) et choisis ESP32 Dev Module comme carte.
  2. Téléverse le sketch ci-dessous et ouvre le moniteur série à 115200 bauds.
  3. La carte se réveille toutes les 10 secondes ; regarde le compteur de démarrages augmenter et la cause du réveil s'afficher comme Timer.
  4. Appuie sur le bouton EN : le compteur revient à 1, car il s'agit d'une réinitialisation normale et non d'un réveil de sommeil profond.
  5. Dans ton vrai projet, règle TIME_TO_SLEEP sur 600 (10 minutes) ou 3600 (1 heure).
C++ (Arduino IDE)
1// ESP32 deep sleep: zamanlayıcıyla uyanma ve RTC sayaç / timer wake-up and RTC counter
2#define uS_TO_S_FACTOR 1000000ULL   // 1 saniye = 1.000.000 µs / 1 second = 1,000,000 µs
3#define TIME_TO_SLEEP  10           // uyku süresi, saniye / sleep time in seconds
4
5RTC_DATA_ATTR int bootCount = 0;    // RTC belleğinde, derin uykuda silinmez / in RTC memory, kept in deep sleep
6
7void printWakeupReason() {
8  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
9  switch (cause) {
10    case ESP_SLEEP_WAKEUP_TIMER:    Serial.println("Zamanlayici / Timer"); break;
11    case ESP_SLEEP_WAKEUP_EXT0:     Serial.println("ext0 (tek pin / single pin)"); break;
12    case ESP_SLEEP_WAKEUP_EXT1:     Serial.println("ext1 (coklu pin / multiple pins)"); break;
13    case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Dokunmatik / Touch"); break;
14    default: Serial.printf("Ilk acilis ya da reset / Power-on or reset (%d)\n", (int)cause); break;
15  }
16}
17
18void setup() {
19  Serial.begin(115200);
20  delay(500);                       // Seri Monitör'e zaman tanı / give the Serial Monitor time
21  bootCount++;
22  Serial.printf("Uyanis sayisi / Boot count: %d\n", bootCount);
23  printWakeupReason();
24
25  // Burada sensörü oku, veriyi gönder / read the sensor and send the data here
26
27  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);   // 10 s sonra uyan / wake after 10 s
28  Serial.println("Derin uyku basliyor / Entering deep sleep");
29  Serial.flush();                   // yazı bitmeden uyuma / finish printing before sleeping
30  esp_deep_sleep_start();           // buradan sonrası çalışmaz / nothing below runs
31}
32
33void loop() {
34  // Derin uykuda loop() hiç çalışmaz / loop() never runs with deep sleep
35}

Le cœur du sketch tient en deux lignes : esp_sleep_enable_timer_wakeup() règle le délai de réveil en microsecondes, et esp_deep_sleep_start() endort la puce immédiatement ; rien de ce que tu écris après cette ligne ne s'exécute. N'oublie pas le suffixe ULL (64 bits) dans le calcul du délai : 3600 * 1000000 dépasse la limite d'un int 32 bits, le compilateur ne donne qu'un avertissement et la carte se réveille au mauvais moment ou ne se réveille plus du tout. Serial.flush() attend que le tampon d'envoi soit vide ; sans elle, les dernières lignes sont tronquées. esp_sleep_get_wakeup_cause() t'indique pourquoi la carte s'est réveillée et ne renvoie aucune source de sommeil après la première mise sous tension ou une réinitialisation. Le timer RTC qui compte la durée du sommeil fonctionne par défaut avec un oscillateur RC interne d'environ 150 kHz. Il est moins stable qu'un quartz et peut dériver de quelques pour cent avec la température ; si l'heure compte dans ton projet, il vaut mieux la synchroniser par NTP au réveil.

Garder des compteurs et des mesures dans la mémoire RTC

Si tu dois te souvenir de quelque chose entre deux réveils, écris RTC_DATA_ATTR devant la variable : le compilateur la place dans les 8 Ko de mémoire RTC SLOW, qui restent alimentés en sommeil profond, au lieu de la RAM principale. C'est idéal pour de petites données comme des compteurs, les dernières mesures, les informations du canal Wi-Fi ou la dernière température envoyée. Mais cette mémoire n'est pas permanente : selon la documentation d'Espressif, les données de la mémoire RTC sont réinitialisées à chaque redémarrage, sauf au réveil d'un sommeil profond. Changer la batterie, appuyer sur EN, téléverser un nouveau code ou appeler ESP.restart() remet le compteur à zéro. Les réglages qui doivent survivre à une coupure de courant s'écrivent dans la flash avec la bibliothèque Preferences, mais pas à chaque réveil, car la flash supporte un nombre limité d'écritures.

ÉvénementVariable normaleRTC_DATA_ATTRPreferences (flash)
Réveil du sommeil profondRemise à zéroConservéeConservée
Bouton EN ou ESP.restart()Remise à zéroRevient à sa valeur initialeConservée
Batterie retirée, coupure de courantRemise à zéroEffacéeConservée
Nouveau code téléverséRemise à zéroEffacéeConservée (si la flash n'est pas effacée)

Bien utilisée, cette mémoire multiplie l'autonomie. La connexion au Wi-Fi est la partie la plus coûteuse de chaque réveil. C'est pourquoi le sketch suivant mesure la tension de la batterie toutes les 10 minutes mais n'allume le Wi-Fi qu'une fois par heure : six mesures s'accumulent dans un tableau en mémoire RTC et sont envoyées toutes ensemble au sixième réveil. Il enregistre aussi en mémoire RTC le canal et l'adresse MAC (BSSID) de la box ; à la connexion suivante, l'ESP32 va directement vers cette box sans balayer tous les canaux, ce qui raccourcit nettement la connexion.

C++ (Arduino IDE)
1// RTC belleğinde ölçüm biriktirip saatte bir gönderme / buffer readings in RTC memory, send hourly
2#include <WiFi.h>
3
4const char* SSID = "AgAdi";                       // Wi-Fi adı / Wi-Fi name
5const char* PASS = "Sifre123";                    // Wi-Fi şifresi / Wi-Fi password
6const int BAT_PIN = 35;                           // 1M + 1M bölücünün orta noktası / divider midpoint
7const uint64_t SLEEP_US = 600ULL * 1000000ULL;    // 10 dakika / 10 minutes
8const int BATCH = 6;                              // 6 ölçümde bir gönder / send every 6 readings
9
10RTC_DATA_ATTR float readings[BATCH];              // uykuda korunan ölçümler / readings kept in sleep
11RTC_DATA_ATTR int count = 0;                      // biriken ölçüm sayısı / number of stored readings
12RTC_DATA_ATTR int32_t savedChannel = 0;           // son Wi-Fi kanalı / last Wi-Fi channel
13RTC_DATA_ATTR uint8_t savedBssid[6];              // modemin MAC adresi / access point MAC address
14
15bool connectFast() {
16  WiFi.mode(WIFI_STA);
17  if (savedChannel > 0) {
18    WiFi.begin(SSID, PASS, savedChannel, savedBssid);   // taramadan bağlan / connect without scanning
19  } else {
20    WiFi.begin(SSID, PASS);                             // ilk sefer: normal bağlantı / first time: normal connect
21  }
22  unsigned long start = millis();
23  while (WiFi.status() != WL_CONNECTED) {
24    if (millis() - start > 10000) {                     // 10 s içinde bağlanamazsa vazgeç / give up after 10 s
25      savedChannel = 0;                                 // bir dahaki sefere tara / scan next time
26      return false;
27    }
28    delay(50);
29  }
30  savedChannel = WiFi.channel();
31  memcpy(savedBssid, WiFi.BSSID(), 6);
32  return true;
33}
34
35void setup() {
36  Serial.begin(115200);
37  // Pili Wi-Fi açılmadan önce ölç / measure the battery before Wi-Fi starts
38  float v = analogReadMilliVolts(BAT_PIN) * 2 / 1000.0;   // bölücü gerilimi yarıya indirir / divider halves it
39  readings[count++] = v;
40  Serial.printf("Olcum / Reading %d: %.2f V\n", count, v);
41
42  if (count >= BATCH) {
43    if (connectFast()) {
44      for (int i = 0; i < BATCH; i++) {
45        Serial.printf("Gonder / Send: %.2f V\n", readings[i]);   // burada HTTP ya da MQTT / HTTP or MQTT here
46      }
47      count = 0;
48    } else {
49      for (int i = 1; i < BATCH; i++) readings[i - 1] = readings[i];   // en eskiyi at / drop the oldest
50      count = BATCH - 1;
51    }
52    WiFi.disconnect(true);
53    WiFi.mode(WIFI_OFF);                                // radyoyu kapat / turn the radio off
54  }
55
56  Serial.flush();
57  esp_sleep_enable_timer_wakeup(SLEEP_US);
58  esp_deep_sleep_start();
59}
60
61void loop() {
62}

La tension de la batterie est divisée par deux par un pont diviseur de 1 MΩ + 1 MΩ et lue sur la GPIO 35, un canal de l'ADC1. Un condensateur de 100 nF entre le point milieu du pont et GND stabilise la mesure, même avec un pont d'une impédance aussi élevée. Il est aussi important de mesurer avant d'allumer le Wi-Fi, car le courant consommé par la radio fait chuter un instant la tension de la batterie. Si le Wi-Fi ne se connecte pas, la mesure la plus ancienne est abandonnée et les autres sont gardées pour la tentative suivante. Couper proprement la radio avant de dormir avec WiFi.disconnect(true) et WiFi.mode(WIFI_OFF) est d'ailleurs ce que recommande Espressif. Pour accélérer encore la connexion, attribue une IP fixe avec WiFi.config() et évite l'attente du DHCP. Le calcul du pont est expliqué dans le guide pont diviseur de tension et le circuit de charge dans module de charge TP4056.

Réveil par bouton ou capteur PIR : ext0 et ext1

En plus du timer, un signal extérieur peut aussi réveiller l'ESP32. Il existe deux façons de le faire, et toutes deux ne fonctionnent que sur les broches RTC GPIO : 0, 2, 4, 12–15, 25–27 et 32–39. ext0 surveille une seule broche et réveille la carte quand elle atteint le niveau choisi (HIGH ou LOW) ; comme il garde les périphériques RTC alimentés, les résistances internes de pull-up et de pull-down continuent de fonctionner pendant le sommeil. ext1 surveille plusieurs broches à la fois grâce à un masque de bits. Sur l'ESP32 classique, ext1 a deux modes : ESP_EXT1_WAKEUP_ANY_HIGH réveille la carte dès qu'une des broches choisies passe à HIGH, et ESP_EXT1_WAKEUP_ALL_LOW quand toutes sont à LOW en même temps. Le mode ANY_LOW, qui réveille dès qu'une broche passe à LOW, n'existe que sur les ESP32-S2, S3, C6 et H2. Si tu veux réveiller un ESP32 classique avec plusieurs boutons, relie donc les boutons au 3V3 et mets une résistance de pull-down de 10 kΩ sur chaque broche. Tu peux aussi activer plusieurs sources à la fois ; avec le PIR et un timer horaire activés, par exemple, la carte se réveille avec celui qui arrive en premier.

Source de réveilFonctionBrochesRemarque
Timeresp_sleep_enable_timer_wakeup()Aucune brocheDurée en microsecondes, 64 bits
ext0esp_sleep_enable_ext0_wakeup()Une RTC GPIORéveil sur HIGH ou LOW ; incompatible avec le tactile et l'ULP
ext1esp_sleep_enable_ext1_wakeup_io()Plusieurs RTC GPIOANY_HIGH ou ALL_LOW ; résistances externes conseillées
TactiletouchSleepWakeUpEnable()T0–T9 (10 broches)Réveil quand la valeur passe sous le seuil ; incompatible avec ext0
Coprocesseur ULPesp_sleep_enable_ulp_wakeup()Selon le programmePeut lire des capteurs pendant le sommeil ; niveau avancé

Câblage du circuit d'exemple

ComposantBroche du composantBroche de l'ESP32Remarque
Capteur PIR (HC-SR501 ou AM312)OUTGPIO 33Réveille la carte via ext0
Capteur PIRVCC / GND5V (HC-SR501) ou 3V3 (AM312) / GNDLe HC-SR501 demande au moins 4,5 V
Bouton AUne patte / l'autre patte3V3 / GPIO 25Pull-down de 10 kΩ entre GPIO 25 et GND
Bouton BUne patte / l'autre patte3V3 / GPIO 26Pull-down de 10 kΩ entre GPIO 26 et GND
Pastille tactile ou fil–GPIO 27 (T7)Plus fiable si le fil reste court
LED + 220 ΩAnodeGPIO 2Sur la plupart des DevKit, la LED bleue intégrée est aussi sur cette broche
Pont diviseur de batterie (1 MΩ + 1 MΩ)Point milieuGPIO 35100 nF entre le point milieu et GND
18650 + TP4056 + LDO 3,3 VSortie du LDO / GND3V3 / GNDCondensateur de 470 µF sur la sortie du LDO
Évite les broches GPIO 0, 2, 12 et 15 comme entrées de réveil. Ce sont des broches de démarrage (strapping) : si un bouton ou un capteur les maintient au mauvais niveau pendant la réinitialisation, la carte passe en mode programmation ou ne démarre pas du tout. Par exemple, si la GPIO 12 est à HIGH au démarrage, la tension de la flash est réglée sur 1,8 V et la carte ne peut pas démarrer. Les GPIO 34–39 sont des entrées seules, sans résistance interne de pull-up ni de pull-down ; si tu réveilles la carte avec elles, ajoute la résistance à l'extérieur. Tu peux consulter le brochage complet de ta carte avec l'outil Pinout.

Sketch de réveil par capteur PIR (ext0)

C++ (Arduino IDE)
1// PIR ile uyanma (ext0) / wake on PIR motion (ext0)
2#include "driver/rtc_io.h"
3
4const gpio_num_t PIR_PIN = GPIO_NUM_33;   // RTC GPIO olmalı / must be an RTC GPIO
5const int LED_PIN = 2;                    // uyarı LED'i / alert LED
6
7RTC_DATA_ATTR int motionCount = 0;        // toplam hareket sayısı / total motion count
8
9void setup() {
10  Serial.begin(115200);
11  rtc_gpio_deinit(PIR_PIN);               // pini yeniden normal GPIO yap / turn the pad back into a normal GPIO
12  pinMode(PIR_PIN, INPUT);
13  pinMode(LED_PIN, OUTPUT);
14
15  if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
16    motionCount++;
17    Serial.printf("Hareket! / Motion! Toplam / Total: %d\n", motionCount);
18    digitalWrite(LED_PIN, HIGH);          // burada bildirim gönderebilirsin / send a notification here
19    delay(1000);
20    digitalWrite(LED_PIN, LOW);
21  }
22
23  // PIR çıkışı LOW olana kadar bekle, yoksa hemen yeniden uyanır / wait for LOW or it wakes again at once
24  while (digitalRead(PIR_PIN) == HIGH) {
25    delay(100);
26  }
27
28  esp_sleep_enable_ext0_wakeup(PIR_PIN, 1);   // pin HIGH olunca uyan / wake when the pin goes HIGH
29  rtc_gpio_pullup_dis(PIR_PIN);
30  rtc_gpio_pulldown_en(PIR_PIN);              // boştayken LOW tut / keep it LOW while idle
31  Serial.println("Uyku / Sleep");
32  Serial.flush();
33  esp_deep_sleep_start();
34}
35
36void loop() {
37}

Au réveil, le sketch commence par remettre la broche en GPIO normale avec rtc_gpio_deinit(). Après un réveil par ext0, la broche reste en mode RTC et, sans cette ligne, digitalRead() risque de mal fonctionner. Il compte le mouvement, allume la LED puis attend que la sortie du PIR repasse à LOW. Cette attente est essentielle : si la carte s'endort alors que la sortie est encore à HIGH, elle se réveille aussitôt et entre dans une boucle qui s'allume et s'éteint plusieurs fois par seconde. Le HC-SR501 garde sa sortie à HIGH pendant la durée réglée ; tourne le potentiomètre de temporisation au minimum pour raccourcir l'attente. Comme le HC-SR501 demande au moins 4,5 V, choisis plutôt le petit module PIR AM312, qui fonctionne aussi en 3,3 V, pour les projets alimentés par une seule 18650. Pour régler le capteur, consulte le guide capteur de mouvement PIR.

Sketch de réveil avec deux boutons (ext1)

C++ (Arduino IDE)
1// İki butonla uyanma (ext1) / wake with two buttons (ext1)
2#include "driver/rtc_io.h"
3
4const gpio_num_t BTN_A = GPIO_NUM_25;     // buton A: 3V3'e, 10k pull-down / button A: to 3V3, 10k pull-down
5const gpio_num_t BTN_B = GPIO_NUM_26;     // buton B: 3V3'e, 10k pull-down / button B: to 3V3, 10k pull-down
6const uint64_t WAKE_MASK = (1ULL << BTN_A) | (1ULL << BTN_B);
7
8void setup() {
9  Serial.begin(115200);
10  rtc_gpio_deinit(BTN_A);                 // pinleri normal GPIO'ya döndür / back to normal GPIO
11  rtc_gpio_deinit(BTN_B);
12  pinMode(BTN_A, INPUT);
13  pinMode(BTN_B, INPUT);
14
15  if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT1) {
16    uint64_t pins = esp_sleep_get_ext1_wakeup_status();   // hangi pin uyandırdı? / which pin woke us?
17    if (pins & (1ULL << BTN_A)) Serial.println("Buton A: isigi ac / Button A: lights on");
18    if (pins & (1ULL << BTN_B)) Serial.println("Buton B: isigi kapat / Button B: lights off");
19  } else {
20    Serial.println("Ilk acilis / First boot");
21  }
22
23  while (digitalRead(BTN_A) == HIGH || digitalRead(BTN_B) == HIGH) {
24    delay(10);                            // butonlar bırakılana kadar bekle / wait until released
25  }
26
27  esp_sleep_enable_ext1_wakeup_io(WAKE_MASK, ESP_EXT1_WAKEUP_ANY_HIGH);  // biri HIGH olunca / any goes HIGH
28  Serial.flush();
29  esp_deep_sleep_start();
30}
31
32void loop() {
33}

Après un réveil par ext1, esp_sleep_get_ext1_wakeup_status() renvoie un masque de bits qui indique quelle broche a réveillé la carte. Tu peux ainsi donner deux rôles différents aux boutons : l'un allume la lumière et l'autre l'éteint, ou l'un envoie une mesure et l'autre ouvre un menu. Comme les boutons sont reliés au 3V3 et que les broches sont tirées vers GND par 10 kΩ, elles lisent LOW au repos et HIGH quand on appuie : c'est exactement ce qu'attend le mode ANY_HIGH. Avant de dormir, le sketch attend que les boutons soient relâchés ; sinon, un bouton encore enfoncé réveillerait la carte immédiatement. Si tu utilises la version 2.x ou 3.0.x du cœur Arduino ESP32, qui ne connaît pas la fonction _io, écris esp_sleep_enable_ext1_wakeup avec les mêmes paramètres à la place de esp_sleep_enable_ext1_wakeup_io. Le guide comment brancher un bouton sur Arduino explique en détail pourquoi la résistance de pull-down est nécessaire.

Réveil par toucher (touch wake-up)

Dix broches de l'ESP32 (T0–T9) fonctionnent comme capteurs tactiles capacitifs et détectent ton doigt même en sommeil profond. Un fil, une bande de ruban de cuivre ou une pastille de PCB reliée à la broche se comporte comme un bouton et peut même se cacher derrière un fin couvercle en plastique ou en bois. Sur l'ESP32 classique, la valeur de touchRead() baisse quand on touche : avec un fil court, elle vaut souvent 60–80 sans contact et 10–20 au toucher. Le seuil de réveil se place entre ces deux valeurs ; le 40 de l'exemple est un bon point de départ. Sur l'ESP32 classique, tu peux utiliser plusieurs broches tactiles à la fois comme source de réveil. Sur les ESP32-S2 et S3, en revanche, une seule broche peut réveiller la puce, la valeur augmente au toucher et le seuil utilise une tout autre échelle (5000 dans l'exemple d'Espressif). Le réveil tactile ne peut pas être combiné avec ext0 ; si tu as aussi besoin d'un bouton, choisis ext1. Pour la liste des broches et l'étalonnage, lis le guide broches tactiles de l'ESP32.

C++ (Arduino IDE)
1// Dokunarak uyandırma: T7 = GPIO 27 / touch wake-up: T7 = GPIO 27
2#define THRESHOLD 40                      // değer bunun altına inince uyanır / wakes when the value drops below this
3
4RTC_DATA_ATTR int touchWakes = 0;
5
6void setup() {
7  Serial.begin(115200);
8  delay(500);
9  if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) {
10    touchWakes++;
11    Serial.printf("Dokunusla uyanma / Touch wake #%d\n", touchWakes);
12  }
13  // Eşiği ayarlamak için dokunmadan ve dokunarak değeri izle / watch the value untouched and touched
14  Serial.printf("T7 degeri / value: %d\n", (int)touchRead(T7));
15
16  touchSleepWakeUpEnable(T7, THRESHOLD);  // dokunmatikle uyanmayı aç / enable touch wake-up
17  Serial.flush();
18  esp_deep_sleep_start();
19}
20
21void loop() {
22}

Deep sleep de l'ESP32 avec MicroPython

Si tu programmes l'ESP32 en MicroPython, tu obtiens le même résultat avec moins de code. machine.deepsleep(ms) endort la carte pendant le nombre de millisecondes indiqué, esp32.wake_on_ext0() fait d'une broche une source de réveil et machine.RTC().memory() fournit un tampon d'octets qui survit au sommeil ; sur l'ESP32, il fait 2048 octets par défaut. Au réveil, main.py repart du début ; machine.reset_cause() t'indique si la carte sort du sommeil profond et machine.wake_reason() ce qui l'a réveillée. Les broches RTC configurées avec un pull-up ou un pull-down gardent ce réglage pendant le sommeil. Si tu débutes en MicroPython, commence par le guide les bases de MicroPython.

MicroPython
1import machine, esp32, time
2from machine import Pin
3
4rtc = machine.RTC()
5led = Pin(2, Pin.OUT)
6
7mem = rtc.memory()                            # RTC belleğini oku / read RTC memory
8count = int.from_bytes(mem, "little") if mem else 0
9
10if machine.reset_cause() == machine.DEEPSLEEP_RESET:
11    count += 1
12    if machine.wake_reason() == machine.EXT0_WAKE:
13        print("Butonla uyandi / Woken by button")
14    else:
15        print("Zamanlayiciyla uyandi / Woken by timer")
16else:
17    count = 0
18    print("Ilk acilis / First boot")
19
20rtc.memory(count.to_bytes(4, "little"))       # sayacı sakla / store the counter
21print("Uyanis / Wake:", count)
22
23led.on()                                      # kısa iş: ölç ve gönder / short task: measure and send
24time.sleep_ms(200)
25led.off()
26
27button = Pin(33, Pin.IN, Pin.PULL_DOWN)       # buton GPIO 33 ile 3V3 arasında / button between GPIO 33 and 3V3
28esp32.wake_on_ext0(button, esp32.WAKEUP_ANY_HIGH)   # basınca uyan / wake on press
29machine.deepsleep(60000)                      # 60 s uyu / sleep for 60 s

Le Raspberry Pi Pico, lui, n'a pas de sommeil profond à quelques microampères comme l'ESP32. En MicroPython, machine.lightsleep(ms) arrête la plupart des horloges, met le CPU en pause et conserve la RAM, tandis que machine.deepsleep(ms) réinitialise la carte après le même type de sommeil. Même dans ces modes, la consommation de la carte reste de l'ordre du milliampère. Si tu veux qu'un montage à base de Pico tienne des mois sur batterie, tu obtiendras donc de meilleurs résultats en coupant complètement son alimentation entre deux mesures avec un minuteur d'alimentation comme le TPL5110. Pour les bases du Pico, consulte le guide qu'est-ce que le Raspberry Pi Pico.

Un capteur qui tient des mois sur une 18650 : calcul de l'autonomie

Pour trouver l'autonomie d'un appareil qui dort et se réveille, tu calcules d'abord le courant moyen : Courant moyen = (Courant éveillé × Durée éveillée + Courant en sommeil × Durée de sommeil) / Durée totale. Ensuite, tu divises la capacité utile de la batterie par cette moyenne. On ne peut pas exploiter toute une 18650 marquée 3000 mAh ; compter environ 85 %, soit 2550 mAh, pour la coupure basse tension, les pertes du régulateur et le vieillissement est réaliste. Le tableau ci-dessous a été calculé pour un capteur qui se réveille toutes les 10 minutes, envoie ses données en Wi-Fi et consomme en moyenne 120 mA pendant la connexion.

ScénarioCourant en sommeilDurée éveilléeCourant moyenAutonomie estimée
Carte DevKit8 mA3 s, 120 mA8,56 mA≈12 jours
Carte DevKit, connexion rapide8 mA1 s, 120 mA8,19 mA≈13 jours
Module nu + MCP1700 + pont de 1 MΩ15 µA3 s, 120 mA0,61 mA≈173 jours (5,7 mois)
Module nu, connexion rapide15 µA1 s, 120 mA0,215 mA≈494 jours (16 mois)
Module nu, envoi groupé toutes les heures15 µA1 s de Wi-Fi par heure (120 mA) + 5 × 0,3 s de mesure (40 mA)0,065 mA≈4,5 ans en théorie

La conclusion est nette : sur une carte de développement, raccourcir la phase d'éveil ne change presque rien, car ce qui vide vraiment la batterie, ce sont les 8 mA en sommeil. Quand le courant de sommeil descend aux microampères, l'équilibre s'inverse et chaque seconde d'éveil compte : passer la connexion Wi-Fi de 3 secondes à 1 seconde triple presque l'autonomie. Quand le courant moyen descend sous 0,1 mA, l'autodécharge de la batterie entre en jeu. Une cellule Li-ion perd environ 2–3 % de sa capacité par mois, si bien que les 4,5 ans théoriques se réduisent à environ 2 ans en pratique. Pour faire le calcul avec tes propres valeurs, utilise le calculateur d'autonomie de batterie et découvre les notions de mAh et de Wh dans le guide que signifie mAh.

  • Choisis la bonne carte : les cartes sans puce USB ni LED d'alimentation, ou un module ESP32 nu, ne consomment que quelques microampères en sommeil.
  • Change de régulateur : utilise un LDO dont le courant de repos ne dépasse pas quelques microampères à la place de l'AMS1117.
  • N'alimente le capteur que pendant la mesure : les capteurs qui consomment quelques mA peuvent être alimentés directement par une GPIO, les charges plus lourdes via un MOSFET canal P ; place une résistance de pull-up sur la grille du MOSFET pour qu'il reste bloqué pendant le sommeil. Les détails sont dans le guide MOSFET avec Arduino.
  • Allume rarement le Wi-Fi : accumule les mesures en mémoire RTC et envoie-les en bloc ; si tu envoies des données à un autre ESP32 proche, ESP-NOW transmet beaucoup plus vite car il n'a pas besoin de s'associer à une box.
  • Accélère la connexion : avec une IP fixe, le canal et le BSSID enregistrés, la connexion Wi-Fi prend souvent moins d'une seconde.
  • Supprime les attentes inutiles : dans le projet terminé, retire les sorties vers le moniteur série et les longues lignes delay() ; chaque milliseconde d'éveil se paie sur la batterie.
  • N'oublie pas le pont diviseur ni les LED : un pont de 100 kΩ + 100 kΩ branché en permanence consomme deux fois plus que l'ESP32 endormi.

Idées de projets avec le deep sleep de l'ESP32

  • Station météo sur batterie : mesure la température, l'humidité et la pression avec un BME280 toutes les 10 minutes et envoie-les toutes les heures à Home Assistant via MQTT.
  • Capteur d'humidité pour le jardin : réveille-toi toutes les heures, mesure l'humidité du sol et préviens ton téléphone quand la terre devient sèche.
  • Alarme de porte et de fenêtre : quand la porte s'ouvre, un interrupteur reed réveille l'ESP32 via ext0 et un bot Telegram t'envoie un message.
  • Capteur de sécurité sur batterie : fabrique un appareil qui se réveille et envoie une alerte quand le PIR détecte un mouvement et qui dort des mois le reste du temps.
  • Sonnette tactile : colle du ruban de cuivre derrière un panneau en bois ; au toucher, l'ESP32 se réveille et envoie un signal au carillon intérieur via ESP-NOW.
  • Enregistreur de température sur batterie : mesure la température d'un réfrigérateur ou d'un aquarium avec un DS18B20 étanche, accumule les valeurs en mémoire RTC et envoie-les quelques fois par jour.

Erreurs fréquentes et solutions

SymptômeCauseSolution
La carte se réveille juste après s'être endormieLa broche de réveil est encore active (PIR à HIGH, bouton enfoncé) ou flottanteAttends que la broche revienne à son niveau de repos avant de dormir et ajoute une résistance de pull-down ou de pull-up
La carte ne se réveille pas à l'heure prévueDépassement 32 bits dans le calcul du délai (3600 * 1000000)Ajoute ULL aux constantes : 3600ULL * 1000000ULL
Le compteur repart toujours de 1La variable n'est pas en RTC_DATA_ATTR ou la carte a été réinitialiséeAjoute RTC_DATA_ATTR ; utilise Preferences pour les données permanentes
On mesure 5–15 mA en sommeilRégulateur, LED d'alimentation, puce USB, pont diviseur ou capteursCarte basse consommation ou module nu, LDO à faible courant de repos
Les dernières lignes du moniteur série sont tronquéesLa carte s'est endormie avant que le tampon soit videAppelle Serial.flush() avant esp_deep_sleep_start()
digitalRead() renvoie de fausses valeurs après le réveilLa broche de réveil est restée en mode RTCAppelle rtc_gpio_deinit() avant d'utiliser la broche
Un bouton sur GPIO 34–39 ne réveille pas la carteCes broches n'ont pas de résistance de tirage interne, la broche flotteAjoute une résistance externe de 10 kΩ
Impossible de téléverser pendant le sommeilLa carte n'a pas de circuit de reset automatique ; sur les S3 et C3, le port USB natif disparaît pendant le sommeilMaintiens BOOT, appuie puis relâche EN (RESET), puis lance le téléversement
Un relais ou une LED change d'état à l'endormissementEn sommeil profond, les broches numériques passent en haute impédanceUtilise une résistance de tirage ou garde le niveau de la broche avec rtc_gpio_hold_en()
Pendant le développement, ajoute temporairement une attente de 5 secondes au début de setup(), ou une condition qui empêche le sommeil tant qu'un bouton est enfoncé. Tu auras ainsi le temps d'ouvrir le moniteur série et de téléverser un nouveau code même si la carte dort presque tout le temps ; pense à retirer cette ligne une fois le projet terminé. Si, sur batterie, la carte redémarre d'elle-même de temps en temps, les pics de courant du Wi-Fi sont très probablement en cause ; les solutions sont dans le guide erreur brownout de l'ESP32.

Le deep sleep de l'ESP32 est la clé pour faire tourner le même code des mois plutôt que des jours sur batterie : garde le travail court, choisis la bonne source de réveil, stocke en mémoire RTC les petites données utiles entre deux réveils et n'oublie jamais la consommation propre de la carte. Pour revoir les bases de l'ESP32, le guide qu'est-ce que l'ESP32 est un bon point de départ. Dans l'application BlueGrays, le projet ESP32 Deep Sleep — Économie de batterie (OLED + compteur en RAM RTC) te permet d'essayer la logique du timer et du compteur RTC de cet article sur un circuit avec écran OLED, avec un schéma pas à pas et un code prêt à l'emploi.

Questions fréquentes

Combien de courant consomme l'ESP32 en deep sleep ?

D'après la fiche technique d'Espressif, la puce ESP32 consomme environ 10 µA en sommeil profond avec le timer et la mémoire RTC actifs, et 5 µA en mode hibernation. Sur les cartes de développement comme la DevKit, le régulateur, la LED d'alimentation et la puce USB-série portent toutefois le courant de sommeil à 5–15 mA dans la plupart des cas.

Comment réveiller un ESP32 du deep sleep ?

Il existe cinq moyens : le timer RTC, une seule broche RTC (ext0), plusieurs broches RTC (ext1), les broches tactiles et le coprocesseur ULP. Tu configures la source de réveil avant d'appeler esp_deep_sleep_start() et tu peux en activer plusieurs à la fois ; seuls ext0 et le réveil tactile ne peuvent pas être utilisés ensemble.

Les variables sont-elles effacées en deep sleep sur l'ESP32 ?

Oui, les variables normales sont effacées, car le réveil d'un sommeil profond est un redémarrage et setup() repart du début. Les variables marquées RTC_DATA_ATTR sont stockées en mémoire RTC et conservées d'un réveil à l'autre, mais elles reviennent à leur valeur initiale après une coupure de courant, un appui sur EN ou un nouveau téléversement.

Combien de temps un ESP32 tient-il sur une batterie 18650 ?

D'une journée à plus d'un an, selon la carte et l'usage. Une DevKit connectée en permanence au Wi-Fi ne tient que 1 à 2 jours avec une 18650 de 3000 mAh, et une DevKit qui se réveille toutes les 10 minutes environ 12 jours. Un circuit basse consommation qui fait le même travail avec 15 µA en sommeil tient de 5 à 16 mois, selon la durée de chaque connexion.

Quelle est la différence entre light sleep et deep sleep sur l'ESP32 ?

En light sleep, le CPU est mis en pause mais la RAM est conservée ; au réveil, le programme reprend à la ligne où il s'était arrêté et la puce consomme environ 0,8 mA. En deep sleep, la RAM est coupée aussi et la consommation descend à 10 µA, mais le programme redémarre à chaque réveil. Le sommeil léger convient aux pauses de quelques secondes, le sommeil profond aux attentes de plusieurs minutes ou heures.

Comment téléverser un code sur un ESP32 en deep sleep ?

Sur les cartes équipées d'un circuit de reset automatique, le téléversement démarre en général sans souci, car l'outil réinitialise la puce par la broche EN. Sinon, maintiens le bouton BOOT, appuie puis relâche EN (RESET), puis lance le téléversement. Sur les cartes à USB natif comme l'ESP32-S3 et le C3, le port disparaît pendant le sommeil : cette méthode y est souvent indispensable.

Voir tous les projets
Clignotement LED avec ESP32
#103Débutant

Clignotement LED avec ESP32

Enseigne l'utilisation de base des sorties GPIO avec l'ESP32. Nous obtenons un effet de clignotement en allumant et éteignant une LED à partir de la broche numérique. Version ESP32 du projet blink classique sur Arduino UNO ; les commandes de base de blink dans l'environnement Arduino restent les mêmes, mais le brochage et les niveaux GPIO de 3,3 V de l'ESP32 diffèrent de ceux de l'Arduino UNO.

4.7(37)
99
ESP32 Contrôle de LED avec bouton poussoir (Push)
#104Débutant

ESP32 Contrôle de LED avec bouton poussoir (Push)

La LED s'allume lorsque le bouton est enfoncé et s'éteint lorsqu'il est relâché. Montre comment la broche d'entrée numérique de l'ESP32 et la résistance pull-up interne sont utilisées. Grâce au mode INPUT_PULLUP, aucune résistance externe n'est nécessaire.

4.6(36)
55
Mode veille profonde de l'ESP32 — Économie de batterie (OLED + compteur RAM RTC)
#135Avancé
Premium

Mode veille profonde de l'ESP32 — Économie de batterie (OLED + compteur RAM RTC)

Le mode « Deep Sleep » de l'ESP32 réduit la consommation de courant à environ 10 µA en désactivant le processeur et la plupart des périphériques, ce qui revêt une importance cruciale pour les appareils IoT fonctionnant sur batterie. Dans ce projet, nous utilisons trois sources de réveil différentes : une minuterie (timer, 15 s), une broche externe (EXT0 — bouton GPIO 33) et un capteur tactile (T0/GPIO 4). Les variables marquées avec RTC_DATA_ATTR sont conservées pendant le mode Deep Sleep — le

4.3(10)
16
Système d'Alarme de Mouvement ESP32 (PIR + Buzzer + LED + Telegram)
#145Avancé
Premium

Système d'Alarme de Mouvement ESP32 (PIR + Buzzer + LED + Telegram)

Un système d'alarme de sécurité intelligent qui active le buzzer et la LED lorsque le capteur PIR détecte un mouvement, tout en envoyant une notification instantanée au propriétaire via Telegram. Il intègre un délai d'attente de 30 secondes pour limiter la fréquence des alarmes répétées ; ce mécanisme ne vérifie pas la validité des détections du capteur PIR et n'élimine pas les faux déclenchements. Idéal pour la sécurité domestique, la surveillance de garage, d'entrepôts ou de bureaux. Avec l'ES

0.0(0)
9
Éclairage automatique avec le capteur de mouvement PIR ESP32
#121Intermédiaire
Premium

Éclairage automatique avec le capteur de mouvement PIR ESP32

Dans ce projet, nous allons détecter toute personne entrant dans la pièce à l'aide du capteur de mouvement PIR HC-SR501 et allumer automatiquement la LED. Nous suivrons la durée d'allumage de la LED avec millis() ; chaque lecture HIGH du capteur actualisera l'instant du dernier mouvement, et la LED s'éteindra au moins 10 secondes après la dernière lecture HIGH. Le code actuel attend également 50 ms à chaque itération avec delay(50) ; la boucle de l'application n'est donc pas entièrement non

4.4(24)
38
ESP32 DHT22 Température et humidité (avec écran LCD)
#117Intermédiaire

ESP32 DHT22 Température et humidité (avec écran LCD)

Il s'agit d'un projet permettant de mesurer la température ambiante et le taux d'humidité à l'aide d'un capteur DHT22 et d'afficher ces données en temps réel sur un écran LCD I2C 16x2. Les données du capteur sont lues à l'aide du protocole one-wire grâce à la bibliothèque Adafruit DHT. Ce projet constitue la base des stations météo IoT, de la domotique ou des systèmes de surveillance de l'environnement dans les serres.

4.8(38)
56
Enregistreur de Température ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avancé
Premium

Enregistreur de Température ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

Construis un enregistreur de température horodaté avec ESP32 ! Lis la température/humidité du DHT22 chaque minute, obtiens l'heure réelle du DS1307 RTC et enregistre sur carte microSD au format CSV. L'OLED affiche en direct la température (grande police), le pourcentage d'humidité, l'horodatage et le compteur. Le fichier /temp_log.csv sur la carte SD s'ouvre dans Excel, Google Sheets ou Python pandas pour analyse — parfait pour surveillance de serre, suivi de température à domicile, c

4.7(7)
12