Running NodeMCU on a battery: ESP8266 low power consumption revisited

Over the last year I have standardised on the ESP8266 for all my small IoT projects. Its low price, ease of use (now that the Arduino IDE is available), tiny size and built in Wi-Fi makes it a compelling option.

Using Wi-Fi is a convenient way to link your newly created IoT device into your existing IT infrastructure – including cloud services – but it also has a drawback. Wi-Fi’s demand for power usually makes battery operation impractical for any real deployment. I have been able to get around this issue for most of my projects (e.g. the train and the smart shelf described on this blog) because they are for demonstration purposes only, requiring the battery to last no longer than a few hours.

Nevertheless, it is possible to put the ESP8266 into deep sleep and wake up periodically to check and activate Wi-Fi only when required. This would suit a scenario in which an IoT sensor sends relatively infrequent one way traffic (i.e. where real time control of the device is not needed). I wrote about the ESP8266 deep sleep option more than a year ago, but have not explored it any more until recently, when exactly such a project arose.

The other thing that I have done over the last year is to standardise on using the NodeMCU (hardware, not the LUA software). Especially when rolling out multiple small projects, it is immensely convenient to be able to plug a device into a USB port and just program it (automatically without having to wire up serial pins and then get the correct pins tied high / low for flashing / running). With no need to worry about providing 3.3V power, adding capacitors to prevent the ESP8266 power spikes from causing instability, or adding a resistor + cap for a power-on reset. No need to scale down the ADC input to 1V or to add my own test led… and all of this in a breadboard friendly package.

Also, just to be clear for those who may wish to follow along, I always use the “second generation” NodeMCU known as v2. The different versions are described here and I agree with that poster – i.e. don’t buy the v3 variant because its larger size means that it leaves no free breadboard holes on either side.

Unfortunately, with all this added convenience comes the drawback of added power consumption, which continues even when the ESP8266 is in deep sleep.

I measured 18mA to the NodeMCU board while the ESP8266 was in deep sleep mode – orders of magnitude more power hungry than I was looking for.

So for my iot-container project, I sought to retain the convenience of using the NodeMCU, but to address its power consumption shortcomings to allow battery operation.

Read further to hear what I did.

The two immediate suspects are the power regulator, and the UART, as discussed in the forum here.

The first step is to target the power regulator. The AMS1117 LDO draws a quiescent current of “typically” 5mA. To prevent this, it may be sufficient to lift just pin 1. However, I chose to remove the whole chip to free up space for later.

You won’t need the LDO if you supply your own power directly to the 3.3V pin of the NodeMCU. I often use a single cell Li-Ion battery via a 1N4001 dropper diode. Note that from now on you will need to supply this power, even if a USB cable is connected for programming / monitoring.

Place a small amount of flux and solder on the pins, starting with the big tag, and it should lift easily.Then remove the remaining 3 pins. Without the LDO, I measured a saving of 3mA.

Now for the biggest saving – to disable the USB UART. This can be done with reference to the NodeMCU schematic by cutting power to pins 6 and 7.

In practice this means cutting a track with an X-Acto knife under the best magnification you can find, and with steady hands. Also scrape away the protective coating to the right side of the cut:

Congratulations! You will now have reduced power consumption by some 360x to around 50μA 20μA [Updated 28 Jan 2017 when I was powering only the NodeMCU, without additional circuitry].

Earlier I mentioned using OTA to program your device. If you have already installed the OTA code prior to cutting the track, in theory you could finish at this point, and permanently forego the use of the USB port. In real life, things go wrong, and it is useful to have the option of going back to having a serial port.

Option 1: Add Switch or Jumper

The first (and easier) option is to put a switch in the position formerly occupied by the regulator, attached to the two points shown below:

With this in place, you can re-enable the USB port for programming or debugging via the serial monitor.

A note to the unwary: The first time I tried this I glued down the switch with epoxy. The problem is that, unless you are more careful than I was, a drop of epoxy becomes suddenly HUGE under these magnifications. The glue seeped into the switch, preventing it from working, and the NodeMCU ended up in the bin. Second time around I used super glue with more success.

[Update 4 Sep 2016]: I have replaced the switch with a simpler and more reliable solution: a jumper.

