Posted on

5 Hacks to Prolong your ESPaper’s Battery Run-Time

In the last post I showed you how you can use cheap hardware to get a reasonable good power consumption test rig. In this post we are going to use this tool to improve the runtime of the ESPaper significantly. The short trial and error cycle possible with this tool will let us validate several ideas for improvement in only very little time.

The Test Subject – ESPaper Plus Kit

Last year we released the 2.9″ ESPaper Plus Kit to the maker community. It is our first near-end-user ready device, coming with an enclosure, batteries, programmer and USB cable. And everything packed up in a really nice box. The device has a built-in battery which complicates a lot of things. One being the safety requirements of our shipping providers.

Another new challenge for us was the new area for optimization. The ESP8266 Classic and Color Starter Kits were running only with a connected USB cable so energy consumption was not a primary concern. The ESPaper Plus on the other hand is supposed to run from batteries for many days without recharging. So eventually we had to figure out if there was room for improvement on the software side. And without spoiling the rest of the article I can say there was!

The ESPaper Plus Kit comes with a stock LiPo battery with 3.7V and 600mAh. We chose this capacity because of the limited space we had in the enclosure. A charging circuit and an LDO control charging the battery and bringing the voltage down to the ESP8266’s 3.3V for operation.

During the development of the ESPaper module we were concerned mostly about the sleeping current consumption of the device. But even back then a quick calculation showed that the current consumed during sleep phase was nearly negligible compared to the current consumed by the WiFi module during the awake phase.

 

The ESPaper Duty Cycle

Let’s have a look at a regular duty cycle of the ESPaper module. The device wakes up, connects to WiFi, fetches some data from a web server, updates the display and goes back to sleep. You can configure the duration until it wakes up next in the device settings. We usually use 20min intervals but that depends on your use case. Normally weather doesn’t change very quickly so 20min seem to be a good value.

Let’s further break down the awake phase. As a first step the device has to establish a connection with an WiFi access point on the physical level. Your WiFi credentials are validated. Then device and AP negotiate settings for the subsequent session. The device negotiates an IP with the router over the DHCP protocol. At this point we move one layer up in the network stack. The devices tries to establish a connection with the content service (e.g. Wunderground). In case we chose to use an encrypted channel our client negotiates encryption settings with the server.

Then we initiate a direct connection with the content service, usually by using the HTTP protocol. The server then sends a stream of bytes to our ESP8266, usually in a JSON representation. The parser on the client tries to get the interesting data out of that content. Using this information we draw text and symbols to the frame buffer residing in the ESP memory. Once we have drawn everything to the frame buffer the commit command transfers the pixels to the e-paper video memory. We disconnect from WiFi and send the device to sleep by defining the sleep duration.

Why do I explain this here in such a detail? Because the awake phase in total is the biggest factor in energy consumption. In order to save energy we have to understand this phase in detail.

 

Baseline Code

“Baseline Code” is the name I gave  to the setup from which I started to check the effects of the later described hacks. It is the espaper-client code I wrote for our upcoming espaper web application server. It uses best practices and no special tricks to fetch a JSON object from a secured (SSL) webserver over HTTPS. To get a good average I ran my monitoring tool 10 times and wrote down the forecasted runtime for the 600mAh battery. This average forecasted that the device would run about 34 days from one charge. Honestly I wouldn’t pay too much attention to the exact number. What has more significance is the relative change after applying the hack.

After implementing a hack I measured the change 10 times and reverted then back to the baseline. This way it was easy to identify the effect of a single change rather than just see the sum of a change.

 

Hack #1 – Statically define the ESPaper’s IP address

The first change I tried was to statically set the device’s IP address. Without additional code the device will use the Dynamic Host Configuration Protocol (DHCP) to get an IP address from the access point. This process is a negotiation between client and server. Several messages are exchanged before the the device knows its IP address:

DHCP negotiation. Source: Wikipedia

While this is a very convenient thing to do it also takes time. And time in our case is energy. If you know for certain that you will never have two different devices using the same IP in your network you can define the IP at compile time. This will save you save you a lot of time while the device is online. Here’s how you can do that:

IPAddress ip(192, 168, 0, 51); 
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);


WiFi.begin(WIFI_SSID.c_str(), WIFI_PASS.c_str());
WiFi.config (ip, gateway, subnet, dns);

You define the ip, network gateway to the internet, the subnet segment and the name service. Then after connecting to WiFi you set this information to the WiFi object. Since the ESPaper now doesn’t have to negotiate the IP it can proceed with downloading data much faster than before. The average over 10 samples shows an improvement of 6.6 days longer battery runtime or 13% longer battery life compared to the baseline code!

One word of warning though: this like some of the following hacks come at a cost. By statically setting the IP at compile time you increase the chance of a conflict between two devices in your network. If you have a couple of devices with a static IP you are responsible to make sure that never two devices use the same address. Otherwise your devices will show strange behavior. Further you will have a hard time to find out what is going on. Basically you replace convenience and stability for a longer battery life.

 

Hack #2 – Avoid unnecessary storing and loading of WiFi settings

