Very Deep Sleep and energy saving on ESP8266 – Part 5: ESP-NOW and WiFi

In the previous 4 articles on deepsleep and energy saving, I mainly focussed on establishing a WiFi connection to send data.

Part 1 General – DeepSleep
Part 2 Http requests – DeepSleep
Part 3 MQTT publish – DeepSleep
Part 4 MQTT subscribe – DeepSleep

There are other ways to send data though that cost less time and therefore less energy than establishing a WiFi connection. One of those ways is to use ESP-NOW. ESP-NOW is a kind of connectionless Wi-Fi communication protocol that is defined by Espressif. In ESP-NOW, application data is encapsulated in a vendor-specific action frame and then transmitted from one Wi-Fi device to another without connection.
The big gain in using ESP-NOW is that the ESP8266 (or ESP32 for that matter) does not need to make connection with a router, but it sends data immediately to another designated ESP, which makes the process much faster. That is also one of the drawbacks: you need an extra ESP8266 (or ESP32). That extra ESP can receive data from 20 other ESP’s.
Another drawback is that the receiving ESP is ‘isolated’. Sure you can add an LCD to read the data, but it would be handier if the received data would be available on a network, for Home Assistant or openHAB being able to do something with it, or to store it in a database.
ESP-NOW works fairly straightforward on the ESP32 and a very good “How To” can be found on randomnerdtutorials.

It is perfectly well possible though to also use it on an ESP8266 and that is what I will be doing here. I am certainly no pioneer in this. Anthony Elder in fact already published code using ESP-NOW to transfer BME280 data and go to sleep in between, and also “The guy with the Swiss accent’ did, as did some others, but usually based on Anthony’s code.
Anthony’s sketches though do not have the receiving ESP connect to a network as well, but it can be done, albeit in a bit unorthodox way. Wim3D on instructables however follows an interesting concept as well as he has the sending ESP8266 connect to MQTT if the ESP-NOW transfer goes faulty. Sample code can be found here too (pdf),

So what I will do here is:
1 use one ESP8266 to read a sensor like the BME280 and send the data via ESP-NOW, keeping the ESP in deepsleep in between.
2 use another ESP8266 to receive the incoming data and eventually send that via an http request or MQTT to the network

1 The Sender
There is plenty of information on the Web so there is no real need to reinvent the wheel. I used a sketch from Anthony Elder, that I adapted for my needs. It can be found here. Although this sketch does not have all the energy savings that can be made as shown in my parts 1-4, it is a good begin to test the ESP-NOW datatransfer.

We can see that the transfer only takes a tadd less than 300ms and part of that is not even the active connection. By removing the print statements it is possible to shave off another 40-50msec. So can we win some more energy savings here. Let’s see. It turns out that that the biggest time saver we can implement is to add WiFi.persistent( false ); right at the beginning of the Setup(). Once we do that we go from 300msec to 87msec.

That addition is now already in the sendfile I linked to earlier. When you decide to take out the Serial.print statements, do not remove the Serial.println(bme280.begin(), HEX); statement as that one initializs the BME280. You could ofcourse replace that by a simple bme280.begin(); call

2 The receiver-basic
As there is much info already available on the web, there is no need to re-invent the wheel. I adapted a sketch from Anthony Elder to serve my needs and it can be found here. It simply receives the ESPNOW messages and printes them to the serial monitor. Obviously that is still not what we want as we want it to function as either an HTTP or MQTT gateway, but for now it will do to test if we can make the ESPNOW data transfer.

2 The receiver-MQTT
Of course just printing data to the serial monitor is not going to be of much use, so I was looking for a way to make an ESP-NOW to MQTT Gateway. As it happens, ‘Swiss guy’ Andreas Spiess had already done work on that and provided a sketch that I only had to adapt slightly.
As the present ESP-NOW sdk does not support simultaneous use of ESP-NOW and a wifi connection, the WiFi connection to the broker is now started a new when an ESP-NOW message is received. After a WiFi channel is used, the ESP-NOW protocol can only start when the same WiFi channel is used. As this comes with some limitations I for now have solved it by testarting the sketch every time an MQTT message is published.  Possibly there is another way that I have not tried yet and that is to define the receiver both as AP and STA and use different channels for each and use the AP for the ESP-NOW  and the STA for internet connection. Rui Santos from randomnerdtutorials gives an example of this for the ESP32 although that is just to have the receiving ESP32 to serve a webpage as well. Whether it will work for the ESP8266 to be an MQTT or HTTP client I cannot confirm it yet.

