Skip to content

ZeroTrace HID

TraceNetwork — Usage Guide

Set up a fleet, run synchronized payloads, scan WiFi together, and orchestrate light shows

This is the full operator's guide to TraceNetwork — the multi-device coordination feature. For the high-level "what is this" overview see the feature page.


How it works

                ┌────────────┐
                │ Controller │   the device whose webui you have open
                │  (any ZT)  │
                └─────┬──────┘
              ESP-NOW │  AES-128-GCM, channel 1
        ┌─────────────┼─────────────┐
        ▼             ▼             ▼
  ┌──────────┐  ┌──────────┐  ┌──────────┐
  │  Agent   │  │  Agent   │  │  Agent   │   each runs the same firmware,
  │  ghost   │  │  glitch  │  │  phantom │   shares the passphrase
  └──────────┘  └──────────┘  └──────────┘

There's no central server — every device runs the same firmware and the same TraceNetwork stack. Whichever one you happen to be looking at via webui acts as the controller; the others act as agents. Heartbeats fly out every 10 seconds (1 second while a script runs) so the fleet stays current.


1. Setup

Prereq: Every device in the fleet needs a TraceNetwork-capable firmware build (any current ZeroTrace release).

On every device's webui:

  1. Open Settings
  2. Scroll to the TraceNetwork card
  3. Toggle Enable TraceNetwork on
  4. Set a passphrase — minimum 8 characters. Use the same passphrase on every device.
  5. Pick an Identify color (default red)
  6. Reboot the device

The passphrase is the encryption key. Devices with a mismatched passphrase produce traffic that other devices silently drop — they're invisible to each other. Pick something strong, and remember: rotating it later means re-keying every device.

After all devices have rebooted, open the webui on any one of them. Within ~10 seconds, every other device shows up in the Network tab. Your own device is the first row, marked THIS.


2. The target picker

The header (top right) has a target picker with the current selection. Click it (or press Ctrl+K).

It's a multi-select — you can check any combination of:

  • Local — the device whose webui you're viewing
  • All agents — selects every online agent at once
  • Per-agent checkboxes — check exactly the units you want

Whatever's selected becomes the implicit target for run/stop, light show, and WiFi scan actions. The selection persists across tabs — pick targets in the header, then go to the Executor or WiFi tab and your choice is already in effect.

The header also has a polling-status dot next to the target picker:

  • Green — heartbeats arriving fine
  • Yellow — at least one source is stale (no recent success)
  • Red — at least one source is erroring

Click the dot for a per-source breakdown with last-success age and any error message. Useful when an agent disappears and you're not sure if it's the radio or the webui.


3. Identify a device

The simplest fleet operation. In the Network tab, click Identify on any row — that device's LED blinks 5 times in its configured Identify color.

Use it to physically locate planted hardware in a room of identical units. From the Agent details drawer (click any row) you can also Identify.


4. Run a script across the fleet

This is the headline use case.

Workflow

  1. In the header, pick targets — Local + agents, all agents, or any subset.
  2. Open the Executor tab.
  3. Paste a script (or load one from the file picker).
  4. When the target includes more than one device, a Fire simultaneously (500ms offset) checkbox appears above the Run button. Keep it checked.
  5. Hit Run (or Ctrl+Enter).

Every selected device starts typing within ~10–20 ms of each other. The 500 ms offset gives the controller time to dispatch all the ESP-NOW packets so every agent has scheduled the run before any of them starts firing.

What's actually happening

  • Controller sends RUN (with start_at_offset_ms = 500) to each agent over ESP-NOW.
  • Each agent, upon receiving the packet, schedules executeTranspilation() for now() + 500ms on a FreeRTOS task.
  • At the deadline, every agent fires.
  • ESP-NOW unicast latency over short range is single-digit ms, so the deadlines align tightly.

If a script touches the LED (ledColor, ledOff, ledBlink), the firmware records that and won't auto-reset the LED to green at script end. So ledOff actually stays off after the script ends.

Recipe — synchronized AltGr injection

