Reducing WiFi power consumption on ESP8266, part 2

In my previous post I showed the baseline power consumption data for one of my ESP8266-based weather monitors.

The device wakes up from deep sleep, reads some sensors, connects to a WiFi network and transmits the readings over MQTT, it will then go back to sleep for 5 minutes.  One such reporting cycle would consume 0.164 mAh.

This time I’ll show the first steps on the way to reducing this to less than half.

Disabling WiFi when waking up

As the WiFi radio is on when the ESP wakes up, we wake up with 70 mA current even if we’re not using the WiFi yet.

To try to reduce this, let’s switch off the WiFi radio at the beginning of the setup() function, keep it off while we’re reading the sensors, and switch it back on when we are ready to send the results to the server.

void setup() {
  WiFi.mode( WIFI_OFF );
  delay( 1 );

In my experiments, I have found that both WiFi.mode() and WiFi.forceSleepBegin() were required in order to switch off the radio.  The forceSleepBegin() call will set the flags and modes necessary, but the radio will not actually switch off until control returns to the ESP ROM.  To do that we’re adding a delay( 1 ), but I suppose a yield() would work as well.

Then, just before the calls to establish the WiFi connection, we switch the radio back on:

delay( 1 );

// Bring up the WiFi connection
WiFi.mode( WIFI_STA );

As above, forceSleepWake() will set the correct flags and modes, but the change will not take effect until control returns to the ESP ROM, so we add a delay( 1 ) call here as well.

Let’s have a look at the result…

Ah, we can clearly see the radio switching off at the beginning of the sketch and it coming back after the 1.2 seconds it takes to read the sensors.

(Un)fortunately, the DHCP ended up being faster this time, so we can’t look at the total energy usage, but will have to calculate how much was saved while the radio was off.  The current has dropped from 71 mA to 17 mA, giving us a 54 mA saving.  Over 1.2 seconds that gives us 0.018 mAh.  Not much, but on the right track.


There’s still a sharp power peak as the ESP wakes up, and by the time the setup() is called, we will have used 0.008 mAh already.

To avoid this we can go to sleep using the WAKE_RF_DISABLED flag.  This configures the chip to keep the radio disabled until told to enable it.

So we’ll change the call to ESP.deepSleep:

WiFi.disconnect( true );
delay( 1 );

// WAKE_RF_DISABLED to keep the WiFi radio disabled when we wake up

The calls to WiFi.disconnect() and delay() are needed in order to ensure the chip goes into proper deep sleep.  Without them, the chip usually ends up consuming about 1.2 mA of current while sleeping.  This indicates that deep sleep was not achieved and that the chip is in Power Save DTIM3 mode.  (0.86 mA according to this, a little bit for the voltage regulator and another little bit for the faint sleep LED.)

OK, the ESP now wakes up with the radio disabled, it stays disabled until after the sensors have been read and we can collect another 0.006 mAh reduction for a total of 0.024 mAh.  Not much, but there are bigger gains to be had next time by changing how the WiFi connection is being managed.

2 thoughts on “Reducing WiFi power consumption on ESP8266, part 2”

  1. If you start temperature conversions on the DS18B20 sensors and DON’T wait; then start up WiFi, you won’t have any “wasted” WiFi time while waiting for the sensors. Connecting to WiFi takes (for me) 2.5 – 5 secs; more than enough for the DS18B20 to finish conversion (750ms worst case). Actually reading the values from the temperature sensors and formatting the MQTT message doesn’t take much time; so there’s not much wasted WiFi time for this process either.

    Maybe your other sensors can be similarly multiplexed with WiFi startup.

  2. I was experimenting quite a bit with how to schedule the different operations, and at the time this was the combination that resulted in the lowest overall power consumption.

    The current version of the sketch calls WiFi.begin() and immediately after that it reads the DHT22, which typically takes 750-1000ms, and optionally (if configured) a BMP280 module.
    The WiFi.begin() call returns almost immediately, so the conversions are then run while the WiFi connects and associates in the background.
    After the conversions have happened, I enter the loop to wait for the WiFi to connect.

    You do have a good point, though, and there could certainly be room for further improvement here.
    Unfortunately, the DHT library I am using is synchronous, so I can’t currently separate the start of conversion from reading the results. However, I’ll check if there is a newer version that features asynchronous calls, or worst case I’ll just have to roll my own.

    Thanks for your suggestion.

Leave a Reply

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