Battery-powered ESP32 projects live and die by their power consumption. In active mode the ESP32 draws ~240 mA — enough to drain a 1000 mAh LiPo in under 5 hours. With deep sleep correctly configured, that same battery can last months or even years.

// What you'll learn: All five ESP32 power modes, every wake-up source, practical code for the most common patterns, and a real battery-life calculator example.
ACTIVE ~240 mA CPU + WiFi ON sleep() LIGHT SLEEP ~0.8 mA RAM retained deep_sleep() DEEP SLEEP ~10 µA RTC RAM only hibernate() HIBERNATE ~2.5 µA Timer wake only Wake-up → reset/resume
// AD SLOT — IN-CONTENT RESPONSIVE

Power Modes Compared

ModeCurrentCPUWiFi/BTRAMWake sources
Active~240 mAONONFull
Modem Sleep~15 mAONOFFFullAny
Light Sleep~0.8 mAPausedOFFRetainedTimer, GPIO, UART, Touch
Deep Sleep~10 µAOFFOFFRTC onlyTimer, EXT0, EXT1, Touch, ULP
Hibernate~2.5 µAOFFOFFNoneTimer only

Timer Wake-up — Most Common Pattern

The ESP32 reads a sensor, publishes the data, then sleeps for N seconds. The RTC timer fires after the interval, causing a reset — setup() runs again from the top.

// deep_sleep_timer.ino
#include <WiFi.h>
#include <DHT.h>

#define DHT_PIN     4
#define DHT_TYPE    DHT22
#define SLEEP_SEC   30          // wake every 30 seconds
#define uS_TO_S     1000000ULL

RTC_DATA_ATTR int bootCount = 0; // survives deep sleep in RTC RAM

DHT dht(DHT_PIN, DHT_TYPE);

void setup() {
  Serial.begin(115200);
  bootCount++;
  Serial.printf("Boot #%d\n", bootCount);

  dht.begin();
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  Serial.printf("Temp: %.1f°C  Hum: %.1f%%\n", t, h);

  // TODO: connect WiFi, publish MQTT, then disconnect
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

  esp_sleep_enable_timer_wakeup(SLEEP_SEC * uS_TO_S);
  Serial.println("Entering deep sleep...");
  esp_deep_sleep_start();
}

void loop() {} // never reached

GPIO (EXT0) Wake-up — Button or PIR

// ext0_wakeup.ino
// Wake when GPIO 33 goes HIGH (e.g. PIR sensor trigger)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);  // 1 = HIGH level
esp_deep_sleep_start();
// Note: EXT0 only supports a single GPIO. Use EXT1 for multiple GPIO wake sources with a bitmask.

Touch Pad Wake-up

// touch_wakeup.ino
// T0 = GPIO 4 (touch pin)
touchAttachInterrupt(T0, [](){}, 40); // threshold = 40
esp_sleep_enable_touchpad_wakeup();
esp_deep_sleep_start();

Battery Life Calculation

A common IoT pattern: active for 2 seconds every 60 seconds.

PhaseDurationCurrentCharge used
Active (WiFi, read, publish)2 s240 mA0.133 mAh
Deep sleep58 s0.010 mA0.000161 mAh
Total per cycle (60s)~0.133 mAh
1000 mAh LiPo life~7,500 cycles ≈ 125 hrs ≈ 5 days

Reduce active time to 500 ms and add an external 10 µA ultra-low-power MCU to handle wakeup logic and you can push this to weeks or months.

Pro Tips

  • Disable Bluetooth at boot if unused: btStop(); saves ~30 mA
  • Lower CPU frequency: setCpuFrequencyMhz(80); to cut active current by ~20%
  • Use static IP to skip DHCP handshake — saves ~500 ms of active time per cycle
  • RTC GPIO: Only GPIO 0, 2, 4, 12–15, 25–27, 32–39 can be used as wake sources
  • External pull-downs: floating GPIOs can cause phantom wake-ups — always pull unused wake pins to GND
A
Engr. Aamir Aziz Butt
PhD Researcher · IoT Engineer · Founder ESPSTACK

PhD candidate at Muslim Youth University, Islamabad. MS Computer Engineering from COMSATS. 10+ years of IoT development experience across ESP32, Jetson Nano, and cloud platforms.