powerpods/goTool/docs/API_REST.md
simon 31e539052a Unify cache polling on CACHE_STATUS and split API docs.
Replace separate accel/tap snapshot UART commands with one clients[] response
that omits unsubscribed fields; remove snapshot handlers and CLI commands.
Add goTool/docs for WebSocket streams and REST; tap-snapshot REST uses CACHE_STATUS.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 21:23:09 +02:00

285 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# REST API
`go run . -port /dev/ttyUSB0 serve` starts two HTTP servers on the same UART link:
| Base URL | Flag | Used by |
|----------|------|---------|
| `http://localhost:8080` | `-addr` (default `:8080`) | Web dashboard + automation on the UI routes |
| `http://localhost:8081` | `-api-addr` (default `:8081`, `""` disables) | External programs; subset of routes + service info |
WebSocket streaming (accel/tap push): [`API_WEBSOCKET.md`](API_WEBSOCKET.md).
All JSON responses use `Content-Type: application/json`. On UART errors many routes return **503** with `"error"` in the body.
---
## External API (`:8081`)
### Service info
```http
GET /
GET /api/v1/
```
```json
{
"name": "powerpod-external-api",
"version": "1",
"serial_port": "/dev/ttyUSB0",
"websocket": "/ws",
"default_interval_ms": 16,
"min_interval_ms": 1,
"max_interval_ms": 10000,
"tap_display_min_ms": 2000,
"description": "..."
}
```
### Battery
```http
GET /api/battery?all_clients=true
GET /api/battery?client_id=16
POST /api/battery
Content-Type: application/json
```
POST body:
```json
{"all_clients": true}
{"client_id": 0}
{"client_id": 16}
```
Response:
```json
{
"success": true,
"samples": [
{
"client_id": 16,
"lipo1": {"valid": true, "voltage_mv": 3850, "percent": 71},
"lipo2": {"valid": false},
"age_ms": 1200
}
]
}
```
Slaves push battery to the master every **30 s**; these routes read the master cache.
WebSocket equivalent: `get_battery` on `ws://localhost:8081/ws` (reply type `battery_status`).
### LED ring
```http
POST /api/led-ring
Content-Type: application/json
```
Body:
```json
{"mode":"color","client_id":16,"r":255,"g":0,"b":0,"intensity":128}
{"mode":"digit","client_id":0,"digit":3,"r":0,"g":255,"b":0}
{"mode":"find-me","all_clients":true,"slaves_only":true}
```
| `mode` | Notes |
|--------|--------|
| `clear` | Turn off |
| `color` | Full ring RGB + `intensity` |
| `progress` | `progress` 0100 |
| `digit` | `digit` 010 |
| `blink` | `blink_ms`, `blink_count` |
| `find-me` | Locate pod |
Use `client_id` (`0` = master) or `all_clients` (+ optional `slaves_only`) for broadcast.
Response: `success`, `slaves_updated`, optional `error`.
WebSocket: `set_led_ring` with the same fields plus `"type":"set_led_ring"``led_ring_status`.
---
## Dashboard API (`:8080`)
Used by the web UI; safe for scripts that drive the same features.
### Live stream (host `CACHE_STATUS` poll ~16 ms)
```http
GET /api/live-stream
PUT /api/live-stream
Content-Type: application/json
{"enable": true}
```
```json
{"enabled": true, "success": true}
```
Enables fast UART polling for dashboard accel/tap display. Per-slave accel still requires accel-stream (below).
### Accel stream (firmware ESP-NOW, per slave)
```http
GET /api/clients/16/accel-stream
PUT /api/clients/16/accel-stream
Content-Type: application/json
{"enable": true}
```
```json
{"enabled": true, "client_id": 16, "success": true}
```
All slaves:
```http
POST /api/accel-stream
Content-Type: application/json
{"write": true, "enable": true, "all_clients": true}
```
Polling on the host runs only while at least one slave has streaming enabled (here or via external WebSocket / dashboard).
### Tap notify (firmware; does not start host tap polling)
```http
GET /api/clients/16/tap-notify
PUT /api/clients/16/tap-notify
Content-Type: application/json
{"single": true, "double_tap": false, "triple": false}
```
```json
{
"client_id": 16,
"success": true,
"slaves_updated": 1,
"single": true,
"double_tap": false,
"triple": false
}
```
All slaves:
```http
POST /api/tap-notify
Content-Type: application/json
{"single": true, "double_tap": false, "triple": false, "all_clients": true}
```
Host tap display / external `set_tap_stream` is separate.
### Tap snapshot (one-shot, via `CACHE_STATUS`)
```http
GET /api/tap-snapshot?client_id=16
```
Reads the combined cache (`CACHE_STATUS`); optional `client_id` filters pending tap events. Pending taps are consumed on read.
```json
{
"events": [
{"client_id": 16, "kind": "single", "age_ms": 4}
]
}
```
### Deadzone
```http
GET /api/deadzone?client_id=0
POST /api/deadzone
Content-Type: application/json
{"write": true, "deadzone": 128, "client_id": 0}
```
With `all_clients` + `slaves_only`: push to ESP-NOW slaves only (master BMA456 unchanged).
```json
{"deadzone": 128, "client_id": 0, "success": true, "slaves_updated": 2}
```
### Unicast test
```http
POST /api/unicast-test
Content-Type: application/json
{"client_id": 16, "seq": 42}
```
### Find me
```http
POST /api/find-me
Content-Type: application/json
{"client_id": 16}
```
`client_id` `0` = master LED ring.
### Restart
```http
POST /api/restart
Content-Type: application/json
{"client_id": 16}
```
### OTA (master UART upload)
```http
POST /api/ota
Content-Type: multipart/form-data
```
Form field **`firmware`**: binary image, max **2 MiB**.
```json
{"success": true, "bytes_written": 123456, "target_slot": 1}
```
Firmware distributes to slaves over ESP-NOW after `OTA_END`. Progress also appears on dashboard WebSocket as `ota_progress` messages.
CLI equivalent: `go run . -port /dev/ttyUSB0 ota build/powerpod.bin`
### LED ring and battery
Same as external API:
- `POST /api/led-ring`
- `GET` / `POST` `/api/battery`
---
## Dashboard vs external
| Feature | Dashboard `:8080` | External `:8081` |
|---------|-------------------|------------------|
| Client list | Via dashboard WebSocket state / CLI `clients` | WebSocket `list_clients` |
| Accel/tap **push stream** | WebSocket state when live-stream on | WebSocket `set_stream` / `set_tap_stream` |
| Accel stream enable | REST `PUT .../accel-stream` | WebSocket `set_accel_stream` |
| Tap notify | REST `PUT .../tap-notify` | WebSocket `set_tap_notify` |
| LED / battery | REST | REST + WebSocket on `:8081` |
---
## UI mapping
| UI action | REST / CLI |
|-----------|------------|
| Nur Master deadzone | `POST /api/deadzone` `client_id: 0` or CLI `deadzone -set -client 0` |
| Einzelner Slave | `client_id: <id>` |
| Alle Slaves deadzone | `all_clients` + `slaves_only` on POST |
| Unicast test | `POST /api/unicast-test` |
| Tap notify S/D/T | `PUT /api/clients/{id}/tap-notify` |
| Tap receive (UI) | Live stream + tap notify; see WebSocket doc for external API |