Guías · 17 min de lectura

ESP32 Deep Sleep: modos de sueño, consumo en µA y batería 18650

ESP32 deep sleep paso a paso: consumo en µA de cada modo, despertar por temporizador, botón, PIR y táctil (ext0/ext1), memoria RTC y autonomía con una 18650.

El deep sleep del ESP32 (sueño profundo) es el modo de energía en el que el ESP32 apaga sus núcleos, la radio Wi-Fi y Bluetooth y la memoria principal, y deja encendida solo la pequeña sección RTC. En este modo el consumo del chip baja de 240 mA, cuando transmite por Wi-Fi, a unos 10 µA: veinticuatro mil veces menos. La placa se despierta cuando termina el tiempo que fijaste, cuando se pulsa un botón, cuando un sensor PIR detecta movimiento o cuando se toca un pin; hace su trabajo en pocos segundos y vuelve a dormir. Así, estaciones meteorológicas, sensores de jardín, alarmas de puerta y registradores remotos funcionan meses en lugar de días con una sola batería 18650.

En esta guía conocerás los modos de sueño del ESP32 y sus consumos reales, aprenderás a despertar la placa con un temporizador, un botón, un sensor PIR (ext0 y ext1) o un toque, a guardar contadores y lecturas en la memoria RTC que no se borra durante el sueño, entenderás por qué las placas de desarrollo siguen gastando miliamperios mientras duermen y calcularás paso a paso cuántos meses dura una sola 18650. Los sketches de Arduino están escritos para la versión 3.1 o posterior del núcleo Arduino del ESP32 y, al final, verás cómo hacer lo mismo con MicroPython.

Placa de desarrollo ESP32 (DevKit)
Placa de desarrollo ESP32: el módulo con blindaje metálico consume unos 10 µA en sueño profundo, pero el regulador, el LED de encendido y el chip USB-serie de la placa elevan esa cifra a miliamperios.

¿Qué es el deep sleep del ESP32 y cómo funciona?

Dentro del ESP32 hay dos mundos separados. El primero es la sección principal, con los núcleos, 520 KB de RAM y la radio Wi-Fi y Bluetooth. El segundo es la sección RTC, con su propio temporizador, 8 KB de memoria RTC FAST y 8 KB de RTC SLOW, los pines RTC GPIO y un coprocesador de ultrabajo consumo llamado ULP. En sueño profundo la sección principal se apaga por completo y solo sigue funcionando la sección RTC. Cuando llega el momento de despertar, el chip en realidad se reinicia: arranca el bootloader, el programa se vuelve a cargar desde la flash y setup() empieza desde el principio. Por eso un programa con deep sleep hace todo su trabajo dentro de setup() y loop() nunca se ejecuta. Las variables normales se reinician en cada despertar; solo se conservan las que colocas en la memoria RTC.

Modos de sueño del ESP32 y consumo (µA)

Modo¿Qué sigue funcionando?Corriente (chip ESP32)
Activo: transmisión Wi-Fi (802.11b, 19,5 dBm)CPU y radio240 mA
Activo: recepción y escucha Wi-FiCPU y radio95–100 mA
Modem sleep, 240 MHzLa CPU funciona, radio apagada30–68 mA
Modem sleep, 80 MHzLa CPU funciona más lenta, radio apagada20–31 mA
Sueño ligero (light sleep)CPU en pausa, la RAM se conserva0,8 mA
Sueño profundo con ULPSección RTC y coprocesador ULP150 µA
Sueño profundo (deep sleep)Temporizador RTC y memoria RTC10 µA
HibernaciónSolo el temporizador RTC y algunos pines RTC5 µA
Apagado (pin EN en LOW)Nada1 µA

Los valores proceden de la hoja de datos del ESP32 de Espressif y corresponden solo al chip. Hay dos puntos importantes en la tabla. Primero, en sueño ligero el programa continúa en la línea donde se detuvo y todo lo que hay en la RAM se conserva, pero el consumo es ochenta veces mayor que en sueño profundo; sirve para pausas de unos segundos. En sueño profundo el programa empieza de nuevo, pero el consumo baja a microamperios, así que es la opción correcta para esperas de minutos u horas. Segundo, ninguno de los dos modos mantiene la conexión Wi-Fi o Bluetooth; tienes que reconectar en cada despertar. Los chips más nuevos varían un poco: el ESP32-C3 consume unos 5 µA en sueño profundo y el ESP32-S3 unos 7–8 µA.

