Initial sanitized SmartSpeaker snapshot
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
# ESP32-S3 Audio Board - WebSocket API Specification
|
||||
|
||||
This document serves as the official protocol source of truth for developing the host server (Dev Gateway / Monitor Dashboard) and client (ESP32-S3 device) software.
|
||||
|
||||
All communications over the WebSocket connection use JSON text frames.
|
||||
|
||||
---
|
||||
|
||||
## 1. Downlink Control Commands (Server ➔ Device)
|
||||
|
||||
Commands are sent from the server to control the device's state. The message structure is:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "<command_name>",
|
||||
"value": <command_value>
|
||||
}
|
||||
```
|
||||
|
||||
### 1.1. Set Volume (`set_volume`)
|
||||
Sets the output gain level on the ES8311 mono DAC audio codec.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "set_volume",
|
||||
"value": 85
|
||||
}
|
||||
```
|
||||
* **Parameters:** `value` must be an integer between `0` (mute) and `100` (max amplification).
|
||||
|
||||
### 1.2. Query State (`query_state`)
|
||||
Requests the device to compile and send its complete state telemetry payload immediately.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "query_state"
|
||||
}
|
||||
```
|
||||
* **Parameters:** None. The device will reply immediately with a `state_report` payload (see Section 2).
|
||||
|
||||
### 1.3. Set LED Mode (`set_led`)
|
||||
Sets the active visual feedback preset mode on the WS2812B LED ring.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "set_led",
|
||||
"value": "rainbow"
|
||||
}
|
||||
```
|
||||
* **Parameters:** `value` must be a string: `"rainbow"` (moving rainbow), `"connecting"` (flashing orange), `"failed"` (solid red), `"idle"` (off), or `"updating"` (breathing blue - OTA flash).
|
||||
|
||||
### 1.4. Play Audio Track (`play_audio`)
|
||||
Triggers the ES8311 DAC codec to play an internal chime asset file from flash SPIFFS.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "play_audio",
|
||||
"value": "startup"
|
||||
}
|
||||
```
|
||||
* **Parameters:** `value` must be a string: `"startup"`, `"wifi_connecting"`, or `"wifi_connected"`.
|
||||
|
||||
### 1.5. Set LED Brightness (`set_brightness`)
|
||||
Sets the overall brightness coefficient for the WS2812B LED ring.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "set_brightness",
|
||||
"value": 0.25
|
||||
}
|
||||
```
|
||||
* **Parameters:** `value` must be a float between `0.0` (completely dark) and `1.0` (maximum intensity).
|
||||
|
||||
### 1.6. Set Haptic Vibration (`set_haptics`) [PROTO-1 Only]
|
||||
Sets the PWM vibration intensity on the GPIO 5 haptic motor.
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"command": "set_haptics",
|
||||
"value": 50
|
||||
}
|
||||
```
|
||||
* **Parameters:** `value` must be an integer between `0` (off) and `100` (max vibration).
|
||||
|
||||
---
|
||||
|
||||
## 2. Uplink State Reporting (Device ➔ Server)
|
||||
|
||||
The device reports its complete operational state to the server.
|
||||
* **Trigger Conditions:**
|
||||
1. **Periodic Telemetry:** Broadcasted automatically every `5` seconds.
|
||||
2. **Event-Driven:** Broadcasted immediately when a state changes (e.g. volume adjustment, LED mode transition, or a hardware button press).
|
||||
3. **On-Demand:** Sent in direct response to a `query_state` command.
|
||||
|
||||
* **State Report Payload:**
|
||||
```json
|
||||
{
|
||||
"type": "state_report",
|
||||
"deviceId": "ESP32-S3-A2D4",
|
||||
"timestamp": "2026-06-28T05:12:00Z",
|
||||
"system": {
|
||||
"mac_address": "A0:F2:62:E3:5C:F0",
|
||||
"model": "DEV-1",
|
||||
"firmware_version": "v1.0.0",
|
||||
"idf_version": "v6.0.1",
|
||||
"cpu_freq_mhz": 240,
|
||||
"flash_size_mb": 16,
|
||||
"psram_size_mb": 8
|
||||
},
|
||||
"health": {
|
||||
"uptime_seconds": 1205,
|
||||
"free_heap_bytes": 3842420,
|
||||
"min_free_heap_bytes": 3720100,
|
||||
"reset_reason": "POWERON_RESET"
|
||||
},
|
||||
"network": {
|
||||
"wifi_connected": true,
|
||||
"wifi_ssid": "ExampleWiFi",
|
||||
"wifi_rssi": -47,
|
||||
"ip_address": "192.0.2.10",
|
||||
"websocket_connected": true
|
||||
},
|
||||
"peripherals": {
|
||||
"audio": {
|
||||
"volume": 85,
|
||||
"player_state": "idle",
|
||||
"current_track": "none"
|
||||
},
|
||||
"led_ring": {
|
||||
"state_id": 5,
|
||||
"state_name": "rainbow",
|
||||
"brightness_coef": 0.2
|
||||
},
|
||||
"buttons": {
|
||||
"btn_play": false,
|
||||
"btn_mute": false,
|
||||
"btn_vol_up": false,
|
||||
"btn_vol_down": false
|
||||
},
|
||||
"haptic_intensity": 50,
|
||||
"ambient_light": 2048,
|
||||
"touch_active": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.1. Payload Field Definitions
|
||||
|
||||
#### System Info (`system`)
|
||||
* `mac_address` (string): Globally unique MAC address of the device network interface.
|
||||
* `model` (string): Physical hardware configuration model identifier ("DEV-1" or "PROTO-1").
|
||||
* `firmware_version` (string): Compiled application version.
|
||||
* `idf_version` (string): ESP-IDF framework version.
|
||||
* `cpu_freq_mhz` (integer): Dual-core clock speed in MHz (typically `240`).
|
||||
* `flash_size_mb` / `psram_size_mb` (integer): Total sizes of physical flash and PSRAM chips.
|
||||
|
||||
#### Health (`health`)
|
||||
* `uptime_seconds` (integer): Elapsed seconds since device boot.
|
||||
* `free_heap_bytes` (integer): Available dynamic DRAM size.
|
||||
* `min_free_heap_bytes` (integer): Lowest free memory watermark (critical for memory leak analysis).
|
||||
* `reset_reason` (string): Hardware restart source code (e.g. `POWERON_RESET`, `SW_RESET`).
|
||||
|
||||
#### Network (`network`)
|
||||
* `wifi_connected` (boolean): `true` if connected to Wi-Fi.
|
||||
* `wifi_ssid` (string): Connected Wi-Fi AP name.
|
||||
* `wifi_rssi` (integer): Wi-Fi Signal Strength in dBm (e.g., `-50` is strong, `-85` is weak).
|
||||
* `ip_address` (string): Device local IP.
|
||||
* `websocket_connected` (boolean): `true` if active control socket link is connected.
|
||||
|
||||
#### Peripherals (`peripherals`)
|
||||
* `audio` (object): DAC output status:
|
||||
* `volume` (integer): Gain scaling (`0` to `100`).
|
||||
* `player_state` (string): Current player thread status (`"idle"`, `"playing"`, `"paused"`, `"stopped"`).
|
||||
* `current_track` (string): Active file URI (e.g. `file://spiffs/startup.mp3`) or `"none"`.
|
||||
* `led_ring` (object): WS2812B visual task status:
|
||||
* `state_id` (integer): Numeric preset state enum value:
|
||||
* `0`: `LED_STATE_OFF` (Off)
|
||||
* `1`: `LED_STATE_WIFI_CONNECTING` (Flashing Red)
|
||||
* `2`: `LED_STATE_WIFI_FAILED` (Solid Red)
|
||||
* `3`: `LED_STATE_SERVER_CONNECTING` (Flashing Orange)
|
||||
* `4`: `LED_STATE_SERVER_FAILED` (Solid Orange)
|
||||
* `5`: `LED_STATE_CONNECTED` (Rainbow Rotate)
|
||||
* `6`: `LED_STATE_UPDATING` (Pulse Blue slowly - OTA flashing)
|
||||
* `state_name` (string): Visual pattern tag name (`"rainbow"`, `"connecting"`, `"failed"`, `"idle"`, `"updating"`).
|
||||
* `brightness_coef` (float): Active brightness coefficient between `0.0` and `1.0`.
|
||||
* `buttons` (object): Realtime physical state of the TCA9555 IO expander button pins (`true` if key is pressed down).
|
||||
* `haptic_intensity` (integer) [PROTO-1 Only]: Active haptic vibration level (`0` to `100`).
|
||||
* `ambient_light` (integer) [PROTO-1 Only]: Measured ambient light intensity (`0` to `4095`).
|
||||
* `touch_active` (boolean) [PROTO-1 Only]: `true` if capacitive/digital touch sensor is active.
|
||||
|
||||
---
|
||||
|
||||
## 3. Monitor Dashboard Commands (Dashboard ➔ Server)
|
||||
|
||||
Commands sent by the Monitor Dashboard client to the Dev Gateway server to manage connected device sessions. These differ from Section 1 commands in that they are **server-side operations** — the server acts on them directly rather than forwarding them to a device.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "<command_type>",
|
||||
"targetId": "<client_id>"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.1. Boot Device (`boot_device`)
|
||||
Forces a connected device to disconnect by closing its WebSocket connection server-side. Used to simulate a disconnect event, trigger device reconnection logic, or evict a misbehaving client.
|
||||
|
||||
* **Sender:** Monitor Dashboard
|
||||
* **Receiver:** Dev Gateway Server (not forwarded to device)
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"type": "boot_device",
|
||||
"targetId": "esp32-a2d4f1"
|
||||
}
|
||||
```
|
||||
* **Parameters:** `targetId` (string) — the unique client session ID of the device to disconnect.
|
||||
* **Server Behaviour:** The server locates the WebSocket for `targetId`, sends a close frame (`1000 Normal Closure`), logs a `boot` event, and broadcasts an updated `status_update` to all monitors.
|
||||
* **Device Behaviour:** The device's WebSocket client receives the close event and triggers its reconnect logic (up to 5 retries with backoff).
|
||||
|
||||
### 3.2. Control Device (`control_device`)
|
||||
Routes a downlink command (from Section 1) from the Monitor Dashboard through the server to a specific target device.
|
||||
|
||||
* **Sender:** Monitor Dashboard
|
||||
* **Receiver:** Dev Gateway Server → forwarded to target device
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"type": "control_device",
|
||||
"targetId": "esp32-a2d4f1",
|
||||
"payload": {
|
||||
"command": "set_volume",
|
||||
"value": 70
|
||||
}
|
||||
}
|
||||
```
|
||||
* **Parameters:** `targetId` (string), `payload` (object) — any valid Section 1 command object.
|
||||
|
||||
### 3.3. Trigger OTA Update (`trigger_ota`)
|
||||
Instructs the server to push a firmware binary (previously uploaded via HTTP POST `/ota/upload`) to a target device and begin the OTA flash process.
|
||||
|
||||
* **Sender:** Monitor Dashboard
|
||||
* **Receiver:** Dev Gateway Server → forwards `start_ota` downlink to target device
|
||||
* **Payload:**
|
||||
```json
|
||||
{
|
||||
"type": "trigger_ota",
|
||||
"targetId": "esp32-a2d4f1",
|
||||
"version": "latest"
|
||||
}
|
||||
```
|
||||
* **Parameters:**
|
||||
* `targetId` (string) — the ID of the target ESP32 device.
|
||||
* `version` (string, optional) — select which firmware version to deploy:
|
||||
* `"latest"` (default): Deploys the latest catalog release built by `release.ps1`.
|
||||
* `"<semver>"` (e.g. `"v0.0.32-4471303"`): Deploys a specific catalog release version.
|
||||
* `"custom"` (or omitted): Deploys the manually uploaded binary from `/ota/firmware.bin`.
|
||||
* **Server Behaviour:** Resolves target URL (either `/releases/firmware-vX.Y.Z.bin` or `/ota/firmware.bin`), sends a `start_ota` command (Section 4.1) to target device. Updates `metadata.otaStatus` to `"pending"` and broadcasts to monitors.
|
||||
|
||||
---
|
||||
|
||||
## 4. OTA Firmware Update Protocol
|
||||
|
||||
### 4.1. Downlink: Start OTA (`start_ota`)
|
||||
Server instructs the device to begin an OTA firmware download and flash.
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "start_ota",
|
||||
"url": "https://example.com/releases/firmware-v0.0.37-proto1.bin",
|
||||
"cert_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
}
|
||||
```
|
||||
|
||||
* **Parameters:**
|
||||
* `url` (string) — HTTP/HTTPS URL from which the device should fetch the firmware binary.
|
||||
* `cert_pem` (string, optional) — PEM-formatted CA certificate used to verify the HTTPS server. If omitted, the device falls back to validating the HTTPS server certificate using the built-in ESP x509 Certificate Bundle.
|
||||
* **Device Behaviour:** Spawns an OTA task. Downloads the binary in chunks. Validates the image. Writes to the inactive OTA partition. On success, commits the new partition and reboots. On failure, rolls back and reports an error.
|
||||
|
||||
### 4.2. Uplink: OTA Progress (`ota_progress`)
|
||||
Device reports download/flash progress.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "ota_progress",
|
||||
"percent": 45,
|
||||
"bytes_written": 204800,
|
||||
"bytes_total": 450000
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3. Uplink: OTA Complete (`ota_complete`)
|
||||
Device reports successful flash before rebooting.
|
||||
|
||||
```json
|
||||
{ "type": "ota_complete" }
|
||||
```
|
||||
|
||||
* Device reboots ~500ms after sending this message to apply the new firmware.
|
||||
|
||||
### 4.4. Uplink: OTA Error (`ota_error`)
|
||||
Device reports a failure during download or flash.
|
||||
|
||||
```json
|
||||
{ "type": "ota_error", "reason": "HTTP connection failed: -1" }
|
||||
```
|
||||
|
||||
* Device continues running the existing firmware after an OTA error. No rollback is needed.
|
||||
|
||||
### 4.5. Server HTTP Endpoints (OTA)
|
||||
|
||||
| Method | Path | Description |
|
||||
|:---|:---|:---|
|
||||
| `POST` | `/ota/upload` | Upload a `.bin` firmware file (multipart/form-data, field: `firmware`) |
|
||||
| `GET` | `/ota/firmware.bin` | Serve the most recently uploaded firmware binary |
|
||||
| `GET` | `/ota/status` | Return current OTA metadata: filename, size, upload time |
|
||||
| `GET` | `/ota/catalog` | Return the full catalog JSON (`firmware-catalog.json`) generated by `release.ps1` |
|
||||
| `GET` | `/releases/*` | Serve versioned release binaries (e.g. `/releases/firmware-vX.Y.Z.bin`) |
|
||||
|
||||
Reference in New Issue
Block a user