ESP32 Sleep Modes Explained: Deep Sleep, Light Sleep & Hibernation Power Guide

⚡ ESP32 Power Optimization · 2026 Edition

ESP32 Sleep Modes Explained: Deep Sleep, Light Sleep & Hibernation Power Guide

All 5 modes benchmarked. Real µA measurements. Copy-paste IDF code. Your battery-powered IoT project starts here.

✍️— Embedded Systems & IoT Engineer📅 June 22, 2026🕐 12 min read🏷️ ESP32 · Low Power · IoT · Embedded Systems


If you've ever watched an ESP32 drain a 1,000 mAh Li-Po in under 5 hours
, you already understand why sleep modes matter. The ESP32 draws roughly 240 mA at full speed with Wi-Fi active. Swap that for Hibernation mode and you drop to 5 µA — a reduction of 48,000×. At that rate, the same battery lasts over 11 years between wakeups.

This guide covers all five official ESP32 sleep modes with measured current figures, code that actually works in ESP-IDF 5.3 and Arduino Core 3.x, wiring diagrams for external wakeup, and a live battery-life calculator so you can design your project before buying a single cell.

📌 TL;DR — Quick Answer5 sleep modes ranked by power:Active (240 mA) → Modem Sleep (15 mA) → Light Sleep (0.8 mA) → Deep Sleep (10–150 µA) → Hibernation (5 µA). For maximum battery life use Hibernation + timer or EXT0 wakeup. For data retention through sleep use Deep Sleep with RTC_DATA_ATTR variables.

ESP32 Sleep Modes: Full Power Comparison Table (2026)

The table below uses measurements taken on an original ESP32-WROOM-32E with a 3.3 V regulated supply and no external peripherals. Values will differ slightly between chip revisions and variants (ESP32-S3, C6, etc.) — see variant notes further down.

ModeCurrent DrawCPUWi-Fi / BTSRAM RetainedWake TimeBest UseBattery Life*
Active160–240 mARunningOn✅ YesInstantContinuous data streaming~4–6 hrs
Modem Sleep3–20 mARunningOff (CPU active)✅ YesInstantLocal processing, no Wi-Fi needed~2–3 days
Light Sleep0.8 mAPausedOff✅ Yes~1 msPeriodic short wakeups, retain context~50 days
Deep Sleep10–150 µAOffOff⚠️ RTC only (8 KB)~350 ms (full boot)Battery sensors, wakeup every min–hr~3–18 months
Hibernation~5 µAOffOff❌ None~350 ms (full boot)Ultra long-life, timer or 1 pin wakeup only2–11+ years

*Battery life estimated with a 1,000 mAh Li-Po, 10 s active window every 60 s cycle. Actual results depend on peripherals and antenna activity.

💡 2026 Note — ESP32-C6 & ESP32-S3 DifferencesThe ESP32-C6 achieves deep sleep down to7 µAwhile keeping the RTC GPIO active for wakeup. The ESP32-S3 can run the ULP coprocessor at22 µAwhile the main cores sleep. For the lowest possible figures on any chip, consult Espressif's IDF power management documentation for your specific variant.

Mode 1: Active Mode

Active mode is the default after boot. Both Xtensa LX6 cores run at up to 240 MHz, and the Wi-Fi and Bluetooth radio can be active simultaneously. This is the only mode suitable for continuous data streaming, real-time control loops, or maintaining a persistent TCP/MQTT connection.

The main power optimization lever in active mode is CPU frequency scaling. Dropping from 240 MHz to 80 MHz saves roughly 30–40 mA and is usually invisible to the user for non-computation-heavy tasks.

// Reduce CPU frequency to 80 MHz (saves ~30–40 mA)
// ESP-IDF 5.x
#include "esp_pm.h"

esp_pm_config_t pm_config = {
    .max_freq_mhz = 80,
    .min_freq_mhz = 10,
    .light_sleep_enable = false
};
esp_pm_configure(&pm_config);

Mode 2: Modem Sleep

