WeMos D1 mini (esp8266), the three type of sleep mode to manage energy savings – Part 4

Spread the love

When you create a new IoT project probably you need to connect microcontroller to a battary power source, but if you don’t use a power saving options your battery will run out in no time.

As a lot of IoT microcontroller, WeMos D1 mini have some power saving mode.

To create a simple rechargeable power bank read “Emergency power bank homemade“.

Here the WeMos D1 mini WeMos D1 mini - NodeMCU V2 V2.1 V3 - esp01 - esp01 programmer

The sleep modes types are modem sleeplight sleep, and deep sleep. The table below shows the differences between each mode.

ItemModem-sleepLight-sleepDeep-sleep
Wi-FiOFFOFFOFF
System clockONOFFOFF
RTCONONON
CPUONPendingOFF
Substrate current15 mA0.4 mA~20 uA
Average current (DTIM = 1)16.2 mA1.8 mA
Average current (DTIM = 3)15.4 mA0.9 mA
Average current (DTIM = 10)15.2 mA0.55 mA

Modem sleep

This is the default state of esp8266, but normally you interrupt this state when connect device via WIFI. But if you don’t use WIFI for a while, the better thing is to put the device in Modem-sleep.

You can put your device in modem-sleep with this command:

WiFi.disconnect();
WiFi.forceSleepBegin();
delay(1); //For some reason the modem won't go to sleep unless you do a delay

you can restore WIFI with:

WiFi.forceSleepWake();
delay(1);
//Insert code to connect to WiFi, start your servers or clients or whatever

Remember that if you want use a delay in normal mode you must add this:

      wifi_set_sleep_type(NONE_SLEEP_T);

Or you must disabled the auto sleep mode (better explained in the next paragraph) we are going to call this function.

  wifi_fpm_auto_sleep_set_in_null_mode(NULL_MODE);

Here a complete sketch, pay attention I use Serial1 to debug, refer to Part 3 WeMos D1 mini (esp8266), debug on secondary UART

#include "Arduino.h"
#include <ESP8266WiFi.h>
// Required for LIGHT_SLEEP_T delay mode
extern "C" {
#include "user_interface.h"
}

const char* ssid = "<your-ssid>";
const char* password = "<your-passwd>";

//The setup function is called once at startup of the sketch
void setup() {
  Serial1.begin(115200);
  while(!Serial1) { }

  Serial1.println();
  Serial1.println("Start device in normal mode!");

  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
  Serial1.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial1.print(".");
  }
  Serial1.println("");
  Serial1.print("Connected to ");
  Serial1.println(ssid);
  Serial1.print("IP address: ");
  Serial1.println(WiFi.localIP());
}
void callback() {
  Serial1.println("Callback");
  Serial.flush();
}
void loop() {
	  Serial1.println("Enter modem sleep mode");


      uint32_t sleep_time_in_ms = 10000;
//      WiFi.disconnect();
      WiFi.forceSleepBegin();
      delay(sleep_time_in_ms + 1);

      WiFi.forceSleepWake();
      delay(1);
      Serial1.println("Exit modem sleep mode");

      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      Serial1.println("");

      // Wait for connection
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial1.print(".");
      }
      Serial1.println("");
      Serial1.print("Connected to ");
      Serial1.println(ssid);
      Serial1.print("IP address: ");
      Serial1.println(WiFi.localIP());

      wifi_set_sleep_type(NONE_SLEEP_T);
      delay(10000);  //  Put the esp to sleep for 15s
}

This type of sleep mode, as you can see in the video permit to get 20mA of power consumption from the device.

Light sleep

This type of sleep is quite usefully if you need to mantain the device active, and the big difference from the previous type is that you can wake up the device via interrupt on GPIO.

To put on light sleep mode you must use this code, there isn’t a simple way to activate It like modem sleep.

