In a previous article, we covered sleep modes in ESP8266. ESP32 is another popular Wi-Fi development board from Expressif Systems. It is more feature-rich than the ESP8266, but it also consumes more power. The ESP32's power consumption can reach 790 mA when Wi-Fi and Bluetooth are operational – almost double that of the ESP8266, which maxes out at around 400 mA when highly active. Breakout board components can also add a few hundred mAs to the net power consumption.
Many IoT developers prefer to use the feature-rich SoC in their applications so that minimal external components are required on the board. This is why ESP32 is the ideal choice for many who choose between the two Expressif cards. However, the power consumption of the ESP32 can pose a challenge for battery-powered IoT devices. Fortunately, it offers several power management options that help.
Next, we will discuss ESP32 power and sleep modes, covering the different wake-up sources and how both (the sleep and wake-up sources) are managed in the MicroPython framework. Using the ESP32's proper sleep modes in a battery-powered network application makes it possible to reduce system power consumption from hundreds to a few mAs.
Sleep modes in ESP32
On the ESP32, there are five power modes available: active, modem sleep, soft sleep, deep sleep, and sleep modes.
Active sleep is the default mode of ESP32 where all peripherals including Wi-Fi, Bluetooth module, CPU, system clock and RTC are turned on. Typical SoC power consumption in this mode is 240 mA, although this can increase to 790 mA when Wi-Fi and Bluetooth work together at peak operation. However, power consumption in active mode can be adjusted by configuring Wi-Fi settings.
Typically, when the Wi-Fi module transmits an output between 13 and 21dBm, the SoC consumes between 160 and 260 mAs. Output power is the sum of radio transmission power and antenna gain minus cable losses.
If the Wi-Fi output is set to 0dBm, consumption is reduced to 120 mA. If the application receives data only over the network, the Wi-Fi module can be set to receive and listen mode. In this configuration, SoC consumption in active mode is reduced to 80~90 mA.
In modem sleep mode, the CPU, system clock, and RTC are on while Wi-Fi, Bluetooth, and radio are off. Consumption in this mode is 20 mA if the CPU runs at high speed and can reach 3 mA if the CPU runs slower.
In this mode, the SoC uses the DTIM beacon mechanism to stay connected to the network. Wi-Fi is turned off between the two beacon intervals and turns on before the next one arrives. Sleep time is determined by the Wi-Fi router's DTIM beacon interval, which varies between 100 and 1000 ms. The ESP32 Wi-Fi module can be configured to publish a DTIM after one, three, or 10 beacon intervals. The default DTIM value is three.
In Light Sleep mode, the CPU goes into a pending state, which means it is interrupted by turning off clock pulses. Wi-Fi, Bluetooth and radio are also turned off. Wi-Fi remains connected to the network via the DTIM beacon engine, where it periodically enters sleep and wake modes and reconnects to the modem.
The current state of the RAM is preserved before entering soft sleep mode, which resumes when the chip wakes up. The RTC is the only thing that stays on, necessary to maintain the date and time. The power consumption of the ESP32 SoC is reduced to 0.8 mA in this mode.
In deep sleep mode, the Wi-Fi, Bluetooth, radio, system clock, CPU and RAM are turned off. The only connected peripheral is the RTC module. Wi-Fi and Bluetooth connection data is preserved in RTC memory as main memory is erased whenever the SoC goes into deep sleep.
The ULP coprocessor also remains active and continues to aggregate sensor data. The sensor data is used to wake the chip from a deep sleep. The power consumption of the ESP32 in deep sleep is reduced to 0.15 mA ~ 10 uA depending on the activities of the ULP coprocessor.
In hibernate mode, everything is turned off, including Wi-Fi, Bluetooth, radio, system clock, CPU, ULP coprocessor, and RTC. Only the RTC timer is kept at slow clock. The power consumption of the ESP32 is reduced to 2.5 uA in this mode.
By default, MicroPython only supports soft and deep sleep modes for supported ports. These are the only two modes supported when using ESP32 in MicroPython.
ESP32 wake up sources
There are four activation sources in the ESP32: timer, external, touch pins and ULP processor.
In timer wake-up, the built-in RTC is used to wake the SoC from a deep sleep after a specified period. On external wake-up, the SoC goes into an indefinite deep sleep until a signal is detected by the RTC GPIO. There are two external “wake-ups” in ESP32: ext0 and ext1.
On ext0, only one RTC GPIO is used to wake the SoC from a deep sleep. In ext1, two RTC GPIO are used to activate the chip. On touch pin activation, the chip is awakened from a deep sleep by one of its capacitive touch pins. The ULP coprocessor is used to activate the main processor through sensor data.

