ESP32 Power Management: Sleep Modes & Battery Optimization
Introduction to ESP32 Power Management
The ESP32 offers sophisticated power management capabilities that can dramatically extend battery life in IoT applications. By strategically using the different sleep modes, you can reduce power consumption from hundreds of milliamps to just a few microamps when the device is idle.
This guide explores the various sleep modes available on the ESP32, their power characteristics, and how to implement them in your projects. Understanding these modes is essential for creating battery-powered IoT devices that can operate for months or even years on a single charge.
Looking for more advanced implementation details? Check out our Advanced ESP32 Sleep Modes Guide for ESP32 model differences, UART wake-up, touch wake-up, and more.
ESP32 Sleep Modes Overview
The ESP32 supports five main power modes, each with different characteristics:
| Mode | Power | Wake-up Sources | Features |
|---|---|---|---|
| Active Mode | ~240mA | N/A | CPU, Wi-Fi, Bluetooth all active |
| Modem Sleep | ~15mA | Any | CPU active, Wi-Fi/BT off between beacons |
| Auto Light Sleep | ~3mA | Any | CPU inactive but clock running |
| Light Sleep | ~800μA | GPIO, Timer, UART, Touch, ULP | CPU paused, RTC active, RAM retained |
| Deep Sleep | ~10μA | GPIO, Timer, Touch, ULP | Only RTC memory retained, ULP coprocessor can run |
| Hibernation | ~5μA | GPIO, Timer | RTC slow memory shut down, only timer and ext. wakeup |
Note: Actual power consumption may vary depending on specific hardware, enabled peripherals, and supply voltage. The values provided here are approximate.
ESP32 Model Differences
Different ESP32 models (ESP32, ESP32-S2, ESP32-S3) have varying capabilities regarding sleep modes and available wake-up sources. See our advanced guide for detailed comparison.
Deep Sleep Mode
Deep Sleep is the most power-efficient sleep mode where most of the ESP32 is powered down, leaving only the RTC memory and basic RTC peripherals active. This mode uses around 10μA of current, making it ideal for battery-powered applications that need to wake up periodically.
Wake-up Sources in Deep Sleep
- Timer: Wake up after a specified duration
- External wake-up: Wake on GPIO state change (RTC GPIOs only)
- Touch sensors: Wake on capacitive touch threshold
- ULP (Ultra Low Power) coprocessor: Wake when a condition is detected by the ULP
Need more control over external wake-up? Check out our detailed comparison of ext0, ext1, and GPIO wake-up methods.
Deep Sleep Example Code
#include// Define the GPIO pin connected to the sensor #define SENSOR_PIN 33 // Define wake-up sources #define uS_TO_S_FACTOR 1000000 // Conversion factor for micro seconds to seconds #define TIME_TO_SLEEP 60 // Time ESP32 will go to sleep (in seconds) RTC_DATA_ATTR int bootCount = 0; // Stored in RTC memory, persists through deep sleep void setup() { Serial.begin(115200); delay(1000); // Allow serial connection to establish // Increment and print the boot count bootCount++; Serial.println("Boot number: " + String(bootCount)); // Print wake-up reason print_wakeup_reason(); // Set GPIO33 as input for external wake-up esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, HIGH); // Configure the timer wake-up esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); Serial.println("Setting up ESP32 to sleep for " + String(TIME_TO_SLEEP) + " seconds"); // Do your sensor readings or other work here read_sensor(); // Enter deep sleep Serial.println("Going to deep sleep now"); Serial.flush(); esp_deep_sleep_start(); } void loop() { // This is never executed in this example // Because we go to deep sleep at the end of setup() } void print_wakeup_reason() { esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); switch(wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break; case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break; default: Serial.println("Wakeup was not caused by deep sleep: " + String(wakeup_reason)); break; } } void read_sensor() { // Example sensor reading code int sensorValue = analogRead(SENSOR_PIN); Serial.println("Sensor value: " + String(sensorValue)); // You would typically process this data, maybe send it to a server // or make decisions based on the reading }
Important Notes about Deep Sleep:
- Only RTC GPIOs can be used as wake-up sources (GPIO0, GPIO2, GPIO4, GPIO12-15, GPIO25-27, GPIO32-39)
- After waking from deep sleep, the ESP32 restarts, so any data in RAM is lost
- To preserve data between sleep cycles, use RTC memory with the
RTC_DATA_ATTRattribute - When using external wake-up, include a debounce circuit if connecting to a mechanical switch
Light Sleep Mode
Light Sleep mode uses around 800μA and offers a good balance between power saving and wake-up time. Unlike Deep Sleep, the ESP32 can resume exactly where it left off after waking up from Light Sleep. The CPU is paused, but memory contents are preserved.
Light Sleep supports additional wake-up sources like Touch and UART. Learn more in our advanced guide.
Light Sleep Example Code
#include// Define the GPIO pin used for wake-up #define BUTTON_PIN GPIO_NUM_32 // Variables to track execution int sleepCount = 0; void setup() { Serial.begin(115200); delay(1000); // Allow serial connection to establish Serial.println("ESP32 Light Sleep Demo"); // Configure GPIO for wake-up pinMode(BUTTON_PIN, INPUT_PULLUP); // Initialize variables sleepCount = 0; } void loop() { // Do some work Serial.println("Doing some work... Iteration: " + String(sleepCount)); delay(1000); // Prepare for light sleep Serial.println("Entering light sleep"); Serial.flush(); // Configure wake-up sources: // 1. Timer wake-up after 10 seconds esp_sleep_enable_timer_wakeup(10 * 1000000); // 10 seconds in microseconds // 2. GPIO wake-up (can use any GPIO, not just RTC GPIOs) esp_sleep_enable_ext0_wakeup(BUTTON_PIN, LOW); // Wake on button press (LOW) // Enter light sleep esp_light_sleep_start(); // Code continues here after waking up sleepCount++; // Print wake-up reason esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) { Serial.println("Woke up from light sleep due to GPIO (button press)"); } else if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) { Serial.println("Woke up from light sleep due to timer"); } else { Serial.println("Woke up from light sleep for other reason"); } delay(500); // Short delay to allow button release if woken by button }
Advantages of Light Sleep over Deep Sleep:
- Much faster wake-up time (milliseconds vs hundreds of milliseconds)
- Program execution continues from where it left off, no reset occurs
- All memory contents are preserved
- More wake-up sources available, including UART
- Can use any GPIO for wake-up, not just RTC GPIOs
Modem Sleep Mode
Modem Sleep is designed for wireless applications that need to maintain a Wi-Fi or Bluetooth connection while minimizing power consumption. It turns off the RF components between beacon intervals, reducing power usage to around 15mA.
This mode is automatically enabled when using power save mode with Wi-Fi station mode:
#include#include const char* ssid = "YourWiFiSSID"; const char* password = "YourWiFiPassword"; void setup() { Serial.begin(115200); delay(1000); Serial.println("ESP32 Modem Sleep Demo"); // Connect to Wi-Fi with power save mode enabled WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); // Enable modem sleep (power save mode) // Available modes: // WIFI_PS_NONE: No power save // WIFI_PS_MIN_MODEM: Minimum modem power saving // WIFI_PS_MAX_MODEM: Maximum modem power saving esp_wifi_set_ps(WIFI_PS_MAX_MODEM); Serial.println("Modem sleep enabled"); } void loop() { // Periodic tasks while maintaining power efficiency Serial.println("Device is active but using modem sleep between data transfers"); // Perform a data transfer (e.g., HTTP request) // This will temporarily wake the modem Serial.println("Making a data transfer..."); // Your HTTP or MQTT code here // After data transfer, the modem will automatically go back to sleep // between beacon intervals // Wait before next data transfer delay(60000); // Wait 1 minute before next transfer }
Note: Modem Sleep is most effective with longer beacon intervals. You can configure your router's beacon interval (typically 100ms by default) to a larger value if possible. Be aware that longer beacon intervals may affect network responsiveness.
Hibernation Mode
Hibernation is the most power-efficient sleep mode, using only about 5μA. It turns off even more components than Deep Sleep, including the RTC slow memory. Only the RTC controller remains powered to provide wake-up capability.
In this mode:
- The ULP coprocessor is disabled
- RTC slow memory is powered off
- Only timer and external wake-up sources (RTC GPIOs) can be used
#include#define uS_TO_S_FACTOR 1000000 // Conversion factor for micro seconds to seconds #define TIME_TO_SLEEP 3600 // Time ESP32 will go to sleep (in seconds) - 1 hour void setup() { Serial.begin(115200); delay(1000); Serial.println("ESP32 Hibernation Mode Demo"); // Configure hibernation wake-up sources: // 1. Timer wake-up esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); Serial.println("Setup ESP32 to wake up after " + String(TIME_TO_SLEEP) + " seconds"); // 2. External wake-up on GPIO // Only RTC GPIOs can be used in hibernation mode esp_sleep_enable_ext0_wakeup(GPIO_NUM_32, LOW); Serial.println("Setup ESP32 to wake up on GPIO 32 going LOW"); // Perform critical operations before hibernation // For example, save any critical data to flash if needed // Enter hibernation mode - this turns off RTC slow memory Serial.println("Going to hibernation..."); Serial.flush(); // Power down RTC peripherals and enter hibernation esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); 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_deep_sleep_start(); } void loop() { // This is never executed }
Hibernation Limitations:
Hibernation is extremely power efficient but comes with significant limitations:
- Cannot use ULP coprocessor as a wake-up source
- Cannot use touch sensors as a wake-up source
- No data can be retained in RTC slow memory
- Limited to timer and external GPIO wake-up sources only
Additional Wake-up Methods
The ESP32 offers several specialized wake-up methods that can be useful for specific applications:
Touch Wake-up
Wake up your ESP32 when a user touches capacitive sensors. Ideal for touch-activated devices with minimal power consumption.
Learn moreUART Wake-up
Wake up your ESP32 when serial data is received. Perfect for sensor modules or other microcontrollers that communicate via UART.
Learn moreVisit our Advanced ESP32 Sleep Modes Guide for detailed implementation of these wake-up methods with code examples and wiring diagrams.
Power Optimization Best Practices
To maximize battery life in your ESP32 projects, consider these best practices:
-
Use the appropriate sleep mode for your application:
- Deep Sleep for periodic wake-up applications (sensor monitoring)
- Light Sleep for faster wake-up needs
- Modem Sleep for applications that need to maintain a Wi-Fi connection
-
Minimize active time:
- Complete tasks quickly and return to sleep
- Avoid unnecessary delays
- Optimize code for efficiency
-
Configure peripherals correctly:
- Disable unused peripherals
- Set appropriate ADC and GPIO states before sleep
- Consider lower CPU frequency when high performance isn't needed
-
Hardware considerations:
- Use low quiescent current voltage regulators
- Add power isolation for sensors that aren't needed during sleep
- Consider removing power LEDs for battery applications
-
Use the Ultra Low Power (ULP) coprocessor for simple tasks:
- Offload simple monitoring tasks to the ULP
- Only wake the main CPU when necessary
Battery Life Calculations
To estimate battery life for your ESP32 application, you need to consider the duty cycle (ratio of active to sleep time) and the current consumption in each state.
Battery Life Estimation Formula:
Battery Life (hours) = Battery Capacity (mAh) / Average Current (mA)
Average Current (mA) = (Active Time × Active Current + Sleep Time × Sleep Current) / (Active Time + Sleep Time)
Example:
- Battery Capacity: 2000mAh
- Active Time: 2 seconds (every 10 minutes)
- Sleep Time: 598 seconds (10 minutes - 2 seconds)
- Active Current: 150mA
- Deep Sleep Current: 0.01mA (10μA)
Average Current = (2s × 150mA + 598s × 0.01mA) / (2s + 598s) = (300 + 5.98) / 600 = 0.51mA
Battery Life = 2000mAh / 0.51mA = 3922 hours = ~163 days