Deep Sleep Mode Configuration
Deep Sleep Mode Configuration
Overview
Section titled “Overview”This section covers ESP32 deep sleep mode configuration for battery-powered e-paper display applications. Deep sleep dramatically reduces power consumption by shutting down the main CPU and most peripherals, keeping only the RTC (Real-Time Clock) active for timed wake-up. After completing this section, you will be able to:
- Configure ESP32 deep sleep with timer wake-up
- Calculate power savings between active and sleep modes
- Implement periodic wake-refresh-sleep cycle for e-paper displays
- Handle WiFi reconnection after deep sleep
Prerequisites
Section titled “Prerequisites”Before starting this section, please ensure:
- Basic ESP32 programming knowledge
- Display is wired and working with GxEPD2 (see 02-03)
- Power measurement tools (multimeter or power monitor)
Key Concepts
Section titled “Key Concepts”ESP32 Power Modes
Section titled “ESP32 Power Modes”The ESP32 has several power modes:
| Mode | CPU | WiFi/BT | RTC | RAM | Typical Current |
|---|---|---|---|---|---|
| Active | Running | On | On | Full | 80-260 mA |
| Modem Sleep | Running | Off | On | Full | 30-50 mA |
| Light Sleep | Paused | Off | On | Full | 5-10 mA |
| Deep Sleep | Off | Off | On | RTC only | 5-150 µA |
| Hibernation | Off | Off | Off | Off | 0.5-5 µA |
Deep sleep is the key to battery-powered operation: reducing consumption from ~100 mA (active) to ~10 µA (deep sleep) — a 10,000x reduction.
Wake-Up Sources
Section titled “Wake-Up Sources”ESP32 supports these wake-up sources from deep sleep:
| Source | Description | Typical Use |
|---|---|---|
| Timer | RTC timer wakes after duration | Periodic data refresh |
| External (EXT0) | GPIO level change | Button press |
| External (EXT1) | Multiple GPIO OR | Motion sensor |
| Touch | Touch sensor | User interaction |
| ULP Coprocessor | Ultra-low-power sensor reading | Continuous monitoring |
For the e-paper display project, Timer wake-up is the primary mechanism.
Deep Sleep Cycle for E-Paper
Section titled “Deep Sleep Cycle for E-Paper” Active Period (~10 seconds)┌──────────────────────────────────────────────────────┐│ 1. Wake from deep sleep ││ 2. Reconnect WiFi (2-5 seconds) ││ 3. Fetch data via MQTT (0.5 second) ││ 4. Update display (3-5 seconds) ││ 5. Enter deep sleep │└──────────────────────────────────────────────────────┘ │ │ Timer wake-up (1 hour) ▼ Deep Sleep (~10 µA)Implementation Steps
Section titled “Implementation Steps”Step 1: Basic Deep Sleep Sketch
Section titled “Step 1: Basic Deep Sleep Sketch”#include <WiFi.h>
// Configurationconst char* ssid = "YOUR_SSID";const char* password = "YOUR_PASSWORD";const int SLEEP_HOURS = 1; // Wake up every hour
void setup() { Serial.begin(115200); Serial.println("Device waking up...");
// Connect WiFi WiFi.begin(ssid, password); int attempts = 0; while (WiFi.status() != WL_CONNECTED && attempts < 20) { delay(500); Serial.print("."); attempts++; }
if (WiFi.status() == WL_CONNECTED) { Serial.println("\nWiFi connected"); Serial.print("IP: "); Serial.println(WiFi.localIP());
// TODO: Fetch data and update display here delay(1000); }
Serial.println("Entering deep sleep...");
// Configure deep sleep for 1 hour esp_sleep_enable_timer_wakeup(SLEEP_HOURS * 3600 * 1000000ULL);
// Enter deep sleep esp_deep_sleep_start();}
void loop() { // Never reaches here — device goes to sleep in setup()}Important: In deep sleep mode,
loop()never runs. All logic must be insetup().
Step 2: Complete Display with Deep Sleep
Section titled “Step 2: Complete Display with Deep Sleep”Full implementation combining display update and deep sleep:
#include <WiFi.h>#include <PubSubClient.h>#include <ArduinoJson.h>#include <GxEPD2_BW.h>
// Configurationconst char* ssid = "YOUR_SSID";const char* password = "YOUR_PASSWORD";const char* mqtt_server = "192.168.1.100";const char* mqtt_topic = "factory/weather/data";
// Deep sleep settingsconst unsigned long SLEEP_INTERVAL_US = 3600 * 1000000ULL; // 1 hour
// E-Paper pins#define EPD_CS 5#define EPD_DC 17#define EPD_RST 16#define EPD_BUSY 4
// Display constructorGxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display( GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
WiFiClient espClient;PubSubClient client(espClient);
// Data variableschar temperature[8] = "--.-";int humidity = 0;char description[32] = "Loading...";
void callback(char* topic, byte* payload, unsigned int length) { char buffer[256]; if (length >= 256) return; memcpy(buffer, payload, length); buffer[length] = '\0';
JsonDocument doc; DeserializationError error = deserializeJson(doc, buffer);
if (!error) { strlcpy(temperature, doc["temperature"] | "--.-", sizeof(temperature)); humidity = doc["humidity"] | 0; strlcpy(description, doc["description"] | "Unknown", sizeof(description)); }}
void updateDisplay() { display.init(115200); display.setRotation(1); display.fillScreen(GxEPD_WHITE);
// Display temperature (large) display.setFont(&FreeMonoBold18pt7b); display.setCursor(10, 50); display.print(temperature); display.print(" C");
// Display humidity display.setFont(&FreeMonoBold12pt7b); display.setCursor(10, 80); display.print("Humidity: "); display.print(humidity); display.print("%");
// Display description display.setFont(&FreeMono9pt7b); display.setCursor(10, 105); display.print(description);
display.display(); display.powerOff(); // Turn off display power after update}
void setup() { Serial.begin(115200); Serial.println("[WAKE] Starting...");
// Connect WiFi WiFi.begin(ssid, password); int retries = 0; while (WiFi.status() != WL_CONNECTED && retries < 30) { delay(500); Serial.print("."); retries++; }
if (WiFi.status() == WL_CONNECTED) { Serial.println("\n[WAKE] WiFi connected");
// Connect MQTT and fetch data client.setServer(mqtt_server, 1883); client.setCallback(callback);
if (client.connect("ESP32_Display_DeepSleep")) { client.subscribe(mqtt_topic);
// Request fresh data by publishing to a trigger topic client.publish("factory/weather/request", "update");
// Wait for data with timeout unsigned long timeout = millis() + 5000; while (millis() < timeout) { client.loop(); delay(10); } }
// Update display updateDisplay();
// Disconnect WiFi before sleep client.disconnect(); WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } else { Serial.println("\n[WAKE] WiFi failed, using cached data"); updateDisplay(); // Show cached/blank display }
Serial.println("[SLEEP] Entering deep sleep...");
// Configure wake-up timer esp_sleep_enable_timer_wakeup(SLEEP_INTERVAL_US);
// Enter deep sleep esp_deep_sleep_start();}
void loop() { // Never executed}Step 3: RTC Memory for Data Persistence
Section titled “Step 3: RTC Memory for Data Persistence”Use RTC memory to preserve data across sleep cycles:
// RTC memory — preserved during deep sleepRTC_DATA_ATTR int bootCount = 0;RTC_DATA_ATTR char cachedTemperature[8] = "--.-";RTC_DATA_ATTR int cachedHumidity = 0;
void setup() { Serial.begin(115200);
// Increment boot counter bootCount++; Serial.print("Boot count: "); Serial.println(bootCount);
// On first boot, use cached values if (WiFi.status() != WL_CONNECTED) { // Use cached data from RTC memory Serial.print("Using cached temp: "); Serial.println(cachedTemperature); }
// ... update display and cache new data strlcpy(cachedTemperature, temperature, sizeof(cachedTemperature)); cachedHumidity = humidity;}Step 4: Adjustable Sleep Interval
Section titled “Step 4: Adjustable Sleep Interval”Make the sleep interval configurable:
// Sleep intervals in microseconds#define ONE_MINUTE_US 60 * 1000000ULL#define ONE_HOUR_US 3600 * 1000000ULL#define SIX_HOURS_US 6 * 3600 * 1000000ULL#define ONE_DAY_US 24 * 3600 * 1000000ULL
// Select interval based on use caseconst unsigned long SLEEP_INTERVAL = ONE_HOUR_US;
// Dynamic interval — change based on conditionsvoid configureSleep(bool dataReceived) { if (dataReceived) { // Normal interval esp_sleep_enable_timer_wakeup(ONE_HOUR_US); } else { // Retry sooner if data fetch failed esp_sleep_enable_timer_wakeup(5 * ONE_MINUTE_US); }}Power Measurement
Section titled “Power Measurement”To measure actual power consumption:
# Measure current with multimeter# 1. Set multimeter to DC mA range# 2. Connect in series with ESP32 power line# 3. Monitor during active and sleep phases
Expected measurements: Active (WiFi + Display): 100-200 mA (~10 seconds) Deep Sleep: 10-50 µA (~1 hour)Verification
Section titled “Verification”- ESP32 enters deep sleep and wakes up at the configured interval
- “Boot count” increments each wake cycle
- Display updates correctly after each wake
- WiFi reconnects successfully after deep sleep
- Power consumption drops to µA range in sleep mode
Troubleshooting
Section titled “Troubleshooting”Issue 1: ESP32 Won’t Wake from Deep Sleep
Section titled “Issue 1: ESP32 Won’t Wake from Deep Sleep”Symptoms:
- Device never wakes up
- Display doesn’t update
Solutions:
- Verify the timer configuration:
esp_sleep_enable_timer_wakeup() - Check if GPIO wake-up is interfering
- Try a shorter interval (10 seconds) for testing
- Ensure EN pin is not being held low
Issue 2: WiFi Fails After Deep Sleep
Section titled “Issue 2: WiFi Fails After Deep Sleep”Symptoms:
- WiFi connection fails on wake-up
- Need to power cycle to restore WiFi
Solutions:
// Force WiFi to reinitialize properlyWiFi.disconnect(true); // Delete stored credentialsWiFi.mode(WIFI_OFF); // Turn off WiFi hardwaredelay(100);WiFi.mode(WIFI_STA); // Set to station modeWiFi.begin(ssid, password);Issue 3: Display Shows Previous Content
Section titled “Issue 3: Display Shows Previous Content”Symptoms:
- After wake-up, display shows old data briefly
Solutions:
- Call
display.fillScreen(GxEPD_WHITE)before drawing new content - The e-paper’s bistable property means it retains the previous image until overwritten
Best Practices
Section titled “Best Practices”- ✅ Minimize active time — Everything in setup(), no delays in loop()
- ✅ Disconnect WiFi before sleep — Saves power and avoids connection issues on wake
- ✅ Use RTC memory for counters and cached data across sleep cycles
- ✅ Test with short intervals (10 seconds) during development
- ❌ Don’t use delay() extensively in active phase — Every millisecond counts
- ❌ Avoid deep sleep with peripherals powered — Disconnect power to sensors
- ❌ Don’t use WiFi scan before connect — It adds 3-5 seconds of active time
Summary
Section titled “Summary”- Deep sleep reduces power from ~100 mA to ~10 µA — enabling battery-powered operation
- Timer wake-up is the primary mechanism for periodic display updates
- All logic must be in setup() — loop() never executes after deep sleep
- RTC memory persists data (but not variables) across sleep cycles
- Minimize active time — Design the wake cycle to be as brief as possible
- For a 1-hour refresh cycle, the ESP32 is in deep sleep ~99.7% of the time
References
Section titled “References”- ESP32 Deep Sleep Guide (Espressif)
- ESP32 Deep Sleep Arduino Implementation
- Power Management on ESP32
Target Audience: Alibaba.com IoT Pre-sales Engineers
Status: ✅ Completed