Closed beyonlo closed 1 year ago
A proper firmware update is sized at least 1.4MB
. An ideal approach can be prefixing messages with their order number as an 'H' (unsigned short
) which will takes 2 bytes
. So considering that, we have 248 bytes
in each message which will leads us to something about 6K messages per each OTA
update. This can keep your esp32 awake for a long time.
If everything goes well (no packet loss, firmware update checksum match, no need to resend packets) update will be done successfully. But according to my personal experience in my projects, ESP-NOW
can consume much energy (about 80mA
on 3.3V
after initiated) which is not ideal for battery based systems if used improperly. I recommend to take a look at this issue on esp-idf project repository. The issue reveals that ESP-NOW
can be used in battery based environments only if gets deinitiated after sending each message (which cannot be done in OTA
over ESP-NOW
scenario).
Conclusion: OTA
over ESP-NOW
needs you to develope some mechanisms (such as packet ordering and corruption) which TCP
over WiFi
already has. So I guess sending OTA
update over WiFi
consumes less time and energy (both in development and execution). You can also play with PHY_RATE
of esp32 which can change power consumption, WiFi range, transfer rate.
Thanks @AmirHmZz. My own prior investigations came to much the same conclusions. For several reasons (overlapping with those made above):
It is possible that these limitations may be overcome by implementing more robust re-transmission operations when the receiving device is in MIN_MODEM power saving mode and implementing a retransmission protocol, but it is unlikely to provide any power advantages over update over wifi (happy to be proved wrong on this :-).
@tve did some prior work on OTA updates over MQTT which might be useful if you would like to investigate further (https://github.com/tve/mqboard).
@beyonlo - Thanks for raising this issue - it's very helpful for getting perspectives on the challenges. I'm happy to leave this issue open for some weeks or months in case it sparks some interesting ideas.
All right. Maybe for now to continue using the OTA
over WiFi
is the best option.
But according to my personal experience in my projects,
ESP-NOW
can consume much energy (about80mA
on3.3V
after initiated) which is not ideal for battery based systems if used improperly. I recommend to take a look at this issue on esp-idf project repository. The issue reveals thatESP-NOW
can be used in battery based environments only if gets deinitiated after sending each message (which cannot be done inOTA
overESP-NOW
scenario).
That's the point that I was as well looking for. How much is the low consumption using ESP-NOW.
Acordly with that issue:
"
But I have made good progress now, and found that the key is to de-initialize ESP-NOW at the transmitter side as soon as the message is sent. This cuts the consumption down to 21/28 mA (CPU at 80/160 MHz), measured on a barebone ESP32-WROOM module. I measured the total transmit duration (including initialization and de-initialization) to be 31-33 ms (mostly 32 ms).
"
@glenn20
Is possible to do that (de-initialize ESP-NOW at the transmitter side as soon as the message is sent
) on the MicroPython
as well?
If yes:
MicroPython?
Just to compare with that results aboved that was done directly in the esp-idf.
Maybe this is a bit off-topic with the OTA,
but I think that is the mostly important information about ESP-NOW
when used on battery applications. If you you want I can to open a new issue for this.
Thank you very much!
@beyonlo The main advantage of espnow for battery usage is that you can turn on the radio, send the message and turn off in much less time than it takes to turn on the radio, connect to an access point, send the message and shutdown the radio. ie. you get to avoid the time it takes to negotiate a connection with an access point. When the radio is on the power consumption rises dramatically (100s of mA - depending on setup).
The radio is turned on/off whenever you call network.WLAN().active(True/False)
.
- Could you to provide us an example?
A simple example for deepsleep would be (beware - this simple example will put your device into a deepsleep boot loop if you run it from main.py or boot.py without some additional logic):
import network, machine, espnow
peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer
sta = network.WLAN(network.STA_IF)
e = espnow.ESPNow()
e.active(True)
e.add_peer(peer) # Register peer on STA_IF
sta.active(true) # Turn on the radio
e.send(peer, b'ping')
sta.active(False) # Turn off the radio before sleep
e.active(False)
machine.deepsleep(10000) # Sleep for 10 seconds then reboot
and for lightsleep:
import network, machine, espnow
sta = network.WLAN(network.STA_IF)
peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer
e = espnow.ESPNow()
e.active(True)
e.add_peer(peer) # Register peer on STA_IF
while True:
sta.active(True) # Turn on the radio
e.send(peer, b'ping')
sta.active(False) # Disable the wifi before sleep
print('Going to sleep...')
machine.lightsleep(10000) # Sleep for 10 seconds
(Adapted from my docs on light/deep sleep).
- Did you tried to mensure how much is the consumption using the
MicroPython?
Just to compare with that results aboved that was done directly in theesp-idf.
I haven't done this yet as it is difficult to measure, but I have very recently purchased a Nordic Power Profiler Kit II device so I can optimise my sensor devices. When I get a chance, I'll post the results of my experiments.
Additional Notes:
e.send(peer, b'ping', False)
in the examples. In this case the device will not wait for acknowledge from the receiver and will not try to retransmit if there is no response._boot.py
frozen script when a DEEPSLEEP_RESET is detected. This lets your app run without even mounting the filesystem. I use this for a network of battery operated sensors which send messages to a powered espnow mqtt relay.
@glenn20 Thank you very much for the detailed explanation and examples. The Additional Notes is very useful!
Will be great when you will post the consumption results using the Nordic Power Profiler Kit II device :)
@beyonlo I have posted some of my experiments with my new Nordic Power Profiler Kit II at https://github.com/glenn20/upy-esp32-experiments.
This includes an investigation into:
There is also an investigation into using the ESP32 wake stubs. I am planning to develop these further to be more useful for micropython users.
I was a bit time constrained during these measurements, so they are not as systematic or consistent as I would prefer, but there are still some useful conclusions to be drawn. I welcome any comments, suggestions or requests via the Issues or Discussions tabs on that repo.
@glenn20 Sorry for the delay, there are many information in your experiments! Thank you very much to share that and for all that incridible optimizations that you did in MicroPython for speed, to use less energy. I would love to use MicroPython with just batteries for sensors aplications using ESPNOW!
Well, wake ESP32-S3 from deepsleep, boot micropython, Send ESPNOW message and return to deepsleep
use
10.7
microWh with time of 119ms
- that is very good to me. That report with C ESPNOW implementation do not report about the all process (wake, send message, go to deepsleep), it report just 31-33 ms of time to send message.
wake from deep sleep, send message and back to deepsleep
? Something like as MicroPython ~10.7
microWh and C ~5.3 microWh
.PRs
on the official MicroPython for all that optimizations that you did? Would be amazing!Well,
wake ESP32-S3 from deepsleep, boot micropython, Send ESPNOW message and return to deepsleep
use10.7
microWh with time of119ms
- that is very good to me.
Just to clarify - that measurement was done with an ESP32. I should have been clearer about which tests are with ESP32 and which with ESP32-S3 (For some tests I found it easier to code for ESP32 first - then port to the S3 as there were sometimes subtle differences).
That report with C ESPNOW implementation do not report about the all process (wake, send message, go to deepsleep), it report just 31-33 ms of time to send message.
Yes. They report only for the time that the ESPNow radio is on. According to my test, the Wifi radio is on for about 8ms - which is shorter than the 30ms claimed in the test above.
Two things to note:
- Could we suppose, even with all Micropython optimizations that you did, that MicroPython use ~100% more energy than that C implementation, to
wake from deep sleep, send message and back to deepsleep
? Something like as MicroPython~10.7
microWh and C~5.3 microWh
.
That conclusion would not be supported by the evidence ;-). My test shows 8ms vs. their measurement of 33ms for the time that the radio is turned on to send a message. Their report does not count wake from deepsleep time.
- Is possible to optimise still more to have in MicroPython near of energy use used in C Implementation, or you think that already is in the limits, with natural MicroPython limitation?
In fact, IF you freeze your app into the image (so it is not necessary to mount the filesystem on the flash) Micropython adds very little overhead to the boot time from deepsleep. It is completely dominated by the native ESP32 boot process. So, in this case there should be little difference between a micropython and a C implementation.
- Do you think to create
PRs
on the official MicroPython for all that optimizations that you did? Would be amazing!
I am thinking about that. The two biggest impacts are:
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
to ports/esp32/boards/sdkconfig.base
. I am guessing that it is unlikely this will be accepted in the micropython main due to the comments on the espressif docs page - but you never know :-).I am working on a PR to enable a runtime flag to enable some of the other savings on wake from deepsleep and also another PR to provide some wake_stubs code which would handle common use cases (such as count pulses on a pin/pins or wake at fixed time intervals and sample the state of input pins, etc.). Once I have draft PRs for those, I'll seek further input.
@beyonlo
- Is possible to optimise still more to have in MicroPython near of energy use used in C Implementation, or you think that already is in the limits, with natural MicroPython limitation?
I have found a few other recommendations for saving time in the bootloader during wake from deepsleep. I will try them when I get a chance (eg. disable UART output from the bootloader).
Hello @glenn20
- Could we suppose, even with all Micropython optimizations that you did, that MicroPython use ~100% more energy than that C implementation, to
wake from deep sleep, send message and back to deepsleep
? Something like as MicroPython~10.7
microWh and C~5.3 microWh
.That conclusion would not be supported by the evidence ;-). My test shows 8ms vs. their measurement of 33ms for the time that the radio is turned on to send a message. Their report does not count wake from deepsleep time.
Excellent!
- Is possible to optimise still more to have in MicroPython near of energy use used in C Implementation, or you think that already is in the limits, with natural MicroPython limitation?
In fact, IF you freeze your app into the image (so it is not necessary to mount the filesystem on the flash) Micropython adds very little overhead to the boot time from deepsleep. It is completely dominated by the native ESP32 boot process. So, in this case there should be little difference between a micropython and a C implementation.
All right. I think that this is not a problem. Who want to have very little overhead need to freeze the code into the image.
- Do you think to create
PRs
on the official MicroPython for all that optimizations that you did? Would be amazing!I am thinking about that. The two biggest impacts are:
- Freeze your app into the micropython image. You can do this now, but you have to compile your own image.
As I commented above, I think this will be just a condition - not a problem for a very specific scenario (power just for batteries)
- Add
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
toports/esp32/boards/sdkconfig.base
. I am guessing that it is unlikely this will be accepted in the micropython main due to the comments on the espressif docs page - but you never know :-).
Understood! But if we think that at some point the ESPNOW
PR
will need to merged to mainstream, this can be a condition as well :) Or maybe, if need to change so much, to have two MicroPython official firmwares, one for normal use, and other for ESPNOW
(power by batteries) :) But maybe to have two official firmwares is not a good idea!
Question: your tests use ESP32
and ESP32-S3,
both has two cores. Did you tried with ESP32-C3
or ESP32-S2
to check if the power consumption is lower? I assume that two cores use more energy than one core, right?
Great works! Thanks!
Hello @glenn20
As exposed here I would like to request if is a good idea to implement the
OTA
overESPNOW,
or if is better just to change the protocol, fromESPNOW
to regular WiFi, execute normalOTA
overWiFi
and whenOTA
is finished, back to works in theESPNOW
protocol. My fear is just about in applications that use just battery, where using theWiFi
can to be use so much energy at theOTA
overWiFi
process.Thank you!