⌁Networked serial consoles
Read each target's serial console live and type into its serial login, all from the browser over the network — with a real terminal renderer and ANSI cleanup.
Pico · TeleTYpewriter
A star-topology serial console for a fleet of Raspberry Pi Pico nodes. Each node plugs into a headless machine's USB port and becomes a networked serial console with keyboard injection — it reads the target's serial line over the network and types keystrokes back into it. One hub coordinates the swarm and gives you a single browser dashboard to drive every node.
Why it exists
Consumer mini PCs expose no accessible serial port — no BMC/IPMI, no DB9/RJ45 console, often not even a usable header. There's no out-of-band way to see a stuck boot, poke a frozen box, catch a kernel panic, or drive the BIOS without walking over with a keyboard and monitor.
PICOTTY gives every headless machine exactly that, over the network: a tiny Pico on its USB port acts as a USB keyboard — so you can type at BIOS, GRUB, initramfs, and the OS — and reads back its serial console, all surfaced in one dashboard.
The topology
A shared Raspberry Pi Zero 2 W runs the hub. Each node is a Pico on a target's USB port, reachable over your management network. You drive the whole fleet from a browser — or from your phone via the Telegram sidecar.
What you get
Read each target's serial console live and type into its serial login, all from the browser over the network — with a real terminal renderer and ANSI cleanup.
Each node is a USB HID keyboard, so it drives the target everywhere a keyboard works: BIOS, GRUB, initramfs, the OS. Per-node keyboard layouts.
Reusable HID sequences built from type / keys / wait steps, saved in a library and replayable on any node. Custom quick chords you save and fire.
A wait-for-output expect engine and YAML runbooks you author, view, and edit in the browser — then run across a whole group.
Push bundles over the wire: chunked, checksummed, .zip-upload, with canary rollout and watchdog-revert. Firmware-only or settings-only pushes.
Prompt-state badges and a machine up/dead badge that tells you whether the target is alive — not just the node — plus a three-method reboot menu.
Every node, command, result, and output chunk recorded in SQLite. Timestamped event log, asciicast session replay, and a raw serial bridge for minicom / PuTTY.
A primary + backup hub per node with a shared node token, runtime steering (move / set-home / pin), offline command queue, and webhook / ntfy alerts.
On PyPI
The hub ships as the picotty
package, built with the uv build backend. The base install is a lean client; the server and
Telegram stacks live behind extras so a client stays small.
picotty.protocol
The wire protocol — version, frame encode/read, send validation.
base install
picotty.client
The SDK — HubClient (async REST) + HubEvents (WebSocket).
base install
picotty.hub
The FastAPI server behind picotty-hub.
[hub] extra
# drive a running hub from the lean client SDK — no server stack needed import asyncio from picotty.client import HubClient async def main(): async with HubClient("http://hub:8080") as hub: print(await hub.health()) async with hub.events_stream() as stream: await stream.subscribe("node-01") async for ev in stream: print(ev["event"], ev) asyncio.run(main())
Quick start
Your node ids, hub address, and token live only under private/ (gitignored) —
nothing machine-specific is committed.
uv tool install 'picotty[hub]' # server stack + both CLIs picotty-hub # → dashboard at http://<hub-ip>:8080
bash firmware/scripts/install-deps.sh
bash firmware/scripts/build.sh --node <id> \
--drive /run/media/$USER/CIRCUITPY
Point the target's serial console at the node (example for Proxmox):
sudo bash target-setup/proxmox-serial.sh
uv run picotty-sim --id demo --token <TOK>
and explore the whole dashboard before you solder anything.
Hardware
Per target machine: a Raspberry Pi Pico (or Pico 2) + a WIZnet W5100S Ethernet HAT + a data-capable USB cable + an Ethernet drop. One shared Pi Zero 2 W runs the hub. The all-in-one W5100S-EVB-Pico replaces the Pico + HAT.
Pico + HAT
SPI Ethernet over the WIZnet W5100S HAT, leaving USB free for the target.
Pi Zero 2 W
One shared hub coordinates the whole swarm and serves the dashboard.
Enclosure
A 3D-printable case — STL, STEP, and editable Fusion 360 source in the repo.
Documentation
Component roles, the single-loop hub, the one-cable USB design, the wire protocol, data model.
Physical topology, bill of materials, component tree, sizing.
The three build phases, the end-to-end workflow, the full script reference.
Firmware lifecycle, LED codes, keyboard layout, OTA capability, hardening.
Dual-hub failover, runtime steering, the independent-peers model, the shared node token.
Observability, prompt-state badges, HID vs serial input, session recording, alerting.
Prompt-state detection, the expect engine, offline command queue, YAML runbooks.
Over-the-wire firmware updates: the safety model and rollout posture.
The picotty package: import surfaces, extras, entry points, the client SDK, publishing.
The Telegram bot sidecar: stats / alerts / gated terminal over chat.
Security boundary, target requirements, power, roadmap.