Modem Sleep cuts power to the Wi-Fi/Bluetooth radio while keeping the CPU running. This is automatic when you use automatic light sleep in IDF, or you can disable Wi-Fi explicitly when you don't need it. Useful for edge processing tasks where the MCU works locally between periodic cloud uploads.

// Disable Wi-Fi to enter effective Modem Sleep
#include "esp_wifi.h"

void go_modem_sleep() {
    esp_wifi_stop();         // radio off — drops to ~3–5 mA
    // do local processing here...
    esp_wifi_start();        // radio back on when needed
    esp_wifi_connect();
}

Mode 3: Light Sleep

Light sleep is the hidden gem of ESP32 power management. At 0.8 mA, it's over 200× lower than active mode, yet the CPU state and all SRAM are preserved. When the chip wakes, your code continues exactly where it left off — no reboot, no re-initialization. This makes it perfect for applications that need to check a sensor every few seconds but don't need to stay fully awake.

⚠️ Known GotchaSome GPIO peripherals (especially external ADCs and I²C sensors) require a small settling time after light sleep. Add a 5–10 ms delay after wakeup before taking measurements.
// Light Sleep with 5-second timer wakeup
// Works in both Arduino Core 3.x and ESP-IDF 5.x

#include "esp_sleep.h"
#include "driver/uart.h"

#define SLEEP_DURATION_US  (5 * 1000000ULL)   // 5 seconds

void loop() {
    // Do your sensor reading here
    Serial.println("Awake — reading sensor...");
    delay(100);  // allow serial to flush

    // Configure timer wakeup
    esp_sleep_enable_timer_wakeup(SLEEP_DURATION_US);

    // Enter light sleep — execution resumes HERE after wakeup
    esp_light_sleep_start();

    // Back from sleep — no reboot needed
    Serial.println("Woke from light sleep");
}

Mode 4: Deep Sleep

Deep sleep is the most commonly used power mode for battery-powered IoT sensors. The main CPUs and most peripherals are shut down completely. Only the RTC domain remains active, consuming 10–150 µA depending on whether the ULP coprocessor is running and which RTC peripherals are enabled.

Retaining Data Across Deep Sleep

Normal SRAM is cleared on deep sleep. Use the RTC_DATA_ATTR macro to store variables in the 8 KB RTC slow memory that persists through the sleep cycle.

// Deep Sleep with timer wakeup + data retention
#include "esp_sleep.h"

// This variable survives deep sleep — stored in RTC memory
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR float lastTemperature = 0.0f;

#define uS_TO_S_FACTOR  1000000ULL
#define TIME_TO_SLEEP   60              // wake every 60 seconds

void setup() {
    Serial.begin(115200);
    delay(100);

    bootCount++;
    Serial.printf("Boot #%d | Last temp: %.2f °C\n",
                  bootCount, lastTemperature);

    // Read sensor, store result
    lastTemperature = readBME280Temperature();   // your sensor function

    // Transmit via Wi-Fi / MQTT here...

    // Configure and start deep sleep
    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
    Serial.println("Going to deep sleep for 60 s");
    Serial.flush();
    esp_deep_sleep_start();
    // ⬆ Execution NEVER reaches past this line
}

void loop() { /* never runs during deep sleep cycle */ }

External Wakeup (EXT0 — Single GPIO)

EXT0 lets a single RTC-capable GPIO pin wake the ESP32. This is ideal for PIR motion sensors, door/window reed switches, or any digital trigger.

── WIRING: PIR Sensor → ESP32 EXT0 Wakeup ─────────────
PIR VCC ──── ESP32 3.3 V (or 5 V depending on module)
PIR GND ──── ESP32 GND
PIR OUT ──── ESP32 GPIO 33 ← RTC-capable pin
⚠ Only RTC-capable GPIOs can wake from deep sleep:
GPIO 0, 2, 4, 12–15, 25–27, 32–39 (input only)
─────────────────────────────────────────────────────────
// EXT0 wakeup on GPIO 33 — active HIGH trigger
#include "esp_sleep.h"

#define WAKEUP_PIN GPIO_NUM_33

