The sleep states of the ESP8266

For the ESP32 see here.

As there is quite a bit of confusing documentation about the power management of the ESP8266, here’s a little overview.

We are going to use the Arduino core for ESP8266 because it seems to be more mature than Espressif’s own SDK. The latest release is 2.3.0 and contains SDK 1.5.3 and this article will refer to that version. The master branch contains a few more convenience functions like wifi_fpm_auto_sleep_set_in_null_mode() and WiFi.setSleepMode() but we’ll ignore them here because it doesn’t look like there’s a new release coming any time soon.

 

The ESP8266 has 6 power states:

 

Fully on
Behavior:
Everything on
Consumption:
about 70 mA
When to use:
Usually never
How to use with Arduino:
extern "C" {
  #include "user_interface.h"
}
void setup() {
  wifi_set_sleep_type(NONE_SLEEP_T);
}

Fully on, no Wifi configured

Fully on, Wifi configured and reachable
Auto Modem Sleep
Behavior:
After an idle timeout of 10 seconds the WiFi hardware will be shut down. It wakes up every <100 ms * Access Point DTIM interval> to check for incoming data. Everything else powered up.

Note: If the WiFi connection is not configured or not reachable, the chip will not sleep at all.

Note: Auto Modem Sleep will not happen if there are no delay() or only delay(0) calls in the code.

Consumption:
If Wifi is idle, about 70 mA until timeout, then about 18 mA.
When to use:
If you need Wifi connectivity and Auto Light Sleep didn’t work for you.
How to use with Arduino:
Do nothing, this is the default.

Auto Light Sleep
Behavior:
After an idle timeout of 10 seconds the WiFi hardware will be shut down. It wakes up every <100 ms * Access Point DTIM interval> to check for incoming data. Furthermore while the program is running delay() the system clock will be shut down too.

Note: If the WiFi connection is not configured or not reachable, the chip will not sleep at all.

Note: Auto Light Sleep will not happen if there are no delay() or only delay(0) calls in the code.

Consumption:
If Wifi is idle, about 70 mA until timeout, then about 2 mA.
When to use:
Recommended power state if you need Wifi connectivity.

Because of the halted system clock some peripherals might not work in this mode, use Auto Modem Sleep in those cases.

How to use with Arduino:
extern "C" {
  #include "user_interface.h"
}
void setup() {
  wifi_set_sleep_type(LIGHT_SLEEP_T);
}
Forced Modem Sleep
Behavior:
WiFi hardware is off, everything else powered up.
Consumption:
about 16 mA
When to use:
When you don’t need WiFi
How to use with Arduino:
WiFi.forceSleepBegin(); // Wifi off
WiFi.forceSleepWake(); // Wifi on

If you also use ESP.deepSleep(), you can add RF_DISABLED as the second argument, this prevents the Wifi hardware from booting up after deep sleep. (See below.) Note that there is no way to enable it again without deep sleeping again.

Forced Light Sleep
Behavior:
Everything is halted until woken up by a GPIO interrupt.
Consumption:
about 1 mA
When to use:
When you want to sleep until an external event happens and you want to keep the current execution state.
How to use with Arduino:
extern "C" {
  #include "user_interface.h"
}
void loop() {
  ...
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
  wifi_fpm_open();
  wifi_enable_gpio_wakeup(12, GPIO_PIN_INTR_LOLEVEL);
  wifi_fpm_do_sleep(0xFFFFFFF);
  wifi_fpm_close();
  ...
}
Note:
The Espressif Non-OS API reference contains an example where wifi_fpm_do_sleep(50*1000) is called to wake up from Forced Light Sleep by a timeout. I think that won’t work, only 0xFFFFFFFF with GPIO wakeup works. If you call wifi_fpm_do_sleep() with a timeout, the chip will only go to Force Modem Sleep. There is some indication that it might actually work with timeouts, but it seems to be super unreliable. If you want to do that, you’re on your own.
Deep Sleep
Behavior:
Everything is off and (almost) all execution state is lost. (You can save some configuration and wakeup counters and also some custom state.)
Consumption:
about 20 µA
When to use:
Use if you want the device to sleep for seconds, minutes, hours. (Note that there is a maximum time you can sleep.)
How to use with Arduino:
Hardware: Connect GPIO16 to RST (not to CH_PD). Contrary to what I’ve read, this does not seem to prevent programming.

ESP.deepSleep(time_in_us)

Waking up from 3 seconds of Deep Sleep and
connecting to Wifi

Waking up from Deep Sleep and going to
Forced Modem Sleep immediately

Waking up from Deep Sleep with RF_DISABLED

 

Unfortunately there does not seem to be a mode where WiFi is off and the CPU will still sleep during delay().

This application note recommends to use light sleep instead of deep sleep when sleeping less than 2 seconds, but I don’t consider that very practical advice given the fact that you can’t use a timer to wake up from light sleep.

 

Further observations:

It seems that ESP.deepSleep(time, RF_CAL) and ESP.deepSleep(time, RF_NO_CAL) lead to identical behavior:


RF_CAL

NO_RF_CAL

 

I further noticed that connecting to Wifi after waking up from Forced Modem Sleep seems to take longer than after waking up from Deep Sleep: