This module shares a MicroPython board's REPL from a station with everyone in the station's room. It talks to the board over WebREPL, MicroPython's REPL over a WebSocket, so the board only needs Wi-Fi, no USB connection to the station.
- Everyone in the room types into the same REPL and sees its output, also students who join later.
- Station and teachers can send files to the board and get files from it.
- Editor modules can run code on the board (
executemessage, see Messages). - Optionally, an Arduino Alvik drives back to its charger when the last user leaves the room.
It is based on the official WebREPL client for MicroPython.
Add the module to your class with this URL:
https://edrys-labs.github.io/module-micropython-webrepl/
The module is only shown in stations (show-in: station), not in normal rooms. It follows the classroom's light or
dark theme (the operating system's when opened on its own); the REPL stays dark in both.
- Enable WebREPL on the board and set its password (
import webrepl_setupin the board's REPL, see the MicroPython documentation). - Start the proxy on the station's computer.
- Set the board's address in the module's station settings (
websocket, see Configuration), e.g.ws://localhost:8765/ws://192.168.4.1:8266, or type it into Address in the station. - Open the station and click Connect (or a teacher in the station's room does). Then anyone in the room types the WebREPL password into the terminal.
The header shows the board's status to everyone: not connected, connecting… or connected. While a
connection is wanted, the station keeps it up: after a reload of the station, or when the board drops the
connection, it reconnects by itself (after 1, 2, 5, then every 10 seconds) until someone clicks Cancel or
Disconnect. Errors are printed in the terminal, e.g. [cannot reach …, retrying…].
| Station | Teacher | Student | |
|---|---|---|---|
| See the board's status, type into the REPL, run code from an editor module | yes | yes | yes |
| Connect / Disconnect, change the address | yes | yes | – |
| Send and get files, Run Self Charge | yes | yes | – |
The station holds the connection to the board. Everyone else goes through it, so only the station needs to reach the board (or the proxy). Students don't get the controls, and the station also checks who asks: it carries out a connect, address, file or self charge request only from a teacher (by the sender's role in the class, which edrys-Lite signs), and puts the shared connection state back if anyone else changes it.
Send a file: pick it and click Send to device. Get a file: type its name on the board (e.g.
main.py) and click Get from device; the file is downloaded by whoever asked. Everyone in the room sees the
transfer in the status line (Sent main.py, 15 bytes). File names may have up to 64 ASCII characters (a limit of
WebREPL).
All settings are under Station config in the module settings:
| Field | Type | Default | Description |
|---|---|---|---|
websocket |
text | (empty) | Address of the board, usually through the proxy: ws://localhost:8765/ws://<board-ip>:8266. Changing it also changes the address in the station room. |
execute |
text | execute |
Message subject on which code from editor modules is run |
self_charge_alvik |
boolean | false |
Arduino Alvik: run self_charge.py on the board when the last user leaves the station room, and show a Run Self Charge button. The script must be on the board. |
{
"websocket": "ws://localhost:8765/ws://192.168.4.1:8266",
"execute": "execute",
"self_charge_alvik": false
}Without an address, the module says how to set one.
Edrys is served over https, and an https page may only open secure (wss://) WebSockets, except to localhost.
MicroPython boards only offer plain ws://. The proxy (proxy/) runs on the station's computer, listens on
localhost and forwards each connection to the board named in its path:
ws://localhost:8765/ws://192.168.4.1:8266 -> ws://192.168.4.1:8266
So one proxy serves any number of stations and boards. Chrome, Edge and Firefox allow an https page to connect to
ws://localhost.
Run it with Python 3:
pip install -r proxy/requirements.txt
python3 proxy/proxy.pyor with Docker:
docker run -it --network host edryslabs/micropython-webrepl-proxy:latest(proxy/docker-compose.yml builds the image from this folder and restarts it with
the computer: docker compose -f proxy/docker-compose.yml up -d.)
Settings, as environment variables:
| Variable | Default | Description |
|---|---|---|
PROXY_ALLOWED_TARGETS |
(empty: any) | Boards the proxy may connect to, as comma-separated host or host:port patterns, e.g. 192.168.4.1,10.0.0.*:8266. Set it: without it, any web page open in the station's browser can use the proxy to reach any WebSocket in the local network. |
PROXY_HOST |
localhost |
Address to listen on |
PROXY_PORT |
8765 |
Port to listen on |
PROXY_LOG_LEVEL |
INFO |
DEBUG also logs the size of each message. Message contents (password, code) are never logged. |
docker run -it --network host -e PROXY_ALLOWED_TARGETS=192.168.4.1 edryslabs/micropython-webrepl-proxy:latestThe image is built and pushed by .github/workflows/docker-publish.yml
when the proxy changes, as :latest and as :<commit sha>.
Other modules may send one message: code to run on the board.
| Subject | From → to | Body |
|---|---|---|
execute (setting execute) |
any module → station | MicroPython code as a string |
The station uploads the code as temp_code.py, waits until the board confirmed it, interrupts a running program
(Ctrl-C) and runs the file with exec(open('temp_code.py').read()). Runs are queued, one at a time. If the
station is not connected, everyone sees [code not run: not connected] in the terminal.
The other subjects are only accepted from this module itself. The station carries out those marked teacher only when a teacher sent them.
| Subject | From → to | Body |
|---|---|---|
write |
station → room | terminal output |
data |
peer → station | keystrokes |
history_request / history |
peer → station / station → room | a peer that loads asks for the recent output (up to 16 KB); the answer carries the request's id |
connect_request |
teacher → station | true to connect, false to disconnect |
set_url |
teacher → station | the board's address |
put_file |
teacher → station | { filename, data } |
get_file / got_file |
teacher → station / station → room | { id, filename } / { id, filename, data | error }; only the requester saves it |
run_self_charge |
teacher → station | (empty) |
Room state (Edrys.getState(key, 'Value')), written only by the station; other peers read it:
| Key | Written by | Value |
|---|---|---|
url |
station (its Address field, a teacher's set_url, the config) |
the board's address |
url_config |
station | the websocket config the address was last taken from |
wanted |
station (its button, a teacher's connect_request) |
a connection is wanted |
connected |
station | the station is connected to the board |
file_status, file_busy |
station | the file status line, and whether a transfer is running |
index.html: markup and the module's declarations (show-in,module-config)app.js: the Edrys side: shared state, messages, the station's connection and the file boxeswebrepl.js: the board side: terminal (xterm.js 6, from jsDelivr), WebSocket and the WebREPL file transfer protocol; no Edrys codestyles.css,FileSaver.js(vendored, saves downloaded files)proxy/: the proxy (proxy.py), its Docker image and compose file; separate from the module, which needs only the files above
There is no build step: serve the folder (e.g. python3 -m http.server) and add its URL to a class.
End-to-end tests run the module in a real edrys-Lite with a station, a teacher and students, against a fake
MicroPython board. They are in the edrys-module-tests repository, under modules/module-micropython-webrepl.
They read the terminal as window.term; keep that when changing the terminal.
MIT © edrys-labs, based on micropython/webrepl