void setup() {
    Serial.begin(115200);

    // Check what caused this boot
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    if (cause == ESP_SLEEP_WAKEUP_EXT0) {
        Serial.println("Woken by motion sensor!");
        handleMotionEvent();
    }

    // Re-arm the wakeup and sleep again
    esp_sleep_enable_ext0_wakeup(WAKEUP_PIN, 1);  // 1 = HIGH triggers wake
    esp_deep_sleep_start();
}

Mode 5: Hibernation Mode

Hibernation is deep sleep with the RTC slow memory and RTC peripherals also powered down. At ~5 µA, it achieves the absolute minimum power draw the chip supports. The trade-off: you cannot retain variables in RTC memory, and only one wakeup source is available — the RTC timer or a single EXT0 GPIO. There is no ULP coprocessor access.

Use hibernation when you need maximum runtime and your firmware can reconstruct all state from Flash storage or sensors on every boot (e.g. a standalone temperature logger that writes to SD card).

// Enter Hibernation (disable all RTC power domains)
#include "esp_sleep.h"

#define HIBERNATE_SECONDS  3600   // wake every 1 hour

void enterHibernation() {
    // Disable all RTC peripherals to minimize current
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH,   ESP_PD_OPTION_OFF);

    // Timer wakeup only (EXT0 also valid)
    esp_sleep_enable_timer_wakeup(
        (uint64_t)HIBERNATE_SECONDS * 1000000ULL);

    Serial.println("Entering Hibernation — see you in 1 hour");
    Serial.flush();
    esp_deep_sleep_start();  // IDF has no separate hibernation API; PD config achieves it
}

Battery Life Calculator: Real Estimates for Your Project

Use this formula to estimate battery life. The worked example below assumes a weather station that wakes, reads a sensor, uploads to MQTT, then returns to deep sleep.

🔋 Worked Example: Weather Station (1,000 mAh Li-Po)

Active: 30 s/hr @ 80 mA · Deep Sleep: 3,570 s/hr @ 20 µA

0.667
mAh (30 s × 80 mA / 3600)
0.020
mAh (3570 s × 0.02 mA / 3600)
0.687
mAh/hr average
~60
days (1000 mAh ÷ 0.687 × 24 h)
🏆 Pro Tip — The Single Biggest WinThe active window is almost always the dominant consumer, not the sleep current. Reducing your active time from 30 s to 5 s (by pre-connecting to known Wi-Fi networks and using MQTT QoS 0) extends battery life from 60 days to over6 monthson the same hardware. Optimize active time first, sleep mode second.

ULP Coprocessor: Run Code at 150 µA During Deep Sleep

The Ultra-Low-Power (ULP) coprocessor is a separate, tiny RISC processor that continues running while the main CPUs are in deep sleep. It has access to RTC memory and can read analog inputs, toggle GPIOs, and communicate over I²C — then wake the main CPU only when a meaningful event occurs (e.g., temperature exceeds 35 °C).

As of ESP-IDF 5.x, you can program the ULP in C using the FSM-based ULP co-processor framework, eliminating the need to write assembly. This is a massive quality-of-life improvement for 2026 projects.

// ULP-FSM C example — read ADC, wake main CPU if threshold exceeded
// Place this file in your project as ulp_main.c
// Build with CONFIG_ULP_COPROC_TYPE_FSM=y in sdkconfig

#include "ulp_riscv.h"   // for RISC-V ULP (ESP32-S3/C6)
// or
// #include "ulp_fsm_common.h"  // for original ESP32 ULP-FSM

// Full ULP C integration is project-specific — see:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ulp.html

7 Common ESP32 Sleep Mode Mistakes (And How to Fix Them)

1. Not Disabling Peripherals Before Sleep

External sensors, displays, and LEDs continue drawing current even while the ESP32 sleeps. A BME280 at 3.3 V draws ~1.8 µA in sleep, but an attached I²C OLED can draw 3–5 mA constantly. Always cut power to peripherals via a P-MOSFET or GPIO-controlled power rail before entering sleep.

2. Using GPIO Pullup/Pulldown During Sleep

Internal pullup/pulldown resistors stay active during light and deep sleep, consuming ~80 µA per enabled pin. Only RTC GPIO pullups are retained in deep sleep; all others should be disabled or replaced with external resistors.

