Cableless Development with Micropython Server#
Ever tired of having to connect your microcontroller to your laptop with a cable? Wifi-able chips and remote servers come to the rescue.
I encountered this problem recently when I was building a robot car to prepare for the Scioly Robot Tour Event. This is why I hand-wrote a tiny http server based on Microdot to deal with this situation.
This server is capable of displaying the files stored on your microcontroller as well as updating them through an http POST request.
The following is the entire Python script for the server.
1from microdot import Microdot
2from tarfile import TarFile
3from pathlib import Path
4from network import WLAN
5
6import tarfile
7import network
8import time
9import os
10import io
11
12server = Microdot()
13
14DIR_HTML = """\
15<html>
16 <head>
17 <title>{dir}</title>
18 </head>
19 <body>
20 <h1>{dir}</h1>
21 <ul>
22 {files}
23 </ul>
24 </body>
25<html>
26"""
27
28DIR_ELEMENT = """\
29<li>
30 <a href="{url}">{text}</a>
31</li>
32"""
33
34HOST_CONFIG = {
35 "essid": "<your-ssid>",
36 "password": "<your-password>"
37}
38
39
40@server.post("/update")
41def update_program(request):
42 tar = TarFile(fileobj=io.BytesIO(request.body))
43 try:
44 for file in tar:
45 if file.type == tarfile.DIRTYPE:
46 Path(file.name).mkdir(parents=True, exist_ok=True)
47 else:
48 contents = tar.extractfile(file)
49 Path(file.name).write_bytes(contents.read())
50 except OSError as e:
51 return {
52 "status": "error",
53 "details": str(e),
54 }
55
56 return {"status": "success"}
57
58
59def _format_html(path):
60 return DIR_HTML.format(
61 dir=path,
62 files="\n".join(
63 DIR_ELEMENT.format(
64 url=f"/files{(path / file).resolve()}",
65 text=file,
66 )
67 for file in os.listdir(path.resolve())
68 ),
69 ), {"Content-Type": "text/html"}
70
71
72@server.get("/files")
73def display_file_root(request):
74 return _format_html(Path("/"))
75
76
77@server.get("/files/<path:path>")
78def display_file(request, path):
79 path = Path(path)
80 if not path.exists():
81 return str(path), 404
82 if path.is_file():
83 return path.read_text(), {"Content-Type": "text/plain"}
84
85 # a directory
86 return _format_html(path)
87
88
89@server.get("/shutdown")
90def shutdown(request):
91 request.app.shutdown()
92 return {"status": "success"}
93
94
95def setup():
96 ap = WLAN(network.AP_IF)
97 ap.active(True)
98 ap.config(**HOST_CONFIG)
99
100 while not ap.active():
101 time.sleep_ms(100)
102
103
104def run():
105 server.run()
To run this server, first install the necessary packages with mip
:
import mip
mip.install("tarfile")
mip.install("pathlib")
mip.install("github:miguelgrinberg/microdot/src/microdot.py")
Note
You may need to compile microdot.py
with mpy-cross
to avoid MemoryError
s.
Then simply import the server and run it!
import server
server.setup()
server.run() # This will never return unless shutdown is requested
After running it, connect your laptop to the microcontroller via WiFi and go to http://192.168.4.1:5000/files (or whichever IP your server is running on) and you should see your files!
To update the files via the server, archive your code with tar
and send an http POST request to
http://192.168.4.1:5000/update. With tar
and httpx
, it looks like this:
tar -cf app.tar ./app
followed by
import httpx
httpx.post(
f"http://192.168.4.1:5000/update",
content=b"<tar file in bytes>",
)
Have fun developing cableless!