ESP32 power consumption in different sleep modes.
MicroPython supports activating the ESP32 using a timer, external signals and touch pins. What is not supported is enabling the ULP coprocessor. There are functions available to access the ULP coprocessor, load a binary into the ULP coprocessor, run the ULP from an entry point, or activate the ULP coprocessor at periodic intervals. These functions are not related to awakening from deep or light sleep modes. This means that although the ULP coprocessor can be used to enable ESP32, it is not currently accessible in MicroPython.
How Deep Sleep is Used in ESP32
As mentioned, the ESP32 is a power-hungry chip. Therefore, its deep sleep mode is particularly useful in battery-powered network applications. It allows the chip to remain primarily in a deep sleep or inactive state, periodically waking up to perform assigned tasks. These tasks include taking readings from a sensor, sending sensor data to a server via an IoT protocol (such as MQTT or CoAP), and/or taking an on-site action based on sensor readings or insights received over the network.
After performing a task by the user application, the chip returns to deep sleep for a specified period of time. Even in deep sleep, Wi-Fi and Bluetooth network details are stored in RTC memory. This allows the card to easily reconnect to the network whenever it wakes up from a deep sleep. The cycle of deep sleep, waking up, performing embedded/IoT tasks, and going back to sleep continues indefinitely.
MicroPython Power-Related Functions
The MicroPython machine module provides the following functions for power management of supported boards.
machine.lightsleep((time_ms)) : puts the port in light sleep mode. If time in milliseconds is specified as an argument, soft sleep mode lasts for the specified time. The door can be activated before the set time, triggered by a source. If no arguments are passed, soft sleep mode lasts indefinitely or until interrupted by a wake source.
machine.deepsleep((time_ms)) : puts the port in deep sleep mode. If time in milliseconds is specified as an argument, deep sleep mode lasts for the specified time. The door can be activated before the set time, triggered by a source. If no arguments are passed, deep sleep lasts indefinitely, until interrupted by a wake source. Waking up from deep sleep mode is the same as a hard reset.
machine.wake_reason : Returns the wake source. The returned value can be machine.WLAN_WAKE, machine.PIN_WAKE, or machine.RTC_WAKE — depending on whether the wake source is WLAN, pin change, or RTC. This method can record an activation reason in a variable or print it to the console.
The wake source must be configured before requesting light or deep sleep. And machine.wake_reason can only be called after asking for light or deep sleep.
The machine.idle is another useful function for port power management. When called, clock ports (to the CPU) cause the port to go into sleep mode, where the port wakes up if it receives an interrupt.
MicroPython implementation of sleep modes in ESP32
MicroPython only supports light and deep sleep modes in ESP32. They are implemented by the machine.lightsleep and machine.deepsleep methods. There is an ESP32-specific module, esp32, in MicroPython that provides additional functions for configuring the activation source.
These methods are:
esp32.wake_on_touch(awakening) : configures whether or not the “touch” will wake up the ESP32. It takes a boolean argument. If set to '1', the ESP32 is activated on touch. If set to '0', the ESP32 will not activate when touched.
esp32.wake_on_ext0(pin, level) : configures external wake-up, EXT0. This wake-up can be applied to one pin, which must be RTC GPIO. It requires two arguments: a pin object and a level. The level can be set to esp32.WAKEUP_ALL_LOW or esp32.WAKEUP_ANY_HIGH.
esp32.wake_on_ext1(pins, level) : configures external wake-up, EXT1. This wake-up can be applied to multiple pins, as long as they are RTC GPIO. It requires two arguments: a list or tuple of pin objects and a level. The level can be set to esp32.WAKEUP_ALL_LOW or esp32.WAKEUP_ANY_HIGH.
esp32.gpio_deep_sleep_hold(enable) : Determines whether or not the non-RTC GPIO pin configuration is held for blocks held during deep sleep mode. It takes a Boolean argument, which can be set to '0' or '1'.
Wake up with timer on ESP32
The ESP32 alarm clock does not require any special arrangements. Simply call the deepsleep or lightsleep methods with a specified time in milliseconds to put the ESP32 into deep or light sleep.
For this project, we will use the ESP32's wake-up timer to blink an LED. To do this, connect an LED to the ESP32 in GPIO2 as shown in the image below.
This MicroPython script puts the ESP8266 into a soft sleep mode. It flashes an LED, which is connected to the GPIO2 pin, each time the ESP8266 wakes up from the timer.
import machine
Machine Import Pin
of time matter sleep
led = Pin (2, Pin.OUT) #GPIO2 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# wait 5 seconds so you can wake up the ESP to establish serial communication later
# you must remove this suspend line in your final script
sleep(5) #10 second delay
print('Entering soft sleep mode')
machine.lightsleep(10000) #10000ms sleep time
The following MicroPython script puts the ESP8266 into deep sleep mode. It flashes an LED, which is connected to the GPIO2 pin, each time the ESP8266 wakes up from the timer.
import machine
Machine Import Pin
of time matter sleep
led = Pin (2, Pin.OUT) #GPIO2 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# wait 5 seconds so you can wake up the ESP to establish serial communication later
# you must remove this suspend line in your final script
sleep(5) #10 second delay
print('Entering deep sleep mode')
machine.deepsleep(10000) #10000ms sleep time
EXT0 external activation on ESP32
External activation is triggered by a pin change. There are two external sources of activation in the ESP32. EXT0 applies pin change activation to only one of the RTC GPIOs. The RTC GPIOs on the ESP32 are shown below.
Next, we will blink the LED when EXT0 wakes up. To do this, connect the LED to GPIO2 and then a button to GPIO14 – pulled up as shown below.
The following MicroPython script puts the ESP8266 into a soft sleep mode. It flashes an LED, which is connected to the GPIO2 pin, each time the ESP8266 wakes up from an external pin change.
import machine
import esp32
Machine Import Pin
of time matter sleep
led = Pin (2, Pin.OUT) #GPIO2 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# checks if the device woke up from light sleep
if machine.reset_cause == machine.DEEPSLEEP_RESET:
print('I woke up from a light sleep')
push_button = Pin(14, mode = Pin.IN) #defining push_button as wake source
esp32.wake_on_ext0(pin = push_button, level = esp32.WAKEUP_ANY_HIGH) #initializing wakeup
sleep (5)
print('Entering soft sleep mode')
machine.lightsleep
The following MicroPython script puts the ESP8266 into deep sleep mode. It flashes an LED, which is connected to the GPIO2 pin, each time the ESP8266 wakes up from an external pin change.
import machine
import esp32
Machine Import Pin
of time matter sleep
led = Pin (2, Pin.OUT) #GPIO2 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# checks if the device woke up from a deep sleep
if machine.reset_cause == machine.DEEPSLEEP_RESET:
print('I woke up from a deep sleep')
push_button = Pin(14, mode = Pin.IN) #defining push_button as wake source
esp32.wake_on_ext0(pin = push_button, level = esp32.WAKEUP_ANY_HIGH) #initializing wakeup
sleep (5)
print('Entering deep sleep mode')
machine.deepsleep
Note: The machine.lightsleep and machine.deepsleep methods are called without an argument for external activation.
EXT1 external activation on ESP32
For EXT1 external activation, more than one GPIO RTC can be configured as activation source.
For our project, we will blink an LED on the EXT1 wake-up call. To do this, connect the LED to GPIO22. Additionally, connect one button to GPIO2 and a second button to GPIO4, both pulled up as shown below.
This MicroPython script puts the ESP8266 into a soft sleep mode. It flashes an LED connected to GPIO2 each time the ESP8266 wakes up from an external pin change on more than one of the RTC GPIOs.
import machine
import esp32
Machine Import Pin
of time matter sleep
led = Pin (22, Pin.OUT) #GPIO22 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# checks if the device woke up from light sleep
if machine.reset_cause == machine.DEEPSLEEP_RESET:
print('I woke up from a light sleep')
push_button1 = Pin(2, mode = Pin.IN) #defining push_button1 as wake source
push_button2 = Pin(4, mode = Pin.IN) #defining push_button2 as wake source
esp32.wake_on_ext1(pins = (push_button1, push_button2), level = esp32.WAKEUP_ANY_HIGH) #initializing ext1
sleep (5)
print('Going to soft sleep mode')
machine.lightsleep
This MicroPython script puts the ESP8266 into deep sleep mode. It flashes an LED connected to GPIO2 each time the ESP8266 wakes up from an external pin change on more than one of the RTC GPIOs.
import machine
import esp32
Machine Import Pin
of time matter sleep
led = Pin (22, Pin.OUT) #GPIO22 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
# checks if the device woke up from a deep sleep
if machine.reset_cause == machine.DEEPSLEEP_RESET:
print('I woke up from a deep sleep')
push_button1 = Pin(2, mode = Pin.IN) #defining push_button1 as wake source
push_button2 = Pin(4, mode = Pin.IN) #defining push_button2 as wake source
esp32.wake_on_ext1(pins = (push_button1, push_button2), level = esp32.WAKEUP_ANY_HIGH) #initializing ext1
sleep (5)
print('Going to deep sleep mode')
machine.deepsleep
Touch pin activation on ESP32
The ESP32 has touch-sensitive pins that can be used to wake up.
You can use GPIO4 or Touch0 for touch detection. Do this by connecting a wire or jumper to GPIO4 and attaching a piece of aluminum foil for touch detection. The wire or jumper should be as short as possible.
The following MicroPython script puts the ESP8266 into a soft sleep mode. It flashes an LED connected to GPIO22 each time the ESP8266 wakes up from the touch sensor.
machine import Pin, TouchPad, deepsleep
import time
import esp32
led = Pin (22, Pin.OUT) #GPIO22 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
wake = Pin(4, mode = Pin.IN)
touch = TouchPad (wake)
touch.config(500)
esp32.wake_on_touch (True)
sleeptime(5)
light sleep (5000)
The following MicroPython script puts the ESP8266 into deep sleep mode. It flashes an LED connected to GPIO22 each time the ESP8266 wakes up from the touch sensor.
machine import Pin, TouchPad, deepsleep
import time
import esp32
led = Pin (22, Pin.OUT) #GPIO22 as output for LED
led.value(1) #LED is ON
sleep(1) #1 second delay
led.value(0) #LED is OFF
sleep(1) #1 second delay
wake = Pin(4, mode = Pin.IN)
touch = TouchPad (wake)
touch.config(500)
esp32.wake_on_touch (True)
sleeptime(5)
deep sleep (5000)
Conclusion
ESP32 is a power-hungry chip. When used with battery-powered network applications, it is important to use the ESP32's sleep modes to preserve battery life. However, MicroPython only supports ESP32 light and deep sleep modes. The functions to implement either mode come from the machine module. These functions are shared by all supported ports.
Unlike the ESP8266, the ESP32 has multiple activation sources. These include the RTC timer, external pin change, touch pins, and the ULP coprocessor. MicroPython's ESP32-specific module is esp32, which allows you to configure the timer, EXT0, EXT1, and ringtone as activation sources.
The original ESP32 firmware supports configuring the ULP coprocessor as a wake source, but MicroPython currently does not allow using the ULP coprocessor as a wake source.