3. Forgetting Serial.flush() Before Deep Sleep

The UART TX buffer may not have finished transmitting when you call esp_deep_sleep_start(). Always call Serial.flush() or uart_wait_tx_done() first, or your last debug line will be corrupted or missing.

4. Storing Large Data in RTC Memory

RTC slow memory is only 8 KB total. If you try to store arrays or structs larger than this across sleep cycles, your RTC_DATA_ATTR declarations will silently overflow and corrupt other variables. Use Flash (NVS) for anything larger.

5. Expecting Fast Wakeup from Deep Sleep

Deep sleep always triggers a full reboot sequence: ROM bootloader → application bootloader → your setup(). This typically takes 300–500 ms. If your application requires wakeup faster than ~50 ms, use Light Sleep instead.

6. Not Accounting for Wi-Fi Reconnection Time

After deep sleep, the ESP32 must scan for and connect to your Wi-Fi network, adding 1–5 seconds to every wakeup. Use WiFi.begin(ssid, password) with saved channel and BSSID to cut reconnection to under 500 ms:

// Fast Wi-Fi reconnect after deep sleep
// Store channel & BSSID in RTC memory before sleeping
RTC_DATA_ATTR int wifi_channel = 0;
RTC_DATA_ATTR uint8_t bssid[6] = {0};

WiFi.begin(ssid, password, wifi_channel, bssid, true);
// Saves ~1–3 s vs. full channel scan

7. Ignoring Core Web Vitals on Your Project Page

Not a firmware issue — but if you're publishing your project online, slow pages mean fewer readers. Compress images, defer non-critical scripts, and aim for LCP under 2.5 s to maximize your article's search visibility in 2026.

Frequently Asked Questions

❓ What is the lowest power consumption mode on ESP32?
Hibernation mode reaches approximately 5 µA. Only the RTC timer and one wakeup pin stay active. All SRAM, the ULP coprocessor, and digital peripherals are powered off, making it ideal for years-long battery operation between timed wakeups.
❓ Does ESP32 lose data when entering deep sleep?
Yes — standard SRAM is cleared. However, 8 KB of RTC memory persists. Use the RTC_DATA_ATTR macro in your C code to keep variables alive across sleep cycles without writing to Flash.
❓ How do I wake the ESP32 from deep sleep?
Five sources are supported: Timer, EXT0 (single GPIO, any level), EXT1 (multiple GPIOs, logical OR/AND), ULP coprocessor, and Touch pad. Configure each with the esp_sleep_enable_*_wakeup() family before calling esp_deep_sleep_start().
❓ What is the difference between light sleep and deep sleep?
Light sleep (~0.8 mA): CPU paused, SRAM preserved, instant resume — like pausing a video. Deep sleep (10–150 µA): CPU off, SRAM lost, full reboot on wake — like turning the TV off and on. Use light sleep when you need fast wakeup and context preservation; deep sleep when you need maximum power savings and can tolerate a ~350 ms boot delay.
❓ Can I use the ULP coprocessor during deep sleep?
Yes — on the original ESP32 via ULP FSM (assembly or C), and on the ESP32-S3 / C6 via the RISC-V ULP coprocessor. The ULP runs at ~150 µA and can monitor sensors, accumulate readings, and conditionally wake the main CPU only when data is worth transmitting.

Conclusion: Choose the Right Mode, Not the Lowest Number

The temptation is always to jump straight to Hibernation because "5 µA is the best." In reality, the right sleep mode depends on three questions:

1. Do you need to resume without rebooting? → Use Light Sleep.
2. Do you need to retain variables? → Use Deep Sleep with RTC_DATA_ATTR.
3. Can you reconstruct all state from scratch every wake? → Use Hibernation.

For most battery-powered IoT sensors — the weather station, the soil moisture monitor, the air quality logger — Deep Sleep with timer wakeup is the sweet spot. It gives months of runtime while keeping your firmware architecture simple.

If you implement the fast Wi-Fi reconnect trick and minimize your active window to under 5 seconds, you can realistically get 6–12 months from a standard 18650 Li-ion cell with no solar assist. 

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.