Replies: 14 comments 44 replies
-
Missing aioespnow and WLAN.config(pm=XX)Now that PR #6515 has been merged into micropython master, the The precompiled images at https://github.com/glenn20/micropython-espnow-images included the |
Beta Was this translation helpful? Give feedback.
-
I've discovered ESPNow only since it was committed to master branch here in the last few days. I have set up a few devices with it and have the following minor(?) comments/suggestions.
|
Beta Was this translation helpful? Give feedback.
-
Another useful resource that you could link to is: Excellent work getting ESPNow into the "main" images. |
Beta Was this translation helpful? Give feedback.
-
Seeing as ESPNow is supported for two platforms I wondered if a new category called: |
Beta Was this translation helpful? Give feedback.
-
Hi, I want to make some changes based on the routine at the beginning of the document, so that the receiver receives the message and sends a message back to the sender, the code is as follows, it can run, the receiver can receive the message, but the sender can not get the message it sends back. sender: import network
import espnow
import wifi
# A WLAN interface must be active to send()/recv()
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.disconnect() # Because ESP8266 auto-connects to last Access Point
wifi.status()
e = espnow.ESPNow()
e.active(True)
peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface
e.add_peer(peer) # Must add_peer() before send()
e.send(peer, "Starting...")
for i in range(100):
e.send(peer, str(i)*20, True)
e.send(peer, b'end')
while True:
host, msg = e.recv()
if msg: # msg == None if timeout in recv()
print(host, msg)
break receiver: import network
import espnow
import wifi
# A WLAN interface must be active to send()/recv()
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.disconnect() # Because ESP8266 auto-connects to last Access Point
wifi.status()
e = espnow.ESPNow()
e.active(True)
# peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface
# e.add_peer(peer) # Must add_peer() before send()
while True:
host, msg = e.recv()
if msg: # msg == None if timeout in recv()
print(host, msg)
if msg == b'end':
try:
e.add_peer(host)
except OSError:
pass
sended = e.send(host, "All received.")
print(sended) |
Beta Was this translation helpful? Give feedback.
-
@glenn20 FYI, I found an odd issue using aioespnow but I think it is a MP bug so have raised a bug there. |
Beta Was this translation helpful? Give feedback.
-
I express my gratitude to @glenn20 and @bulletmark for their previous assistance. import network
import aioespnow
import asyncio
import binascii
# A WLAN interface must be active to send()/recv()
sta = network.WLAN(network.STA_IF)
sta.active(True)
mac = binascii.hexlify(sta.config('mac'),":").decode()
print("Current_MAC:", mac) # Print current device's Mac Address
sta.config(channel=3)
print("Current_Channel:", sta.config('channel'))
e = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support
e.active(True)
peer = b'\xbb\xbb\xbb\xbb\xbb\xbb'
e.add_peer(peer)
# Send a periodic ping to a peer
async def heartbeat(e, peer, period=30):
while True:
resp = await e.asend(peer, b'ping',sync=False)
if not resp:
print("Heartbeat: peer not responding:", peer)
else:
print(resp)
print("Heartbeat: ping", peer)
await asyncio.sleep(period)
# Echo any received messages back to the sender
async def echo_server(e):
i = 0
async for mac, msg in e:
i += 1
print(mac)
mac_decode = binascii.hexlify(mac,":").decode()
print(mac_decode, "Echo:", msg.decode(), i)
try:
await e.asend(mac, msg)
except OSError as err:
if len(err.args) > 1 and err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND':
e.add_peer(mac)
print("add mac:",binascii.hexlify(mac,":").decode())
await e.asend(mac, msg)
async def main(e, peer, timeout, period):
# asyncio.create_task(heartbeat(e, peer, period))
# asyncio.create_task(echo_server(e))
# await asyncio.sleep(timeout)
tasks = [heartbeat(e, peer, period),echo_server(e)]
await asyncio.gather(*tasks)
asyncio.run(main(e, peer, 20, 1)) I mainly made three modifications:
mac = binascii.hexlify(sta.config('mac'),":").decode()
print("Current_MAC:", mac) # Print current device's Mac Address
sta.config(channel=3)
print("Current_Channel:", sta.config('channel'))
import binascii
async def echo_server(e):
i = 0
async for mac, msg in e:
i += 1
mac_decode = binascii.hexlify(mac, ":").decode()
print(f"Iteration {i}: Received from MAC {mac_decode} - Echo: {msg.decode()}")
async def main(e, peer, timeout, period):
# asyncio.create_task(heartbeat(e, peer, period))
# asyncio.create_task(echo_server(e))
# await asyncio.sleep(timeout)
tasks = [heartbeat(e, peer, period), echo_server(e)]
await asyncio.gather(*tasks) I have these questions I'd like to ask.
|
Beta Was this translation helpful? Give feedback.
-
This is a popular idiom in python, I have defined the
Though I haven't tried it on micropython, you should be able to use await asyncio.wait_for(ayncio.gather(*tasks), timeout=30) If the gather does not complete in 30 seconds, all the incomplete tasks and the gather are cancelled and an |
Beta Was this translation helpful? Give feedback.
-
@glenn20 , you are the expert who integrated ESP-Now into MP. Have you or anybody else considered integrating ESP-Wifi-Mesh? Unfortunately, from what I can tell, Espressif seems to have created ESP-Wifi-Mesh completely distinct and independent to ESP-Now. |
Beta Was this translation helpful? Give feedback.
-
So I am not sure if this is still true 2y later, but if I'm in the wrong place please redirect me. First a documentation suggestion: in the description of how to make a receive callback you show a problematic way of implementing it. I think an example like this might be better: from micropython import schedule
...
RECV_BUFFER = [None, bytearray(250)]
def recv_cb(e):
global RECV_BUFFER
while True:
n = e.recvinto(RECV_BUFFER, 0)
if n == 0:
return
mac, msg = RECV_BUFFER
if mac is None:
return
schedule(handle_message, (mac, msg, n))
try:
schedule(recv_cb, e)
return
except:
# if the network is less important than other tasks
# you are scheduling, return instead.
pass
e.irq(recv_cb) This example would ideally replace the smaller sample at https://docs.micropython.org/en/latest/library/espnow.html#espnow.ESPNow.irq ... the main caveat with it being do you really want to hog the schedule when the schedule queue is already full? This leads to a possible API issue: Finally, a feature request that I have no idea how hard it is. Now that ESP.Now v2 supports up to 6 vendor specific frames, it'd be excellent if on devices that support this I could pass a 1500 byte array in RECV_BUFFER to receive these larger messages (and of course, also allow sending them). Is that on your radar at all? The per-message overhead seems very high in my mesh network code and having fewer messages would be a godsend. Thanks for your time/consideration. |
Beta Was this translation helpful? Give feedback.
-
Well now you have me doubting myself so I will have to dig in and reproduce again. My code didn't exactly match yours and I'm afraid I probably never committed the non-working state, but I'll see if I can write a specific example that exhibits the problem. I was definitely getting receive buffers of length 250 when the messages were shorter, but I was likely passing in the buffer, not calling |
Beta Was this translation helpful? Give feedback.
-
Unfortunately I did not in fact commit the code that demonstrated the 'problem'. But inspecting the C code that implements
In my current code I have a ring buffer of buffers so the problem of processing multiple input packets simultaneously won't exist, but in the code at that time I was probably missing any notion of doing the buffer management myself, imagining that each call to Possibly it would be less error prone to add the code that sets the message length correctly in both return paths instead of setting the length to the full size when no data are read. There's a better chance the reader of the stale buffer would realize that the data were truncated than that they'd realize they're processing stale data with a length that is too long, making it easier to recognize the bug of continuing to process the shared buffer when it's been invalidated by a subsequent call. |
Beta Was this translation helpful? Give feedback.
-
In fact, the code with the bug is probably the ancestor of the proposed documentation example above! It originally wouldn't have had the try/catch at the bottom and called I still think it would be a small improvement to truncate the buffer when an empty read happens. |
Beta Was this translation helpful? Give feedback.
-
Can you clarify what you meant by "static scheduler nodes added a few years ago" in a comment above? I am trying to clean up my scheduling code and can't seem to find what you mean, nor a really satisfactory way to work well with micropython to build a reasonable scheduling approach. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I am posting this as a place holder for general discussions or questions for new or old users of the micropython
espnow
module.In particular, any questions or suggestions on documentation, usage or api are sought and welcome here.
Of course, if you have any specifc Issues to post or proposed changes, you can post Issues and Pull Requests to the micropython repo.
Resources:
espnow
module is also available in micropython nightly builds: https://micropython.org/download/.Beta Was this translation helpful? Give feedback.
All reactions