Expose the command via goTool CLI/REST and dashboard controls so log verbosity can be tuned without reflashing. Co-authored-by: Cursor <cursoragent@cursor.com>
goTool
Host-side UART client for the Powerpod master ESP.
Full system documentation (roles, ESP-NOW, framing, protobuf): ../main/README.md.
Usage
cd goTool
go mod tidy
go run . -port /dev/ttyUSB0 version
go run . -port /dev/ttyUSB0 clients
| Flag | Default | Description |
|---|---|---|
-port |
(required) | Serial port on master UART (GPIO2/3 adapter) |
-baud |
921600 |
Must match firmware UART_BAUD_RATE |
Commands
| Command | UART payload | Description |
|---|---|---|
version |
0x03 |
Prints version and git_hash from firmware |
clients |
0x04 |
Lists slaves registered on the master via ESP-NOW |
deadzone |
0x06 |
Get/set accelerometer deadzone LSB (-set, -value, -client, -all) |
tap-notify |
0x1b |
Get/set which tap kinds (single/double/triple) notify via ESP-NOW (-set, -client, -all, -single, -double, -triple) |
cache-status |
0x1d |
Subscribed accel + tap cache (CACHE_STATUS); one UART round-trip for 16 ms polling |
unicast-test |
0x07 |
Sends ESP-NOW unicast test to one slave (-client, -seq) |
echo-ping |
0x1e |
ESP-NOW echo round-trip to one slave (-client); prints rtt_ms (host UART chain) and esp_rtt_us (master ESP-NOW, raw µs) |
test |
— | Run an automated scenario (JSON configs under testdata/) |
serve |
— | Web dashboard at http://localhost:8080 (WebSocket live updates) |
ota |
16–19 | UART firmware upload to master; firmware then pushes to slaves via ESP-NOW |
ota-progress |
21 | Query per-slave ESP-NOW OTA progress on the master (-client N, default all) |
led-ring |
8 | LED ring: -mode clear|color|progress|digit|blink|find-me, -client, -all |
find-me |
22 | Locate pod (-client 0 master, >0 slave via ESP-NOW) |
restart |
23 | Reboot master or slave (-client 0 / >0) |
log-level |
0x1f |
Get/set master ESP-IDF log level for tag "*" (-set, -level 0–5); output on UART0 debug, not host UART |
clients requires slaves to have responded to master discover broadcasts first.
For adding commands end-to-end (UART, ESP-NOW, CLI, dashboard), see docs/adding-a-feature.md (Find me example).
Automated tests
Bench configs (testdata/configs/) list network, MACs, and serial ports (uart.master for commands, *_console for esptool reset). Scenarios run UART commands plus optional reset steps.
go run . test -list-configs
go run . test -list-scenarios
go run . test -config example-lab -scenario smoke
go run . test -config example-lab -scenario uart_cmds
go run . test -config my-lab -scenario smoke -port /dev/ttyUSB1 -v
With a complete bench config, -port is optional for test (uses uart.master from JSON).
See testdata/README.md for the JSON schema.
Web dashboard
Polls the master over UART and pushes state to the browser via WebSocket (Alpine.js + Bootstrap 5).
go run . -port /dev/ttyUSB0 serve
go run . -port /dev/ttyUSB0 serve -addr :8080 -interval 2s
go run . -port /dev/ttyUSB0 serve -api-addr :8081 -accel-interval 16ms
make gotool-serve PORT=/dev/ttyUSB0
Open http://localhost:8080 — shows master firmware info and the ESP-NOW client table from CLIENT_INFO.
Tap (dashboard): two independent controls per slave:
| Column | Meaning |
|---|---|
| Tap-Notify (S/D/T) | Which tap kinds the slave sends to the master over ESP-NOW (UART TAP_NOTIFY) — does not poll UART |
| Tap (An/Aus) | Host receive: poll master tap cache (~16 ms) and show last tap for ≥2 s |
Enable notify first, then turn receive on to see events. Same split as the external WebSocket API (set_tap_notify vs set_tap_stream).
If the UART device is unplugged or the port disappears, serve keeps running and retries on each poll interval; the UI shows UART off until the port is available again.
HTTP / WebSocket API
serve also listens on :8081 for external programs (-api-addr, empty to disable). Same UART as the dashboard.
| Doc | Content |
|---|---|
| docs/API_WEBSOCKET.md | ws://…:8081/ws commands and input push stream (accel + tap) |
| docs/API_REST.md | REST on :8080 (dashboard) and :8081 (battery, LED, service info) |
CLI:
go run . -port /dev/ttyUSB0 tap-notify -client 16 -set -single
go run . -port /dev/ttyUSB0 cache-status
| UI / API | Behaviour |
|---|---|
| Firmware OTA card | Same as ota CLI; dashboard WebSocket ota_progress (REST doc) |
POST /api/ota |
Upload .bin to master — slaves updated by firmware over ESP-NOW after OTA_END |
go run . -port /dev/ttyUSB0 ota build/powerpod.bin
Waits for ready after start (~30 s erase), sends 200-byte OTA_PAYLOAD frames, reads block_ack every 4 KiB, then OTA_END. The master then distributes to all available slaves (no extra host traffic); success is reported only when that finishes. Allow several minutes for large images. Reboot master and slaves to boot the new firmware.
go run . -port /dev/ttyUSB0 unicast-test -client 16 -seq 42
On success the slave serial log should show UNICAST TEST OK from master … seq=42.
go run . -port /dev/ttyUSB0 echo-ping -client 16
go run . -port /dev/ttyUSB0 log-level
go run . -port /dev/ttyUSB0 log-level -set -level 3
log-level controls esp_log_* on the master (UART0 USB console). The host protocol UART (GPIO 2/3) is unchanged.
Measures latency to one slave. rtt_ms is the full host round-trip (UART + ESP-NOW + UART back). esp_rtt_us is the master-side ESP-NOW leg only (esp_timer_get_time() delta, raw microseconds from firmware).
Example output:
echo ping: success=true client_id=16 rtt_ms=49.729 esp_rtt_us=18234
clients example:
clients (2):
[0] id=42 mac=aabbccddeeff ver=1 available=true used=false last_ping=250 last_success_ping=250
Regenerate protobuf
From repo root (needs protoc, protoc-gen-go, and for C also pip install protobuf):
make gotool-proto # Go: goTool/pb/uart_messages.pb.go
make proto_generate # C: main/proto/*.pb.h, *.pb.c