You must add this configuration to the sketch:

	  // Here all the code to put con light sleep
	  // the problem is that there is a bug on this
	  // process
	  //wifi_station_disconnect(); //not needed
	  uint32_t sleep_time_in_ms = 10000;
	  wifi_set_opmode(NULL_MODE);
	  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
	  wifi_fpm_open();
	  wifi_fpm_set_wakeup_cb(callback);
	  wifi_fpm_do_sleep(sleep_time_in_ms *1000 );
	  delay(sleep_time_in_ms + 1);

At the same manner we can use this code to enter in MODEM_SLEEP mode:

	  // Here all the code to put con light sleep
	  // the problem is that there is a bug on this
	  // process
	  //wifi_station_disconnect(); //not needed
	  uint32_t sleep_time_in_ms = 10000;
	  wifi_set_opmode(NULL_MODE);
	  wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
	  wifi_fpm_open();
	  wifi_fpm_set_wakeup_cb(callback);
	  wifi_fpm_do_sleep(sleep_time_in_ms *1000 );
	  delay(sleep_time_in_ms + 1);

The device go in light mode with less use of battery and less temperature.

#include "Arduino.h"
#include <ESP8266WiFi.h>
// Required for LIGHT_SLEEP_T delay mode
extern "C" {
#include "user_interface.h"
}

const char* ssid = "<your-ssid>";
const char* password = "<your-passwd>";

//The setup function is called once at startup of the sketch
void setup() {
  Serial1.begin(115200);
  while(!Serial1) { }

  Serial1.println();
  Serial1.println("Start device in normal mode!");

  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
  Serial1.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial1.print(".");
  }
  Serial1.println("");
  Serial1.print("Connected to ");
  Serial1.println(ssid);
  Serial1.print("IP address: ");
  Serial1.println(WiFi.localIP());
}
void callback() {
  Serial1.println("Callback");
  Serial.flush();
}
void loop() {
	  Serial1.println("Enter light sleep mode");

      // Here all the code to put con light sleep
      // the problem is that there is a bug on this
      // process
      //wifi_station_disconnect(); //not needed
      uint32_t sleep_time_in_ms = 10000;
      wifi_set_opmode(NULL_MODE);
      wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
      wifi_fpm_open();
      wifi_fpm_set_wakeup_cb(callback);
      wifi_fpm_do_sleep(sleep_time_in_ms *1000 );
      delay(sleep_time_in_ms + 1);

      Serial1.println("Exit light sleep mode");

      WiFi.begin(ssid, password);
      Serial1.println("");
    
      // Wait for connection
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial1.print(".");
      }
      Serial1.println("");
      Serial1.print("Connected to ");
      Serial1.println(ssid);
      Serial1.print("IP address: ");
      Serial1.println(WiFi.localIP());
      
      wifi_set_sleep_type(NONE_SLEEP_T);
      delay(10000);  //  Put the esp to sleep for 15s
}

This type of sleep mode, as you can see in the video permit to get 20mA of power to the device, to obtain better power saving you must set the wake up via GPIO.

Light sleep GPIO wake up

WeMos D1 mini on light sleep and debug on Serial1 check ampere
WeMos D1 mini on light sleep and debug on Serial1 check ampere

Light sleep can be wake up by GPIO interrupt, the command to set is

gpio_pin_wakeup_enable(GPIO_ID_PIN(LIGHT_WAKE_PIN), GPIO_PIN_INTR_LOLEVEL);

Than you must set max sleep time and than put a delay to activate all.

	  wifi_fpm_do_sleep(FPM_SLEEP_MAX_TIME);
	  delay(1000);

The complete code can be like this

#include "Arduino.h"
#include <ESP8266WiFi.h>

#define	FPM_SLEEP_MAX_TIME			 0xFFFFFFF

// Required for LIGHT_SLEEP_T delay mode
extern "C" {
#include "user_interface.h"
}

const char* ssid = "<your-ssid>";
const char* password = "<your-passwd>";

//The setup function is called once at startup of the sketch
void setup() {
  Serial1.begin(115200);
  while(!Serial1) { }

  Serial1.println();
  Serial1.println("Start device in normal mode!");

  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
  Serial1.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial1.print(".");
  }
  Serial1.println("");
  Serial1.print("Connected to ");
  Serial1.println(ssid);
  Serial1.print("IP address: ");
  Serial1.println(WiFi.localIP());
}
void callback() {
  Serial1.println("Callback");
  Serial.flush();
}