Si quieres un consumo aún menor, también puedes apagar los periféricos RTC y la memoria RTC. Con esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF) y la misma línea para ESP_PD_DOMAIN_RTC_SLOW_MEM y ESP_PD_DOMAIN_RTC_FAST_MEM, el chip se acerca al modo de hibernación y consume unos 5 µA. En ese caso se pierden las variables de la memoria RTC y solo el temporizador o ext1 pueden despertar la placa. En la mayoría de los proyectos la diferencia entre 10 µA y 5 µA es insignificante frente al resto de la placa, así que resuelve primero los problemas de la siguiente sección.

¿Por qué las placas de desarrollo consumen miliamperios en deep sleep?

Cuando cargas el sketch y conectas un multímetro, muchas veces verás 5–15 mA en lugar de 10 µA. El problema no es el chip, sino las piezas auxiliares de la placa. La mayoría de las placas DevKit y NodeMCU-32S baratas usan un regulador AMS1117 para bajar 5 V a 3,3 V, y ese regulador gasta por sí solo unos 5 mA típicos aunque no tenga carga. A eso se suman el LED de encendido, siempre encendido, y el chip USB-serie (CP2102 o CH340) que se comunica con el ordenador. Juntos suelen rondar los 8 mA y vacían unos 190 mAh al día aunque el ESP32 duerma, así que una 18650 de 3000 mAh apenas dura dos semanas con una placa así. Para medir la corriente, conecta el multímetro en serie entre la batería y el circuito y pasa a la escala de µA durante el sueño; tienes los detalles en la guía cómo usar un multímetro.

Fuente de consumoCorriente en sueñoSolución
Módulo ESP32 (sueño profundo)≈10 µAYa es bajo, no hace falta nada
Regulador AMS11175 mA típicos (en reposo)Usa un MCP1700 (1,6 µA en reposo) o un HT7333 (unos 4 µA)
LED de encendido1–3 mADesuelda el LED o su resistencia
Chip USB-serie (CP2102, CH340)Depende de la placa, puede llegar a mAUsa una placa sin chip USB o un módulo suelto
Divisor de batería de 100 kΩ + 100 kΩ21 µA (a 4,2 V)Usa 1 MΩ + 1 MΩ o activa el divisor con un MOSFET solo al medir
Sensores alimentados siempreDe µA a mA según el sensorAlimenta el sensor desde un GPIO o un MOSFET solo durante la medición
Nunca conectes una batería de iones de litio como la 18650 directamente al pin 3V3: una celda Li-ion llena está a 4,2 V y el ESP32 admite como máximo 3,6 V. Conectarla al pin VIN tampoco es buena idea, porque el AMS1117 pierde alrededor de 1 V y su salida baja de 3 V cuando la batería está a media carga. Lo correcto es alimentar el pin 3V3 a través de un LDO de 3,3 V con baja corriente de reposo y baja caída de tensión. Los LDO pequeños como el MCP1700 y el HT7333 solo entregan 250 mA, así que pon al menos 470 µF en su salida para cubrir los picos de corriente del Wi-Fi. Las celdas LiFePO4, que no superan 3,6 V ni siquiera llenas, se pueden conectar a 3V3 directamente, sin regulador.

Tu primer sketch de deep sleep: despertar con temporizador

  1. En el Gestor de placas del Arduino IDE instala el paquete esp32 by Espressif Systems (versión 3.1 o posterior) y elige ESP32 Dev Module como placa.
  2. Sube el sketch de abajo y abre el Monitor Serie a 115200 baudios.
  3. La placa se despierta cada 10 segundos; observa cómo sube el contador de arranques y cómo se imprime Timer como motivo del despertar.
  4. Pulsa el botón EN: el contador vuelve a 1, porque es un reinicio normal y no un despertar del sueño profundo.
  5. En tu proyecto real pon TIME_TO_SLEEP a 600 (10 minutos) o 3600 (1 hora).
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}

