Deep sleep and wake sources
The chip switches almost all of itself off and draws around 10 microamps. That is the easy part. The number that decides whether the battery lasts a week or a year is how many seconds it is awake either side.
Where the battery actually goes
delay() waiting for a sensor you could have started before connecting.The wake sources
| Source | Costs | Use for |
|---|---|---|
| Timer | Nothing extra | Anything periodic |
ext0 — one RTC pin | Nothing extra | A single button or a reed switch |
ext1 — several RTC pins | Nothing extra | A keypad, several sensors |
| Touch pad | A few µA | A button with no moving parts |
| ULP co-processor | ~100 µA while checking | Watching an analog value |
Only RTC-capable GPIOs can wake the chip. On the classic ESP32 that is 0, 2, 4, 12–15, 25–27 and 32–39 — an ordinary GPIO cannot do it.
Light sleep, and when to prefer it
Light sleep keeps RAM and the Wi-Fi connection alive and costs around 800 µA. Execution resumes on the next line rather than restarting. It is the right choice when the wake-up must be immediate and the connection must survive; deep sleep is the right choice for anything measured in minutes.
The code
Deep sleep is not a pause - the board restarts from the top of setup when it wakes. Anything that must survive goes in RTC memory, which is the only RAM that stays powered.
#include <esp_sleep.h>
RTC_DATA_ATTR int wakeCount = 0; // survives deep sleep, not power loss
void setup() {
Serial.begin(115200);
delay(50);
esp_sleep_wakeup_cause_t why = esp_sleep_get_wakeup_cause();
Serial.printf("boot %d, cause %d\n", ++wakeCount, why);
// ... take a reading, send it, and be quick about it ...
esp_sleep_enable_timer_wakeup(15ULL * 60 * 1000000); // 15 minutes
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 0); // or a low pin
Serial.flush(); // or the last line is lost
esp_deep_sleep_start(); // nothing after this line runs
}
void loop() {}The reset reason tells you whether this is a cold boot or a wake-up, and they usually want different code. A first boot might provision Wi-Fi; a wake-up must not.
Same restart-from-the-top behaviour. RTC memory here is a bytes buffer, which is enough for a counter or a cached Wi-Fi channel.
import machine, esp32, time
rtc = machine.RTC()
state = rtc.memory()
count = int(state) + 1 if state else 1
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print('woke up, boot', count)
else:
print('cold start')
# ... read the sensor, send it ...
esp32.wake_on_ext0(pin=machine.Pin(33), level=0)
rtc.memory(str(count))
machine.deepsleep(15 * 60 * 1000) # millisecondsmachine.deepsleep never returns. Put everything you need to do above it, and flush any output first.
When it does not work
Almost always the dev board rather than the chip. A power LED, a USB-serial chip and an inefficient regulator all keep drawing while the ESP32 sleeps. Measure the bare module, or cut the LED.
That is correct - deep sleep restarts the program. Mark anything that must survive with RTC_DATA_ATTR, and keep it small.
Look at how long it is awake, not at the sleep current. Four seconds at 120 mA every minute is the whole budget. Cache the Wi-Fi channel and IP in RTC memory to cut the reconnect from three seconds to under one.
Deep sleep cuts power to the UART mid-transmission. Call Serial.flush() before sleeping.
Ten microamps is not the floor. Five is, and getting there is a matter of what you switch off before the same function call.
Hibernation, the floor below sleep →Edit this page — content/esp32/deep-sleep-and-wake-sources.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.