sábado, 28 de enero de 2017

Modo deep-sleep en ESP8266

Si utilizamos el módulo ESP8266 en algún proyecto donde existan muchos periodos de inactividad (por ejemplo, debemos enviar ciertos datos cada x minutos) y más si la alimentación del módulo se realiza con baterías, es interesante que el consumo sea muy bajo en los periodos de inactividad. Para ello, el módulo ESP8266 cuenta con varios modos de sleep.

El ESP8266 dispone de tres modos de ahorro de energía:
  • modem-sleep: este modo de ahorro permite desactivar la conexión WiFi de tipo Station , establecida con un punto de acceso (router), cuando no sea necesario su uso y volver a activarla cuando se necesite.. El consumo típico en este modo es de 15mA.
  • light-sleep: este modo de ahorro permite mantener la conexión WiFi de tipo Station,  pero reduce el consumo de energía en los momentos en los que no hay envío de información.. El consumo típico pasa a ser de unos 0,5 mA.
  • deep-sleep: es el modo que genera mayor ahorro, pero a costa de dejar la placa en suspenso. La única parte de la placa que funciona durante este modo es reloj en tiempo real (Real Time Clock o RTC) para poder reiniciarla cuando haya finalizado el tiempo de reposo. El consumo típico pasa a ser de unos 10 uA.


En este artículo nos centraremos en deep-sleep que es el procedimiento que genera mayor ahorro a costa de desactivar la WiFi, el reloj del sistema –System Clock– y la unidad central de proceso –Central Process Unit o CPU-, por lo que la placa queda en suspenso, finalizando todos los procesos activos. Únicamente permanece en funcionamiento el reloj en tiempo real –Real Time Clock o RTC-, que será quien envíe la señal para que se pueda reiniciar el microprocesador, cuando finalice la cuenta atrás de tiempo de suspenso que hayamos establecido.

La función ESP.deepSleep() tiene dos variables: ESP.deepSleep (tiempo_en_us, modo_reinicio)

tiempo_en_us (uint32_t): tiempo en microsegundos que de debe estar el microprocesdor en suspenso. El tiempo máximo que se puede mantener el microprocesador en suspenso es de aproximadamente 71 minutos y 30 segundos. Esto se debe a que los microprocesadores ESP8266 trabajan a 32 bits, por lo tanto el número más alto que admiten es 232 = 4.294.967.295. Dado que el tiempo de suspenso se da en microsegundos (μs) tenemos que: 4.294.967.295 μs  = 4.294,967295 s ≈ 71′ 30”

modo_reinicio: indica como se debe proceder cuando se reinicia el microprocesador con la calibración de la señal de radio para la WiFi. Existen cuatro posibilidades:
  • 1 = WAKE_RF_DEFAULT: cuando se reinicia el microprocesador, únicamente se calibra la señal de radio si el chequeo da error (init data byte 108>0).
  • 2 = SLEEP_TIME, WAKE_RFCAL: cuando se reinicia el microprocesador siempre se calibra la señal de radio. Esto incrementa el consumo.
  • 3 = SLEEP_TIME, WAKE_NO_RFCAL: cuando se reinicia el microprocesador no se calibra la señal de radio. Esto reduce el consumo.
  • 4 = WAKE_RF_DISABLED: cuando se reinicia el microprocesador se deshabilita la señal de radio (como en el modo modem sleep). Este es el modo con menor consumo, pero no permite ni enviar ni recibir datos vía WiFi.
Cuando ha finalizado el tiempo que se ha establecido que el microprocesador debe estar en suspenso, el Real Time Clock envía una señal para que el microprocesador se reinicie (Reset), es por esto que el se debe conectar con un cable el pin GPIO16 (Pin D0 en placas NodeMCU) con el pin de Reset. Si no se realizara la conexión el ESP no se reiniciará.

En las placas NodeMCU el pin D0 (GPIO16) es el que envía la señal de reset para que se pueda reiniciar el microprocesador cuando finaliza la cuenta atrás de tiempo de suspenso. Si no se conectara la placa únicamente realizaría una vez las funciones programadas y después se quedaría en suspenso indefinidamente. De hecho para volver a hacerla funcionar es necesario un reset manual.

Nota: esta conexión se ha de realizar una vez el módulos ESP haya sido programado.

En el artículo Stream de datos con thinger.io enviamos los datos a thinger.io cada 10 segundos. En el caso de que quisieramos enviar los datos con una menor cadencia, por ejemplo, cada 5 minutos, podríamos "dormir" el módulo para el ahorro de batería.

El esquema sería el siguiente:

Lo primero que hacemos es definir el tiempo que permanecerá en modo sleep el módulo ESP8266:

// Tiempo de Deep Sleep del ESP8266 (segundos)
#define SLEEP_TIME 300


En loop(), indicamos que despúes de transcurridos 10 segundos desde el reset, el dispositivo pase a modo sleep. Este margen servirá para garantizar la correcta lectura de los sensores y el envío de los datos a la plataforma

void loop() {
  thing.handle();
  thing.stream(thing["sensores"]);
  if (millis() >= 10000) {
    ESP.deepSleep(SLEEP_TIME * 1000000, WAKE_RF_DEFAULT);
  }
}


El código completo sería el siguiente:

#include <ESP8266WiFi.h> // ESP8266
#include <ThingerESP8266.h> // thinger.io
#include "DHT.h" //Sensor DHT
#include <Wire.h> // I2C
#include <Adafruit_BMP085.h> // Sensor BMP180

// thinger.io
// Parámetros del dispositivo ESP8266
#define username "USERNAME"
#define deviceId "DEVICE_ID"
#define deviceCredential "DEVICE_CREDENTIAL"

// Parámetros de nuestra red wifi
#define wifi_ssid "SSID"
#define wifi_password "PASSWORD"

// Parámetros del sensor DHT11
#define dht_pin D7 // GPIO13
#define dht_type DHT22 // Seleccionamos el sensor
DHT dht(dht_pin, dht_type);

// Tiempo de Deep Sleep del ESP8266 (segundos)
#define SLEEP_TIME 300

Adafruit_BMP085 bmp;

ThingerESP8266 thing(username, deviceId, deviceCredential, false);

void setup() {
  dht.begin(); //Inicializamos el sensor de temperatura
  Wire.pins(D2, D3);
  Wire.begin(D2, D3); //Inicializa I2C en NodeMCU
  bmp.begin(); // Inicializamos el BMP180
 
  thing.add_wifi(wifi_ssid, wifi_password);
  thing["sensores"] >> [](pson & out) {
    out["dht_humedad"] = dht.readHumidity();
    out["dht_temperatura"] = dht.readTemperature();
    out["bmp180_presion"] = bmp.readPressure();
    out["bmp180_temperatura"] = bmp.readTemperature();
    out["bmp180_altitud"] = bmp.readAltitude(101500);
  };

}

void loop() {
  thing.handle();
  thing.stream(thing["sensores"]);
  if (millis() >= 10000) {
    ESP.deepSleep(SLEEP_TIME * 1000000, WAKE_RF_DEFAULT);
  }
}


Fuente:
Enlaces:

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.