El corazón del sketch son dos líneas: esp_sleep_enable_timer_wakeup() fija el tiempo de despertar en microsegundos y esp_deep_sleep_start() manda el chip a dormir al instante; nada de lo que escribas después se ejecuta. No olvides el sufijo ULL (64 bits) al calcular el tiempo: 3600 * 1000000 desborda un int de 32 bits, el compilador solo muestra una advertencia y la placa se despierta a destiempo o no se despierta nunca. Serial.flush() espera a que se vacíe el búfer de envío; sin ella, las últimas líneas se cortan. esp_sleep_get_wakeup_cause() te dice por qué se despertó la placa y no devuelve ninguna fuente de sueño tras el primer encendido o un reinicio. El temporizador RTC que cuenta el tiempo de sueño funciona por defecto con un oscilador RC interno de unos 150 kHz. No es tan estable como un cristal y puede desviarse unos pocos puntos porcentuales con la temperatura; si la hora importa en tu proyecto, conviene sincronizarla por NTP al despertar.

Guardar contadores y lecturas en la memoria RTC

Si necesitas recordar algo entre despertares, escribe RTC_DATA_ATTR delante de la variable: el compilador la coloca en los 8 KB de memoria RTC SLOW, que siguen alimentados en sueño profundo, en lugar de la RAM principal. Es ideal para datos pequeños como contadores, las últimas lecturas, la información del canal Wi-Fi o la última temperatura enviada. Pero esta memoria no es permanente: según la documentación de Espressif, los datos de la memoria RTC se inicializan en cada reinicio, salvo al despertar del sueño profundo. Cambiar la batería, pulsar EN, subir código nuevo o llamar a ESP.restart() pone el contador a cero. Los ajustes que deban sobrevivir a un corte de luz guárdalos en la flash con la biblioteca Preferences, pero no lo hagas en cada despertar, porque la flash admite un número limitado de escrituras.

EventoVariable normalRTC_DATA_ATTRPreferences (flash)
Despertar del sueño profundoSe reiniciaSe conservaSe conserva
Botón EN o ESP.restart()Se reiniciaVuelve a su valor inicialSe conserva
Batería retirada, corte de luzSe reiniciaSe borraSe conserva
Subir código nuevoSe reiniciaSe borraSe conserva (si no se borra la flash)

Bien aprovechada, esta memoria multiplica la autonomía. Conectarse al Wi-Fi es la parte más cara de cada despertar. Por eso el sketch siguiente mide la tensión de la batería cada 10 minutos, pero solo enciende el Wi-Fi una vez por hora: seis lecturas se acumulan en un array de la memoria RTC y en el sexto despertar se envían todas juntas. Además guarda en la memoria RTC el canal y la dirección MAC (BSSID) del router, de modo que en la siguiente conexión el ESP32 va directo a ese router sin escanear todos los canales y la conexión se acorta notablemente.

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 tensión de la batería se reduce a la mitad con un divisor de tensión de 1 MΩ + 1 MΩ y se lee en GPIO 35, un canal del ADC1. Un condensador de 100 nF entre el punto medio del divisor y GND mantiene estable la lectura incluso con un divisor de impedancia tan alta. También es importante medir antes de encender el Wi-Fi, porque la corriente que consume la radio hace caer la tensión de la batería por un instante. Si el Wi-Fi no logra conectar, se descarta la lectura más antigua y el resto se guarda para el siguiente intento. Apagar bien la radio antes de dormir con WiFi.disconnect(true) y WiFi.mode(WIFI_OFF) es además lo que recomienda Espressif. Para acelerar aún más la conexión, asigna una IP fija con WiFi.config() y evita la espera del DHCP. Encontrarás el cálculo del divisor en la guía divisor de tensión y el circuito de carga en módulo de carga TP4056.

Despertar con un botón o un sensor PIR: ext0 y ext1

Además del temporizador, una señal del exterior también puede despertar al ESP32. Hay dos formas de hacerlo y ambas funcionan solo en los pines RTC GPIO: 0, 2, 4, 12–15, 25–27 y 32–39. ext0 vigila un único pin y despierta la placa cuando ese pin alcanza el nivel que elijas (HIGH o LOW); como mantiene alimentados los periféricos RTC, las resistencias internas pull-up y pull-down siguen funcionando durante el sueño. ext1 vigila varios pines a la vez mediante una máscara de bits. En el ESP32 clásico, ext1 tiene dos modos: ESP_EXT1_WAKEUP_ANY_HIGH despierta cuando cualquiera de los pines elegidos pasa a HIGH y ESP_EXT1_WAKEUP_ALL_LOW cuando todos están en LOW a la vez. El modo ANY_LOW, que despierta cuando cualquiera pasa a LOW, solo existe en el ESP32-S2, S3, C6 y H2. Por eso, si quieres despertar un ESP32 clásico con varios botones, conecta los botones a 3V3 y pon a cada pin una resistencia pull-down de 10 kΩ. También puedes activar varias fuentes a la vez; con el PIR y un temporizador horario activos, por ejemplo, la placa se despierta con el que llegue primero.

