Battery lifespan test complete

A while back, after using my Nordic PPK2 Power Profiler to gather power-usage data for the floater, I did some basic calculations to try and determine the theoretical battery lifespan.

The test has been running for many months and finished on 31st Dec 2022.
With the floater sending data every 5-min, my theoretical lifespan was 8 and-a-bit months.
What was actually achieved was 7 months, 3 weeks, 5 days.
Considering the events over the testing time, I’m pretty happy about the end result.
It is a sample-size of one so not necessarily typical. It is what it is.

In that time I had WiFi dropouts, power-cuts, my Raspberry-pi that logs the data locked-up for over a week before I noticed, and the home router died and was replaced.
The Raspberry-pi lockup did not affect the battery lifespan but the other stuff did so there was several periods of WiFi logon-timeouts for the floater. Considering all that, just under 8 months was a good result.

Device cut-off was 2.9V. Looking at the graph, its definitely over the edge of the discharge cliff so perhaps 3V would be better.

The shape of the discharge was unexpected. I have no explanation of the dip and recovery about 2/3 of the way through the test. There were no WiFi issues around that time.
As the final steep decline starts, the router started to have issues and the ‘lift’ of the voltage was after a series of high-discharge events (WiFi timeouts).
I’m speculating if the higher-than-normal discharges have an effect on the battery chemistry (the mobility of charge transfer).
The normal discharging current pulses are short and infrequent. Maybe the higher (and more sustained) current pulses help things to move around more at a molecular level.
Or I could be completely barking up the wrong tree and its a software glitch in my sampling/averaging routine. The reported voltage is the average of a run of 64 samples.
The step-down a bit later is when the router died so a bunch of WiFi timeouts for the floater, till the replacement router was fitted. This happened after the knee of rapid voltage drop.

If anyone reading this knows more about the low level battery chemistry of LiFePo4 cells and how they behave, I’d be happy to hear from them 🙂

And another one..
This floater is inside a metal brewery keg, which is in a modified fridge (for temperature control). It uses a small repeater sitting on top of the keg because the loss going from inside two metal containers (keg + fridge) is too much, but from just inside the fridge is OK. The fridge is not so RF ‘sealed’ so easy to get the signal out.
This has run for 8-months so far (4-Nov-22 to 7-Jul-23) and is down to ~3.16 volts so probably time to recharge as its just at the start of the final faster decline.

The WiFi environment was mostly good but the router was unplugged for an afternoon. All in all, a quite reasonable result.
I don’t apply any temperature compensation to the ADC readings and this shows up as the sudden dips/peaks as the temperature swings by 20-degC (or more) during a cold-crash.
The floater reporting rate was set to 5-min.

Discharge lifespan

ESP8266 wake from deep-sleep power profile


This is a single wake from deep-sleep event in the Arduino environment.

Reset pin is pulsed, ESP wakes up, collects data, WiFi connects, sends data by UDP, then back to deep-sleep.

The greyed area starts with the ESP reset pin being activated and ends when the ESP goes back to sleep, in this case (above pic) it takes about 280ms so it is not completely unrealistic to use ESP8266 devices on batteries (many people do). Between 269 and 274ms is fairly typical for me on my home network. Here is 12-hours of connect-times graph
The times are NOT by using millis() as the internal timebase does not start till some time after the reset.

The low-power item before the ESP-reset is a companion-processor (ATtiny1614) that does a bunch of background stuff. It is responsible for waking the ESP and handing over its collected data for transmission. It also handles the DS18B20 for temperature because the ESP is not awake for long enough.

At the bottom of the image, the blue logic trace is the actual Arduino sketch-active time. 1st instruction in sketch sets it high, goes low after initiating the UDP transmission.

There is no RF-Cal on wake so startup is quicker. In my use, every 100th wake, an RF-cal is included.

From reset to start of sketch is (in this case) 113ms. This is dead-time for the user while the ESP is initialised up to the point where the boot process hands over to the user sketch. WiFi becomes connected just after the second-last current peak, so from sketch start to that point, do stuff!

By the time your WiFi connection is active your data should be all packaged-up and ready to send. There is about 160ms of actual usable sketch time available before WiFi is connected. Use it wisely!

With everything sleeping (ESP8266 and ATtiny1614) the standby current is about 78uA. Still a bit high. Now I have my Nordic PPK2 I can try and optimise this so as I modify the software I can actually see the difference.

