--> ESP8266 — running on battery power | Electronza

ESP8266 — running on battery power


The issue of running ESP8266 on battery power came when I was working on a somewhat bigger project, an IoT sensor node which has to collect some sensor data and upload the sensor values to cloud services.

What I wanted is to be able to run the sensor node for extended periods with no human intervention. I have found a 9800mAh LiPo battery that should provide me enough juice to run for several months. Still, to achieve good results I have to reduce the power draw of the ESP8266 to the minimum possible, and I also have to provide a means to protect the LiPo battery when its voltage drops below-given value (typically 3V).

By itself, this proves to be a challenging thing — enough to become a separate article. So this is a tutorial on implementing some strategies to reduce the power consumption of ESP8266 modules and of protecting LiPo batteries from over-discharging.

The first and the simplest way to cut down a few milliamps is to remove the power LED. Some ESP8266 boards have a trace that has to be cut, such as the ESP8266 Thing Dev I’m using in this tutorial. On other boards, one has to physically remove the LED — SMD hot tweezers are a must. Either way, you can shed 8–10 mA.

Then, we go deep into the ESP8266 sleep modes. There are three sleep modes, as detailed in the table below:

Modem sleep Light sleep Seep sleep
System clock ON OFF OFF
CPU ON Pending OFF
Substrate current 15 mA 0.4 mA ~ 20µA
Avg. Current DTIM = 1 16.2 mA 1.8 mA -
Avg. Current DTIM = 3 15.4 mA 0.9 mA -
Avg. Current DTIM = 10 15.2 mA 0.55 mA -
Note: on some routers you cannot change the DTIM value

ESP8266 deep sleep

For a sensor node that wakes up and sends data from time to time, the most interesting is the deep sleep mode. On Arduino IDE one can put the ESP8266 in deep sleep mode by using ESP.deepSleep(sleepTimeSeconds * 1000000);

#include <ESP8266WiFi.h>
/* ESP8266 Deep-sleep mode*/

