esp32: ESP-NOW support for ESP32 and ESP8266 #6515
Conversation
Thanks Glenn! I'll do some testing when I get a chance! |
Has this been addressed?
|
Thanks for bringing this up again - it fell off my radar.
I confess I've had no more success than any others in divining the mysteries behind the espressif docs. I think I am doing just what the docs recommend - handing data off to a queue (ring buffer) from the callback functions (I think of them as ISRs). The ring buffer is thread safe so long as only one producer is pushing new data onto the head of the buffer (recv_cb() and send_cb() - which execute in the "high-priority Wifi Task") and only one consumer (callback_wrapper()) is pulling data off the tail of the ring buffer. So, I don't believe it matters which CPU they are being executed on - so long as recv_cb() is never pre-empted by another recv_cb() (on the same or another CPU) and callback_wrapper() is never pre-empted by another callback_wrapper(). I am interested to understand better the concerns around the mp_sched_schedule vulnerability to Pro CPU invocations. If there is some further protection required I'd welcome any guidance. I'm keen to make this as robust as possible. EDIT: I've done some small sustained transfer tests and haven't seen any buffer corruption yet - but that's no guarantee. |
Tried to use espnow, using the documentation docs/library/espnow.rst. I can't init espnow, what argument is it expecting? see code below.
|
Hi Feiko, Thanks for testing. ESPNow is a Class, you need to invoke a class instance first before calling the init() method. The errors is less than useful - I admit. Typical usage (I'll put a short code snippet at the start of the docs in the next commit).
Furthermore, you need to initialise a WLAN interface before calling init() or your ESP32 may reset (on the todo list): eg.
Additionally, you need to invoke |
Thanks Glenn20, Of course! That did the trick. My Python is a bit rusty. A short code snippet would be very welcome. |
@tve: I've done a little empirical testing, but I'm not sure if they are valid in micropython. Using xPortGetCoreID() I tested the coreid for
I was a little surprised because I thought the micropython thread ran on coreid=1 (but I'm not sure why I had acquired that assumption). Is it possible that xPortGetCoreID() does not report correctly (eg. not initialised under micropython)? Let me know if there are any specific effects I should be protecting against. |
Ok - I've just checked and discovered that arising from #5489 micropython recently switched to pin everything to core 0, so the results of my test were not as unexpected as I thought. |
Code looks good to me! |
Thanks @tve,
Actually, I am in the midst of a significant rewrite to remove the
dependence on mp_sched_schedule to schedule callback functions. I have come
to realise the fragility this introduces, and for these purposes it is not
necessary now that we have a buffering solution.
I've also implemented asyncio and stream support (like uart). I'll post a
new commit within 24 hours. It is a pretty substantial change. I understand
that it is not ideal to make significant changes against a PR, but I do
think it will be a much more robust solution.
…On Sun, 11 Oct 2020 at 15:55, Thorsten von Eicken ***@***.***> wrote:
Let me know if there are any specific effects I should be protecting
against.
Code looks good to me!
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#6515 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABVEQRYPXQYQFXLUT5Y6GOTSKE3DBANCNFSM4SDXWCEA>
.
|
Is possible to do a like wlan.scan() to get all APs MAC and their signal? Thank you. |
@beyonlo
By default, espnow devices respond to acknowledge receipt of packets, so it
would be straightforward to scan status of a local network of known Mac
addresses, but not to scan for unknown devices - as far as I am aware.
I'm not aware of any location based uses of espnow, but it might be an
interesting experiment to see if a network of fixed esp32s could be used
for location with rssi or round trip location. The max peer count might be
a limitation.
Cheers,
Glenn.
…On Fri, 16 Oct 2020, 5:15 am beyonlo, ***@***.***> wrote:
@glenn20 <https://github.com/glenn20>
Is possible to do a like wlan.scan() to get all APs MAC and their signal?
Actually, I'm working (ESP32) with wlan.scan() to get location-based on
fixed APs. How is possible to do that with ESPNOW?
Thank you.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#6515 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABVEQR64EEEPGUITZNQZHVDSK432LANCNFSM4SDXWCEA>
.
|
Actually - scrap that. A little further checking and I see that ToF is not
supported in IDF (though there are hints that the hardware may be capable).
People seem to be more optimistic that the ESP32-S2 may get 802.11mc
support at some point in the future.
…On Fri, 16 Oct 2020 at 07:51, Glenn Moloney ***@***.***> wrote:
@beyonlo
By default, espnow devices respond to acknowledge receipt of packets, so
it would be straightforward to scan status of a local network of known Mac
addresses, but not to scan for unknown devices - as far as I am aware.
I'm not aware of any location based uses of espnow, but it might be an
interesting experiment to see if a network of fixed esp32s could be used
for location with rssi or round trip location. The max peer count might be
a limitation.
Cheers,
Glenn.
On Fri, 16 Oct 2020, 5:15 am beyonlo, ***@***.***> wrote:
> @glenn20 <https://github.com/glenn20>
>
> Is possible to do a like wlan.scan() to get all APs MAC and their signal?
> Actually, I'm working (ESP32) with wlan.scan() to get location-based on
> fixed APs. How is possible to do that with ESPNOW?
>
> Thank you.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#6515 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ABVEQR64EEEPGUITZNQZHVDSK432LANCNFSM4SDXWCEA>
> .
>
|
Progress on ESPNow from #4115. Initial import of code from: https://github.com/nickzoic/micropython/tree/espnow-4115. Including contributions from @nickzoic @shawwwn and @zoland.
As flagged, a substantial rewrite with breaking changes. Apologies for the delay - shoulder injury slowed me down for a while and I spent some time faffing about with various approaches to supporting more reliable IO, allocation-free reads and asyncio support. Learnt a lot more about micropython internals. I know that a substantial change of direction in a pull request is less than ideal, but I do believe the new approach warrants the change. I'm happy to take on board feedback. I will say that I get more reliable and faster data transfers with the new approach. Breaking Changes
Also a substantial internal rewrite to better consolidate the buffer and data packet logic. |
Update for: - v1.13+ compatible - Ring buffers in esp32/ringbuffer.[ch] for robust IO. - Allocate the ESPNow singleton dynamically (protect bufs from gc). Remove: - on_recv() and on_send(): use of "sched" callbacks is unnecessary in this use case and just adds fragility. New methods: - recv() to read incoming messages (instead of callbacks). - irecv() for allocation-free read of incoming messages. - Stream IO support: read(), write() and poll through ioctl(). This can be used to support asyncio use of espnow. - Also added read1() and readinto1(). - Add support for iteration on ESPNow object for alloc-free read. - config(): set tx and rx buf sizes and read timeout - stats(): Returns transfer stats: (tx_packets, tx_packet_responses, rx_packets, lost_rx_packets). - get_peer(mac): Return peer info: (mac,lmk,channel,ifidx,encrypt) - mod_peer(mac, ...) to change peer info parameters. - get_peers(): to return all peer info tuples. Deleted: - espnow_lmk() which is subsumed by mod_peer(). Implementation changes: - send(): Remove automatic changes to ifidx parameter for peers. This is better managed in the app layer since we now provide access to the peer parameters. - Use the new consolidated check_esp_err(0 for exception Add new constants as attributes of the ESPNow object: - MAX_DATA_LEN (=ESP_NOW_MAX_DATA_LEN) (250) - KEY_LEN (=ESP_NOW_KEY_LEN) (16) - MAX_TOTAL_PEER_NUM (=ESP_NOW_MAX_TOTAL_PEER_NUM) (20) - MAX_ENCRYPT_PEER_NUM (=ESP_NOW_MAX_ENCRYPT_PEER_NUM) (6) docs/library/espnow.rst: Add docs for ESPNow module. esp8266/espnow: Revert broken espnow changes from 4115 to esp8266 port
Ok - I've squashed the commits to just two: original import from PR#4115 and my current HEAD. I believe this is ready for review. It is working well for me but happy to hear from others. |
Kudos for the uasyncio support |
Thanks Peter - and thanks for all your great work on uasyncio and the
magnificent support resources.... :)
…On Mon, 19 Oct 2020 at 21:48, Peter Hinch ***@***.***> wrote:
Kudos for the uasyncio support
|
For those interested, I now have a heavily pared down version of the esp32 espnow support working on esp8266 available at: https://github.com/glenn20/micropython/tree/espnow-g20-8266. I am planning to make a separate PR for the esp8266 support after a little more testing, but I welcome any testers or users in the meantime. Does not support:
However, it does support:
With this build my compile builds to exactly the max .text size (32768 bytes) for the esp8266. |
Is there any indication when this will be merged and available for download as part of the main micropython binaries? |
Sorry for the slow response (been away on holiday for a few weeks). I don't really know how to get an eye on the process for getting PRs reviewed and merged. I'm just hoping it will be soon-ish. Any suggestions for prodding the decision makers are welcome :-). |
- No more ring buffer for sent packet responses. Just count transmission failures. - Alloc and init callee-owned tuple and bytearrays (for irecv()) in the ESPnow() constructor instead of on first call to irecv(). - Better comment coverage and fixups for new code - espnow_send(): Wait on send_timeout if ESPNOW internal buffer is full - Streamline some snippets of code - Update docs for latest changes. - Revert mod_peer(key=...) to mod_peer(lmk=...) for consistency with Espressif esp32 docs. - lmk *must* be 16 bytes long now. The aim is to be more explicit about security keys. _get_bytes_max_len() is no longer needed.
I have added some updates:
ESP32 and ESP8266 users can get their code from this one branch now. |
Pared down version of the esp32 espnow support. Supports sync and non-sync send()s and alloc-free buffered irecv() with optional timeout. - init([recv_bufsize]) - deinit() - irecv([timeout]) - send(peer, message, [sync]) - add_peer(peer[, lmk[, channel]]) - del_peer(peer) There is NO support for the stream IO functions or asyncio. This is pared down to fit in the .text segment for esp8266 (total textsize is exactly 32768 bytes in GENERIC_1M build). Conditional compile flag so espnow is not compiled for GENERIC_512K target (it is too big to include in standard build). (Also includes minor formatting fixes for esp32).
ESP-NOW is a proprietary wireless communication protocol which supports communication between ESP32 and ESP8266 devices. See: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
ESP-NOW would be of particular interest for low-power wireless communication requirements, such as battery-powered operations.
This PR is based on the previous work by @nickzoic, @shawwwn and contributions from @zoland, including:
This PR builds on the espnow-4115 branch by adding:
Draft API docs are provided in 3d4058b. See docs/library/espnow.rst.
This is working reliably for my purposes as a low-level ESPNow interface. Testers and proposed improvements are welcome.
Caveat
I have only implemented this for the esp32. I don't have any ESP8266 devices.
Further development
It would be useful to extend this interface with a more robust I/O interface (rather than relying on the send and recv callbacks which run in the sched context and easily overflow the sched stack). Some form of uasyncio would be interesting.
Comments, suggestion are welcome.