ESP32 Deep Sleep: risveglio, consumi in µA e durata batteria
ESP32 deep sleep passo passo: consumi in µA di ogni modalità, risveglio con timer, pulsante, PIR e touch (ext0/ext1), memoria RTC e autonomia con una 18650.
Il deep sleep dell'ESP32 (sospensione profonda) è la modalità di risparmio energetico in cui l'ESP32 spegne i core, la radio Wi-Fi e Bluetooth e la memoria principale, lasciando acceso solo il piccolo dominio RTC. In questa modalità il consumo del chip scende dai 240 mA della trasmissione Wi-Fi a circa 10 µA, cioè ventiquattromila volte meno. La scheda si risveglia allo scadere del tempo che hai impostato, quando viene premuto un pulsante, quando un sensore PIR rileva un movimento o quando tocchi un pin; finisce il suo lavoro in pochi secondi e torna a dormire. È così che stazioni meteo, sensori da giardino, allarmi per porte e registratori remoti funzionano per mesi invece che per giorni con una sola batteria 18650.
In questa guida scoprirai le modalità di sospensione dell'ESP32 e i loro consumi reali, imparerai a risvegliare la scheda con un timer, un pulsante, un sensore PIR (ext0 ed ext1) o un tocco, a conservare contatori e misure nella memoria RTC che sopravvive al sonno, capirai perché le schede di sviluppo consumano milliampere anche mentre dormono e calcolerai passo passo quanti mesi dura una sola 18650. Gli sketch Arduino sono scritti per la versione 3.1 o successiva del core Arduino per ESP32; alla fine vedrai come fare la stessa cosa in MicroPython.