Option 2: Power UART from USB (no switching required)

[Update 28 Jan 2017]: Thanks to Willem Jansen for suggesting this approach in the comments below. It turns out that the cp2102 UART has its own internal 5V to 3.3V regulator, which is not by default used by the NodeMCU circuitry, probably because it would not reliably supply the peak currents required by the ESP8266 (plus any associated circuitry the user might add around the NodeMCU).

As explained in section 10 of the cp2102 datasheet, the cp2102 can be “configured as either a USB bus-powered device or a USB self-powered device”. To reconfigure the chip to use USB power requires isolating the VDD pin (break at X1) in addition to the X2 break described earlier, followed by permanently wiring the Regin pin to USB 5V (Wire3).

You can see on the right what this looks like. The extra PCB break really adds to the difficulty, even under 10X magnification.

Once complete, the UART will only draw power when the USB is connected for programming / debugging. Certainly this is a more elegant solution and convenient to use – offset by the extra time and effort required to make the mod. Depending on how often you plan to update firmware or debug will determine which approach is optimal – you decide!

I need to warn you that after I implemented option 2, I found that intermittently the ESP8266 does not seem to boot up after applying power. Thanks to Mario Valentino – in the comments below – who found that a disconnected UART can pull the ESP8266 TX pin low, causing intermittent booting problems (as hinted at under “Desired level during power on” in: http://microchip.ua/esp8266/ESP8266_Module%20Application%20Design%20Guide.pdf). What I find strange is that in theory this should also be the case for option 1, yet I did not experience that.

The solution is to place a resistor between TX and 3.3v, as shown on the right. Unfortunately this does waste some power. Choosing 1MΩ minimises this to an additional 3uA, bringing the total deep sleep current consumption of the NodeMCU to between 22-23μA.

Which option would I choose? I favour option 1. You save 5% power compared to option 2, and it is less tricky to make the mod. If you use OTA to update your firmware (or seldom update your firmware), you will not very often, if at all, need to replace the jumper to re-enable the serial port. Certainly, however, option 1 is not as “elegant”…

To be able to measure the small currents, I made use of the excellent μCurrent Gold.

You may correctly point out that 50μA is still several times higher than what should be achievable with just the ESP8266 alone. But for what I am doing it is good enough: (theoretically at least you could get towards 10 000 hours from a small 500mAh Li-Ion cell, depending of course on what you do during the wake up periods, and preferably only infrequently using Wi-Fi.

[Update 28 Jan 2017]: While testing option 2 above, I was powering only the NodeMCU (i.e. without the additional HX711 circuitry used previously). I measured deep sleep current at 20μA!

67 thoughts on “Running NodeMCU on a battery: ESP8266 low power consumption revisited”

Interesting — it is a bit surprising that the CP2102 consumes so much power. The datasheet seems to indicate that it operates in a low power mode from reset until USB enumeration. Look for SUSPEND in the datasheet.

Yes, I saw the SUSPEND lines mentioned in the datasheet, but they are outputs only. Suspend seems to triggered when “signaling is detected on the bus”. So I tried removing all “Serial” references in my Arduino code and also not plugging in a USB cable, but to no avail. Report back if you have any success!

Thanks for the great post! I’ve been tearing my hair out today trying to figure out why I could get that reported 70uA! Did you ever get a chance to follow up on the question of the CP2109 power consumption in suspend mode?

When the current gets really low, the diode will drop less voltage than you might expect and your module may get exposed to a voltage that is higher than its maximum spec. To avoid this problem, instead of a regular Li-Ion use a Lithium Iron Phosphate battery (LiFePO4), which has a nominal voltage of 3.2V and never goes higher than 3.6V. An easy way to experiment with them is to use the LiFePO4wered/USB module I sell on Tindie: https://www.tindie.com/products/xorbit/lifepo4weredusb/?pt=ac_prod_search

This is why i wish someone would come up with a proto and go version of nodemcu. Socket the actual nodemcu board for the ESP8266-12E and then sell a second board with just the socket wired to pins. Build and debug your prototype in the nodemcu and when complete pop the 12E out and into the socket only version.

I have ESP01 powered with 2000 mAh power bank and AMS1117. It lasts about 10-12 days waking up every 5 minutes for 10 seconds to connect to wifi, read DS18B20 and send data both to local MQTT and ThingSpeak.

I was wondering if you could improve the running time by removing the LDO and also reduce time 10 seconds for just a few Milliseconds… I’m currently running an old version of the board I mentioned above for over 1.2 years on 2xAA. I know it’s not the same an it can’t send metrics directly to the Internet without a gateway but might be room for some improvement on the ESP8226. Other thing is the power bank, rechargeable batteries normally have a bigger self-discharge rate when compared with non-recharchable ones.

I’m not sure if ESP8266 can survive direct connect to LiPo battery as it’s voltage can be up to 4.2 V. In my case the longest step is WiFi connection, it takes about 5-6 seconds. Reading sensor and sending data adds 1-2 seconds. And I forgot to mention I’m using NodeMCU firmware running my Lua scripts. Probably clean C code could do the job much faster.
I’m pretty sure it is better to use simple broadcasting radio like 315/433 MHz or NRF24L01+ to save time on AP association, though I have not tried them yet.

My proposal would be: Cut the UART power lines as indicated, scratch away the Vcc-pin and connect the REGIN pin (pin in the bottom left corner) to +5V from the USB directly. This way, the SILAB IC is only active when you attach a USB device – without necessitating any jumper at all.

Yes! I like your thinking. As per the cp2102 datasheet (section 10), the chip can be “configured as either a
USB bus-powered device or a USB self-powered device”. I will give your approach a try to confirm, and then update the post with this alternative.

Great article. I want to reduce the power consumption of my ESP8266 NodeMCU as well and I am going to try Option 2: Power UART from USB (no switching required). I have one question though, do I need to still do the other adjustments as well, or does this suffice?

Kevin, for option 2 you still have to first make the mods described before the “option 1” heading. Just be aware that “option 1” is definitely robust and proven – and has been running my IoT device (https://tinker.yeoman.com.au/2016/07/24/iot-container/) for almost 6 months on a single charge of a 14500 cell. However, I only tried option 2 last week and experienced some strange intermittent issues with the NodeMCU not booting – so cannot be as confident of its reliability.

Thanks Mario – I believe you mave have solved this! I must say I did consider something similar, but was thinking of the RX pin (since I thought it more likely to be an input). I couldn’t find any evidence that the TX pin (GPIO1) mattered at boot time. But doing another search there is something – look under “Desired level
during power on” for the TX pin at: http://microchip.ua/esp8266/ESP8266_Module%20Application%20Design%20Guide.pdf
I’ll confirm and update the post.

I have followed Option 1 except I did not remove the voltage regulator, so I can still use a 5V powerbank. Unfortunately, my NodeMCU v2 does not boot without the jumper connecting the track I’ve cut. The blue LED does not even blink and the device draws about 35mA forever. If I wait for the LED to blink before I remove the jumper, it boots normally and when it falls to deepsleep, the current is 2.3mA (rather than 10mA when UART chip is connected).

I also tried to solder a 120kOhm resistor between TX and 3.3V but nothing has changed.

Does anybody have any idea what prevents my NodeMCU from booting? Do you think removing the voltage regulator makes any difference? Thanks.

One possibility: are you putting the NodeMCU into deep sleep in your test software? If so, I found that I had to short 3.3v to ground briefly (with the power off / disconnected!) to cycle the NodeMCU. This is because the current draw is now so low that the onboard caps hold the ESP8266 powered in deep sleep mode for some time… so it can appear not to boot when you reapply power.

Thank you for your tip. I do put the NodeMCU into deep sleep. But it’s the same no matter if I put it into deep sleep or if I just disconnect the power supply. I tried to short 3.3V to GND before connecting the power supply briefly but it’s still the same. I also tried to measure resistance between 3.3V and GND with the NodeMCU off, and found quite surprising that the resistance was only around 1kOhm with the UART chip connected (jumper present), and around 2.5kOhm with the UART chip disconnected (jumper removed). Is this normal? Thanks. Unfortunately, I don’t have another v2 for reference.

I am going to try if I can use a PNP transistor to connect the UART chip only when the NodeMCU is running, and to disconnect it to save power when it goes to sleep.

I had the same problem! after trying option 1, the chip would randomly either work or not work, and I was going crazy! I thought I’ve cut too much tracks or so that it’s now lost. But I kept trying to fix it since it did work sometimes but wasn’t sure what was stopping it from running normally!

I have tried to short 3.3V and Gnd pins, but still doesn’t always work:

So as ROBERTO ARANO mentioned, I tried connecting a resistor between 3.3V and Tx pins:

Just removed the Voltage regulator, It’s now down to 1.9mA in deep sleep. I was hoping I could go to less than 1mA. I guess 1.9 mA is as far as it gets for me. Might be because of the 1 Kohm between 3.3v & Tx pins, but it doesn’t work otherwise…

Dear all,
I want to provide supply to NodeMCU ESP8266 (v0.9) from powerbank (5000mah,10000mah and 20000mah and each has 2 ports). How could i achieve this ?
Purpose is to build robotic car so that using mentioned power bank ( one port goes to controller via to motors(Wheels) and other would be connected to ESP8266 ).
I require support and assistance .

Great hack ! If your wakeup period is periodic (always the time) you can use the TPL5111 Nano-Power System Timer for Power Gating ( http://www.ti.com/lit/ds/symlink/tpl5111.pdf ) you can configure the “deep sleep” period 100 ms to 7200 s and the IC draw only 35 nA… 😉 Just only mofset and resistor

Nice tutorial got my esp8266 node mcu running without the 1 M ohm resistor and it’s consuming a 13 micro amps in deep sleep SWEET!
also i use a arduino uno without chip to program the sketch through rx and tx , so that could also be a solution number 4 for operation without uart.
now i have a microcontroller that can have a semi always on state running on the power from bacteria in a plant based microbial fuel cell

My adafruit Huzzah goes into a proper deep sleep power consumption level without requiring these hardware modifications. Would love it it someone knew of a similar board that is in the price range of the Amica style boards.

I did some experiments with what options there are without cutting the board

TL;DR!
I got down to 450µA (with the regulator removed but leaving the board as it is), by using a custom made USB cable.

For my use-case I wanted to run the NodeMCU from a battery-pack. Therefore I have a somewhat limited current but I’m not speaking coin-cell-limited.
(I probably leave the regulator in, but i measured currents without it for comparison)

My 1st attempt (UNSUCCESSFUL) was writing the EEPROM of the CP2102 to change the value of “BUS POWERED” from NO to YES.
Changing it worked well, but didn’t change the power consumption.
Not sure if this can maybe be used to reduce the amount of cutting in option 2, or whether this is just a descriptor thing. But as I didn’t want to do any cutting, i gave up on this.
(I used http://cp210x-program.sourceforge.net to change the value)

My 2nd attempt (SUCCESSFUL) was sending the CP2102 in suspend mode.
(according to the datasheet, this reduces the CP2102 current from 26mA to 330µA)

The 2 “SUSPEND” pins of the CP2102 sounded interesting at first, but those are status outputs only.

** Suspending using a Linux PC **

First I was able to successfully send the CP2102 into suspend-mode from a Linux-PC
# find out which USB-Port the CP2102 is connected to (here: “3-1”)
echo -n “auto” > “/sys/bus/usb/devices/3-1/power/level”
echo -n “0” > “/sys/bus/usb/devices/3-1/power/autosuspend”
which automatically sends the CP2102 to suspend-mode if /dev/ttyUSB0 is not used

** Suspend using a USB-cable (NodeMCU with regulator) **

After reading up a bit about USB, I learnt that suspend means that the bus is idle for 3ms. (http://www.beyondlogic.org/usbnutshell/usb2.shtml)
But the DS2102 probably doesn’t detect that because there is no hub connected.
The hub is supposed to pull-down “D+” and “D-” with 15k resistors (while the NodeMCU is pulling-up “D+” with 1.5k)
So I built a USB-cable with:
* “D+” & “D-” cut-off from the power supply (as the power-supply has it’s own resistors, that were messing with mine)
* “D-” having a 47k resistor to GND (I didn’t have a 15k)
* “D+” i put a 470k resistor to GND (should be 15k but it would “fight” against the pull-up of the CP2102 causing power consumption, I don’t know whether this is even necessary, but the CP2102 may check levels before activating its pull-up, I don’t know)

This reduced the power consumption of my vanilla NodeMCU (with regulator) from ~18mA to ~3.6mA

Seldomly I noticed, that the DS2102 was not going to suspend right after connecting the USB-cable.
I’m not sure why, but to make sure that the suspend-mode is enforce I could pull-down “D+” to GND briefly after power up.
(both “D+” and “D-” in low-state for 10ms means “USB-RESET”, and “D-” is already low. This can probably be done from a GPIO, after that the GPIO-pin can be changed back to input/no-pullup, didn’t test that though)

** Suspend using cable without regulator **

When removing the regulator and powering the 3.3V directly, the DS2102 still needs to be powered from the USB connector to go into suspend.
It seems that 3.3V is enough for it to detect suspend, so I could feed the 3.3V from the NodeMCU into the 5V of the USB connector
(I put a diode in, so I don’t accidentally put 5V from a PC into the 3.3V of the NodeMCU)
Plugging in and out the USB connector a few times, makes the DS2102 exiting suspend. It can be re-entered by briefly pulling low “D+”, as mentioned above.

This reduced the power consumption of my NodeMCU without voltage regulator from 13.5mA to 420µA

As mentioned in my previous comment I had the same issue on an Adafruit Huzzah32. Unfortunately the trace that connects VDD to REGIN on its SIL CP2104 chip runs under the corner of the chip, so there is absolutely no way to cut that trace (without removing and replacing the CP2104). I did some experiments with the USB D+/D- lines and what I found is that grounding D+ _increases_ power consumption, but grounding D- _decreases_ it. I ended up wiring a 47K SMD resistor between ground and D-. The result is a deep-sleep power consumption that dropped from 6.5mA previously to ~250uA. It’s not where a good esp32 board should be, but it’s 25x better than before! The pull-down does not appear to interfere with USB operation (I haven’t tried a very long cable, though). Thanks again for your info, I would have never figured this out without it!

Anti: If you have a look at my other posts (e.g. https://tinker.yeoman.com.au/2016/07/24/iot-container/ or https://tinker.yeoman.com.au/train/ ) you will find circuit diagrams. I use a diode (e.g. 1N4001) to drop the voltage by nominally 0.6V, which reduces the fully charged 4.2V Li-ion to 3.6V – which is within the tolerance of the ESP8266. It is not a “perfect” solution (e.g.compared to using an LDO like the CAT6219) but is very simple and efficient.

I have a analog-ish kludge that I found useful for low-power drain. I used a solar powered USB battery pack (available anywhere) to power a Nodemcu. The battery pack only outputs 5 v when there is sufficient load (~50 ma), or for 20 seconds after a switch on the pack is depressed. I jumpered across the switch with a PNP transistor that is driven by a cmos 555 timer powered directly from the li-ion battery. The timer fires, the pack turns on for 20 seconds – the Nodemcu starts, sends my data and goes to sleep (8-10 sec). With minimal deep sleep load, the battery pack turns off till the next timer cycle (5 minutes). The 4 extra wires (battery and switch) are a pain, but the 555 load is only 75 ua and I think it will run forever, as long as the sun shines.

Kiki67100: I came across that solution and actually bought some TPL5110s last year, but haven’t got around to experimenting. I thinks that it offers a lower power alternative, but with some drawbacks:
1. The SMD packaging is not exactly friendly to use, unless you make your own boards (or use breakouts?)
2. I make use of the ESP8266 RTC memory, which retains key variables during deep sleep mode to activate Wi-Fi only when something has changed. Using the TPL5110 would require saving to flash – with potential number of write cycle limitations.

I have exactly the same behaviour as ROBERTO ARANO. With CP2102 disabled I need 10k max on TX to wake reliably from deep sleep. This adds an extra 190uA 😦

I’m looking for absolute minimum power consumption to do some tests running on supercaps. I have replaced the AMS1117 with the HT7333 being able to power via usb-connector and use option 1 to switch off the CP2102.

Is there anything else I can try?

Ultimately I remove the CP2102 all together and do updates via OTA only, but of course it would be nice if I could still use the CP2102 sometimes …

The nodemcu is mainly a nice formfactor for the ESP-12E on a breadboard 🙂

I’ve implemented the low power solution, option 2. Works well, but 1M didn’t work for me, and I didn’t like the 10k option, as:
a) Takes too much current
b) would be partially powering up the ‘off’ CP2102 via it’s substrate diodes on the RXD input – yuck ! Could damage it eventually.

Instead I’ve come up with an Option 3 that appears to work quite well.

1) Cut the track to TXD0 between the ESP module and the CP2102, but on the ESP side of the via that goes to “TX” pin on the header.
2) Run a schottky diode such as 1N3132 from TXD0 pin on ESP module (pin 22 is the last pin) to the TX header pin (which still connects to the CP2101).
3) A 1k pullup from TX ideally would go to VDD (pin 6 on CP2102). My soldering gear isn’t up to getting a wire onto VDD as well as onto REGIN, so instead I took the pullup to Vin on header (about 4.8V after the sk diode from Vbus), and ran a ~3.5V zener to ground so the voltage on TXD0 doesn’t exceed 3.3V or so. You could use two 1N4001s in series from Vin to the 1k instead, if you don’t have a convenient zener lying about.

The fairly aggressive 1k pullup is need to ensure the port still works at 115k, but we don’t really care about the current here as it’s from Vbus.
Now the TXD0 pin on the ESP module can happily be pulled high by the weak internal pullup when sleeping, till it becomes a real TX pin output when running.
Resets/chip_en are now reliable.

I’ve since found, using a slightly different PCB cut, that the 1k pullup can easily go to the regulated 3v3 from the CP2102. The two bypass caps are included on the 3v3 regulated output too, which is much better.
You need to isolate *just* the REGIN pin with the cut, but VDD remains connected to the bypass caps.
To the side of the larger bypass cap, you also need to cut the track that connects this VDD to the 3v3 on the NodeMCU. Add a new bypass cap on NodeMCU 3v3 on the pads of the removed regulator (to mkae up for the ones just removed from the 3v3 circuit above).

PS: If you don’t have a schottky diode on hand, a small signal germanium detector diode (crystal set diode) works fine also.

lol this is a dev board, let it be a dev board, why not get a more barebone board? Such as RobotDyn’s ESP8266-PRO, it still have the same LDO but no need to worry about the serial chip..but the EEPROM is only 8Mb…

Yeah but the Wemos doesn’t have that many GPIOs broken out, I was looking for drop-in replacement for the AMS1117 in SOT223 with the same pin out and came across AP2114, not as cheap but relatively affordable, has 200mV dropout at 500mA, 1A output max and 60uA quiescent current, not bad at all.

The MCP1700 and HT7333 have much lower quiescent current but can only handle 250mA, pinout differs (Vin/Vout switched) which is like the bare minimum for the ESP alone, may work ok with adequate caps..

The Wemos uses a ME6211, 500mA, dropout 260mV at 200mA load (700mV at 500mA), quiescent current 60uA also but not available in the same package (SOT23, SOT89) and different pinout again.

It’s almost as if the specifically designed the pinout of the AMS1117 to be NOT compatible with others LDO so that once you design your board around it, you’re kinda stuck with it lol

Great article, well done!
I noticed that in the NodeMCU ESP-32S, they use approach #2, the CP2102 is only powered when USB is connected.
It can be seen here:
I do not see a resistor in there to pull up the TX line. I suspect the reason it happened to you is because you also cut the traces to the capacitors on the VDD pin, perhaps they are needed. Maybe its better to cut the trace from VDD3V3 to these capacitors, and instead, add capacitors for stabilizing 3V3 on your 3V3 source\board.

Then… I loosed this tiny cp2102 chip =D
I resoldered an other cp2102 chip that I found in my old chips box (not a new chip.. could be not working good) but …. now it’s still not working all the times in battery mode (3.3v powered) but works good powered by USB… maybe something is wrong with this cp2102… anyway.

Hi, I tried to do the same on an ESP32 board, but got a “Brownout detector was triggered” error in the serial console. I thought it’s because my MCP1700-3.3v voltage regulator is not powerful enough, so I cranked up my decoupling capacitor to 2.2mF (and later even 1F supercap). The error remains the same.