void setup() {
  // Wait for serial to initialize.
  while(!Serial) { }
    Serial.println("I'm awake.");
    Serial.println("Going into deep sleep for 20 seconds");
    ESP.deepSleep(20e6); // 20e6 is 20 microseconds

void loop() {}

However, there’s a catch: to wake up the ESP8266 one has to connect the RST pin to GPIO16 (WAKE). On the ESP8266 Thing Dev you do this by closing the SJ2 jumper. On other boards, one has to use a wire to connect the RST and GPIO16 pins.

Another aspect is that the ESP8266 will lose everything in its memory, and it will run the code just as it does when it’s powered on for the first time.

Of course, one can save some context variables in the EEPROM. But, if a node wakes up every five minutes, this will result in having 288 writes to the EEPROM per day. The AT25SF041 used by ESP8266 Thing Dev is rated for 100,000 Program/Erase Cycles. That means that the EEPROM will wear in less than one year.
ESP8266 — turning off the modem

This is a neat trick I found in the Arduino examples, in ESP8266 board version 2.5.0 (or higher). It allows the ESP8266 to start with the modem off, then to start the modem at the desired moment in the code. When dealing with slow sensors such as the DGS-H2S sensor from SPEC sensors, one can use this trick to keep the modem off while the sensor data is gathered and to turn on the modem just before uploading to online services.

#include <ESP8266WiFi.h>

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK  "your-password"

// preinit() is called before system startup
// from nonos-sdk's user entry point user_init()

void preinit() {
  // Global WiFi constructors are not called yet
  // (global class instances like WiFi, Serial...
  // are not yet initialized)..
  // No global object methods or C++ exceptions
  // can be called in here!
  // The code line below is a static class method,
  // which is similar to a function, so it's ok.

void setup() {
  Serial.println("sleeping 5s");

  //during this period, a simple amp meter shows
  // an average of 20mA with a Wemos D1 mini

  Serial.println("waking WiFi up, sleeping 5s");

  // amp meter raises to 75mA
  Serial.println("connecting to AP " STASSID);
  WiFi.begin(STASSID, STAPSK);
  // amp meter cycles within 75-80 mA

void loop() {

This is where things become interesting. By the way most ESP8266 boards are designed, one cannot read the battery voltage Vin without external components. But there is a method to detect a discharged battery indirectly, by measuring the input voltage of ESP8266 — that would be V3.3.

// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* ssid     = "myssid";
const char* password = "mypassword";

int Batt;

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

void setup() {

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
  // Print local IP address and start web server
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");

void loop(){
  // Listen for incoming clients
  WiFiClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  
          // the connection will be closed after completion
          // of the response
          client.println("Refresh: 5");  
          // refresh the page automatically every 5 sec
          client.println("<!DOCTYPE HTML>");
          // output the battery value
          Batt = ESP.getVcc();
          client.println("Battery voltage is: ");  
          // refresh the page automatically every 5 sec
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
    // give the web browser time to receive the data
    // close the connection:
    Serial.println("client disconnected");


In the code example above, the ESP8266 is configured to read the V3.3 voltage by placing ADC_MODE(ADC_VCC); on top of the sketch.

Then, the battery voltage in mV is read as in uint32_t getVcc = ESP.getVcc();

In my experiments, I found the following relation between Vin, V3.3 and the Vmeasured by ESP.getVcc(); This applies to the ESP8266 Thing Dev, which uses AP2112K-3.3V LDO regulator. Some other boards might behave differently so you will have to redo my experiment.


First of all, we see there’s an offset of about 0.18V between the Vmeasured and the actual V3.3. One can leave it like this or can compensate in the software.

Then we notice that, when the input voltage Vin = 3.3V, we have V3.3 = 3.2575 (it becomes to drop). The ESP8266 senses this small voltage drop, and it measures 3.44V.

Further, when the battery voltage drops to 3V (which is the safe margin to discharge LiPo batteries), the readout of the ESP.getVcc() is 3.106V. We can use this value to trigger a deep sleep to keep the battery from discharging, as in the code below:

// Low voltage detection
// Note that we read Vin, and not the battery voltage,
// as the battery voltage is not accessible to be measured
// ESP8266 thing uses AP2112K-3.3V
// https://www.diodes.com/assets/Datasheets/AP2112.pdf
// Low DropoutVoltage (3.3V): 250mV (Typ.) @IOUT=600mA
int Batt;

// do other things here

void setup() {
  // Check battery status
  // Reads Vin (not battery voltage!!!)
  // But Vin = battery voltage if battery_voltage < 3.3V
  Batt = ESP.getVcc();
  // If the battery is discharged don't go any further!!!
  if(Batt < 3100){
     // Deep sleep for as long as you can
  // your code goes here

void loop() {
  // your code goes here

What I did here is read the battery voltage one the ESP8266 module starts, and if the value returned by the ESP.getVcc() is below the safe threshold, the ESP8266 goes into deep sleep for as long as it can. Then it will wake up and go back to deep sleep until the battery is recharged.

Please observe that there will be other components (sensors, etc.) that will still drain power from the battery, but the overall discharge rate is considerably slowed down.


Air quality,1,Arduino code library,2,Arduino projects,12,Casual stuff,1,ESP8266,2,PIC projects,1,Review,14,Tutorial,11,
Electronza: ESP8266 — running on battery power
ESP8266 — running on battery power
Loaded All Posts Not found any posts VIEW ALL Readmore Reply Cancel reply Delete By Home PAGES POSTS View All RECOMMENDED FOR YOU LABEL ARCHIVE SEARCH ALL POSTS Not found any post match with your request Back Home Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sun Mon Tue Wed Thu Fri Sat January February March April May June July August September October November December Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec just now 1 minute ago $$1$$ minutes ago 1 hour ago $$1$$ hours ago Yesterday $$1$$ days ago $$1$$ weeks ago more than 5 weeks ago Followers Follow THIS PREMIUM CONTENT IS LOCKED STEP 1: Share to a social network STEP 2: Click the link on your social network Copy All Code Select All Code All codes were copied to your clipboard Can not copy the codes / texts, please press [CTRL]+[C] (or CMD+C with Mac) to copy Table of Content