Fuente de despertarFunciónPinesNota
Temporizadoresp_sleep_enable_timer_wakeup()No necesita pinTiempo en microsegundos, 64 bits
ext0esp_sleep_enable_ext0_wakeup()Un RTC GPIODespierta con HIGH o LOW; no se combina con táctil ni ULP
ext1esp_sleep_enable_ext1_wakeup_io()Varios RTC GPIOANY_HIGH o ALL_LOW; se recomiendan resistencias externas
TáctiltouchSleepWakeUpEnable()T0–T9 (10 pines)Despierta cuando el valor baja del umbral; no se combina con ext0
Coprocesador ULPesp_sleep_enable_ulp_wakeup()Según el programaPuede leer sensores mientras duerme; nivel avanzado

Conexiones del circuito de ejemplo

ComponentePin del componentePin del ESP32Nota
Sensor PIR (HC-SR501 o AM312)OUTGPIO 33Despierta mediante ext0
Sensor PIRVCC / GND5V (HC-SR501) o 3V3 (AM312) / GNDEl HC-SR501 necesita al menos 4,5 V
Botón AUna pata / la otra pata3V3 / GPIO 25Pull-down de 10 kΩ entre GPIO 25 y GND
Botón BUna pata / la otra pata3V3 / GPIO 26Pull-down de 10 kΩ entre GPIO 26 y GND
Pad táctil o cable–GPIO 27 (T7)Funciona mejor si es corto
LED + 220 ΩÁnodoGPIO 2En la mayoría de los DevKit el LED azul integrado también está en este pin
Divisor de batería (1 MΩ + 1 MΩ)Punto medioGPIO 35100 nF entre el punto medio y GND
18650 + TP4056 + LDO de 3,3 VSalida del LDO / GND3V3 / GNDCondensador de 470 µF en la salida del LDO
Evita los pines GPIO 0, 2, 12 y 15 como entradas de despertar. Son pines de arranque (strapping): si un botón o un sensor los mantiene en el nivel equivocado durante el reinicio, la placa entra en modo de programación o no arranca. Por ejemplo, si GPIO 12 está en HIGH al arrancar, la tensión de la flash se ajusta a 1,8 V y la placa no puede iniciar. Los GPIO 34–39 son solo de entrada y no tienen resistencias internas pull-up ni pull-down; si despiertas con ellos, añade la resistencia por fuera. Puedes consultar el mapa completo de pines de tu placa con la herramienta Pinout.

Sketch para despertar con un sensor 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}

Al despertar, el sketch primero devuelve el pin a GPIO normal con rtc_gpio_deinit(). Tras un despertar por ext0 el pin queda en modo RTC y, sin esta línea, digitalRead() podría no funcionar bien. Cuenta el movimiento, enciende el LED y espera a que la salida del PIR vuelva a LOW. Esta espera es fundamental: si duermes mientras la salida sigue en HIGH, la placa se despierta al instante y entra en un bucle que se enciende y apaga varias veces por segundo. El HC-SR501 mantiene su salida en HIGH durante el tiempo ajustado; gira el potenciómetro de tiempo al mínimo para acortar la espera. Como el HC-SR501 necesita al menos 4,5 V, en proyectos alimentados con una sola 18650 elige el pequeño módulo PIR AM312, que también funciona a 3,3 V. Para ajustar el sensor, consulta la guía sensor de movimiento PIR.

Sketch para despertar con dos botones (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}

