This is a work in progress, capturing several observations gleaned from some of my recent experiments and projects of varying success that use ESP32 modules and run from batteries. One project in particular uses disposable AA batteries and another uses an old-school NiCad and small solar panel (it’s a wifi garden thermometer housed in the guts of an old solar garden light).
Power hungry ESPs
If you’ve never thought about the power consumption of an ESP32 (or 8266), then you’ve likely never tried to run one from batteries for any length of time. They chew a LOT of power when the wifi radio is active, however a deep sleep mode is available which is very frugal and has the ability for the chip to wake itself up after a period of time as an RTC remains active. I really prefer the ESP32 over ESP8266 for this use case because ESP32 does not require GPIO16 to be tied to the reset pin (which is a nuisance for UART reprogramming) AND the ESP32 allows you to set most of GPIOs up as interrupts to wake the CPU early.
An over-the-air firmware upgrade is the utter worst case for power draw, averaging nearly half a Watt (power in white Math trace).
Different development boards
Not all ESP32 development boards are created equal. This has become abundantly apparent for a variety of reasons which will be described in more detail.
I have experimented with a couple of development boards – the Lolin32 and Lolin32 Lite as well as a bare ESP32-S.
Lolin32
My Lolin32 board had a measured deep sleep current draw of 1.7mA. This did not change substantially even after removing the rather good SIL2104 usb to part chip that forms the programming portion of the development board. I was unable to track down the culprit any further – possibly it lives under the can. This 1.7mA idle draw vastly eclipsed my firing up the wifi for a quick MQTT exchange every 6 hours.
I used 3x Eveready Gold (Alkaline) AA batteries. I can’t find a proper datasheet for these but assume they’re nearly as good as the Energizer Max alkalines which quote a capacity of about 3000mAH @ 25mA (if we never ran the wifi) or 2000mAH @ 250mA (if wifi ran all the time).
With the ESP likely to drop out around 3V (1V per cell) I’m estimating from the discharge curves that we’d probably only operate down to 25% state of charge. Thus I should in theory get around 35-55 days. I’m getting near the bottom of this range, with the first set of batteries going in on 28 March and the 2nd set running flat on 8th June – an average of 36 days per set. Nowhere near good enough, but a useful datapoint.
Lolin32 Lite
Running low on Lolin32 boards, I bought some cheap Lolin32 Lite figuring they’d do fine for general projects. When experimenting with one of these boards, I initially found that current draw was about 4.9mA during deep sleep. Removing the CH340 USB to UART chip dropped this to about 4.2mA. There was very little difference between running the battery input at 4V through the onboard LDO, and directly powering the 3V3 rail with 3.3V. I then checked the external flash chip that is present on the Lolin32 Lite. Yes, this chip was drawing more than 4mA!
Reading up in the ESP32 datasheet, we find this nugget:
You can tell where this is leading… the Lolin32 Lite has not bothered to allow the VDD_SDIO pin to power down the flash chip during deep sleep, instead hard wiring it (and the flash chip’s Vdd pin) to 3V3.
Can we modify it? Yes! While I don’t have the PCB layout for this board, I discovered that in my case, the 3V3 track does not go under the ESP32 chip. Even better, it runs from the SDIO pin, to the flash chip and then on to a power plane. I was able to isolate the flash & SDIO from 3V3 whilst leaving them connected with a single cut – I could not believe my luck.
This dropped the current draw to 160uA.
Bare ESP32-S
I also tested a bare ESP32-S (S is the single core version).
This is just the module, so I needed to use an external USB to UART board to program it.
In order to flash the board, the EN pin (which is actually the reset line) needs to be pulled high, and GPIO0 has to be pulled low. To run, the EN/Reset still needs to be kept high, but the GPIO0 must be low or floating.
In deep sleep, I measured the ESP32-S drawing 60uA.
Measuring tiny power
To measure really low power during deep sleep, I had to insert a fairly large resistor in series with the board. At 60uA, even a 10 ohm resistor gives only 0.6mV, barely resolvable with my multimeter and drowning in noise on my scope. With the substantial current draw of the Wifi chip, 10 ohms is enough to cause the chip to crash or reboot when connecting to wifi, even if the supply is wound up close to the 3.6V max. For all the boards, I opted to use a 100 ohm resistor, which I kept shorted while the chip booted and ran a program that waits 20sec, then goes into a deep sleep for 20sec, allowing plenty of time to open the short & take a measurement. Electrolytics on both sides of the resistor reduce noise from my power supply and the code also toggles a GPIO which I can monitor with an LED or scope to know when it is in deep sleep mode (GPIO goes high at boot and low right before going into deep sleep).
Running bare ESP32-S from batteries
I had some 3.3V buck converters from Ali. They are not suitable for this purpose – the idle draw is 2.2mA, and their output drops out a lot at no load.
I’m thinking that an LDO is likely to be the best option since most of the time on my project the ESP32 will be in deep sleep mode so the low idle draw is more important than the losses during wifi transmission for ~45 seconds per day.
To be continued..
UPDATE!!! 24th April 2024
Success!! The letterbox has run for a REALLY long time on one set of batteries. I feel like I’ve finally nailed this challenge.
How long? Check out this graph of the battery voltage from Home Assistant….
Note the colour isn’t important, the highlighted section is “History” data, while the dull area is “long term statistics” data in HA. The batteries were installed on 10th September 2022 and (despite some lockups that burned extra power early on) finally went flat on 13th April 2024! That’s more than a year and a half, 581 days in fact.
I kept forgetting to change the batteries so it’s now 24th April. I’ve added a sticker onto one of the batteries with today’s date as well as recording here. I guess the next update may be in 2026! In the mean time I should probably update the firmware.