11-Feb-22: After a bit of tweaking, standby is now down to 22uA. Not bad for an ESP and ATtiny together (and support circuitry).

ESP8266 battery life: Theoretical (1200mAh) vs useable


Since getting my hands on a Nordic PPK2 (power profiler) I have been able to accurately measure the operational and standby/sleep performance of my ESP8266 systems that use batteries.
One of my boards I’ve investigated contains the following:
1 x ESP12S
1 x ATTINY1614
1 x MPU6050 module
1 x DS18B20
plus a few capacitors and resistors.
This is powered from 2 x 600mAh LiFePo4 cells in parallel.

The board is set up to wake up every 5-min, send data, go back to deep-sleep.
I like to use the ESP12S in compact designs because it requires no external resistors. The relevant pull-up/down resistors are built in to the module so if its been programmed, all you need is to supply power (and a VCC decoupling cap).
The MPU6050 module is a common version found on ebay. It has a small regulator (5V to 3.3V), a few caps and resistors and a power LED.
To minimise the power consumption I remove both the power LED and the regulator from the MPU6050 module. Not using a regulator avoids the parasitic drain or voltage drop that would normally be involved.

The charge/discharge voltage profile for this type of cell means that no regulator is required for the electronics.

From the ESP data sheet, operating voltage is from 2.5 to 3.6V.
MPU data says 2.375 to 3.46
ATtiny is 1.8V to 5.5V

By using the Nordic power profiler I obtained the following data for a 5-min wake/sleep cycle

The highlighted grey-section contains a complete 5-min cycle (well.., 4:57.9).
(For an actual wakeup event, see here)

This shows max current (when the ESP transmits), average current and the charge used. (25.95 milli-Coulombs)
To translate Coulombs to mA/h is a simple divide by 3.6 which produces 0.00720833mAh for the 5-min cycle.
So 1 hour takes that figure up to 0.0865mAh, 1 day is 2.076mAh, 30 days uses 62.28mAh.
Theoretically with 1200mAh of battery this allows for 13872 hours of operation. Or 578 days (19.2 months!). Mmm… was not expecting that. Seems a bit optimistic, maybe got my sums wrong somewhere.
But even if its correct, its never going to be that good. Not even close.

This battery chemistry has a self-discharge rate of around 5% a month. Some sources say 3% but 5% seems the most common figure so lets go with 5%.
This equates to 60mAh a month just vanishing. Nothing you can do about it.
The electronics actually uses 62.28mAh/month and the battery looses another 60 in self-discharge. This brings the new monthly ‘consumption’ figure to 122.28mAh so the theoretical run-time changes from 19.2 months to 9.8 months.
But wait, there’s more!

The battery capacity figures given by manufacturers are from full charged to fully discharged. If you read lots of stuff about LiFePo4 batteries, charging/discharging, what constitutes fully charged seems to vary. Some advocate charging as high as 4.2V which packs in an extra percent, others say fully charged is 3.65V (seems to be common). If you charge to 3.65V then stop, take it out the charger and next day measure the voltage it has settled to a more friendly (for my purposes) 3.4-ish V.
(Some very good info about charge voltages and percentage capacity at powerstream)
The minimum voltage for LiFePo4 cells is often given as 2.5V. I don’t let mine get that far down. I shut-down at 2.9V which probably looses maybe 8% of the available capacity so the 1200mAh battery is actually 1200-8% so 1104.
Only charging to 3.4V can loose another 3%, so instead of 1200-8%, make that 1200-11% so now only 1068mAh

At last the numbers should be usable. 1068mAh/122.28 = 8.7 months which I’m hoping is a bit more realistic.
Disappointingly different from the first number of 19.2 months (I’d got a bit excited!) but after thinking about it a bit, and reading more, I realised it just was not going to be.
Theoretical-maximum and realism can be very different.
The style of usage has quite an effect on the usable capacity. If I was discharging at 0.5C then I should get close to the theoretical capacity as the self-discharge is not a factor.
By using low discharge rates over a long period, the self-discharge of the battery becomes very significant. In my case, almost half the energy is lost in self-discharge. 
I have not managed to find any information about LiFePo4 cell very low discharge rates. 0.1C was the lowest test discharge I found.
Although I’m not sure if this qualifies as low, perhaps pulsed is a better description. It does have high current pulses (~230mA), but of very short duration and 5-min apart to allow for ‘recovery’. It probably makes a difference and in a beneficial way to the user but I’m just guessing here.