#define LIGHT_WAKE_PIN D5

void loop() {
	  Serial1.println("Enter light sleep mode");

	  //wifi_station_disconnect(); //not needed
	  gpio_pin_wakeup_enable(GPIO_ID_PIN(LIGHT_WAKE_PIN), GPIO_PIN_INTR_LOLEVEL);
	  wifi_set_opmode(NULL_MODE);
	  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
	  wifi_fpm_open();
	  wifi_fpm_set_wakeup_cb(callback);
	  wifi_fpm_do_sleep(FPM_SLEEP_MAX_TIME);
	  delay(1000);

  	  Serial1.println("Exit light sleep mode");

      WiFi.begin(ssid, password);
      Serial1.println("");

      // Wait for connection
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial1.print(".");
      }
      Serial1.println("");
      Serial1.print("Connected to ");
      Serial1.println(ssid);
      Serial1.print("IP address: ");
      Serial1.println(WiFi.localIP());

      wifi_set_sleep_type(NONE_SLEEP_T);
  	  delay(10000);  //  Put the esp to sleep for 15s
}

The result is

As you can see in the video the power saving is better (6mA), and you can use interrupt to restore device.

Deep sleep

The most common and most used modality is deep-sleep, a pratical application is to send data to a server every predefined time period.

  • You must put your device in deep-sleep
  • set a timer to wake
  • wake
  • send data
  • put device in sleep

All esp8266 (except esp01) have a pin with wake label, and through this pin connected to the RESET it will be possible to wake up the microcontroller.

WeMos D1 mini esp8266 pinout mischianti low resolution
WeMos D1 mini esp8266 pinout mischianti low resolution

You can se various sleep option, check your better choiche.

system_deep_sleep_set_option(0) The 108th Byte of init parameter decides whether RF calibration will be performed after the chip wakes up from Deep-sleep.
system_deep_sleep_set_option(1) The chip will make RF calibration after waking up from Deep-sleep. Power consumption is high.
system_deep_sleep_set_option(2) The chip won’t make RF calibration after waking up from Deep-sleep. Power consumption is low.
system_deep_sleep_set_option(3) The chip won’t turn on RF after waking up from Deep-sleep. Power consumption is the lowest, same as in Modem-sleep.

On WeMos D1 mini, as you can see, the pin for wake il D0.

ESP.deepsleep(0) // suspends the module until it is woken up by a spike on the RST pin
ESP.deepsleep(5 * 1000000) // wake up the module every 5 seconds
ESP.deepsleep(5000000, RF_DISABLED) // wakes up the module every 5 seconds without re-activating the WiFi modem

To wake a microcontroller you must put LOW reset PIN.

You can use a Wake pin (D0) connected to Reset to wake after some time, or you can use external button (or other) pulled up and than go LOW on key press.

After putting the esp8266 into deep sleep mode, there are 2 ways to wake it up:

  • By setting a timer
  • with a button that put low Reset pin.
WeMos D1 mini deep sleep and debug on Serial1 check Ampere
WeMos D1 mini deep sleep and debug on Serial1 check Ampere
#include "Arduino.h"

//The setup function is called once at startup of the sketch
void setup() {
  Serial1.begin(115200);
  while(!Serial1) { }
  Serial1.println();
  Serial1.println("Start device in normal mode!");

  delay(5000);
  // Wait for serial to initialize.
  while(!Serial1) { }

  // Deep sleep mode for 10 seconds, the ESP8266 wakes up by itself when GPIO 16 (D0 in NodeMCU board) is connected to the RESET pin
  Serial1.println("I'm awake, but I'm going into deep sleep mode for 10 seconds");
  ESP.deepSleep(10e6);
}

void loop() {
}

The power that use device is similar to light-sleep with wake up via GPIO (6mA).

Automatic mode