Tras un despertar por ext1, esp_sleep_get_ext1_wakeup_status() devuelve una máscara de bits que indica qué pin despertó la placa. Así puedes dar tareas distintas a los dos botones: uno enciende la luz y el otro la apaga, o uno envía una lectura y el otro abre un menú. Como los botones están conectados a 3V3 y los pines van a GND con 10 kΩ, leen LOW sin pulsar y HIGH al pulsar, justo lo que espera el modo ANY_HIGH. Antes de dormir, el sketch espera a que se suelten los botones; si no, un botón todavía pulsado volvería a despertar la placa enseguida. Si usas la versión 2.x o 3.0.x del núcleo Arduino del ESP32, que no incluye la función _io, escribe esp_sleep_enable_ext1_wakeup con los mismos parámetros en lugar de esp_sleep_enable_ext1_wakeup_io. En la guía cómo conectar un botón a Arduino se explica en detalle por qué hace falta la resistencia pull-down.

Despertar con un toque (touch wake-up)

Diez pines del ESP32 (T0–T9) funcionan como sensores táctiles capacitivos y detectan tu dedo incluso en sueño profundo. Un cable, una tira de cinta de cobre o un pad de PCB conectado al pin se comporta como un botón y puede ir incluso detrás de una tapa fina de plástico o madera. En el ESP32 clásico el valor de touchRead() baja al tocar: con un cable corto suele leer 60–80 sin tocar y 10–20 al tocar. El umbral de despertar se coloca entre esos dos valores; el 40 del ejemplo es un buen punto de partida. En el ESP32 clásico puedes usar varios pines táctiles a la vez como fuente de despertar. En el ESP32-S2 y S3, en cambio, solo un pin puede despertar el chip, el valor sube al tocar y el umbral usa una escala totalmente distinta (5000 en el ejemplo de Espressif). El despertar táctil no se puede combinar con ext0; si además necesitas un botón, usa ext1. Para la lista de pines y la calibración, lee la guía pines táctiles del 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 del ESP32 con MicroPython

Si programas el ESP32 con MicroPython, consigues lo mismo con menos código. machine.deepsleep(ms) duerme la placa durante los milisegundos indicados, esp32.wake_on_ext0() convierte un pin en fuente de despertar y machine.RTC().memory() ofrece un búfer de bytes que sobrevive al sueño; en el ESP32 tiene 2048 bytes por defecto. Al despertar, main.py se ejecuta desde el principio; con machine.reset_cause() sabes si la placa viene del sueño profundo y con machine.wake_reason() qué la despertó. Los pines RTC configurados con pull-up o pull-down mantienen ese ajuste durante el sueño. Si eres nuevo en MicroPython, empieza por la guía fundamentos 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

La Raspberry Pi Pico, en cambio, no tiene un sueño profundo de microamperios como el del ESP32. En MicroPython, machine.lightsleep(ms) detiene la mayoría de los relojes, pausa la CPU y conserva la RAM, mientras que machine.deepsleep(ms) reinicia la placa después del mismo tipo de sueño. Incluso en estos modos el consumo de la placa se queda en el orden de los miliamperios. Por eso, si quieres que un dispositivo con Pico funcione meses con baterías, obtendrás mejores resultados cortando por completo su alimentación entre mediciones con un temporizador de energía como el TPL5110. Para lo básico de la Pico, consulta la guía qué es la Raspberry Pi Pico.

Un sensor que funciona meses con una 18650: cálculo de autonomía

Para calcular la autonomía de un dispositivo que duerme y se despierta, primero calculas la corriente media: Corriente media = (Corriente despierto × Tiempo despierto + Corriente en sueño × Tiempo de sueño) / Tiempo total. Después divides la capacidad útil de la batería entre esa media. No se puede aprovechar toda una 18650 que marca 3000 mAh; contar con un 85 %, es decir, 2550 mAh, por el corte de baja tensión, las pérdidas del regulador y el envejecimiento es realista. La tabla siguiente está calculada para un sensor que se despierta cada 10 minutos, envía datos por Wi-Fi y consume de media 120 mA mientras está conectado.

EscenarioCorriente en sueñoTiempo despiertoCorriente mediaAutonomía estimada
Placa DevKit8 mA3 s, 120 mA8,56 mA≈12 días
Placa DevKit, conexión rápida8 mA1 s, 120 mA8,19 mA≈13 días
Módulo suelto + MCP1700 + divisor de 1 MΩ15 µA3 s, 120 mA0,61 mA≈173 días (5,7 meses)
Módulo suelto, conexión rápida15 µA1 s, 120 mA0,215 mA≈494 días (16 meses)
Módulo suelto, envío agrupado cada hora15 µA1 s de Wi-Fi por hora (120 mA) + 5 × 0,3 s de medición (40 mA)0,065 mA≈4,5 años en teoría

