Skip to content

Commit a1b9aa9

Browse files
glenn20dpgeorge
authored andcommitted
aioespnow: Add library providing asyncio support for espnow module.
This module provides asyncio support for the espnow module on ESP32 and ESP8266 ports.
1 parent c113611 commit a1b9aa9

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

micropython/aioespnow/README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# `aioespnow`
2+
3+
A supplementary module which extends the micropython `espnow` module to provide
4+
`asyncio` support.
5+
6+
- Asyncio support is available on all ESP32 targets as well as those ESP8266
7+
boards which include the `uasyncio` module (ie. ESP8266 devices with at least
8+
2MB flash storage).
9+
10+
## API reference
11+
12+
- class `AIOESPNow()`: inherits all the methods of the `ESPNow` class and
13+
extends the interface with the following async methods:
14+
15+
- `async AIOESPNow.arecv()`
16+
17+
Asyncio support for ESPNow.recv(). Note that this method does not take a
18+
timeout value as argument.
19+
20+
- `async AIOESPNow.airecv()`
21+
22+
Asyncio support for ESPNow.irecv(). Use this method to reduce memory
23+
fragmentation, as it will reuse common storage for each new message
24+
received, whereas the `arecv()` method will allocate new memory for every
25+
message received.
26+
27+
- `async AIOESPNow.asend(mac, msg, sync=True)`
28+
- `async AIOESPNow.asend(msg)`
29+
30+
Asyncio support for ESPNow.send().
31+
32+
- `__aiter__()/async __anext__()`
33+
34+
AIOESPNow also supports reading incoming messages by asynchronous
35+
iteration using `async for`, eg:
36+
37+
```python
38+
e = AIOESPNow()
39+
e.active(True)
40+
async def recv_till_halt(e):
41+
async for mac, msg in e:
42+
print(mac, msg)
43+
if msg == b'halt':
44+
break
45+
asyncio.run(recv_till_halt(e))
46+
```
47+
48+
## Example Usage
49+
50+
A small async server example::
51+
52+
```python
53+
import network
54+
import aioespnow
55+
import uasyncio as asyncio
56+
57+
# A WLAN interface must be active to send()/recv()
58+
network.WLAN(network.STA_IF).active(True)
59+
60+
e = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support
61+
e.active(True)
62+
peer = b'\xbb\xbb\xbb\xbb\xbb\xbb'
63+
e.add_peer(peer)
64+
65+
# Send a periodic ping to a peer
66+
async def heartbeat(e, peer, period=30):
67+
while True:
68+
if not await e.asend(peer, b'ping'):
69+
print("Heartbeat: peer not responding:", peer)
70+
else:
71+
print("Heartbeat: ping", peer)
72+
await asyncio.sleep(period)
73+
74+
# Echo any received messages back to the sender
75+
async def echo_server(e):
76+
async for mac, msg in e:
77+
print("Echo:", msg)
78+
try:
79+
await e.asend(mac, msg)
80+
except OSError as err:
81+
if len(err.args) > 1 and err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND':
82+
e.add_peer(mac)
83+
await e.asend(mac, msg)
84+
85+
async def main(e, peer, timeout, period):
86+
asyncio.create_task(heartbeat(e, peer, period))
87+
asyncio.create_task(echo_server(e))
88+
await asyncio.sleep(timeout)
89+
90+
asyncio.run(main(e, peer, 120, 10))
91+
```

micropython/aioespnow/aioespnow.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# aioespnow module for MicroPython on ESP32 and ESP8266
2+
# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20
3+
4+
import uasyncio as asyncio
5+
import espnow
6+
7+
8+
# Modelled on the uasyncio.Stream class (extmod/stream/stream.py)
9+
# NOTE: Relies on internal implementation of uasyncio.core (_io_queue)
10+
class AIOESPNow(espnow.ESPNow):
11+
# Read one ESPNow message
12+
async def arecv(self):
13+
yield asyncio.core._io_queue.queue_read(self)
14+
return self.recv(0) # type: ignore
15+
16+
async def airecv(self):
17+
yield asyncio.core._io_queue.queue_read(self)
18+
return self.irecv(0) # type: ignore
19+
20+
async def asend(self, mac, msg=None, sync=None):
21+
if msg is None:
22+
msg, mac = mac, None # If msg is None: swap mac and msg
23+
yield asyncio.core._io_queue.queue_write(self)
24+
return self.send(mac, msg, sync) # type: ignore
25+
26+
# "async for" support
27+
def __aiter__(self):
28+
return self
29+
30+
async def __anext__(self):
31+
return await self.airecv()

micropython/aioespnow/manifest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
metadata(
2+
description="Extends the micropython espnow module with methods to support asyncio.",
3+
version="0.1",
4+
)
5+
6+
module("aioespnow.py")

0 commit comments

Comments
 (0)