Three planted devices need to type the same payload at the same instant on three different hosts:

  1. Settings on each device → enable TraceNetwork with the same passphrase. Reboot.
  2. Connect to one of them via webui (it doesn't matter which — they're peers).
  3. Header → target picker → check All agents. Uncheck Local (you don't want this device firing).
  4. Executor → paste payload, check Fire simultaneously, Run.

All three devices type within the same instant.

Recipe — local payload + remote witnesses

You're physically holding one device that types into a target host. Two planted devices nearby need to record what happened (e.g. set a status LED) at the same moment.

  1. Set up the two planted devices as TraceNetwork agents.
  2. On your device, write a script ending with traceBroadcast "fired".
  3. Header → target picker → check Local only.
  4. Run the script. The Local device executes the payload. When it hits traceBroadcast, every other agent receives the broadcast event.

(Per-agent reaction-to-broadcast is on the v2 roadmap; current traceBroadcast is one-way.)


5. Fleet WiFi scan

Each device has its own WiFi radio. Devices placed in different physical locations see different networks. Fleet WiFi scan aggregates them.

Workflow

  1. In the header, pick the agents you want to scan from. (Local scan isn't supported — would disrupt the device's own AP and disconnect your webui.)
  2. Open the WiFi tab.
  3. Hit Scan (or R).

After ~5–12 seconds (per-agent scan time, all run in parallel), the table populates with the deduped union of every WiFi network any selected agent could hear.

What each column means

  • SSID — the network name. (hidden) if it doesn't broadcast.
  • BSSID — the AP's MAC address. Unique even when SSIDs collide.
  • Encryption — color-coded badge. Red = Open, yellow = WPA, green = WPA2/WPA3, etc.
  • Best RSSI — strongest signal across all agents.
  • Channel — 2.4 GHz channel number.
  • Seen by — small badges showing each agent that detected this network and its individual RSSI for that network.

Sort and filter

  • Search box — filters by SSID or BSSID substring.
  • Encryption toggle — show All / Secure-only / Open-only.
  • Sort toggle — by RSSI, SSID, Channel, or number of devices that saw it (Seen).

Recipe — survey a 3-room office

  1. Place one device in each room. Make sure all three are on the same TraceNetwork passphrase.
  2. Connect to your laptop's webui (or to one of the devices' APs).
  3. Header → All agents → WiFi tab → Scan.
  4. The aggregated view shows every AP any device can hear. The "Seen by" column tells you the geographic spread — an AP visible to all three is probably big and central; one visible to only one device is local to that room.

Use the per-agent breakdown badges + signal strength to triangulate APs roughly.


6. Light show

The Network tab has a Light show card.

Patterns

PatternWhat it looks likeBest with
Off / StopTurns the LED offn/a
SolidEvery device shows the same color1+ devices
PulseTriangle-wave fade in/out1+ devices
StrobeOn/off flash1+ devices
RainbowHSV cycle, hue offset by index — wave moves down the chain2+ devices
ChaseOne device lit at a time, rotating through the chain2+ devices
CylonChase that bounces back and forth (Knight Rider)3+ devices

Workflow

  1. In the header, pick targets — Local + agents, just agents, or just one.
  2. Open the Network tab → scroll to the Light show card.
  3. Pick a pattern from the dropdown.
  4. Pick a primary color. The picker supports HEX/RGB/HSL inputs and includes an EyeDropper button (Chromium-only) for picking colors from anything on screen.
  5. Set Speed (ms per step) — 50 ms = rapid strobe, 200 ms = snappy chase, 1000 ms = slow pulse.
  6. Set Duration (s) — 0 means run forever until you hit Stop.
  7. Hit Start.

All selected devices fire ~500 ms later (intentional — gives every agent time to schedule, so they animate in lockstep). When Local + agents are both included, Local actually waits ~600 ms to compensate for the agents' ESP-NOW transit time, so the anchors line up.

The Sync button