La conclusión es clara: en una placa de desarrollo, acortar el tiempo despierto casi no cambia nada, porque lo que de verdad agota la batería son los 8 mA en sueño. Cuando la corriente de sueño baja a microamperios, la balanza se invierte y cada segundo despierto cuenta: reducir la conexión Wi-Fi de 3 segundos a 1 casi triplica la autonomía. Cuando la corriente media baja de 0,1 mA, entra en juego la autodescarga de la batería. Una celda Li-ion pierde alrededor de un 2–3 % de capacidad al mes, así que los 4,5 años teóricos se quedan en unos 2 años en la práctica. Para hacer el cálculo con tus propios valores usa la calculadora de duración de batería y lee sobre mAh y Wh en la guía qué significa mAh.

  • Elige la placa adecuada: las placas sin chip USB ni LED de encendido, o un módulo ESP32 suelto, consumen microamperios en sueño.
  • Cambia el regulador: usa un LDO con una corriente de reposo de pocos microamperios en lugar del AMS1117.
  • Alimenta el sensor solo al medir: los sensores que consumen pocos mA pueden ir directamente a un GPIO y las cargas mayores a través de un MOSFET de canal P; pon una resistencia pull-up en la puerta del MOSFET para que quede apagado en sueño. Tienes los detalles en la guía MOSFET con Arduino.
  • Enciende el Wi-Fi pocas veces: acumula las lecturas en la memoria RTC y envíalas en bloque; si mandas datos a otro ESP32 cercano, ESP-NOW transmite en mucho menos tiempo porque no necesita asociarse a un router.
  • Acelera la conexión: con IP fija y el canal y el BSSID guardados, la conexión Wi-Fi suele tardar menos de un segundo.
  • Quita las esperas innecesarias: en el proyecto terminado elimina la salida al Monitor Serie y las líneas delay() largas; cada milisegundo despierto sale de la batería.
  • No olvides el divisor ni los LED: un divisor de 100 kΩ + 100 kΩ conectado siempre consume el doble que el ESP32 dormido.

Ideas de proyectos con deep sleep del ESP32

  • Estación meteorológica con batería: mide temperatura, humedad y presión con un BME280 cada 10 minutos y envíalas cada hora a Home Assistant por MQTT.
  • Sensor de humedad para el jardín: despierta cada hora, mide la humedad del suelo y avisa a tu móvil cuando la tierra se seque.
  • Alarma de puertas y ventanas: al abrirse la puerta, un interruptor reed despierta al ESP32 por ext0 y un bot de Telegram te envía un mensaje.
  • Sensor de seguridad con batería: crea un dispositivo que se despierte y mande un aviso cuando el PIR detecte movimiento y que duerma meses el resto del tiempo.
  • Timbre táctil: pega cinta de cobre detrás de un panel de madera; al tocarlo, el ESP32 se despierta y envía una señal al timbre interior por ESP-NOW.
  • Registrador de temperatura con batería: mide la temperatura de una nevera o un acuario con un DS18B20 sumergible, acumula los valores en la memoria RTC y envíalos varias veces al día.

Errores comunes y cómo solucionarlos

