22  Deep Sleep

Deep sleep is a power-saving mode on the ESP32 microcontroller that allows it to significantly reduce its power consumption by shutting down most of its components and functionalities. This mode is particularly useful for battery-powered applications where conserving energy is crucial.

22.1 Key Features of Deep Sleep

  1. Low Power Consumption:
    In deep sleep mode, the ESP32 consumes only a few microamps of current, drastically reducing power usage compared to its normal operating modes.
  2. Preservation of Data:
    The ESP32 can save the state of its peripherals and the values of certain variables in RTC (Real-Time Clock) memory, which is retained during deep sleep. This allows the microcontroller to resume tasks efficiently upon waking up.
  3. Wake-Up Sources:
    The ESP32 can be awakened from deep sleep by various events:
    • Timer: The internal RTC can be programmed to wake the device after a specified time interval.
    • External Pin: A change in the state of a designated GPIO pin can trigger a wake-up.
    • Touch Sensor: Touch pad sensors can be used to wake up the device.
    • ULP Coprocessor: The Ultra-Low-Power (ULP) coprocessor can run while the main CPU is in deep sleep and trigger a wake-up event based on sensor readings or other conditions.
  4. Application Examples:
    • Battery-Powered Sensors: Environmental sensors that need to periodically send data can spend most of their time in deep sleep, waking up only to take measurements and transmit data.
    • IoT Devices: Devices that need to conserve power, such as remote weather stations or smart home devices, can use deep sleep to extend battery life.

22.2 Deep Sleep code

Download code
#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  10        /* Time ESP32 will go to sleep (in seconds) */


void setup(){
  Serial.begin(115200);
  Serial.println("Good morning!");
  delay(2000); //Take some time to open up the Serial Monitor

  // turn on LED
  Serial.println("turn on LED");
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(2000); //Take some time to open up the Serial Monitor

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every TIME_TO_SLEEP seconds
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");

  
  Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

22.3 Deep Sleep wake with touch

Adapted from here.

Download code
/*
Deep Sleep with Touch Wake Up
=====================================
This code displays how to use deep sleep with
a touch as a wake up source and how to store data in
RTC memory to use it over reboots

ESP32 can have multiple touch pads enabled as wakeup source
ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled

This code is under Public Domain License.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#if CONFIG_IDF_TARGET_ESP32
#define THRESHOLD 40   /* Greater the value, more the sensitivity */
#else                  //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */
#define THRESHOLD 5000 /* Lower the value, more the sensitivity */
#endif

RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
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.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad() {
  touchPin = esp_sleep_get_touchpad_wakeup_status();

#if CONFIG_IDF_TARGET_ESP32
  switch (touchPin) {
    case 0:  Serial.println("Touch detected on GPIO 4"); break;
    case 1:  Serial.println("Touch detected on GPIO 0"); break;
    case 2:  Serial.println("Touch detected on GPIO 2"); break;
    case 3:  Serial.println("Touch detected on GPIO 15"); break;
    case 4:  Serial.println("Touch detected on GPIO 13"); break;
    case 5:  Serial.println("Touch detected on GPIO 12"); break;
    case 6:  Serial.println("Touch detected on GPIO 14"); break;
    case 7:  Serial.println("Touch detected on GPIO 27"); break;
    case 8:  Serial.println("Touch detected on GPIO 33"); break;
    case 9:  Serial.println("Touch detected on GPIO 32"); break;
    default: Serial.println("Wakeup not by touchpad"); break;
  }
#else
  if (touchPin < TOUCH_PAD_MAX) {
    Serial.printf("Touch detected on GPIO %d\n", touchPin);
  } else {
    Serial.println("Wakeup not by touchpad");
  }
#endif
}

void setup() {
  Serial.begin(115200);
  delay(1000);  //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32 and touchpad too
  print_wakeup_reason();
  print_wakeup_touchpad();

#if CONFIG_IDF_TARGET_ESP32
  //Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27)
  touchSleepWakeUpEnable(T3, THRESHOLD);
  touchSleepWakeUpEnable(T7, THRESHOLD);

#else  //ESP32-S2 + ESP32-S3
  //Setup sleep wakeup on Touch Pad 3 (GPIO3)
  touchSleepWakeUpEnable(T3, THRESHOLD);

#endif

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  //This will never be reached
}

22.4 Save values between sleeps

Recommended tutorial here.

Download code
/*
Good tutorial
https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
*/
#include <Preferences.h> // Include the Preferences library

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for microseconds to seconds */
#define TIME_TO_SLEEP  10          /* Time ESP32 will go to sleep (in seconds) */

Preferences preferences;           // Create a Preferences object

void setup() {
  Serial.begin(115200);
  Serial.println("Good morning!");
  delay(100); // Take some time to open up the Serial Monitor

  // Turn on LED
  Serial.println("Turn on LED");
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(2000);

  // Open Preferences in RW mode
  preferences.begin("my-app", false); // "my-app" is the namespace, false = read/write mode

  // Retrieve stored values
  int storedInt = preferences.getInt("myInt", 0);      // Default value is 0 if not set
  float storedFloat = preferences.getFloat("myFloat", 0.0); // Default is 0.0
  String storedString = preferences.getString("myString", "Default");

  Serial.println("Retrieved values from flash:");
  Serial.println("Int: " + String(storedInt));
  Serial.println("Float: " + String(storedFloat));
  Serial.println("String: " + storedString);

  // Increment and store new values
  storedInt++;
  storedFloat += 1.5;
  storedString = "Wake #" + String(storedInt);

  preferences.putInt("myInt", storedInt);
  preferences.putFloat("myFloat", storedFloat);
  preferences.putString("myString", storedString);

  Serial.println("Stored updated values in flash:");
  Serial.println("Int: " + String(storedInt));
  Serial.println("Float: " + String(storedFloat));
  Serial.println("String: " + storedString);

  // Close Preferences
  preferences.end();

  // Configure the wake-up source
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " seconds");

  Serial.println("Going to sleep now");
  Serial.flush();
  esp_deep_sleep_start();

  Serial.println("This will never be printed");
}

void loop() {
  // This is not going to be called
}