By default the WiFi object stores the WiFi credentials every time they are used to flash memory. By setting the WiFi.setPersistent(false) the credentials are only stored to flash if they are different than last time. This sounds actually like a good idea! Why the default is then to always persist the values? You can read more about this feature here.

You can do this by calling (see documentation):

WiFi.persistent(false);

However, the effect of this change is rather small and only improved the runtime by about half a day. Since I sampled only 10 times this might even be in the range of error. I still kept it here to show that sometimes many small improvements can have an impact together. And I think many of you might be interested that storing the WiFi credentials is the default behavior, even if you always initialize the WiFi module with a password stored elsewhere on flash. So why increase flash wear and waste valuable time to store something twice on flash, right?

Hack #3 – Reduce WiFi output power

Now this is also a code hack with a rather small impact. And I have to say I was surprised that it wasn’t bigger. We already established that the ESP8266 consumes most energy when it is awake. DUH! I also thought that most part of that comes from the WiFi module. So wouldn’t it be logical that reducing WiFi sending strength would reduce energy consumption? My measurements showed only a nearly insignificant improvement of not even a day (0.8d to precise). Why is that? Is it because the setting actually doesn’t work? Or because the WiFi protocol automatically adjusts the power output? At the moment I can’t tell for sure. Maybe you have an idea? Leave your explanation in the comments.

At the same time I also tried to fix the PHY mode to 802.11b. I hoped to limit the data rate to 11 Mbps and further reduce power. Here are the two lines I added to the code before starting WiFi:

WiFi.setPhyMode(WIFI_PHY_MODE_11B);
WiFi.setOutputPower(0);

Update: Ivan Grokhotkov wrote about this hack on Twitter:

Hack #4 – Use Partial/ Fast Refresh with ePaper

Every ePaper module I worked with so far had different update characteristics: how fast can the update the screen? Do they allow to only update parts of the screen? How much control during the update cycle do they give to the driver? The GoodDisplay module we are using with the 2.9″ ESPaper gives a fair amount of control to the implementer of the display driver. By manipulating look up tables (LUT) you can speed up the refresh of the display content.

I added this feature a while back to the MiniGrafx library. It avoids to do several complete black/white refresh cycles and saves a lot of time with this. So why not activate this by default? If you are using only fast refresh mode the screen will deteriorate quickly. The screen will look more dirty with every refresh. In theory we could try to always use fast refresh and do a full update every few times to clean the screen properly. I haven’t done that yet since it complicates the code and it still is hard to predict when you need a full refresh.

So how much did we win by enabling the fast refresh? We gained about 3.4 days (or about 10%). Here is what you need to do to activate fast refresh mode:

gfx.setFastRefresh(false);

while gfx is the MiniGrafx object. You can do this everywhere you like. For this test I ran the command in the setup() method.

 

Hack #5 – Turn off WiFi if you don’t need it

This should actually be a no brainer: only do the costly stuff if you actually have to, right? But what does this practically mean for your code? Every application has different needs when it comes to WiFi usage. Your application might have to connect to WiFi after wakeup. Or you might have to read out some sensors first before sending the data to a server. Similarly the application might have nothing left to do after the data has been exchanged with the server. Or a costly operation might still have to be completed before the device can go to sleep.

The ESPaper has to wake up, connect to WiFi, fetch data, update screen and go back to sleep. Originally I let the WiFi on the whole time. But when I started to analyze to analyze the energy consumption I also realized that only needed WiFi up to the moment the screen would be updated. Now this had to be tested! In the ESPaperParser class I added a forceSleepBegin() call to turn off WiFi:

WiFi.forceSleepBegin();
gfx->commit();

Now hold your breath for the biggest revelation in this post yet! Adding this single line in the right spot added 9.4 days of battery life. This is a 29% improvement compared to the code without this line! So why do we have such a huge improvement? The commit() call alone takes about 3 seconds. Afterwards the device does some clean up on the SPIFFS file system and then goes to sleep. Every second without WiFi counts!

 

Summary and conclusion

I presented here five hacks to improve the time your ESPaper can run a battery. This could be helpful even for other devices than the ESPaper. In case you decide to apply some of these hacks please be aware that they come at the cost of quality or stability: setting a fix IP increases risk of network problems. Enabling the fast refresh mode has impact on the quality of the ePaper content. But I’m also very happy that the biggest improvement can be done without any side effects. Turning off WiFi when you don’t need it is a valuable trick up your sleeve for your ESP8266 and ESP32 devices driven by battery.

In this chart you can compare the 5 hacks and their impact on battery life. For each version I did 10 measurements with the ESP8266 Power Monitor. I also ran the test with all 5 hacks combined and the sum was that of the fix IP hack and the WiFi Off Before Commit hack combined. Not very surprisingly the fast refresh didn’t seem to make much of a difference.

 

All five hacks compared to the base line.

I still have some more ideas I’d like to try in the future. What impact does encryption have on battery life? Would we save energy if we were to disable SSL encryption? After all encryption requires processing power and establishing a connection takes time. Do you also have ideas for how to improve battery run-time? Pleas leave a comment!