SíntomaCausaSolución
La placa se despierta justo después de dormirseEl pin de despertar sigue activo (PIR en HIGH, botón pulsado) o está al aireEspera a que el pin vuelva a su nivel de reposo antes de dormir y añade una resistencia pull-down o pull-up
La placa no se despierta a la hora previstaDesbordamiento de 32 bits en el cálculo del tiempo (3600 * 1000000)Añade ULL a las constantes: 3600ULL * 1000000ULL
El contador siempre empieza en 1La variable no es RTC_DATA_ATTR o la placa se reinicióAñade RTC_DATA_ATTR; usa Preferences para datos permanentes
Se miden 5–15 mA en sueñoRegulador, LED de encendido, chip USB, divisor o sensoresPlaca de bajo consumo o módulo suelto, LDO con baja corriente de reposo
Las últimas líneas del Monitor Serie salen cortadasLa placa durmió antes de vaciar el búferLlama a Serial.flush() antes de esp_deep_sleep_start()
digitalRead() da valores erróneos al despertarEl pin de despertar sigue en modo RTCLlama a rtc_gpio_deinit() antes de usar el pin
Un botón en GPIO 34–39 no despierta la placaEstos pines no tienen resistencias internas y el pin queda al aireAñade una resistencia externa de 10 kΩ
No se puede subir código mientras la placa duermeLa placa no tiene circuito de reinicio automático; en el S3 y el C3 el puerto USB nativo desaparece en sueñoMantén pulsado BOOT, pulsa y suelta EN (RESET) y luego inicia la carga
Un relé o un LED cambia de estado al dormirEn sueño profundo los pines digitales quedan en alta impedanciaUsa una resistencia pull o mantén el nivel del pin con rtc_gpio_hold_en()
Durante el desarrollo, añade de forma temporal una espera de 5 segundos al inicio de setup() o una condición que no duerma mientras haya un botón pulsado. Así tendrás tiempo de abrir el Monitor Serie y subir código nuevo aunque la placa pase casi todo el tiempo dormida; recuerda quitarla al terminar el proyecto. Si con batería la placa se reinicia sola de vez en cuando, lo más probable es que la causa sean los picos de corriente del Wi-Fi; las soluciones están en la guía error de brownout del ESP32.

El deep sleep del ESP32 es la clave para que el mismo código funcione meses y no días con batería: haz el trabajo corto, elige bien la fuente de despertar, guarda en la memoria RTC los pequeños datos que necesitas entre despertares y no olvides nunca el consumo propio de la placa. Si quieres repasar lo básico del ESP32, la guía qué es el ESP32 es un buen comienzo. En la app BlueGrays, el proyecto ESP32 Deep Sleep — Ahorro de batería (OLED + contador en RAM RTC) te permite probar la lógica del temporizador y del contador RTC de este artículo en un circuito con pantalla OLED, con el esquema paso a paso y el código listo.

Preguntas frecuentes

¿Cuánta corriente consume el ESP32 en deep sleep?

Según la hoja de datos de Espressif, el chip ESP32 consume unos 10 µA en sueño profundo con el temporizador y la memoria RTC encendidos, y 5 µA en hibernación. Sin embargo, en placas de desarrollo como la DevKit el regulador, el LED de encendido y el chip USB-serie suelen elevar la corriente de sueño a 5–15 mA.

¿Cómo se despierta un ESP32 del deep sleep?

Hay cinco formas: el temporizador RTC, un solo pin RTC (ext0), varios pines RTC (ext1), los pines táctiles y el coprocesador ULP. La fuente de despertar se configura antes de llamar a esp_deep_sleep_start() y puedes activar varias a la vez; solo ext0 y el despertar táctil no pueden usarse juntos.

¿Se borran las variables en el deep sleep del ESP32?

Sí, las variables normales se borran, porque despertar del sueño profundo es un reinicio y setup() vuelve a empezar. Las variables marcadas con RTC_DATA_ATTR se guardan en la memoria RTC y se conservan entre despertares, pero vuelven a su valor inicial tras un corte de luz, una pulsación de EN o una nueva carga de código.

¿Cuánto dura un ESP32 con una batería 18650?

Desde un día hasta más de un año, según la placa y el uso. Una DevKit conectada siempre al Wi-Fi dura solo 1–2 días con una 18650 de 3000 mAh y una DevKit que se despierta cada 10 minutos, unos 12 días. Un circuito de bajo consumo que hace lo mismo con 15 µA en sueño funciona de 5 a 16 meses, según lo que tarde cada conexión.

¿Qué diferencia hay entre light sleep y deep sleep en el ESP32?

En light sleep la CPU se pausa pero la RAM se conserva; al despertar, el programa sigue en la línea donde se detuvo y el chip consume unos 0,8 mA. En deep sleep también se apaga la RAM y el consumo baja a 10 µA, pero el programa empieza de nuevo en cada despertar. El sueño ligero sirve para pausas de segundos y el profundo para esperas de minutos u horas.

¿Cómo se sube código a un ESP32 en deep sleep?

En las placas con circuito de reinicio automático la carga suele empezar sin problemas, porque el cargador reinicia el chip a través del pin EN. Si no empieza, mantén pulsado el botón BOOT, pulsa y suelta EN (RESET) y después inicia la carga. En placas con USB nativo como el ESP32-S3 y el C3 el puerto desaparece durante el sueño, así que este método suele ser imprescindible.

