Skip to content

Commit 7e94e16

Browse files
authored
Merge pull request #70 from michalpokusa/asyncio-examples
Examples of using `adafruit_httpserver` with `asyncio`
2 parents ed41a3f + 600a692 commit 7e94e16

File tree

4 files changed

+117
-19
lines changed

4 files changed

+117
-19
lines changed

docs/examples.rst

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ a running total of the last 10 samples.
8888
:emphasize-lines: 29,38
8989
:linenos:
9090

91+
92+
If you need to perform some action periodically, or there are multiple tasks that need to be done,
93+
it might be better to use ``asyncio`` module to handle them, which makes it really easy to add new tasks
94+
without needing to manually manage the timing of each task.
95+
96+
``asyncio`` **is not included in CircuitPython by default, it has to be installed separately.**
97+
98+
.. literalinclude:: ../examples/httpserver_start_and_poll_asyncio.py
99+
:caption: examples/httpserver_start_and_poll_asyncio.py
100+
:emphasize-lines: 5,33,42,45,50,55-62
101+
:linenos:
102+
91103
Server with MDNS
92104
----------------
93105

@@ -315,12 +327,15 @@ the client and the server.
315327
Remember, that because Websockets also receive data, you have to explicitly call ``.receive()`` on the ``Websocket`` object to get the message.
316328
This is anologous to calling ``.poll()`` on the ``Server`` object.
317329

330+
The following example uses ``asyncio``, which has to be installed separately. It is not necessary to use ``asyncio`` to use Websockets,
331+
but it is recommended as it makes it easier to handle multiple tasks. It can be used in any of the examples, but here it is particularly useful.
332+
318333
**Because of the limited number of concurrently open sockets, it is not possible to process more than one Websocket response at the same time.
319334
This might change in the future, but for now, it is recommended to use Websocket only with one client at a time.**
320335

321336
.. literalinclude:: ../examples/httpserver_websocket.py
322337
:caption: examples/httpserver_websocket.py
323-
:emphasize-lines: 12,21,67-73,83,90
338+
:emphasize-lines: 12,20,65-72,88,99
324339
:linenos:
325340

326341
Multiple servers

examples/httpserver_sse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: 2023 Dan Halbert for Adafruit Industries
1+
# SPDX-FileCopyrightText: 2023 Michał Pokusa
22
#
33
# SPDX-License-Identifier: Unlicense
44

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# SPDX-FileCopyrightText: 2023 Michał Pokusa
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
from asyncio import create_task, gather, run, sleep as async_sleep
6+
import socketpool
7+
import wifi
8+
9+
from adafruit_httpserver import (
10+
Server,
11+
REQUEST_HANDLED_RESPONSE_SENT,
12+
Request,
13+
FileResponse,
14+
)
15+
16+
17+
pool = socketpool.SocketPool(wifi.radio)
18+
server = Server(pool, "/static", debug=True)
19+
20+
21+
@server.route("/")
22+
def base(request: Request):
23+
"""
24+
Serve the default index.html file.
25+
"""
26+
return FileResponse(request, "index.html")
27+
28+
29+
# Start the server.
30+
server.start(str(wifi.radio.ipv4_address))
31+
32+
33+
async def handle_http_requests():
34+
while True:
35+
# Process any waiting requests
36+
pool_result = server.poll()
37+
38+
if pool_result == REQUEST_HANDLED_RESPONSE_SENT:
39+
# Do something only after handling a request
40+
pass
41+
42+
await async_sleep(0)
43+
44+
45+
async def do_something_useful():
46+
while True:
47+
# Do something useful in this section,
48+
# for example read a sensor and capture an average,
49+
# or a running total of the last 10 samples
50+
await async_sleep(1)
51+
52+
# If you want you can stop the server by calling server.stop() anywhere in your code
53+
54+
55+
async def main():
56+
await gather(
57+
create_task(handle_http_requests()),
58+
create_task(do_something_useful()),
59+
)
60+
61+
62+
run(main())

examples/httpserver_websocket.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# SPDX-FileCopyrightText: 2023 Dan Halbert for Adafruit Industries
1+
# SPDX-FileCopyrightText: 2023 Michał Pokusa
22
#
33
# SPDX-License-Identifier: Unlicense
44

5-
from time import monotonic
5+
from asyncio import create_task, gather, run, sleep as async_sleep
66
import board
77
import microcontroller
88
import neopixel
@@ -17,9 +17,7 @@
1717

1818
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
1919

20-
2120
websocket: Websocket = None
22-
next_message_time = monotonic()
2321

2422
HTML_TEMPLATE = """
2523
<html lang="en">
@@ -75,17 +73,40 @@ def connect_client(request: Request):
7573

7674

7775
server.start(str(wifi.radio.ipv4_address))
78-
while True:
79-
server.poll()
8076

81-
# Check for incoming messages from client
82-
if websocket is not None:
83-
if (data := websocket.receive(True)) is not None:
84-
r, g, b = int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)
85-
pixel.fill((r, g, b))
86-
87-
# Send a message every second
88-
if websocket is not None and next_message_time < monotonic():
89-
cpu_temp = round(microcontroller.cpu.temperature, 2)
90-
websocket.send_message(str(cpu_temp))
91-
next_message_time = monotonic() + 1
77+
78+
async def handle_http_requests():
79+
while True:
80+
server.poll()
81+
82+
await async_sleep(0)
83+
84+
85+
async def handle_websocket_requests():
86+
while True:
87+
if websocket is not None:
88+
if (data := websocket.receive(fail_silently=True)) is not None:
89+
r, g, b = int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)
90+
pixel.fill((r, g, b))
91+
92+
await async_sleep(0)
93+
94+
95+
async def send_websocket_messages():
96+
while True:
97+
if websocket is not None:
98+
cpu_temp = round(microcontroller.cpu.temperature, 2)
99+
websocket.send_message(str(cpu_temp), fail_silently=True)
100+
101+
await async_sleep(1)
102+
103+
104+
async def main():
105+
await gather(
106+
create_task(handle_http_requests()),
107+
create_task(handle_websocket_requests()),
108+
create_task(send_websocket_messages()),
109+
)
110+
111+
112+
run(main())

0 commit comments

Comments
 (0)