Files
system-control/firmware/README-API.md
2026-01-01 17:34:44 +01:00

802 lines
18 KiB
Markdown

# System Control - API Documentation
This document describes all REST API endpoints and WebSocket messages required for the ESP32 firmware implementation.
## Table of Contents
- [REST API Endpoints](#rest-api-endpoints)
- [WiFi](#wifi)
- [Light Control](#light-control)
- [LED Configuration](#led-configuration)
- [Schema](#schema)
- [Devices](#devices)
- [Scenes](#scenes)
- [WebSocket](#websocket)
- [Connection](#connection)
- [Client to Server Messages](#client-to-server-messages)
- [Server to Client Messages](#server-to-client-messages)
---
## REST API Endpoints
### WiFi
#### Scan Networks
Scans for available WiFi networks.
- **URL:** `/api/wifi/scan`
- **Method:** `GET`
- **Response:**
```json
[
{
"ssid": "NetworkName",
"rssi": -45
},
{
"ssid": "AnotherNetwork",
"rssi": -72
}
]
```
| Field | Type | Description |
|-------|--------|------------------------------------|
| ssid | string | Network name (SSID) |
| rssi | number | Signal strength in dBm |
---
#### Save WiFi Configuration
Saves WiFi credentials and initiates connection.
- **URL:** `/api/wifi/config`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"ssid": "NetworkName",
"password": "SecretPassword123"
}
```
| Field | Type | Required | Description |
|----------|--------|----------|-------------------|
| ssid | string | Yes | Network name |
| password | string | No | Network password |
- **Response:** `200 OK` on success, `400 Bad Request` on error
---
#### Get WiFi Status
Returns current WiFi connection status.
- **URL:** `/api/wifi/status`
- **Method:** `GET`
- **Response:**
```json
{
"connected": true,
"ssid": "NetworkName",
"ip": "192.168.1.100",
"rssi": -45
}
```
| Field | Type | Description |
|-----------|---------|------------------------------------------|
| connected | boolean | Whether connected to a network |
| ssid | string | Connected network name (if connected) |
| ip | string | Assigned IP address (if connected) |
| rssi | number | Signal strength in dBm (if connected) |
---
### Light Control
#### Set Light Power
Turns the main light on or off.
- **URL:** `/api/light/power`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"on": true
}
```
| Field | Type | Required | Description |
|-------|---------|----------|--------------------------|
| on | boolean | Yes | `true` = on, `false` = off |
- **Response:** `200 OK` on success
---
#### Set Light Mode
Sets the lighting mode.
- **URL:** `/api/light/mode`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"mode": "simulation"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|------------------------------------------------|
| mode | string | Yes | One of: `day`, `night`, `simulation` |
- **Response:** `200 OK` on success
---
#### Set Active Schema
Sets the active schema for simulation mode.
- **URL:** `/api/light/schema`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"schema": "schema_01.csv"
}
```
| Field | Type | Required | Description |
|--------|--------|----------|-------------------------------------------------------|
| schema | string | Yes | Schema filename: `schema_01.csv`, `schema_02.csv`, etc. |
- **Response:** `200 OK` on success
---
#### Get Light Status
Returns current light status (alternative to WebSocket).
- **URL:** `/api/light/status`
- **Method:** `GET`
- **Response:**
```json
{
"on": true,
"mode": "simulation",
"schema": "schema_01.csv",
"color": {
"r": 255,
"g": 240,
"b": 220
}
}
```
| Field | Type | Description |
|--------|---------|--------------------------------------|
| on | boolean | Current power state |
| mode | string | Current mode (day/night/simulation) |
| schema | string | Active schema filename |
| color | object | Current RGB color being displayed |
---
### LED Configuration
#### Get LED Configuration
Returns the current LED segment configuration.
- **URL:** `/api/wled/config`
- **Method:** `GET`
- **Response:**
```json
{
"segments": [
{
"name": "Main Light",
"start": 0,
"leds": 60
},
{
"name": "Accent Light",
"start": 60,
"leds": 30
}
]
}
```
| Field | Type | Description |
|--------------------|--------|------------------------------------------|
| segments | array | List of LED segments |
| segments[].name | string | Optional segment name |
| segments[].start | number | Start LED index (0-based) |
| segments[].leds | number | Number of LEDs in this segment |
---
#### Save LED Configuration
Saves the LED segment configuration.
- **URL:** `/api/wled/config`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"segments": [
{
"name": "Main Light",
"start": 0,
"leds": 60
},
{
"name": "Accent Light",
"start": 60,
"leds": 30
}
]
}
```
| Field | Type | Required | Description |
|--------------------|--------|----------|------------------------------------------|
| segments | array | Yes | List of LED segments (can be empty) |
| segments[].name | string | No | Optional segment name |
| segments[].start | number | Yes | Start LED index (0-based) |
| segments[].leds | number | Yes | Number of LEDs in this segment |
- **Response:** `200 OK` on success, `400 Bad Request` on validation error
**Notes:**
- Segments define how the LED strip is divided into logical groups
- Changes are persisted to NVS (non-volatile storage)
- Each segment can be controlled independently in the light schema
---
### Schema
#### Load Schema
Loads a schema file.
- **URL:** `/api/schema/{filename}`
- **Method:** `GET`
- **URL Parameters:**
- `filename`: Schema file name (e.g., `schema_01.csv`)
- **Response:** CSV text data
```
255,240,220,0,100,250
255,230,200,0,120,250
...
```
The CSV format has 48 rows (one per 30-minute interval) with 6 values per row:
| Column | Description | Range |
|--------|--------------------------------|---------|
| 1 | Red (R) | 0-255 |
| 2 | Green (G) | 0-255 |
| 3 | Blue (B) | 0-255 |
| 4 | Value 1 (V1) - custom value | 0-255 |
| 5 | Value 2 (V2) - custom value | 0-255 |
| 6 | Value 3 (V3) - custom value | 0-255 |
---
#### Save Schema
Saves a schema file.
- **URL:** `/api/schema/{filename}`
- **Method:** `POST`
- **Content-Type:** `text/csv`
- **URL Parameters:**
- `filename`: Schema file name (e.g., `schema_01.csv`)
- **Request Body:** CSV text data (same format as above)
- **Response:** `200 OK` on success
---
### Devices
#### Scan for Devices
Scans for available Matter devices to pair.
- **URL:** `/api/devices/scan`
- **Method:** `GET`
- **Response:**
```json
[
{
"id": "matter-001",
"type": "light",
"name": "Matter Lamp"
},
{
"id": "matter-002",
"type": "sensor",
"name": "Temperature Sensor"
}
]
```
| Field | Type | Description |
|-------|--------|-----------------------------------------------|
| id | string | Unique device identifier |
| type | string | Device type: `light`, `sensor`, `unknown` |
| name | string | Device name (can be empty) |
---
#### Pair Device
Pairs a discovered device.
- **URL:** `/api/devices/pair`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "matter-001",
"name": "Living Room Lamp"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|------------------------------|
| id | string | Yes | Device ID from scan |
| name | string | Yes | User-defined device name |
- **Response:** `200 OK` on success
---
#### Get Paired Devices
Returns list of all paired devices.
- **URL:** `/api/devices/paired`
- **Method:** `GET`
- **Response:**
```json
[
{
"id": "matter-001",
"type": "light",
"name": "Living Room Lamp"
}
]
```
| Field | Type | Description |
|-------|--------|-------------------------------------------|
| id | string | Unique device identifier |
| type | string | Device type: `light`, `sensor`, `unknown` |
| name | string | User-defined device name |
---
#### Update Device Name
Updates the name of a paired device.
- **URL:** `/api/devices/update`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "matter-001",
"name": "New Device Name"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|------------------------|
| id | string | Yes | Device ID |
| name | string | Yes | New device name |
- **Response:** `200 OK` on success
---
#### Unpair Device
Removes a paired device.
- **URL:** `/api/devices/unpair`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "matter-001"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|---------------|
| id | string | Yes | Device ID |
- **Response:** `200 OK` on success
---
#### Toggle Device
Toggles a device (e.g., light on/off).
- **URL:** `/api/devices/toggle`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "matter-001"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|---------------|
| id | string | Yes | Device ID |
- **Response:** `200 OK` on success
---
### Scenes
#### Get All Scenes
Returns all configured scenes.
- **URL:** `/api/scenes`
- **Method:** `GET`
- **Response:**
```json
[
{
"id": "scene-1",
"name": "Evening Mood",
"icon": "🌅",
"actions": {
"light": "on",
"mode": "simulation",
"schema": "schema_02.csv",
"devices": [
{
"id": "matter-001",
"state": "on"
}
]
}
},
{
"id": "scene-2",
"name": "Night Mode",
"icon": "🌙",
"actions": {
"light": "on",
"mode": "night"
}
}
]
```
**Scene Object:**
| Field | Type | Description |
|---------|--------|------------------------------------|
| id | string | Unique scene identifier |
| name | string | Scene name |
| icon | string | Emoji icon for the scene |
| actions | object | Actions to execute (see below) |
**Actions Object:**
| Field | Type | Optional | Description |
|---------|--------|----------|------------------------------------------|
| light | string | Yes | `"on"` or `"off"` |
| mode | string | Yes | `"day"`, `"night"`, or `"simulation"` |
| schema | string | Yes | Schema filename (e.g., `schema_01.csv`) |
| devices | array | Yes | Array of device actions (see below) |
**Device Action Object:**
| Field | Type | Description |
|-------|--------|----------------------------------|
| id | string | Device ID |
| state | string | `"on"` or `"off"` |
---
#### Create/Update Scene
Creates a new scene or updates an existing one.
- **URL:** `/api/scenes`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "scene-1",
"name": "Evening Mood",
"icon": "🌅",
"actions": {
"light": "on",
"mode": "simulation",
"schema": "schema_02.csv",
"devices": [
{
"id": "matter-001",
"state": "on"
}
]
}
}
```
- **Response:** `200 OK` on success
---
#### Delete Scene
Deletes a scene.
- **URL:** `/api/scenes`
- **Method:** `DELETE`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "scene-1"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|---------------|
| id | string | Yes | Scene ID |
- **Response:** `200 OK` on success
---
#### Activate Scene
Executes all actions of a scene.
- **URL:** `/api/scenes/activate`
- **Method:** `POST`
- **Content-Type:** `application/json`
- **Request Body:**
```json
{
"id": "scene-1"
}
```
| Field | Type | Required | Description |
|-------|--------|----------|---------------|
| id | string | Yes | Scene ID |
- **Response:** `200 OK` on success
---
## WebSocket
### Connection
- **URL:** `ws://{host}/ws` or `wss://{host}/ws`
- **Protocol:** JSON messages
The WebSocket connection is used for real-time status updates. The client should reconnect automatically if the connection is lost (recommended: 3 second delay).
---
### Client to Server Messages
#### Request Status
Requests the current system status.
```json
{
"type": "getStatus"
}
```
---
### Server to Client Messages
#### Status Update
Sent in response to `getStatus` or when status changes.
```json
{
"type": "status",
"on": true,
"mode": "simulation",
"schema": "schema_01.csv",
"color": {
"r": 255,
"g": 240,
"b": 220
}
}
```
| Field | Type | Description |
|--------|---------|--------------------------------------|
| type | string | Always `"status"` |
| on | boolean | Light power state |
| mode | string | Current mode (day/night/simulation) |
| schema | string | Active schema filename |
| color | object | Current RGB color (optional) |
---
#### Color Update
Sent when the current color changes (during simulation).
```json
{
"type": "color",
"r": 255,
"g": 200,
"b": 150
}
```
| Field | Type | Description |
|-------|--------|--------------------------|
| type | string | Always `"color"` |
| r | number | Red value (0-255) |
| g | number | Green value (0-255) |
| b | number | Blue value (0-255) |
---
#### WiFi Status Update
Sent when WiFi connection status changes.
```json
{
"type": "wifi",
"connected": true,
"ip": "192.168.1.100",
"rssi": -45
}
```
| Field | Type | Description |
|-----------|---------|---------------------------------------|
| type | string | Always `"wifi"` |
| connected | boolean | Whether connected to a network |
| ip | string | Assigned IP address (if connected) |
| rssi | number | Signal strength in dBm (if connected) |
---
## Static Files
The web interface files should be served from the `/storage/www/` directory:
| Path | Description |
|----------------------|------------------------------------------------|
| `/` | Serves `index.html` (or `captive.html` in AP mode) |
| `/index.html` | Main HTML file (full interface) |
| `/captive.html` | Captive portal (WiFi setup only) |
| `/css/shared.css` | Shared styles for all pages |
| `/css/index.css` | Styles for main interface |
| `/css/captive.css` | Styles for captive portal |
| `/js/wifi-shared.js` | Shared WiFi configuration logic |
| `/js/*.js` | JavaScript modules |
---
## Captive Portal
When the ESP32 is in Access Point (AP) mode (no WiFi configured or connection failed), it should serve the captive portal:
### Behavior
1. **AP Mode Activation:**
- ESP32 creates an access point (e.g., "marklin-setup")
- DNS server redirects all requests to the ESP32's IP (captive portal detection)
2. **Captive Portal Detection:**
- Respond to common captive portal detection URLs:
- `/generate_204` (Android)
- `/hotspot-detect.html` (Apple)
- `/connecttest.txt` (Windows)
- Return redirect or serve `captive.html`
3. **Serving Files in AP Mode:**
- `/``captive.html`
- `/captive.html` → Captive portal page
- `/js/wifi-shared.js` → WiFi functions
- API endpoints remain the same (`/api/wifi/*`)
4. **After Successful Configuration:**
- ESP32 attempts to connect to the configured network
- If successful, switch to Station mode and serve `index.html`
- If failed, remain in AP mode
### Recommended AP Settings
| Setting | Value |
|---------------|--------------------------|
| SSID | `marklin-setup` |
| Password | None (open) or `marklin` |
| IP Address | `192.168.4.1` |
| Gateway | `192.168.4.1` |
| Subnet | `255.255.255.0` |
---
## Error Handling
All endpoints should return appropriate HTTP status codes:
| Code | Description |
|------|---------------------------------------|
| 200 | Success |
| 400 | Bad Request (invalid input) |
| 404 | Not Found (resource doesn't exist) |
| 500 | Internal Server Error |
Error responses should include a JSON body with an error message:
```json
{
"error": "Description of what went wrong"
}
```