Ver todos los proyectos
LED Parpadeante con ESP32
#103Principiante

LED Parpadeante con ESP32

Enseña el uso básico de la salida GPIO con ESP32. Conseguimos un efecto de parpadeo encendiendo y apagando un LED desde el pin digital. Versión para ESP32 del clásico proyecto blink en Arduino UNO; los comandos básicos de blink en el entorno Arduino son los mismos, pero la distribución de pines y los niveles GPIO de 3,3 V del ESP32 difieren de los del Arduino UNO.

4.7(37)
99
Control de LED con pulsador en ESP32 (Push)
#104Principiante

Control de LED con pulsador en ESP32 (Push)

El LED se enciende cuando se pulsa el botón y se apaga cuando se suelta. Muestra cómo se utiliza el pin de entrada digital del ESP32 y la resistencia pull-up interna. Gracias al modo INPUT_PULLUP, no se necesita ninguna resistencia externa.

4.6(36)
55
Modo de suspensión profunda del ESP32 — Ahorro de batería (OLED + contador en RTC RAM)
#135Avanzado
Premium

Modo de suspensión profunda del ESP32 — Ahorro de batería (OLED + contador en RTC RAM)

El modo «Deep Sleep» del ESP32 reduce el consumo de corriente a unos 10 µA al desactivar la CPU y la mayoría de los periféricos, lo cual es de vital importancia para los dispositivos IoT que funcionan con pilas. En este proyecto utilizamos tres fuentes de activación diferentes: el temporizador (15 s), un pin externo (EXT0 — botón GPIO 33) y el sensor táctil (T0/GPIO 4). Las variables marcadas con RTC_DATA_ATTR se conservan durante el modo Deep Sleep: el contador de arranque, el contador de act

4.3(10)
16
Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
#145Avanzado
Premium

Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)

Un sistema inteligente de alarma de seguridad que activa el buzzer y el LED cuando el sensor PIR detecta movimiento, y envía simultáneamente una notificación instantánea al propietario vía Telegram. Cuenta con un tiempo de espera de 30 segundos para limitar la frecuencia de las alarmas repetidas; este mecanismo no comprueba la validez de las detecciones del sensor PIR ni elimina las falsas detecciones. Ideal para seguridad del hogar, vigilancia de garajes, almacenes o salas de trabajo. Con ESP32

0.0(0)
9
Iluminación automática con el sensor de movimiento PIR del ESP32
#121Intermedio
Premium

Iluminación automática con el sensor de movimiento PIR del ESP32

En este proyecto, utilizaremos el sensor de movimiento PIR HC-SR501 para detectar a las personas que entren en la habitación y encender el LED automáticamente. Controlaremos el tiempo de encendido del LED con millis(); cada lectura HIGH del sensor actualizará el instante del último movimiento, y el LED se apagará cuando hayan transcurrido al menos 10 segundos desde la última lectura HIGH. El código actual también espera 50 ms en cada iteración mediante delay(50), por lo que el bucle de la ap

4.4(24)
38
ESP32 DHT22 Temperatura y humedad (con pantalla LCD)
#117Intermedio

ESP32 DHT22 Temperatura y humedad (con pantalla LCD)

Se trata de un proyecto que mide la temperatura y la humedad ambientales mediante el sensor DHT22 y las muestra en tiempo real en una pantalla LCD I2C 16x2. Los datos del sensor se leen mediante el protocolo de un solo cable (one-wire) utilizando la biblioteca DHT de Adafruit. Este proyecto constituye la base para estaciones meteorológicas IoT, sistemas de automatización doméstica inteligente o sistemas de monitorización ambiental en invernaderos.

4.8(38)
56
Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzado
Premium

Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

¡Construye un registrador de temperatura con marca de tiempo con ESP32! Lee temperatura/humedad del DHT22 cada minuto, obtén la hora real del DS1307 RTC y registra en tarjeta microSD como CSV. El OLED muestra en vivo la temperatura (fuente grande), porcentaje de humedad, marca de tiempo y contador de registros. El archivo /temp_log.csv en la tarjeta SD se abre en Excel, Google Sheets o Python pandas para análisis — perfecto para monitoreo de invernadero, seguimiento de temperatura del hog

4.7(7)
12