How to wake ESP32 from deep sleep with timer, touch, or GPIO

ESP32 deep sleep only wakes from certain sources. The key detail: wake pins must be RTC-capable (not every GPIO works).

Timer wake (easiest, always works)

esp32_wake_timer.ino
cpp
#include <esp_sleep.h>

void setup() {
  Serial.begin(115200);
  delay(200);

  // Wake in 10 seconds
  esp_sleep_enable_timer_wakeup(10ULL * 1000000ULL);

  Serial.println("Sleeping for 10 seconds...");
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {}

GPIO wake (EXT0 and EXT1)

There are two common GPIO wake modes:

  • EXT0: one RTC pin, wake on a specific level (HIGH or LOW)
  • EXT1: a mask of RTC pins, wake when ANY or ALL hit a level

EXT0 example (single pin)

This wakes when the pin goes LOW (great for a button to GND). Pick an RTC-capable pin for your board.

esp32_wake_ext0.ino
cpp
#include <esp_sleep.h>

// Example: wake on GPIO33 going LOW (RTC-capable on classic ESP32)
static const gpio_num_t wakePin = GPIO_NUM_33;

void setup() {
  Serial.begin(115200);
  delay(200);

  pinMode((int)wakePin, INPUT_PULLUP); // button to GND
  esp_sleep_enable_ext0_wakeup(wakePin, 0); // 0 = LOW, 1 = HIGH

  Serial.println("Sleeping. Press button to wake.");
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {}

EXT1 example (multiple pins)

EXT1 uses a bitmask. This example wakes when ANY of the selected pins is LOW.

esp32_wake_ext1.ino
cpp
#include <esp_sleep.h>

void setup() {
  Serial.begin(115200);
  delay(200);

  // Choose RTC-capable pins on your board
  const uint64_t mask =
    (1ULL << GPIO_NUM_32) |
    (1ULL << GPIO_NUM_33);

  pinMode(GPIO_NUM_32, INPUT_PULLUP);
  pinMode(GPIO_NUM_33, INPUT_PULLUP);

  esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_LOW);

  Serial.println("Sleeping. Pull GPIO32 or GPIO33 LOW to wake.");
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {}

Touch wake (nice for “tap to wake” builds)

Touch wake also requires compatible touch pins. Touch thresholds vary by board and wiring, so expect to tune it.

esp32_wake_touch.ino
cpp
#include <esp_sleep.h>

// Example touch pad: T0 is usually GPIO4 on classic ESP32
static const touch_pad_t touchPad = TOUCH_PAD_NUM0;

void setup() {
  Serial.begin(115200);
  delay(200);

  // Set a wake threshold. You may need to tune this.
  touchSleepWakeUpEnable(touchPad, 40);

  Serial.println("Sleeping. Touch the pad to wake.");
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {}

Know why you woke up

This helps when debugging “it wakes instantly” vs “it never wakes.”

esp32_wake_reason.ino
cpp
#include <esp_sleep.h>

void setup() {
  Serial.begin(115200);
  delay(200);

  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  Serial.print("Wake cause: ");
  Serial.println((int)cause);
}

void loop() {}
Bottom line

Timer wake is the easiest baseline. For GPIO wake, use RTC-capable pins and choose EXT0 (one pin) or EXT1 (multiple pins). If wake is flaky, add pullups/pulldowns and print the wake reason.

Related: Deep sleep basics · ESP32 not waking up · ESP32 safe pins