11 KiB
LED Controller API
This document covers:
- HTTP and WebSocket exposed by the Raspberry Pi app (
src/main.py) — profiles, presets, transport send, and related resources. - LED driver JSON — the compact message format sent over the serial→ESP-NOW bridge to devices (same logical API as ESP-NOW payloads).
Default listen address: 0.0.0.0. Port defaults to 80; override with the PORT environment variable (see pipenv run run).
All JSON APIs use Content-Type: application/json for bodies and responses unless noted.
Session and scoping
Several routes use @with_session: the server stores a current profile in the session (cookie). Endpoints that scope data to “the current profile” (notably /presets) only return or mutate presets whose profile_id matches that session value.
Profiles are selected with POST /profiles/<id>/apply, which sets current_profile in the session.
Static pages and assets
| Method | Path | Description |
|---|---|---|
| GET | / |
Main UI (templates/index.html) |
| GET | /settings |
Settings page (templates/settings.html) |
| GET | /favicon.ico |
Empty response (204) |
| GET | /static/<path> |
Static files under src/static/ |
WebSocket: /ws
Connect to ws://<host>:<port>/ws.
- Send JSON: the object is forwarded to the transport (serial bridge → ESP-NOW) as JSON. Optional key
to: 12-character hex MAC address; if present it is removed from the object and the payload is sent to that peer; otherwise the default destination is used. - Send non-JSON text: forwarded as raw bytes with the default address.
- On send failure, the server may reply with
{"error": "Send failed"}.
HTTP API by resource
Below, <id> values are string identifiers used by the JSON stores (numeric strings in practice).
Settings — /settings
| Method | Path | Description |
|---|---|---|
| GET | /settings |
Full settings object (from settings.json / Settings model). |
| PUT | /settings/settings |
Merge keys into settings and save. Returns {"message": "Settings updated successfully"}. |
| GET | /settings/wifi/ap |
Saved Wi‑Fi AP fields: saved_ssid, saved_password, saved_channel, active (Pi: active is always false). |
| POST | /settings/wifi/ap |
Body: ssid (required), password, channel (1–11). Persists AP-related settings. |
| GET | /settings/page |
Serves templates/settings.html (same page as GET /settings from the root app, for convenience). |
Profiles — /profiles
| Method | Path | Description |
|---|---|---|
| GET | /profiles |
{"profiles": {...}, "current_profile_id": "<id>"}. Ensures a default current profile when possible. |
| GET | /profiles/current |
{"id": "...", "profile": {...}} |
| GET | /profiles/<id> |
Single profile. If <id> is current, same as /profiles/current. |
| POST | /profiles |
Create profile. Body may include name and other fields. Returns { "<id>": { ... } } with status 201. |
| POST | /profiles/<id>/apply |
Sets session current profile to <id>. |
| POST | /profiles/<id>/clone |
Clone profile (tabs, palettes, presets). Body may include name. |
| PUT | /profiles/current |
Update the current profile (from session). |
| PUT | /profiles/<id> |
Update profile by id. |
| DELETE | /profiles/<id> |
Delete profile. |
Presets — /presets
Scoped to current profile in session (see above).
| Method | Path | Description |
|---|---|---|
| GET | /presets |
Map of preset id → preset object for the current profile only. |
| GET | /presets/<id> |
One preset, 404 if missing or wrong profile. |
| POST | /presets |
Create preset; server assigns id and sets profile_id. Body fields stored on the preset. Returns { "<id>": { ... } }, 201. |
| PUT | /presets/<id> |
Update preset (must belong to current profile). |
| DELETE | /presets/<id> |
Delete preset. |
| POST | /presets/send |
Push presets to the LED driver over the configured transport (see below). |
POST /presets/send body:
{
"preset_ids": ["1", "2"],
"save": true,
"default": "1",
"destination_mac": "aabbccddeeff"
}
preset_ids(orids): non-empty list of preset ids to include.save: if true, the outgoing message includes"save": trueso the driver may persist presets (default true).default: optional preset id string; forwarded as top-level"default"in the driver message (startup selection on device).destination_mac(orto): optional 12-character hex MAC for unicast; omitted uses the transport default (e.g. broadcast).
Response on success includes presets_sent, messages_sent (chunking splits payloads so each JSON string stays ≤ 240 bytes).
Tabs — /tabs
| Method | Path | Description |
|---|---|---|
| GET | /tabs |
tabs, tab_order, current_tab_id, profile_id for the session-backed profile. |
| GET | /tabs/current |
Current tab from cookie/session. |
| POST | /tabs |
Create tab; optional JSON name, names, presets; can append to current profile’s tab list. |
| GET | /tabs/<id> |
Tab JSON. |
| PUT | /tabs/<id> |
Update tab. |
| DELETE | /tabs/<id> |
Delete tab; can delete current to remove the active tab; updates profile tab list. |
| POST | /tabs/<id>/set-current |
Sets current_tab cookie. |
| POST | /tabs/<id>/clone |
Clone tab into current profile. |
Palettes — /palettes
| Method | Path | Description |
|---|---|---|
| GET | /palettes |
Map of id → color list. |
| GET | /palettes/<id> |
{"colors": [...], "id": "<id>"} |
| POST | /palettes |
Body may include colors. Returns palette object with id, 201. |
| PUT | /palettes/<id> |
Update colors (name ignored). |
| DELETE | /palettes/<id> |
Delete palette. |
Groups — /groups
| Method | Path | Description |
|---|---|---|
| GET | /groups |
All groups. |
| GET | /groups/<id> |
One group. |
| POST | /groups |
Create; optional name and fields. |
| PUT | /groups/<id> |
Update. |
| DELETE | /groups/<id> |
Delete. |
Scenes — /scenes
| Method | Path | Description |
|---|---|---|
| GET | /scenes |
All scenes. |
| GET | /scenes/<id> |
One scene. |
| POST | /scenes |
Create (body JSON stored on scene). |
| PUT | /scenes/<id> |
Update. |
| DELETE | /scenes/<id> |
Delete. |
Sequences — /sequences
| Method | Path | Description |
|---|---|---|
| GET | /sequences |
All sequences. |
| GET | /sequences/<id> |
One sequence. |
| POST | /sequences |
Create; may use group_name, presets in body. |
| PUT | /sequences/<id> |
Update. |
| DELETE | /sequences/<id> |
Delete. |
Patterns — /patterns
| Method | Path | Description |
|---|---|---|
| GET | /patterns/definitions |
Contents of pattern.json (pattern metadata for the UI). |
| GET | /patterns |
All pattern records. |
| GET | /patterns/<id> |
One pattern. |
| POST | /patterns |
Create (name, optional data). |
| PUT | /patterns/<id> |
Update. |
| DELETE | /patterns/<id> |
Delete. |
LED driver message format (transport / ESP-NOW)
Messages are JSON objects. The Pi build_message() helper (src/util/espnow_message.py) produces the same shape sent over serial and forwarded by the ESP32 bridge.
Top-level fields
{
"v": "1",
"presets": { },
"select": { },
"save": true,
"default": "preset_id",
"b": 255
}
v(required): Must be"1"or the driver ignores the message.presets: Map of preset id (string) → preset object (see below). Optionalnamefield on each value is accepted for display; the driver keys presets by map key.select: Map of device name (as in device settings) →[ "preset_id" ]or[ "preset_id", step ].save: If present (e.g. true), the driver may persist presets to flash after applying.default: Preset id string to use as startup default on the device.b: Optional global brightness 0–255 (driver applies this in addition to per-preset brightness).
Preset object (wire / driver keys)
On the wire, presets use short keys (saves space in the ≤240-byte chunks):
| Key | Meaning | Notes |
|---|---|---|
p |
Pattern id | off, on, blink, rainbow, pulse, transition, chase, circle |
c |
Colors | Array of "#RRGGBB" hex strings; converted to RGB on device |
d |
Delay ms | Default 100 |
b |
Preset brightness | 0–255; combined with global b on the device |
a |
Auto | true: run continuously; false: one step/cycle per “beat” |
n1–n6 |
Pattern parameters | See below |
The HTTP app’s POST /presets/send path builds this from stored presets via build_preset_dict() (long names like pattern / colors in the DB are translated to p / c / …).
Pattern-specific parameters (n1–n6)
Rainbow
n1: Step increment on the color wheel per update (default 1).
Pulse
n1: Attack (fade in) msn2: Hold msn3: Decay (fade out) msd: Off time between pulses ms
Transition
d: Transition duration ms
Chase
n1: LEDs with first colorn2: LEDs with second colorn3: Movement on even steps (may be negative)n4: Movement on odd steps (may be negative)
Circle
n1: Head speed (LEDs/s)n2: Max lengthn3: Tail speed (LEDs/s)n4: Min length
Select messages
{
"select": {
"device_name": ["preset_id"],
"other_device": ["preset_id", 10]
}
}
- One element: select preset; step behavior follows driver rules (reset on
off, etc.). - Two elements: explicit step for sync.
Beat and sync behavior
- Sending
selectagain with the same preset name acts as a beat (advances manual patterns / restarts generators per driver logic). - Choosing
offresets step as a sync point; then selecting a pattern aligns step 0 across devices unless a step is passed explicitly.
Example (compact preset map)
{
"v": "1",
"save": true,
"presets": {
"1": {
"name": "Red blink",
"p": "blink",
"c": ["#FF0000"],
"d": 200,
"b": 255,
"a": true,
"n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0
}
},
"select": {
"living-room": ["1"]
}
}
Processing summary (driver)
- Reject if
v != "1". - Apply optional top-level
b(global brightness). - For each entry in
presets, normalize colors and upsert preset by id. - If this device’s
nameappears inselect, run selection (optional step). - If
defaultis set, store startup preset id. - If
saveis set, persist presets.
Error handling (HTTP)
Controllers typically return JSON with an error string and 4xx/5xx status codes. Invalid JSON bodies often yield {"error": "Invalid JSON"}.
Notes
- Human-readable preset fields (
pattern,colors,delay, …) are fine in the web app / database; the send path converts them top/c/dfor the driver. - For a copy of the older long-key reference, see
led-driver/docs/API.mdin this repo (conceptually the same behavior; wire format prefers short keys).