WeMos D1 mini (esp8266), i tre tipi di modalità di sospensione per gestire il risparmio energetico – Parte 4
Quando si crea un nuovo progetto IoT, probabilmente è necessario collegare il microcontrollore a una fonte di energia elettrica come una batteria, ma se non si utilizzano le corrette opzioni di risparmio energetico, la batteria si esaurirà in pochissimo tempo.
Come molti microcontrollori IoT, WeMos D1 mini ha delle modalità di risparmio energetico.
Per creare un semplice power bank, leggi “Power bank di emergenza fatto in casa“.
Puoi trovare questo microcontrollore qui WeMos D1 mini - NodeMCU V2 V2.1 V3 - esp01 - esp01 programmer
I tipi di modalità di sospensione sono modem-sleep, light-sleep e deep-sleep. La tabella seguente mostra le differenze tra ciascuna modalità.
Item | Modem-sleep | Light-sleep | Deep-sleep |
Wi-Fi | OFF | OFF | OFF |
System clock | ON | OFF | OFF |
RTC | ON | ON | ON |
CPU | ON | Pending | OFF |
Substrate current | 15 mA | 0.4 mA | ~20 uA |
Average current (DTIM = 1) | 16.2 mA | 1.8 mA | – |
Average current (DTIM = 3) | 15.4 mA | 0.9 mA | – |
Average current (DTIM = 10) | 15.2 mA | 0.55 mA | – |
Modem sleep
Questo è lo stato predefinito del esp8266, ma lo si interrompe quando si collega il dispositivo tramite WIFI. Se non usi WIFI per un po ‘, la cosa migliore è mettere il dispositivo in modalità di sospensione del modem (modem-sleep).
Puoi mettere il tuo dispositivo in modalità modem-sleep con questo comando:
WiFi.disconnect();
WiFi.forceSleepBegin();
delay(1); //For some reason the modem won't go to sleep unless you do a delay
puoi ripristinare il WIFI con:
WiFi.forceSleepWake();
delay(1);
//Insert code to connect to WiFi, start your servers or clients or whatever
Ricorda che se vuoi usare un delay in modalità “normale” devi aggiungere questo comando (che rimuove le varie modalità di sleep):
wifi_set_sleep_type(NONE_SLEEP_T);
Oppure devi disabilitare la modalità di sospensione automatica (meglio spiegata nel prossimo paragrafo) con questa funzione.
wifi_fpm_auto_sleep_set_in_null_mode(NULL_MODE);
Qui lo sketch completo, fai attenzione per il debug uso la Serial1, fai riferimento alla parte 3 per capire in cosa consiste WeMos D1 mini (esp8266): debug sulla seriale secondaria
#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
}
Questo tipo di modalità di sospensione, come puoi vedere nel video, consente di ottenere 20 mA di consumo energetico dal dispositivo.
Light sleep
Questo tipo di sospensione è abbastanza utile se è necessario mantenere attivo il dispositivo e la grande differenza rispetto al tipo precedente è che è possibile riattivare il dispositivo tramite interruzione su GPIO.
Per attivare la modalità di sospensione leggera è necessario utilizzare questo codice, non esiste un modo semplice per attivarlo come accade per la sospensione del modem.
Devi aggiungere questa configurazione allo 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);
Allo stesso modo possiamo usare questo codice per entrare in modalità MODEM_SLEEP:
// 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);
Il dispositivo passa in modalità luce con un ridotto utilizzo della batteria e temperatura.
#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
}
Questo tipo di modalità di sospensione, come puoi vedere nel video, consente di ottenere 20 mA di consumo energetico dal dispositivo, per ottenere un migliore risparmio energetico è necessario impostare la sveglia tramite GPIO.
Light sleep e sveglia tramite GPIO
Light sleep può essere riattivato dall’interruzione GPIO, il comando da impostare è
gpio_pin_wakeup_enable(GPIO_ID_PIN(LIGHT_WAKE_PIN), GPIO_PIN_INTR_LOLEVEL);
È necessario impostare il tempo di sospensione massimo e impostare un delay
per attivare il tutto.
wifi_fpm_do_sleep(FPM_SLEEP_MAX_TIME);
delay(1000);
Il codice completo può essere così
#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
}
Il risultato sarà
Come puoi vedere nel video, il risparmio energetico è migliore (6mA) e si può usare l’interrupt su GPIO per ripristinare il dispositivo.
Deep sleep
La modalità più comune e più utilizzata è il deep-sleep, un’applicazione pratica è quella di inviare dati a un server ogni periodo di tempo predefinito.
- È necessario mettere il dispositivo in modalità deep-sleep
- impostare un timer per svegliarsi
- sveglia
- invia i dati
- rimetti il dispositivo in sospensione
Tutti esp8266 (tranne esp01) hanno un pin con etichetta wake, e tramite questo pin collegato al RESET sarà possibile risvegliare il microcontrollore.
Puoi selezionare varie opzioni di sleep, controlla la tua scelta migliore.
system_deep_sleep_set_option(0) | Il parametro il Byte 108 di init decide se la calibrazione RF verrà eseguita dopo che il chip si è svegliato dal deep-sleep. |
system_deep_sleep_set_option(1) | Il chip eseguirà la calibrazione RF dopo essersi svegliato dal deep-sleep. Il consumo energetico è elevato. |
system_deep_sleep_set_option(2) | Il chip non eseguirà la calibrazione RF dopo essersi svegliato dal deep-sleep. Il consumo energetico è basso. |
system_deep_sleep_set_option(3) | Il chip non si accende in RF dopo essersi svegliato dal deep-sleep. Il consumo di energia è il più basso (lo stesso del Modem-sleep). |
Sul WeMos D1 mini, come puoi vedere, è il pin di 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
Per riattivare un microcontrollore è necessario mettere il PIN di ripristino a LOW.
È possibile utilizzare un Wake pin (D0) collegato al Reset per riattivare il WeMos dopo qualche tempo, oppure è possibile utilizzare un pulsante esterno (o altro) in pull UP ed al click metterlo in LOW.
Perciò dopo aver impostato l’esp8266 in modalità di sospensione profonda, ci sono 2 modi per riattivarlo:
- Impostando un timer
- con un pulsante che mette il pin di reset a LOW.
#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() {
}
La potenza che utilizza il dispositivo è simile al light-sleep con sveglia tramite GPIO (6mA).
Modalità automatica
Per impostazione predefinita, il dispositivo esp ha la modalità di sospensione automatica abilitata.
Se aggiungi il codice per la sospensione light o per la sospensione modem al momento della configurazione e non disabiliti la modalità automatica sarà abilitata la sospensione in automatico dopo 10 secondi di delay
in questo modo:
#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;
}
}
il risultato è questo:
Quando esegui il comando delay
per i primi 10 secondi non accade nulla, dopo questo tempo viene attivata automaticamente la modalità di sospensione.
- WeMos D1 mini (esp8266): caratteristiche e configurazione dell’Arduino IDE
- WeMos D1 mini (esp8266): SPIFFS Filesystem integrato
- WeMos D1 mini (esp8266): debug sulla seriale secondaria
- WeMos D1 mini (esp8266), i tre tipi di modalità di sospensione per gestire il risparmio energetico
- WeMos D1 mini (esp8266): FileSystem integrato LittleFS
- esp12 esp07 (esp8266): flash, piedinatura, spec e config dell’IDE Arduino
- Firmware and OTA update
- Gestione del firmware
- Aggiornamenti OTA con Arduino IDE
- Aggiornamenti OTA con Web Browser
- Aggiornamenti OTA automatico da server HTTP
- Aggiornamenti firmware non standard
- esp32 e esp8266: file system FAT su memoria SPI flash esterna
- i2c esp8266: how to, rete 5V, 3.3V, velocità e pin personalizzati
- …
Nella modalità light sleep, con l’esempio indicato, scatta il watchdog.
Come mai? E’ un problema risolvibile?
Grazie!
Ciao Paolo,
se il tempo di sonno impostato è troppo lungo e non viene gestito correttamente, il watchdog può scattare.
Potresti considerare di aumentare il timeout del watchdog se il tuo flusso di lavoro lo permette, ma fai attenzione a non compromettere la stabilità del sistema.
// Inizializza il watchdog
ESP.wdtEnable(5000); // 5 secondi di timeout
Comunque c’è anche la possibilità di “nutrirlo” per non farlo scattare.
// Nutri il watchdog
ESP.wdtFeed();
Alla peggio puoi disabilitarlo, ma è comunque una cosa rischiosa, fallo con cautela.
// Disabilita il watchdog
ESP.wdtDisable();
Ciao Renzo