That of course is far from ideal and makes the gateway a bit slow, but it should not be a problem with ESP-NOW messages coming in that have a sensible sleeping period in between. Whether this reset is still necessary with the new sdk I need to check (when I have time)

3 The receiver HTTP
If you prefer an HTTP connection to upload the data to an SQL server (or Thinkspeak), that of course is possible as well. This sketch sends MQTT as well as HTTP.

4 Miscellaneous
There are a couple of functions important/needed to set up the ESP-NOW sender.
Of course we begin with calling the necessary library espnow.h.
Then we set up a data structure that we will send.
We initialize the protocol with esp_now_init().
We define the role with esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
We define the peer (slave) that we will be sending to with esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
and then we register the callback with esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus). The callback function returns whether the delivery was successful or not.
We finally send the data with esp_now_send(NULL, bs, sizeof(sensorData)); NULL means send to all peers (thats to say the ones we added)

The code for the ESP8266 starts with a bit of an awkward instruction:

extern "C" {
#include <espnow.h>

that is basically to instruct the compiler to expect C code rather than C++ code
ReceiveESPNOW and send through MQTT/HTTP code.

27 thoughts on “Very Deep Sleep and energy saving on ESP8266 – Part 5: ESP-NOW and WiFi”

  1. I believe that if you use a non standard protocol that works only between ESP8266 with ESP-NOW other chips works well and get less power like the nRF24L01 or other chips that works on the other ISM bands, 915MHz, 868MHz and 433MHz (maybe using LoRa protocol). You have to add an MCU but the power consumption is much less.

    1. Thank you. Indeed there are various ways of connecting a sensor to a central server. I merely showed how you can do that with ESP-NOW.
      Yes that only works on esp and there is nothing wrong with that coz ESP’s is what i have and use.
      Yes you can use nRF24L01 and you need an microprocessor for that so why would the powerconsumption be lower. Sure, can use other chips as well and as you say you have to add an mcu so why would as if by definition the power consumption be less?
      I can also use bluetooth, or BLE, all possible, but the point is that i have been showing various ways of battery saving techniques while doing wireless transmission and here i showed how to do that with ESP-NOW. Should i write an article on how to do that with the RF24, no doubt someone may comment “why RF24, use ESP-NOW” or “NRF24L01 is a horrible chip, better use NRF52840”.
      ESP-NOW is a protocol that the esp offers and i show how to use it. All the deepsleep commands i give are also ESP proprietary. Not use those either?

      1. I mean that since ESP-NOW communicate only with others devices that use ESP-NOW, like NRF24L01 communicate only with others NRF24L01, the competition is on power consumption. since they use the same 2.4GHz band. NRF24L01 uses less power, you can power it using the 3.3V Arduino pin, about 50mA. Datasheet says 11.3mA TX at 0dBm output power, RX 13.5mA at 2Mbps, but it is average, there are still some peaks that require a cap on the power lines.
        Going to lower bands, power consumption is lower, most of battery operated remote sensor uses these bands.
        So it’s better to know the existence of ESP-NOW and you explained very well about it’s use and it’s limits.

        Instead it will be interesting to use ESP-NOW and WiFi in the same device, not at the same time as you wrote. So I hope that you will hate time to check, since I am curious about that.

      2. Yes i understood what you said. I combine esp now with wifi in my recent published sketch at the receive end in this very article we are commenting under. I also have sketch to combine at the send end that i might publish in a follow up

      3. I may owe you an apology is I might have misunderstood you after all. I was probably put on the wrong track by your first comment which I interpreted as ‘why did you write about ESP-NOW?” Anyways, I looked a bit in powerconsumption of the NRF24 and on idling down it seems almost negligible. It does need another processor and sadly the attiny95 does not have enough pins for the NRF24 plus a decent sensor, but Nick Gammon wrote an article on how to really power down a barebones atmega328. So it definietly a viable option that I have to try

      4. Actually I think it’s doable. The NRF uses SPI so 4 pins (MISO, MOSI, clock and CS), and ie a BME280 can use SPI too. That would only require an extra CS. Even if the Chip Enable pin is of the NRF is required, the ’85 can be fused into reusing the reset pin. It’s “tight”, but hey, that is the fun part no? One thing is certain. Either this or 433 would have insane battery life.
        Caveat: I did not check if the NRF+BME libraries fit.

      5. Interesting thought. In the meantime i did some checking on the atmega328 and that can be brought down to very low sleep current as well, but the 85 is more fun. I think though that the combo of libraries might be stretching it a bit. Will give it a try

      6. Sadly my BME only has I2C, but ofcourse I can use any other sensor if it is just to do proof of concept and a workable sketch. Still so many projects on my list. Byt this may need to get some priority

      7. I have been checking into the NRF24L01. The full connection uses 5 pins. Miso,Mosi,SCK,CSN,CE in which CSN is the chipselect and CE is needed for Receive and send operations.
        So that would still alow for a BME280 if you involve the RST pin.
        There is a 3 pin connect for the NRF in which the CSN signal is derived from the SCK and the CE permanently tied to Vcc that limits some low grade functionality, but does not seem to matter much.
        The only thing I can find on I2C and NRF24L01 involves an extra board to do that, so from an energy point of view that might not be a great idea.
        My guess is that the 3 pin interface may not work well with another SPI chip in place, but it might be worth a try (or use a totally different sensor)
        As far as space goes, I will need to see. What I do know is that the Adafruit BME280 library is very inefficient, both in operation time needed as well as in code space needed.
        I will need to compare with the Sparkfun library that I think is smaller, or I will need to ‘rewrite’ one of the libraries to throw out anything unnecessary.
        The ‘3 pin’ solution requires adaptation of the library anyway to change timings.
        Having said that: the bare Atmega328 chip can be powered down substantially as well. According to nick: “Under the right circumstances you can get to around 0.35 uA (350 nA)”. The ATmega328 datasheet says 0.1µA in Power-Down mode.
        The Attiny85 should be able to get to 0.2uA and possibly less.
        The Atmega328 and Attiny85 have a max sleeptime of I think 8 secs when using the watchdogtimer, so for longer times one would need to set some sort of counter in EEPROM and immediately go back to sleep again when the desired time (say 4 hrs) is not reached yet
        only thing I need is ‘time’ to do it all

      8. You are completely right, no I2C on the NRF. Brain fart. I would indeed not convert it.
        There is an ATTiny with more pins (45? I forgot) between tiny and mega but then again, if using a pro-mini you can get indeed really long life for pennies. Remember my star pointer? It runs for months on end on a single 18650 and that is driving two stepper motors throughout the day.

        But then again, if just BME fits in the ’85, a 433 transmitter would probably be unbeatable in both cost, size, battery life, built-fun (super small!) and avoiding the extra gateway needed (for me).

      9. It still might be an interesting project but i think I’ll start with 85 on 433. I have that working long time already so only need to put the sleepcode in it.
        The 45 also only has 5(6) pins. You probably think of the 2313 and 4313. But in that case might as well use a 328. the ProMini does not even have that many extra components.

  2. I standardized on WiFi as much as possible, having an MQTT backbone and tons of Tasmota devices. But indeed battery life is not great for sensors. If I would change that I indeed would use either the fantastic NRF chips with probably an ATTINY85 (assuming that fits), or 433 MHz with again an ATTINY85. Why the (bleep) the latter? Because I already have a Tasmota running gateway on SonOff’s incredible gateway hardware. And why that again you ask? Because nothing beats that in terms in price, looks and battery life (of the commercial remotes), and immediate performance for light switching. I am gravitating towards the latter, however I dislike the crudeness of 433. But I bet I can improve battery life from under 2 months to more than a year with no change in infrastructure.

    1. You could be on to something. As i recall the attiny does 200uA when in sleep, which is a bit more than the esp8266, but the connection is faster, eventhough esp-now isnt bad at 87msec.
      Sadly 433Mhz has gotten a bit of a bad wrap, but even decent crystal based tx/rx pairs cost peanuts.
      433MHz also one of the frequencies LORA is using, but of course then you are not talking cheap anymore.
      NRF chips are definitely a pretty good choice but it can be a bit hit and miss on getting a proper one. I have seen people claim 100 meters whereas others couldnt bridge a meter. I have a good pair and one bad pair.
      I was tempted already to do a comparison between an ESP and an NRF, but doing a 433 Tx on an attiny might be interesting too. For an easier comparison should all be on one type of battery.
      Ofcourse i could just measure but my dmm is just too crude for that.
      So it probably would need to be a field test of some sort.

      1. Make that sub 1uA if you really try. I seem to remember running mine down to 8uA and by then it really competed with self-discharge 😮

      2. I am sure it can. It has been a while since i worked with an 85 so i was quoting something from the top of my head

      3. It seems 5uA should be possible without too much effort. Sub 1uA would be a challenge but would definitely be interesting. I have to brush off my 85s and give it a try

      4. I have to apologize too, english is not my mother tongue (it is italian, by the way), I usually write and read scientific papers or technical papers so I wrote in a way that you misunderstood my intention 🙂

        Take a look also to RFM69 and HC12 modules. Maybe some other Nordic chips but I didn’t know them.

        About the range a good antenna is useful too.

        Take a look also to SDR radio scanners based on a cheap USB TV-DVB dongle, SDRsharp and rtl_433 for troubleshooting.

      5. Non c’è bisogno di scusarsi.
        Il tuo inglese è migliore del mio italiano.
        Riguardante un’antenna. Ho scritto un articolo su un’antenna a bobina, particolarmente adatta a 433 MHz
        Ho l’RFM69, lo proverò anch’io. Quando avrò tempo

  3. Hi just came across this article as it was exactly what I was looking for.

    I wanted multiple sensors around the house that would use the ESP-NOW protocol to send to a main receiver station, I have a combination of DS18B20 sensors and BME280s, all of that worked great, but I wanted a way to get that data to the Internet and this article has helped fantastically.

    But I wanted to use Blynk not mqtt, so I managed to mid the code and get it working, at least with one sensor so far.

    My question is, once data has been sent to the Internet the ESP8266 device actually does a full reset, is there any way to stop this or is this the current solution to use one device to receive the data packets from sensors and to send to the Internet?

    Also this constant restarting, is it going to damage the ESP8266?

    Cheers and thanks in advance Alan

    1. Hi Alan. I am glad the article was of use to you. With regard to the reset, sadly that is currently a necessity as with the current version of the core it is not possible to to restart the “NOW’ connection after the wifi connection. This may well change in a core upgrade. The ESP will not suffer from Resets.

      1. Fred, that’s very interesting. Apparently it’s a matter of using the same WiFi channel. Ofcourse that comes with different limitations but is is worth checking out

  4. Hi, thank you very much on this very good articles about ESP8266 low power considerations!!
    Related to the Atmel/NRF discussion I find using Atiny85 or Atiny84A usually a little bit more complicated and if you want them in DIP packages they are also quite expensive for what they offer. Of course if you need the form factor, they are still a good choice.
    I usually use Arduino Mini Pro, 3.3V which you can get for as low as 1.5$. If you remove the power-on LED and the regulator the board will consume 21.1uA in SLEEP_MODE_PWR_DOWN. If you disable the watchdog you gain 4uA and disabling the brownout detector will save 17uA, leaving you with very good 0.1uA in sleep. This can be done in SW.
    I usually burn the fuses to disable the watchdog and also set the frequency to 1MHZ. This is usually fast enough for me and allows save operation down to 1.8V.
    List fuses: avrdude -c usbasp -p m328p -U lfuse:r:low_fuse_val.hex:h -U hfuse:r:high_fuse_val.hex:h -U efuse:r:ext_fuse_val.hex:h
    1MHZ: avrdude -c usbasp -p m328p -U lfuse:w:0x7b:m
    Brownout detector off: avrdude -c usbasp -p m328p -U efuse:w:0xff:m
    If you have an external event like button press, or sensor you can run this board with 0.1uA on a lithium button cell for a very long time. If you need time triggered wakeup you need to use the watchdog with 4.1uA and a short wakeup every 8s.
    If you want to avoid burning of fuses you can use sleep_bod_disable(). Please make sure you supply at least 2.7V as you will always wakeup with 8MHz clock speed. I.e. you cannot savely use all the capacity from a lithium cell.

    1. I totally totally agree with you. I love the attiny 13 25 45 85’s but especially the x5’s too expensive. Has been my mantra that for a few dimes more you have a pro mini. I still have some projects on my plate but am looking into real low power for arduino. The 1.8 Volt may be a bit marginal for peripherals such as a 433MHz transmitter or a 24L01 (1.9volt) though, but 2 Volt should be OK for the 24L01. Choice of sensors will be limited. DHT’s dont work at 2 volt. Wonder what the reach will be at that level

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.