Even with everything timed, ESP-NOW packet jitter at start time can offset devices by 5–20 ms. Over a long-running pattern they stay aligned (the firmware anchors steps to wall-clock time per device, so drift doesn't accumulate). But if the initial start lands them visibly out of phase, hit Sync — it re-broadcasts the current pattern with a fresh 500 ms offset. Every device drops its current animation and re-anchors in lockstep.

Recipe — best Cylon demo

3+ devices in a row on a desk:

  1. Put them ~10 cm apart, USB-powered.
  2. All on the same TraceNetwork passphrase, all online in your Network tab.
  3. Header → All agents (or include Local if your laptop's device is in the row).
  4. Network → Light show → Pattern: Cylon, Color: red, Speed: 150 ms, Duration: 0.
  5. Hit Start. The red dot bounces left-right across the row.
  6. If devices look offset, Sync.

Recipe — synchronized strobe

Practical "fleet status" effect:

  1. Pick Pattern: Strobe, Color: white, Speed: 80 ms, Duration: 5 (seconds).
  2. Hit Start.

All selected devices flash white for 5 seconds in unison.


7. The traceBroadcast script command

Inside any HID or BLE script:

traceBroadcast "label"

Sends a broadcast packet to every other device on the fleet. Currently used for emit-only signaling — receiving devices don't react to broadcasts in the v1 firmware, but the receive path is in place for future use.

Useful right now as a marker in serial logs when debugging multi-device scenarios.


8. Settings reference

SettingDefaultNotes
tracenet_enabledfalseMaster enable. When false, ESP-NOW never initializes and TraceNetwork is invisible.
tracenet_passphraseemptyShared key. Minimum 8 characters. Empty = effectively disabled.
tracenet_identify_colorredColor the LED blinks when another device pings this one. Options: red, green, blue, yellow, purple, orange, white, cyan.

All managed from the Settings tab → TraceNetwork card. Changes take effect after reboot for the master enable; passphrase + identify color apply immediately.


9. Constraints & gotchas

Range

~200 m line of sight, single-hop. Indoors with walls, much less. There is no mesh forwarding in v1 — agents must be in direct ESP-NOW range of the controller. Plan device placement accordingly.

WiFi channel

ESP-NOW pins to channel 1 (the same channel the device's SoftAP uses by default). If your wifi_sta setting connects to an upstream AP on a different channel, the device's radio will be tuned to that other channel, and ESP-NOW packets will drop. Either keep STA off, or accept that TraceNetwork won't work while STA is on a non-1 channel.

File transfers

Chunked over ESP-NOW at ~30–60 KB/s in practice. Fine for scripts (KB-sized). Painful for multi-MB logs — minutes, not seconds.

No agent-to-agent direct

All commands flow through the controller. Two agents can't directly talk to each other; they can only broadcast (one-way) via traceBroadcast.

Heartbeat cadence

Idle devices broadcast every 10 seconds. While a script runs, the cadence drops to 1 second so the controller can show live progress. Means: agent rows in the Network table only update every 10 s when idle (RSSI, uptime, free heap). The THIS row updates every 2 s because it's queried live, not heartbeat-driven.

Settings UI mentions BLE host

On variants compiled without BLE (Ghost, Mini, T-Dongle, Waveshare), the BLE host indicator is always false. That's correct, not a bug.


10. Troubleshooting

Devices don't see each other

  • Confirm passphrases are byte-for-byte identical (≥ 8 chars, no leading/trailing whitespace).
  • Confirm tracenet_enabled = true on both.
  • Confirm both devices were rebooted after the passphrase change.
  • Within range? Try moving them closer.

Identify works but the device shows "stale" or "offline"

Identify uses unicast; heartbeats use broadcast. They share the same encryption but go through slightly different ESP-NOW paths. If broadcasts aren't arriving:

  • Check wifi_sta — connecting to an upstream AP on a non-1 channel breaks broadcasts.
  • Check the polling badge in the header for source-specific errors.

Light show devices are out of sync

  • Hit the Sync button to re-anchor every device with a fresh start time.
  • ESP-NOW packet arrival jitter contributes ~10–20 ms variance at start. The firmware bounds drift over time (steps anchored to wall-clock per device), so resyncing once at start is usually enough.

Local LED leads the agents

  • Local has a built-in 100 ms compensation when agents are selected. If your fleet is unusually large (>5 agents) and transit exceeds that, Local might still lead. Open an issue with your fleet size.

WiFi scan returns "timeout" for an agent

  • A scan takes 5–12 s on the agent. The controller's proxy waits 15 s. Timeouts mean the agent is out of range, offline, or busy with a script (scans are blocked while a script runs — the scan would disrupt HID injection).

Webui hammers /api/tracenet/fleet and /api/tracenet/local extremely fast

Fixed in current firmware — was a render loop in the polling-status hook. If you're on an older build, update.

Browser disconnects briefly

Could be a WiFi scan running on the device serving your webui (its AP drops momentarily during a scan). The browser will reconnect. Run scans against agents, not the local device.


Command Palette

Search for a command to run...