Documentation Architecture

Networking

Traffic analysis, protocols, local communication, and the network architecture of the Heron device.

Two integration surfaces

Heron has two distinct network surfaces, used by three clients. The split is intentional - setup and ongoing monitoring have different lifecycles and different trust requirements.

Surface Used by Purpose
USB WebSerial Onboarding PWA only First-time setup over USB - identify, challenge, provision
Local HTTP :8080 Dashboard and CLI Ongoing monitoring on the LAN

The dashboard and CLI do not use WebSerial and do not authenticate with device identity. They find the Pico on the network and read the HTTP API.

DNS observer

Heron is a passive DNS observer. It runs a local DNS server that forwards every query transparently to upstream resolvers (1.1.1.1 / 8.8.8.8) and logs what it sees. It does not block, redirect, or filter. The buzzer is an alert, not enforcement.

device on LAN  ──DNS query──►  Heron (:53)  ──forward──►  1.1.1.1 / 8.8.8.8
                                    │
                                    └──log──►  /dnslog.json (on flash)

USB WebSerial provisioning

Setup runs over USB CDC/ACM at 115200 baud with newline-delimited JSON. Chrome and Edge only - the WebSerial API is not available in Safari or Firefox. Opening the serial port resets the Pico, so the protocol is designed to be restart-safe.

While waiting for commands, the Pico emits a ready beacon every two seconds:

{"status": "ready"}

The PWA waits for this beacon before sending any command. The full onboarding flow runs in five steps:

Step Action System
connectWebSerial open, wait for ready, identifyUSB serial
verifyCryptographic challenge-responseUSB serial + Web Crypto (ECDSA P-256)
wifiScan networks, provision with SSID and passwordUSB serial
routerDNS setup instructionsUSB serial → OUI lookup → router guide
doneUnplug to wall power-

Local HTTP API

After provisioning, the device exposes an HTTP API on port 8080. No authentication - LAN presence is the only access control. The dashboard and the CLI both talk to this API; they are simply two different clients over the same surface.

Discovery order

  1. Probe http://heron.local:8080/health (2-second timeout, mDNS)
  2. Probe the saved IP from localStorage (dashboard) or ~/.heron-host (CLI)
  3. Manual IP entry via the dashboard banner or --host flag

Endpoints

GET    /health
GET    /audit/weekly?since=<ts>&limit=<n>
GET    /devices
GET    /stats
GET    /debug
GET    /token
GET    /allowlist
PUT    /allowlist
DELETE /allowlist/<id>
PUT    /devices/<id>

See the API contract for the full request and response shapes, error codes, and the changelog of additions.

mDNS

The device announces itself as heron.local via mDNS - set with network.hostname("heron") in firmware. Any device on the same Wi-Fi can reach it at http://heron.local:8080 without knowing the IP. The dashboard and CLI both prefer this path and fall back to a saved or manual IP when mDNS is unavailable.

Device naming

Tracked devices are identified by source IP. The firmware also sends a NetBIOS Name Service broadcast on UDP 137 to resolve hostnames, falling back to reverse DNS, then to a generated Device #N name. Custom names set in the dashboard persist to /names.json on flash and survive reboots. Maximum 32 characters.

Wi-Fi reconnection

The firmware reconnects to Wi-Fi automatically. A 30-second retry loop in main.py calls connect_to_wifi() whenever wlan.isconnected() returns false. Credentials live in /config.json on flash.

What never happens