Che cos'è il deep sleep dell'ESP32 e come funziona?
Dentro l'ESP32 ci sono due mondi separati. Il primo è il dominio principale, con i core, 520 KB di RAM e la radio Wi-Fi e Bluetooth. Il secondo è il dominio RTC, con un proprio piccolo timer, 8 KB di memoria RTC FAST e 8 KB di RTC SLOW, i pin RTC GPIO e un coprocessore a bassissimo consumo chiamato ULP. In deep sleep il dominio principale viene spento del tutto e continua a funzionare solo quello RTC. Quando arriva il momento del risveglio, il chip in realtà si riavvia: parte il bootloader, il programma viene ricaricato dalla flash e setup() ricomincia dall'inizio. Per questo un programma con deep sleep fa tutto il lavoro dentro setup() e loop() non viene mai eseguito. Le variabili normali si azzerano a ogni risveglio; si conservano solo quelle che metti nella memoria RTC.
Modalità di sospensione dell'ESP32 e consumi (µA)
| Modalità | Cosa resta attivo? | Corrente (chip ESP32) |
|---|---|---|
| Attiva: trasmissione Wi-Fi (802.11b, 19,5 dBm) | CPU e radio | 240 mA |
| Attiva: ricezione e ascolto Wi-Fi | CPU e radio | 95–100 mA |
| Modem sleep, 240 MHz | La CPU funziona, radio spenta | 30–68 mA |
| Modem sleep, 80 MHz | La CPU funziona più lenta, radio spenta | 20–31 mA |
| Sospensione leggera (light sleep) | CPU in pausa, RAM conservata | 0,8 mA |
| Deep sleep con ULP attivo | Dominio RTC e coprocessore ULP | 150 µA |
| Deep sleep | Timer RTC e memoria RTC | 10 µA |
| Ibernazione | Solo il timer RTC e alcuni pin RTC | 5 µA |
| Spento (pin EN a LOW) | Niente | 1 µA |
I valori provengono dal datasheet dell'ESP32 di Espressif e riguardano solo il chip. Nella tabella ci sono due punti importanti. Primo, in light sleep il programma riprende dalla riga in cui si era fermato e tutto ciò che è in RAM viene conservato, ma il consumo è ottanta volte più alto che in deep sleep; va bene per pause di pochi secondi. In deep sleep il programma riparte da capo, ma il consumo scende a pochi microampere, ed è la scelta giusta per attese di minuti o di ore. Secondo, nessuna delle due modalità mantiene la connessione Wi-Fi o Bluetooth; devi riconnetterti a ogni risveglio. I chip più recenti sono un po' diversi: l'ESP32-C3 consuma circa 5 µA in deep sleep e l'ESP32-S3 circa 7–8 µA.
Se vuoi consumare ancora meno, puoi spegnere anche le periferiche RTC e la memoria RTC. Con esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF) e la stessa riga per ESP_PD_DOMAIN_RTC_SLOW_MEM ed ESP_PD_DOMAIN_RTC_FAST_MEM il chip si avvicina alla modalità di ibernazione e consuma circa 5 µA. In questo caso le variabili nella memoria RTC vanno perse e solo il timer o ext1 possono risvegliare la scheda. Nella maggior parte dei progetti la differenza tra 10 µA e 5 µA è trascurabile rispetto al resto della scheda, quindi risolvi prima i problemi della sezione successiva.
Perché le schede di sviluppo consumano milliampere in deep sleep?
Quando carichi lo sketch e colleghi un multimetro, spesso vedi 5–15 mA invece di 10 µA. Il problema non è il chip, ma i componenti aggiuntivi della scheda. La maggior parte delle schede DevKit e NodeMCU-32S economiche usa un regolatore AMS1117 per abbassare i 5 V a 3,3 V, e questo regolatore da solo consuma tipicamente 5 mA anche senza carico. A questo si aggiungono il LED di alimentazione sempre acceso e il chip USB-seriale (CP2102 o CH340) che comunica con il computer. Insieme arrivano di solito a circa 8 mA e consumano circa 190 mAh al giorno anche mentre l'ESP32 dorme: una 18650 da 3000 mAh dura a malapena due settimane con una scheda del genere. Per misurare la corrente, collega il multimetro in serie tra la batteria e il circuito e passa alla portata µA durante il sonno; trovi i dettagli nella guida come usare un multimetro.
| Fonte di consumo | Corrente in sospensione | Soluzione |
|---|---|---|
| Modulo ESP32 (deep sleep) | ≈10 µA | Già basso, non serve altro |
| Regolatore AMS1117 | Tipicamente 5 mA (a riposo) | Usa un MCP1700 (1,6 µA a riposo) o un HT7333 (circa 4 µA) |
| LED di alimentazione | 1–3 mA | Dissalda il LED o la sua resistenza |
| Chip USB-seriale (CP2102, CH340) | Dipende dalla scheda, può arrivare ai mA | Usa una scheda senza chip USB o un modulo nudo |
| Partitore della batteria da 100 kΩ + 100 kΩ | 21 µA (a 4,2 V) | Usa 1 MΩ + 1 MΩ o accendi il partitore con un MOSFET solo durante la misura |
| Sensori sempre alimentati | Da µA a mA secondo il sensore | Alimenta il sensore da un GPIO o da un MOSFET solo durante la misura |
Il tuo primo sketch deep sleep: risveglio con il timer
- Nel Gestore schede dell'Arduino IDE installa il pacchetto esp32 by Espressif Systems (versione 3.1 o successiva) e scegli ESP32 Dev Module come scheda.
- Carica lo sketch qui sotto e apri il Monitor seriale a 115200 baud.
- La scheda si risveglia ogni 10 secondi; osserva il contatore dei riavvii che sale e la causa del risveglio stampata come Timer.
- Premi il pulsante EN: il contatore torna a 1, perché si tratta di un normale reset e non di un risveglio dal deep sleep.
- Nel tuo progetto reale imposta TIME_TO_SLEEP a 600 (10 minuti) o a 3600 (1 ora).
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}Il cuore dello sketch sono due righe: esp_sleep_enable_timer_wakeup() imposta il tempo di risveglio in microsecondi ed esp_deep_sleep_start() manda subito il chip a dormire; nulla di ciò che scrivi dopo quella riga viene eseguito. Non dimenticare il suffisso ULL (64 bit) nel calcolo del tempo: 3600 * 1000000 supera il limite di un int a 32 bit, il compilatore dà solo un avviso e la scheda si risveglia al momento sbagliato oppure non si risveglia più. Serial.flush() aspetta che il buffer di trasmissione si svuoti; senza, le ultime righe vengono troncate. esp_sleep_get_wakeup_cause() ti dice perché la scheda si è risvegliata e non restituisce alcuna sorgente di sospensione dopo la prima accensione o un reset. Il timer RTC che conta la durata del sonno usa per impostazione predefinita un oscillatore RC interno da circa 150 kHz. Non è stabile come un quarzo e può derivare di qualche punto percentuale con la temperatura; se l'orario è importante nel tuo progetto, conviene sincronizzarlo con NTP al risveglio.
Conservare contatori e misure nella memoria RTC
Se devi ricordare qualcosa tra un risveglio e l'altro, scrivi RTC_DATA_ATTR davanti alla variabile: il compilatore la mette negli 8 KB di memoria RTC SLOW, che restano alimentati in deep sleep, invece che nella RAM principale. È perfetta per piccoli dati come contatori, ultime misure, informazioni sul canale Wi-Fi o l'ultima temperatura inviata. Questa memoria però non è permanente: secondo la documentazione di Espressif, i dati nella memoria RTC vengono reinizializzati a ogni riavvio, tranne al risveglio dal deep sleep. Cambiare la batteria, premere EN, caricare nuovo codice o chiamare ESP.restart() azzera il contatore. Le impostazioni che devono sopravvivere a un'interruzione di corrente scrivile nella flash con la libreria Preferences, ma non a ogni risveglio, perché la flash sopporta un numero limitato di scritture.
| Evento | Variabile normale | RTC_DATA_ATTR | Preferences (flash) |
|---|---|---|---|
| Risveglio dal deep sleep | Azzerata | Conservata | Conservata |
| Pulsante EN o ESP.restart() | Azzerata | Torna al valore iniziale | Conservata |
| Batteria rimossa, mancanza di corrente | Azzerata | Cancellata | Conservata |
| Caricamento di nuovo codice | Azzerata | Cancellata | Conservata (se la flash non viene cancellata) |
Usata bene, questa memoria moltiplica la durata della batteria. Connettersi al Wi-Fi è la parte più costosa di ogni risveglio. Per questo lo sketch seguente misura la tensione della batteria ogni 10 minuti ma accende il Wi-Fi solo una volta all'ora: sei misure si accumulano in un array nella memoria RTC e al sesto risveglio vengono inviate tutte insieme. Inoltre salva nella memoria RTC il canale e l'indirizzo MAC (BSSID) del router, così alla connessione successiva l'ESP32 si collega direttamente a quel router senza scansionare tutti i canali e la connessione si accorcia in modo evidente.
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 tensione della batteria viene dimezzata da un partitore di tensione da 1 MΩ + 1 MΩ e letta sul GPIO 35, un canale dell'ADC1. Un condensatore da 100 nF tra il punto centrale del partitore e GND rende stabile la misura anche con un partitore ad alta impedenza come questo. È importante anche misurare prima di accendere il Wi-Fi, perché la corrente assorbita dalla radio fa calare per un attimo la tensione della batteria. Se il Wi-Fi non si connette, la misura più vecchia viene scartata e le altre vengono tenute per il tentativo successivo. Spegnere correttamente la radio prima di dormire con WiFi.disconnect(true) e WiFi.mode(WIFI_OFF) è anche ciò che consiglia Espressif. Per accelerare ancora la connessione, assegna un IP statico con WiFi.config() e salta l'attesa del DHCP. Trovi il calcolo del partitore nella guida partitore di tensione e il circuito di ricarica in modulo di ricarica TP4056.
Risveglio con pulsante o sensore PIR: ext0 ed ext1
Oltre al timer, anche un segnale dall'esterno può risvegliare l'ESP32. Ci sono due modi per farlo ed entrambi funzionano solo sui pin RTC GPIO: 0, 2, 4, 12–15, 25–27 e 32–39. ext0 controlla un solo pin e risveglia la scheda quando quel pin raggiunge il livello scelto (HIGH o LOW); poiché mantiene alimentate le periferiche RTC, le resistenze interne di pull-up e pull-down continuano a funzionare durante il sonno. ext1 controlla più pin contemporaneamente tramite una maschera di bit. Sull'ESP32 classico ext1 ha due modalità: ESP_EXT1_WAKEUP_ANY_HIGH risveglia la scheda quando uno qualsiasi dei pin scelti va a HIGH, ESP_EXT1_WAKEUP_ALL_LOW quando sono tutti a LOW nello stesso momento. La modalità ANY_LOW, che risveglia quando un pin qualsiasi va a LOW, esiste solo su ESP32-S2, S3, C6 e H2. Quindi, se vuoi risvegliare un ESP32 classico con più pulsanti, collega i pulsanti al 3V3 e metti su ogni pin una resistenza di pull-down da 10 kΩ. Puoi anche attivare più sorgenti insieme; con il PIR e un timer orario attivi, per esempio, la scheda si risveglia con quello che arriva per primo.
| Sorgente di risveglio | Funzione | Pin | Nota |
|---|---|---|---|
| Timer | esp_sleep_enable_timer_wakeup() | Nessun pin | Tempo in microsecondi, 64 bit |
| ext0 | esp_sleep_enable_ext0_wakeup() | Un RTC GPIO | Risveglia su HIGH o LOW; non si combina con touch e ULP |
| ext1 | esp_sleep_enable_ext1_wakeup_io() | Più RTC GPIO | ANY_HIGH o ALL_LOW; consigliate resistenze esterne |
| Touch | touchSleepWakeUpEnable() | T0–T9 (10 pin) | Risveglia quando il valore scende sotto la soglia; non si combina con ext0 |
| Coprocessore ULP | esp_sleep_enable_ulp_wakeup() | Dipende dal programma | Può leggere sensori durante il sonno; livello avanzato |
Collegamenti del circuito di esempio
| Componente | Pin del componente | Pin dell'ESP32 | Nota |
|---|---|---|---|
| Sensore PIR (HC-SR501 o AM312) | OUT | GPIO 33 | Risveglia la scheda tramite ext0 |
| Sensore PIR | VCC / GND | 5V (HC-SR501) o 3V3 (AM312) / GND | L'HC-SR501 richiede almeno 4,5 V |
| Pulsante A | Un piedino / l'altro piedino | 3V3 / GPIO 25 | Pull-down da 10 kΩ tra GPIO 25 e GND |
| Pulsante B | Un piedino / l'altro piedino | 3V3 / GPIO 26 | Pull-down da 10 kΩ tra GPIO 26 e GND |
| Piazzola touch o filo | – | GPIO 27 (T7) | Più affidabile se resta corto |
| LED + 220 Ω | Anodo | GPIO 2 | Sulla maggior parte delle DevKit anche il LED blu integrato è su questo pin |
| Partitore della batteria (1 MΩ + 1 MΩ) | Punto centrale | GPIO 35 | 100 nF tra il punto centrale e GND |
| 18650 + TP4056 + LDO da 3,3 V | Uscita LDO / GND | 3V3 / GND | Condensatore da 470 µF sull'uscita dell'LDO |
Sketch di risveglio con sensore PIR (ext0)
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}Al risveglio lo sketch riporta prima il pin a GPIO normale con rtc_gpio_deinit(). Dopo un risveglio con ext0 il pin resta in modalità RTC e, senza questa riga, digitalRead() potrebbe non funzionare correttamente. Conta il movimento, accende il LED e poi aspetta che l'uscita del PIR torni a LOW. Questa attesa è fondamentale: se vai a dormire mentre l'uscita è ancora HIGH, la scheda si risveglia subito ed entra in un ciclo che si accende e si spegne più volte al secondo. L'HC-SR501 tiene l'uscita a HIGH per il tempo impostato; gira al minimo il trimmer del tempo per accorciare l'attesa. Poiché l'HC-SR501 richiede almeno 4,5 V, nei progetti alimentati da una sola 18650 scegli il piccolo modulo PIR AM312, che funziona anche a 3,3 V. Per le regolazioni del sensore consulta la guida sensore di movimento PIR.
Sketch di risveglio con due pulsanti (ext1)
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}Dopo un risveglio con ext1, esp_sleep_get_ext1_wakeup_status() restituisce una maschera di bit che indica quale pin ha risvegliato la scheda. Così puoi dare compiti diversi ai due pulsanti: uno accende la luce e l'altro la spegne, oppure uno invia una misura e l'altro apre un menu. Dato che i pulsanti sono collegati al 3V3 e i pin sono portati a GND con 10 kΩ, leggono LOW da rilasciati e HIGH da premuti, esattamente ciò che si aspetta la modalità ANY_HIGH. Prima di dormire lo sketch aspetta che i pulsanti vengano rilasciati, altrimenti un pulsante ancora premuto risveglierebbe subito la scheda. Se usi la versione 2.x o 3.0.x del core Arduino per ESP32, che non ha la funzione _io, scrivi esp_sleep_enable_ext1_wakeup con gli stessi parametri al posto di esp_sleep_enable_ext1_wakeup_io. Nella guida come collegare un pulsante ad Arduino trovi spiegato in dettaglio perché serve la resistenza di pull-down.
Risveglio con un tocco (touch wake-up)
Dieci pin dell'ESP32 (T0–T9) funzionano come sensori touch capacitivi e rilevano il tuo dito anche in deep sleep. Un filo, una striscia di nastro di rame o una piazzola sul PCB collegata al pin si comporta come un pulsante e può stare perfino dietro un sottile coperchio di plastica o di legno. Sull'ESP32 classico il valore di touchRead() scende quando tocchi: con un filo corto di solito legge 60–80 senza contatto e 10–20 al tocco. La soglia di risveglio va messa tra questi due valori; il 40 dell'esempio è un buon punto di partenza. Sull'ESP32 classico puoi usare più pin touch insieme come sorgenti di risveglio. Su ESP32-S2 e S3, invece, un solo pin può risvegliare il chip, il valore sale al tocco e la soglia usa una scala completamente diversa (5000 nell'esempio di Espressif). Il risveglio touch non si può combinare con ext0; se ti serve anche un pulsante, usa ext1. Per l'elenco dei pin e la calibrazione leggi la guida pin touch dell'ESP32.
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 dell'ESP32 con MicroPython
Se programmi l'ESP32 in MicroPython, ottieni lo stesso risultato con meno codice. machine.deepsleep(ms) fa dormire la scheda per i millisecondi indicati, esp32.wake_on_ext0() trasforma un pin in sorgente di risveglio e machine.RTC().memory() offre un buffer di byte che sopravvive al sonno; sull'ESP32 contiene 2048 byte per impostazione predefinita. Al risveglio main.py riparte dall'inizio; con machine.reset_cause() capisci se la scheda esce dal deep sleep e con machine.wake_reason() che cosa l'ha risvegliata. I pin RTC configurati con pull-up o pull-down mantengono questa impostazione durante il sonno. Se sei alle prime armi con MicroPython, parti dalla guida basi di 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 sIl Raspberry Pi Pico, invece, non ha una sospensione profonda da pochi microampere come quella dell'ESP32. In MicroPython machine.lightsleep(ms) ferma gran parte dei clock, mette in pausa la CPU e conserva la RAM, mentre machine.deepsleep(ms) resetta la scheda dopo lo stesso tipo di sonno. Anche in queste modalità il consumo della scheda resta nell'ordine dei milliampere. Quindi, se vuoi costruire con il Pico un dispositivo che funzioni a batteria per mesi, otterrai risultati migliori togliendo del tutto l'alimentazione tra una misura e l'altra con un timer di alimentazione come il TPL5110. Per le basi del Pico consulta la guida che cos'è il Raspberry Pi Pico.
Un sensore che dura mesi con una 18650: calcolo della durata della batteria
Per trovare la durata della batteria di un dispositivo che dorme e si risveglia, calcoli prima la corrente media: Corrente media = (Corrente da sveglio × Tempo da sveglio + Corrente in sospensione × Tempo di sospensione) / Tempo totale. Poi dividi la capacità utile della batteria per questa media. Non si può sfruttare tutta una 18650 che riporta 3000 mAh sull'etichetta; considerare circa l'85 %, cioè 2550 mAh, per lo stacco a bassa tensione, le perdite del regolatore e l'invecchiamento è realistico. La tabella seguente è calcolata per un sensore che si risveglia ogni 10 minuti, invia dati via Wi-Fi e durante la connessione assorbe in media 120 mA.
| Scenario | Corrente in sospensione | Tempo da sveglio | Corrente media | Durata stimata |
|---|---|---|---|---|
| Scheda DevKit | 8 mA | 3 s, 120 mA | 8,56 mA | ≈12 giorni |
| Scheda DevKit, connessione rapida | 8 mA | 1 s, 120 mA | 8,19 mA | ≈13 giorni |
| Modulo nudo + MCP1700 + partitore da 1 MΩ | 15 µA | 3 s, 120 mA | 0,61 mA | ≈173 giorni (5,7 mesi) |
| Modulo nudo, connessione rapida | 15 µA | 1 s, 120 mA | 0,215 mA | ≈494 giorni (16 mesi) |
| Modulo nudo, invio cumulativo ogni ora | 15 µA | 1 s di Wi-Fi all'ora (120 mA) + 5 × 0,3 s di misura (40 mA) | 0,065 mA | ≈4,5 anni in teoria |
Il risultato è chiaro: su una scheda di sviluppo accorciare il tempo da sveglio non cambia quasi nulla, perché a scaricare davvero la batteria sono gli 8 mA in sospensione. Quando la corrente di sospensione scende ai microampere, l'equilibrio si ribalta e ogni secondo da sveglio conta: ridurre la connessione Wi-Fi da 3 secondi a 1 quasi triplica la durata della batteria. Quando la corrente media scende sotto 0,1 mA entra in gioco l'autoscarica della batteria. Una cella Li-ion perde circa il 2–3 % della capacità al mese, quindi i 4,5 anni teorici diventano in pratica circa 2 anni. Per fare il calcolo con i tuoi valori usa il calcolatore della durata della batteria e approfondisci mAh e Wh nella guida che cosa significa mAh.
- Scegli la scheda giusta: le schede senza chip USB e LED di alimentazione, o un modulo ESP32 nudo, consumano pochi microampere in sospensione.
- Cambia regolatore: al posto dell'AMS1117 usa un LDO con una corrente di riposo di pochi microampere.
- Alimenta il sensore solo durante la misura: i sensori che assorbono pochi mA possono essere alimentati direttamente da un GPIO, i carichi più grandi tramite un MOSFET a canale P; metti una resistenza di pull-up sul gate del MOSFET perché resti spento durante il sonno. Trovi i dettagli nella guida MOSFET con Arduino.
- Accendi raramente il Wi-Fi: accumula le misure nella memoria RTC e inviale in blocco; se invii dati a un altro ESP32 vicino, ESP-NOW trasmette in molto meno tempo perché non deve associarsi a un router.
- Velocizza la connessione: con IP statico, canale e BSSID salvati, la connessione Wi-Fi spesso richiede meno di un secondo.
- Elimina le attese inutili: nel progetto finito togli le stampe sul Monitor seriale e le righe delay() lunghe; ogni millisecondo da sveglio lo paga la batteria.
- Non dimenticare il partitore e i LED: un partitore da 100 kΩ + 100 kΩ sempre collegato assorbe il doppio della corrente dell'ESP32 addormentato.
Idee di progetto con il deep sleep dell'ESP32
- Stazione meteo a batteria: misura temperatura, umidità e pressione con un BME280 ogni 10 minuti e inviale ogni ora a Home Assistant via MQTT.
- Sensore di umidità per il giardino: risvegliati ogni ora, misura l'umidità del terreno e avvisa il tuo telefono quando la terra si secca.
- Allarme per porte e finestre: quando la porta si apre, un reed switch risveglia l'ESP32 tramite ext0 e un bot Telegram ti manda un messaggio.
- Sensore di sicurezza a batteria: costruisci un dispositivo che si risveglia e invia un avviso quando il PIR rileva un movimento e che per il resto del tempo dorme per mesi.
- Campanello touch: incolla del nastro di rame dietro un pannello di legno; al tocco l'ESP32 si risveglia e manda un segnale al campanello in casa tramite ESP-NOW.
- Datalogger di temperatura a batteria: misura la temperatura di un frigorifero o di un acquario con un DS18B20 impermeabile, accumula i valori nella memoria RTC e inviali qualche volta al giorno.
Errori comuni e soluzioni
| Sintomo | Causa | Soluzione |
|---|---|---|
| La scheda si risveglia appena si addormenta | Il pin di risveglio è ancora attivo (PIR a HIGH, pulsante premuto) o flottante | Prima di dormire aspetta che il pin torni al livello di riposo e aggiungi una resistenza di pull-down o pull-up |
| La scheda non si risveglia al momento previsto | Overflow a 32 bit nel calcolo del tempo (3600 * 1000000) | Aggiungi ULL alle costanti: 3600ULL * 1000000ULL |
| Il contatore riparte sempre da 1 | La variabile non è RTC_DATA_ATTR oppure la scheda è stata resettata | Aggiungi RTC_DATA_ATTR; per dati permanenti usa Preferences |
| In sospensione si misurano 5–15 mA | Regolatore, LED di alimentazione, chip USB, partitore o sensori | Scheda a basso consumo o modulo nudo, LDO con bassa corrente di riposo |
| Le ultime righe del Monitor seriale sono troncate | La scheda si è addormentata prima che il buffer si svuotasse | Chiama Serial.flush() prima di esp_deep_sleep_start() |
| digitalRead() dà valori errati dopo il risveglio | Il pin di risveglio è rimasto in modalità RTC | Chiama rtc_gpio_deinit() prima di usare il pin |
| Un pulsante su GPIO 34–39 non risveglia la scheda | Questi pin non hanno resistenze interne di pull, quindi il pin è flottante | Aggiungi una resistenza esterna da 10 kΩ |
| Non si riesce a caricare il codice mentre la scheda dorme | La scheda non ha il circuito di reset automatico; su S3 e C3 la porta USB nativa sparisce durante il sonno | Tieni premuto BOOT, premi e rilascia EN (RESET), poi avvia il caricamento |
| Un relè o un LED cambia stato quando la scheda si addormenta | In deep sleep i pin digitali restano in alta impedenza | Usa una resistenza di pull o mantieni il livello del pin con rtc_gpio_hold_en() |
Il deep sleep dell'ESP32 è la chiave per far funzionare lo stesso codice a batteria per mesi invece che per giorni: tieni breve il lavoro, scegli la sorgente di risveglio giusta, conserva nella memoria RTC i piccoli dati che ti servono tra un risveglio e l'altro e non dimenticare mai il consumo proprio della scheda. Se vuoi ripassare le basi dell'ESP32, la guida che cos'è l'ESP32 è un buon punto di partenza. Nell'app BlueGrays, il progetto ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RAM RTC) ti permette di provare la logica del timer e del contatore RTC di questo articolo su un circuito con display OLED, con schema passo passo e codice pronto.
Domande frequenti
Quanta corrente consuma l'ESP32 in deep sleep?
Secondo il datasheet di Espressif, il chip ESP32 consuma circa 10 µA in deep sleep con timer e memoria RTC attivi, e 5 µA in modalità ibernazione. Sulle schede di sviluppo come la DevKit, però, il regolatore, il LED di alimentazione e il chip USB-seriale portano di solito la corrente in sospensione a 5–15 mA.
Come si risveglia un ESP32 dal deep sleep?
Ci sono cinque modi: il timer RTC, un singolo pin RTC (ext0), più pin RTC (ext1), i pin touch e il coprocessore ULP. La sorgente di risveglio si configura prima di chiamare esp_deep_sleep_start() e se ne possono attivare più di una insieme; solo ext0 e il risveglio touch non si possono usare contemporaneamente.
Le variabili si cancellano nel deep sleep dell'ESP32?
Sì, le variabili normali si cancellano, perché il risveglio dal deep sleep è un riavvio e setup() riparte dall'inizio. Le variabili con RTC_DATA_ATTR vengono salvate nella memoria RTC e si conservano tra un risveglio e l'altro, ma tornano al valore iniziale dopo un'interruzione di corrente, la pressione di EN o il caricamento di nuovo codice.
Quanto dura un ESP32 con una batteria 18650?
Da un giorno a più di un anno, a seconda della scheda e dell'uso. Una DevKit sempre connessa al Wi-Fi dura solo 1–2 giorni con una 18650 da 3000 mAh, mentre una DevKit che si risveglia ogni 10 minuti dura circa 12 giorni. Un circuito a basso consumo che fa lo stesso lavoro con 15 µA in sospensione funziona da 5 a 16 mesi, secondo la durata di ogni connessione.
Che differenza c'è tra light sleep e deep sleep nell'ESP32?
In light sleep la CPU viene messa in pausa ma la RAM si conserva; al risveglio il programma riprende dalla riga in cui si era fermato e il chip consuma circa 0,8 mA. In deep sleep si spegne anche la RAM e il consumo scende a 10 µA, ma il programma riparte da capo a ogni risveglio. La sospensione leggera è adatta a pause di qualche secondo, quella profonda ad attese di minuti o ore.
Come si carica il codice su un ESP32 in deep sleep?
Sulle schede con circuito di reset automatico il caricamento di solito parte senza problemi, perché lo strumento di upload resetta il chip tramite il pin EN. Se non parte, tieni premuto il pulsante BOOT, premi e rilascia EN (RESET) e poi avvia il caricamento. Sulle schede con USB nativa come l'ESP32-S3 e il C3 la porta sparisce durante il sonno, quindi questo metodo è spesso indispensabile.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
LED Lampeggiante con ESP32
Insegna l'uso di base delle uscite GPIO con l'ESP32. Otteniamo un effetto lampeggiante accendendo e spegnendo un LED dal pin digitale. Versione ESP32 del classico progetto blink su Arduino UNO; i comandi di base di blink nell'ambiente Arduino sono gli stessi, ma la disposizione dei pin e i livelli GPIO a 3,3 V dell'ESP32 sono diversi da quelli di Arduino UNO.

