ESP8266 – running on battery power


These days I’m working on a somewhat bigger project, a sensor node with ESP8266 which has to collect some sensor data and upload the sensor values to cloud services. One of the challenges I’m facing is running the sensor node on battery power, and it should be able to run 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 blog post. So, this blog post is about implementing some strategies to reduce the power consumption of ESP8266 modules and of protecting LiPo batteries from over-discharging.

ESP8266 Low Power Modes

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 sleepLight sleepSeep sleep
System clockONOFFOFF
Substrate current15mA0.4mA~ 20µA
Avg. Current DTIM = 116.2mA1.8 mA
Avg. Current DTIM = 315.4 mA0.9 mA
Avg. Current DTIM = 1015.2 mA0.55 mA

* 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);

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.

Protecting the battery

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.

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.

Relation between Vin, V3.3 and ESP.getVcc(); readout

Relation between Vin, V3.3 and ESP.getVcc(); readout



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:

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 parts (sensors, etc.) that will still drain power from the battery, but the overall discharge rate is considerably slowed down.


Leave A Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.