ESP8266 and deep sleep - tips on increasing battery life

I’m interested to learn more about deep sleep, I would welcome any information on how to increase battery life (or general tips).

I currently have a test rig running:

Wemos D1 mini (ESP8266)
Wemos battery shield
BME280 connected as I2C
18650 2200mAh battery connected to battery shield

This is publishing sensor readings every 10 seconds and going to deep sleep. At present I am only getting 5 days battery life.

I will of course increase the sleep time to more like 120 seconds (as it’s controlling a heater I don’t want too long an interval). But from my research so far, it seems the deep sleep time battery usage is not the factor, actually getting the ‘awake time’ battery usage down in more important.

Code general description:
Define Wifi, MQTT credentials.
Define topics to publish to.
Call wifi setup function
Check for BME280 sensor
Call MQTT connect function
Call heartbeat function (sends RSSI value to node red)
Call sendSensor function (read temp/humidity)
Call battery level function (send battery level to node red)
delay 500ms to allow MQTT messages to be published
Deep sleep for x seconds

Full code is at the bottom of the post.

Ideas:
Increase deep sleep time (not too long as the sensor is indirectly controlling a heater, via node red)
Remove serial prints might reduce time ‘awake’?
Reducing time wifi is connected - read sensor first then connect?

Further reading on my list:
Three part blog on redcing power usage

Full code:

//v004 MQTT conservatory weather station
////Code originally based on https://www.home-assistant.io/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/
//
//Hardware:
//Wemos D1 mini, BME280 sensor wired as I2C, Raspberry Pi 3 node red and moquitto MQTT server.
//
//Description:
//BME temp, humidity and pressure readings are published to the MQTT server (also printed to serial).
//Heartbeat RSSI value of device gets sent to MQTT broker, node red can light a Blynk LED/colour text (if online/offline)
//BME280 wiring - 3V to Vcc / Gnd to Gnd / D1 to SCL / D2 to SDA
//
//Changelog:
//v002 added deep sleep (first attempt)
//v003 added battery voltage monitoring
//v004 testing battery life improvements (removed serial prints)
//


#include <ESP8266WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <BME280I2C.h>
#include <SimpleTimer.h>

#define wifi_ssid ""
#define wifi_password ""

#define mqtt_server ""
#define mqtt_user ""
#define mqtt_password ""

#define temperature_topic "house/consv/sensor/temperature"
#define humidity_topic "house/consv/sensor/humidity"
#define pressure_topic "house/consv/sensor/pressure"
#define heartbeat_topic "house/consv/sensor/heartbeat" //for heartbeat
#define freeram_topic "house/consv/sensor/freeram" // send device free ram
#define battery_topic "house/consv/sensor/battery" // send battery voltage

WiFiClient espClient;
PubSubClient client(espClient);

BME280I2C bme;    // Default : forced mode, standby time = 1000 ms
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,

long rssi; // setup variable for RSSI heartbeat value
char *client_id = "Wemos_no_1_MQTT";  //  MQTT Client ID


//Setup variables for later
float temp;
int hum;
int pres;


void setup() {
  
  // Connect D0 to RST to wake up
  pinMode(D0, WAKEUP_PULLUP);

  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);

  while (!Serial) {} // Wait

  Wire.begin();

  while (!bme.begin())
  {
    Serial.println("Could not find BME280 sensor!");
    delay(500);
  }

  // bme.chipID(); // Deprecated. See chipModel().
  switch (bme.chipModel())
  {
    case BME280::ChipModel_BME280:
      Serial.println("Found BME280 sensor! Success.");
      break;
    case BME280::ChipModel_BMP280:
      Serial.println("Found BMP280 sensor! No Humidity available.");
      break;
    default:
      Serial.println("Found UNKNOWN sensor! Error!");
  }
  
  reconnect();  //connect to MQTT server
  heartbeat(); // publish RSSI value as heartbeat
  sendSensor(); //publish sensor readings
  battery();  // read battery level

  delay(500); //delay to allow for MQTT messages to be published
  
  ESP.deepSleep(10 * 1000000);  // 10 seconds
  
}




void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    // If you do not want to use a username and password, change next line to
    // if (client.connect("ESP8266Client")) {
    if (client.connect(client_id, mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 1 seconds");
      // Wait 1 seconds before retrying
      delay(1000);
    }
  }
}



void heartbeat()  // function for heartbeat check
{
  Serial.print("RSSI:");
  Serial.println(WiFi.RSSI());
  client.publish(heartbeat_topic, String(WiFi.RSSI()).c_str(), true);
  client.publish(freeram_topic, String(ESP.getFreeHeap()).c_str(), true);
}



void sendSensor() // function to send sensor readings to MQTT
{
  //read latest values
  temp = bme.temp();
  hum = bme.hum();
  pres = bme.pres();

  if (isnan(temp)) {
    Serial.println("Error reading temperature!");
  }
  else
  {
    Serial.print("Temperature: ");
    Serial.println(String(temp).c_str());
    client.publish(temperature_topic, String(temp , 1).c_str(), true);
  }

  if (isnan(temp)) {
    Serial.println("Error reading humidity!");
  }
  else
  {
    Serial.print("Humidity: ");
    Serial.println(String(hum).c_str());
    client.publish(humidity_topic, String(hum).c_str(), true);
  }

  if (isnan(pres)) {
    Serial.println("Error reading pressure!");
  }
  else
  {
    Serial.print("Pressure: ");
    Serial.println(String(pres / 100).c_str());
    client.publish(pressure_topic, String(pres / 100).c_str(), true);
  }
}



void battery()
{
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);   
   // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 4.5V):
  float voltage = 4.5 * (sensorValue/1023.0);
  // send out the value you read:
  Serial.print("Voltage: ");
  Serial.println(voltage);
  client.publish(battery_topic, String(voltage).c_str(), true);
}

void loop(){}

To really reduce power avoid using the D1 Mini as it still consumes current powering the USB2TTL chip and 5V to 3V3 regulator when the ESP8266 is sleeping.
Also the chip consumes a largish spike of power when waking up (even if the WiFi is turned off).
Better to use a bare ESP12 module with suitable support components and a known good battery level converter.

Other options might be to use something different for the wireless signalling. As an example I use BME280 sensors on LoRa32u4 boards (Adafruit Feathers) that transmit to a base station that then forward the data to Node-Red over WiFi. They only transmit 3 packets once per 30 minutes and sleep most of the rest of the time and I get 6 months from a single 18650.
If your close enough range then maybe step up to an ESP32 and use Bluetooth.

Hi Riva,

Thanks for all the information, yes the wemos does seems power hungry. I do have an ESP32 so I could try that. I’ve not heard of an ESP12 so will check that out. Also will check out the LoRa32u4.
Thanks

An ESP-12 is just an ESP8266 in a neat little module designed to add to your own project. You will need to supply the correct voltages as it has no voltage regulator and also a USB2TTL to initially program it. Once first programmed you could then maybe use OTA programming to update it.