Controllo LED ESP32 con pulsante (Push)
Il LED si accende quando il pulsante viene premuto e si spegne quando viene rilasciato. Mostra come vengono utilizzati il pin di ingresso digitale dell'ESP32 e la resistenza di pull-up interna. Grazie alla modalità INPUT_PULLUP, non è necessaria alcuna resistenza esterna.

ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RTC RAM)
La modalità Deep Sleep dell'ESP32 riduce il consumo di corrente a circa 10 µA spegnendo la CPU e la maggior parte dei dispositivi periferici ed è di fondamentale importanza per i dispositivi IoT alimentati a batteria. In questo progetto utilizziamo tre diverse fonti di risveglio: il timer (15 secondi), un pin esterno (EXT0 — pulsante GPIO 33) e il sensore tattile (T0/GPIO 4). Le variabili contrassegnate con RTC_DATA_ATTR vengono preservate durante la modalità Deep Sleep: il contatore di avvio,

Sistema di Allarme Movimento ESP32 (PIR + Buzzer + LED + Telegram)
Un sistema di allarme di sicurezza intelligente che attiva buzzer e LED quando il sensore PIR rileva movimento, inviando contemporaneamente una notifica istantanea al proprietario tramite Telegram. Dispone di un tempo di attesa di 30 secondi per limitare la frequenza degli allarmi ripetuti; questo meccanismo non verifica la validità dei rilevamenti del sensore PIR né elimina le false attivazioni. Adatto a sicurezza domestica, monitoraggio di garage, magazzini o studi. Con l'ESP32-CAM è possibile