15 thoughts on “5 Hacks to Prolong your ESPaper’s Battery Run-Time

  1. hack#1: static IP-address
    on a router it‘s common to define a range of addresses for DHCP.
    The rest up to .254 could be assigned to devices.
    So it‘s easy to avoid conflicts.

    1. Hi Urs. Thank you for your feedback. Of course you are right about reserving IPs so the DHCP server will not assign conflicting IPs. My point was to warn the readers about unexpected / undesired side-effects. They now are responsible that every new device they add with a fixed IP doesn’t conflict with any other device in their network. This is probably no problem for 1 or 2 ESPapers at home. But if you have dozens of battery driven sensors with a fixed IP their management will be more of a burden…

  2. Hi Dani,
    I assume hacks 1,2, 3 can be applied also if for example you are using the weather station kit running on battery.
    Hopefully on one of your next releases you can add a battery indicator for the weather station(happy to help with the beta testing if needed 🙂 ).

  3. Daniel,
    WiFi uses QDPSK, OFDM, QAM etc. technology to modulate the RF signal. Since there is an amplitude component in the modulated RF signal quite lineair Tx RF amplifiers are needed. Lineair RF amplifiers inherently have a low efficiency. So if you say halve the RF-power (-3dB) of the WiFi Transmit signal you definitely will not halve the power consumption of the WiFi transmitter part of the ESP8266. Together with the low Tx duty cycle mentioned by Ivan the effect of tweaking WiFi Tx power will have a minimum effect on battery life as you found out.

    1. Hi Pim
      Thank you for sharing your in-depth knowledge with us! I think this is a nice example how tuning hardware and software can sometimes lead to counter intuitive results. Where intuition usually stems from the sum of your experience and knowledge… Do you see other possibilities to save power with the radio module?

    2. Daniel,
      No, can’t think of anything else then the one you already deployed: Minimizing Air-time.
      Pim

  4. For #1, why not do the DHCP negotiation the first time, then store the IP, and use it directly the next time?

    1. You can’t be sure it’s still available next time. The AP/DHCP-server might have handed it out to some other device in the meantime. The lease your device gets with the first request will eventually expire. If you decide to use static IPs you really should reserve a range on the AP/DHCP-server that is not in conflict with the DCHP range.

      1. Normally dhcp gives a lease time, this could be set to, say, 14 days on the dhcp server, for fixed MAC reservations or on networks with a small number of clients. Only after expiry of half the lease time the client needs to renew its lease. So, until 7 days have expired, the ESP could use the leased address statically without doing any dhcp calls at all. This would combine the advantage of low power with the flexibility not having to define the ip address statically.

        1. Yes, indeed. We had been discussing this idea when Dani experimented with the power saving options. We just didn’t get around to actually try it out. However, I may be mistaken but AFAIK there is no function in the NONOS SDK to access the DHCP lease time in station mode. This means you need to add a config option in the application (defining DHCP lease time) – and then keep it in sync with the router setting.

  5. Hi Daniel,
    nice work! Additionally to turning off the WIFI prior updating – if you have control over the high voltages of the EPD you could also try setting the ESP itself to deep sleep mode during (…) the time it takes to update the image. Only needed to wakeup shortly again when the update is over to turn the high-voltages off and then go back to sleep again. This should be useful for more frequent updates (+BLE), not sure what the gain is for your use case though…
    Ciao,
    Rob

    1. Interesting suggestion. But the ESP is driving the update so won’t putting the ESP to sleep block the update. Or maybe I didn’t completely grasp your idea…:-)

      1. Jepp not sure about your setup, but sounds like the image update is blocking so you can only put the ESP to sleep after the update is done. Usually the smaller E-Paper screens have their own driver IC which is actually “doing” the update independenlty, you only need the host MCU (ie ESP32) to copy the image content, put the voltages on, trigger the update and put the voltages off again. Doiing the update is usually in the range of some hundred milliseconds, putting the host MCU during this time to sleep can reduced the power budget of the update itself significantly, but in combination with Wifi the effect is most likely rather small. Maybe its worth thinking about a BLE based ESPaper.. wouldn’t increase that battery live even more? 😉

  6. Hi,
    Weather updates are not really needful during night. Why not define scheduled wake-up ?
    Regards,

    1. True, this could be done.

      However, the ESP8266 would still wake up as you can only define a deep sleep interval not a deep sleep schedule. You would have to mimic the schedule yourself by immediately putting it into deep sleep again after wake up – all of that before turning on WiFi of course.

      The alternative would be to re-calculate the interval value every time before putting the device to sleep. So, usually the interval would e.g. 30min but if you detect that you now entered the scheduled “night time” you could increase the interval accordingly (for this one single interval). When it wakes up next morning you then reset the interval. It’s just that the ESP8266 is a 32-bit processor and the maximum value for a 32-bit unsigned integer is 4294967295 or 0xffffffff. Hence, the max deep sleep interval appears to be ~71 minutes.

      Update
      When my co-founder Dani asked “didn’t they change that recently?” I was curious to find out. Here’s what I learned: https://thingpulse.com/2018/04/10/max-deep-sleep-for-esp8266/

Leave a Reply

Your email address will not be published. Required fields are marked *