demo-game/API_REST.md
simon 4f3435ba37 Add per-client LED controls aligned with the REST API schema.
Each client panel gets mode-specific LED inputs (color, intensity, progress, digit, blink) and the Makefile now copies API_REST.md alongside the WebSocket docs.

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

285 lines
6.2 KiB
Markdown
Raw Permalink 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 |