Since the self-discharge has such a large effect on my battery life I looked at using 2 AA alkaline cells in series, no regulator. So lets look at some numbers here..

Capacity of a AA alkaline cell seems to be from 1700 to 2850mAh depending on the manufacturer so 2000mAh seems reasonable to use.
Self discharge for alkaline cells is 2-3% a year, so 3%/12 gives 0.25% per month, or 5mAh per month loss.
The ESP8266 needs 2.5V minimum so each cell only gets down to 1.25V which means only about 35% of its 2000mAh is available for use, so 700mAh
Monthly use is 62.28mAh for the electronics plus 5mAh self discharge = 67.28mAh
700mAh/67.28 = 10.4 months. An extra 1.7 months than the rechargeable cells and starting with a lower available mAh. The self-discharge makes the difference.

Its not quite that simple. The circuit would need more capacitance because as the internal resistance in the cells rises (as its discharged), the high current peaks for the ESP transmission need the energy reservoir of the caps to source it.  (Excellent article here with measurements and examples)
There is also a degree of waste involved. The AA batteries still have 65% charge left. Maybe OK for a TV remote? The rechargeables are, well, rechargeable. 1000 charge cycles for the LiFePo4 batteries seems quite reasonable, but the alkaline cells probably go in the bin.
Or modify the circuit to have a very efficient micropower boost regulator so much more energy can be extracted from the alkaline cells. I have not looked into this, I’m going for low component count and simplicity. Ease of building at home.

The figures above (apart from the actual measurements) are gathered (and interpreted) from the dreaded internet so don’t take it all as rigorously defined. It should however be ball-park enough to be useful and food for thought.

ESP8266 on batteries, discharge curves

So how long would a simple configuration last running on batteries…

Only one way to find out.

The circuit is very basic. An ESP12 module on a carrier, the required pull up/down resistors, and a HTU21D humidity/temperature sensor. Power source is 2 alkaline C-cells. No regulator, just powered direct from the batteries.

The two C-cells measured about 3.15V to start and the ESP data sheet says it runs down to 2.5V. Data is read from the sensor every 3-min then posted by UDP packet to a local Influx-DB on a Raspberry-Pi. UDP because its fast and the occasional lost packet is not an issue for this function.

This is the 1st (nearly) 6-months.

The steps at 1,2,3 were because when the ESP wakes up from sleep and tries to connect, on these occasions the local WiFi was missing so instead of just going back to sleep, it kept trying to connect. This had a significant impact on the battery. I found it interesting that after the battery takes a bigger discharge-hit, it recovers somewhat in the time after. This can be over several days or a week or more.

4 was when i decided to tweak the software and fix the constant-retries issue but then I discovered that a breaking-change happened when I upgraded from ESP (arduino) 2.74 to 3.02.

Now WiFi defaults to WiFi OFF at the start of a sketch so every connect takes longer. Another battery-hit from that one! Till I found the fix to change behaviour back to the old-method of WiFi ON at startup.

The green spikes are WiFi connect time. These vary considerably. This is a closer view of number 4 above.

Some connect times (in the early days) are over 10-sec which is a terrible waste of battery power. This is now changed so if no connection by 2.5-sec, it just goes back to sleep. No more retries if it fails (1,2,3 above), it now just shuts-down and tries again later. 2.5-sec is probably still too high as the green spikes for connect times are about 1.2-sec. It looks like if its not connected by 1.5-sec then its not going to happen is a sensible timescale.

This is 24hrs at the head of the graph. Almost all of the connect times are 253ms. This is slightly longer after the V3.02 changes. 247ms was the V2.74 baseline. Sometimes a 1.2-sec connection but the vast majority are pretty fast. Some gaps due to missing packets which could be because its UDP (and not a great environment), or possibly >2.5-sec WiFi timeouts. The time is measured from when millis() starts counting (prior to the user sketch beginning) till just before the UDP post.

Now the constant-retries has been fixed, and the attempt-connect time reduced to 2.5-sec it seems believable that I might get a year from this set of batteries. Battery voltage is now down to 2.85V from the starting 3.15V.

The early discharge rate was quite steep due to a combination of software (constant retries) and the initial discharge behaviour of the batteries but this has flattened out now. The major step (1) in the first graph probably lost a month or more of runtime.

Apart from my dodgy software, its doing a lot better than I thought it would. Running a WiFi sensor from batteries had never seemed that practical to me but it looks like it is more realistic than I had initially thought. Maybe it will manage a year, maybe not. Time will tell.

One year later and still going…