By default the esp device have auto sleep mode enabled. If you add the code for light sleep or modem sleep at the setup and not disable the auto mode WeMos go in sleep automaticalli after 10 seconds of delay like so:

#include "Arduino.h"
#include <ESP8266WiFi.h>
// Required for LIGHT_SLEEP_T delay mode
extern "C" {
#include "user_interface.h"
}

const char* ssid = "<your-ssid>";
const char* password = "<your-passwd>";

//The setup function is called once at startup of the sketch
void setup() {
  Serial1.begin(115200);
  while(!Serial1) { }

  Serial1.println();
  Serial1.println("Start device in normal mode!");

  WiFi.mode(WIFI_STA);

  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);

  WiFi.begin(ssid, password);
  Serial1.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial1.print(".");
  }
  Serial1.println("");
  Serial1.print("Connected to ");
  Serial1.println(ssid);
  Serial1.print("IP address: ");
  Serial1.println(WiFi.localIP());
}
unsigned long interval = 30000;
unsigned long previousMillis = millis() + interval;

void loop() {
	  unsigned long currentMillis = millis();

	  if (currentMillis - previousMillis >= interval) {
		  Serial1.println("Enter delay");

		  delay(20000);

		  Serial1.println("Exit delay");

		  WiFi.begin(ssid, password);
		  Serial1.println("");

		  // Wait for connection
		  while (WiFi.status() != WL_CONNECTED) {
			delay(500);
			Serial1.print(".");
		  }
		  Serial1.println("");
		  Serial1.print("Connected to ");
		  Serial1.println(ssid);
		  Serial1.print("IP address: ");
		  Serial1.println(WiFi.localIP());
		  previousMillis = currentMillis;

	  }
}

the result is this:

When execute delay command for the first 10 seconds nothing append, than after that sleep mode is automatic activated.

  1. WeMos D1 mini (esp8266), specs and IDE configuration
  2. WeMos D1 mini (esp8266), integrated SPIFFS Filesystem
  3. WeMos D1 mini (esp8266), debug on secondary UART
  4. WeMos D1 mini (esp8266), the three type of sleep mode to manage energy savings
  5. WeMos D1 mini (esp8266), integrated LittleFS Filesystem
  6. esp12 esp07 (esp8266): flash, pinout, specs and IDE configuration
  7. Firmware and OTA update management
    1. Firmware management
      1. esp8266: flash firmware binary (.bin) compiled and signed
      2. esp8266: flash firmware and filesystem binary (.bin) compiled with GUI tools
    2. OTA update with Arduino IDE
      1. esp8266 OTA update with Arduino IDE: filesystem, signed and password
    3. OTA update with Web Browser
      1. esp8266 OTA update with Web Browser: firmware, filesystem and authentication
      2. esp8266 OTA update with Web Browser: sign the firmware and HTTPS (SSL/TLS)
      3. esp8266 OTA update with Web Browser: custom web interface
    4. Self OTA uptate from HTTP server
      1. esp8266 self OTA update firmware from server
      2. esp8266 self OTA update firmware from server with version check
      3. esp8266 self OTA update in HTTPS (SSL/TLS) with trusted self signed certificate
    5. Non standard Firmware update
      1. esp8266 firmware and filesystem update from SD card
      2. esp8266 firmware and filesystem update with FTP client
  8. esp32 and esp8266: FAT filesystem on external SPI flash memory
  9. i2c esp8266: how to, network 5v, 3.3v, speed, and custom pins
  10. […]

Spread the love

6 Responses

  1. Rob says:

    Hi there, your light sleep with GPIO interupt seems to just loop after the initial wake up. How can I point the program back to the initial task that it should do when it wakes up?

  2. OSIXER says:

    @Rob, had the same problem, setting LIGHT_WAKE_PIN to INPUT_PULLUP in setup() solved it for me.

    @Renzo, this is a SUPERDUPER documentation of sleep modes, saved me so much time, thank you very much!!!!!

Leave a Reply to Rob Cancel reply

Your email address will not be published. Required fields are marked *