Illuminazione automatica con sensore di movimento PIR ESP32
In questo progetto, utilizzeremo il sensore di movimento PIR HC-SR501 per rilevare la presenza di una persona che entra nella stanza e accendere automaticamente il LED. Monitoreremo il tempo di accensione del LED con millis(); ogni lettura HIGH del sensore aggiornerà l'istante dell'ultimo movimento e il LED si spegnerà quando saranno trascorsi almeno 10 secondi dall'ultima lettura HIGH. Il codice attuale attende anche 50 ms a ogni iterazione con delay(50), quindi il ciclo dell'applicazione n

ESP32 DHT22 Temperatura e umidità (con display LCD)
Si tratta di un progetto che misura la temperatura e l'umidità dell'ambiente tramite il sensore DHT22 e le visualizza in tempo reale su un display LCD I2C 16x2. I dati vengono letti dal sensore utilizzando il protocollo one-wire tramite la libreria Adafruit DHT. Questo progetto costituisce la base per stazioni meteorologiche IoT, sistemi di automazione domestica intelligente o sistemi di monitoraggio ambientale nelle serre. La comunicazione con il DHT22 avviene tramite il pin GPIO 4 dell'ESP32.

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni minuto, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file /temp_log.csv sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta
Altri articoli
App BlueGrays
Costruisci questo circuito passo passo sul telefono
Schema, codice ed elenco componenti in un’unica schermata. Oltre 200 progetti Arduino, ESP32 e Pico da realizzare.
Inquadra con il telefono
Punta la fotocamera sul codice: si apre lo store del tuo telefono.
oppure apri lo store

