Standardize API UART parity and update docs

This commit is contained in:
2026-06-04 14:10:13 -06:00
parent 6884bc7b32
commit f46e72fc7f
7 changed files with 576 additions and 6 deletions
+305
View File
@@ -233,3 +233,308 @@ text 0.3.x
Future firmware versions may add fields while maintaining backward compatibility. Future firmware versions may add fields while maintaining backward compatibility.
Consumers should ignore unknown fields. Consumers should ignore unknown fields.
---
## Embedded Dashboard
The ESP32 is planned to serve a lightweight mobile dashboard at:
GET /
When connected directly to the ESP32 AP:
http://192.168.4.1/
The page should:
- Poll /status
- Display battery state
- Display temperature sensors
- Display relay states
- Show alarms
- Allow basic relay control
Design limits:
- Small inline HTML/CSS/JS
- No external libraries
- No large assets
- No heavy JavaScript framework
The embedded dashboard is intended as a convenient phone view, not a replacement for the physical Pico dashboard.
---
## Future WiFi API
Future configuration may include WiFi management endpoints.
Possible future endpoints:
GET /config/wifi
POST /config/wifi
POST /config/wifi/add
POST /config/wifi/remove
POST /config/wifi/reorder
Potential config model:
ap_enabled
sta_enabled
hostname
saved_networks
Saved networks should support priority order.
Example:
Starlink
Home WiFi
Shop WiFi
The AP should remain enabled even when connected to STA WiFi.
---
# HTTP / UART Parity Endpoints
These endpoints mirror UART setup/control messages.
## Save Config
POST /config/save
Equivalent UART message:
{"type":"save_config"}
## BMS Setup Mode
Enter BMS setup mode:
POST /bms/setup/enter
Equivalent UART message:
{"type":"enter_bms_setup"}
Exit BMS setup mode:
POST /bms/setup/exit
Equivalent UART message:
{"type":"exit_bms_setup"}
## BLE Scan
Scan for BLE devices:
POST /bms/scan
Equivalent UART message:
{"type":"scan_ble"}
Response:
{
"type": "ble_scan_response",
"devices": [
{
"index": 1,
"name": "House Battery",
"address": "aa:bb:cc:dd:ee:ff",
"rssi": -65
}
]
}
## Select BMS
Select a BMS from the most recent scan:
POST /bms/select
Request body:
{
"index": 1
}
Equivalent UART message:
{"type":"select_bms","index":1}
---
# Preferred Relay Command Endpoint
The preferred relay control endpoint is:
POST /relay/set
Request body:
{
"id": "relay_1",
"state": true
}
Example:
curl -X POST http://192.168.88.108/relay/set \
-H "Content-Type: application/json" \
-d '{"id":"relay_1","state":true}'
Equivalent UART message:
{"type":"set_relay","relay":"relay_1","enabled":true}
Legacy GET relay routes may remain for compatibility:
GET /relay/relay_1/on
GET /relay/relay_1/off
GET /relay/relay_2/on
GET /relay/relay_2/off
---
# WiFi Configuration API
## Get WiFi Config
GET /config/wifi
## Set WiFi Config
POST /config/wifi
Request body:
{
"ssid": "Starlink",
"password": "password_here"
}
## Connect STA WiFi
POST /wifi/connect
## Clear WiFi Config
POST /wifi/clear
The ESP32 AP remains available even when STA WiFi is configured.
Equivalent UART messages:
{"type":"wifi_request"}
{"type":"config_wifi","ssid":"Starlink","password":"password_here"}
{"type":"wifi_connect"}
{"type":"wifi_clear"}
---
# WiFi Priority and Runtime Failover
Saved WiFi networks support priority.
Lower priority numbers are attempted first.
Example:
{
"networks": [
{
"ssid": "Starlink",
"password": "starlink_password",
"priority": 1
},
{
"ssid": "Home WiFi",
"password": "home_password",
"priority": 2
}
]
}
The ESP32 behavior is:
AP always stays enabled
STA tries saved networks by priority
If disconnected at runtime, STA retries saved networks every 30 seconds
If all STA networks fail, AP remains available at 192.168.4.1
---
# API Parity Notes
The HTTP API is intended to mirror the UART JSON protocol where practical.
## Preferred Relay Control
Preferred endpoint:
POST /relay/set
Request:
{
"id": "relay_1",
"state": true
}
Response:
{
"type": "relay_response",
"ok": true,
"id": "relay_1",
"state": true
}
Legacy relay routes may remain available for compatibility:
GET /relay/relay_1/on
GET /relay/relay_1/off
GET /relay/relay_2/on
GET /relay/relay_2/off
## WiFi Parity
WiFi configuration supports multiple saved STA networks.
Request:
POST /config/wifi
Body:
{
"networks": [
{
"ssid": "Starlink",
"password": "starlink_password",
"priority": 1
},
{
"ssid": "Home WiFi",
"password": "home_password",
"priority": 2
}
]
}
Lower priority numbers are attempted first.
Runtime behavior:
AP always remains enabled.
STA tries saved networks by priority.
If STA disconnects, saved networks are retried every 30 seconds.
+96
View File
@@ -233,3 +233,99 @@ Possible future integrations:
- OTA updates - OTA updates
All future integrations should consume the same generic status/config model. All future integrations should consume the same generic status/config model.
---
## Networking Architecture
### Current Network Mode
The ESP32 currently runs in Access Point mode.
Default access:
http://192.168.4.1
The AP is the recovery/setup network.
### Planned Network Mode
The planned long-term network mode is AP + STA.
AP mode:
Always available
Used for recovery and direct setup
STA mode:
Connects to a configured WiFi network
Used for camp/home access from phone or laptop
Example networks:
Starlink
Home WiFi
Shop WiFi
### Multiple WiFi Profiles
The ESP32 should eventually store multiple WiFi profiles and try them in priority order.
Example:
1. Starlink
2. Home WiFi
3. Shop WiFi
Expected behavior:
Start AP first
Try configured STA networks
Connect to the first available network
Keep AP available even after STA connects
Reason:
- Starlink may be off
- Home WiFi may only be available in the driveway
- AP must remain available for recovery
- User should not lose access because of a bad WiFi password
### Phone Dashboard Access
When connected to the ESP32 AP:
http://192.168.4.1
When connected through Starlink/home WiFi:
http://controller-ip
Future mDNS target:
http://overland-controller.local
### Dashboard Roles
ESP32:
Source of truth
Lightweight phone dashboard
HTTP API
Recovery AP
Pico 2 W:
Instant physical dashboard
UART client
Touchscreen UI
Optional future Pi Zero:
Advanced web dashboard
Logging
Charts
Integrations
The Pi Zero should be optional, not required for core operation.
+81
View File
@@ -0,0 +1,81 @@
# Command Parity Matrix
This document tracks feature parity across the three control surfaces.
Control surfaces:
- USB serial console
- UART JSON protocol
- HTTP API
## Current Parity
| Feature | USB Serial | UART JSON | HTTP API | Notes |
|---|---:|---:|---:|---|
| Status | Yes | Yes | Yes | `/status` equals `status_request` |
| Config view | Yes | Yes | Yes | `/config` equals `config_request` |
| Relay control | Yes | Yes | Yes | Preferred HTTP endpoint is `POST /relay/set` |
| Device name config | Yes | Yes | Yes | `devicename`, `config_device`, `/config/device` |
| Relay config | Yes | Yes | Yes | `relayname`, `config_relay`, `/config/relay` |
| Temperature config | Yes | Yes | Yes | `tempname`, `config_temp`, `/config/temp` |
| BMS config | Yes | Yes | Yes | `bmsname`/`bmsaddr`, `config_bms`, `/config/bms` |
| Save config | Yes | Yes | Yes | `save`, `save_config`, `/config/save` |
| Factory reset | Yes | Yes | Yes | AP remains recovery path |
| BMS setup enter | Yes | Yes | Yes | Setup pauses normal BMS reconnect behavior |
| BMS setup exit | Yes | Yes | Yes | Returns to normal mode |
| BLE scan | Yes | Yes | Yes | Some BMS devices require repeated scans |
| Select BMS | Yes | Yes | Yes | Uses most recent scan result index |
| WiFi config | Yes | Yes | Yes | Supports multiple saved STA networks |
| WiFi priority | Yes | Yes | Yes | Lower priority number is tried first |
| WiFi connect | Yes | Yes | Yes | AP remains available |
| WiFi clear | Yes | Yes | Yes | Clears saved STA networks |
## Preferred Command Model
Use generic IDs everywhere.
Relays:
relay_1
relay_2
Temperature sensors:
temp_1 through temp_8
Preferred relay command shape:
{
"type": "set_relay",
"id": "relay_1",
"state": true
}
Legacy UART relay fields may still be accepted:
relay
enabled
Preferred HTTP relay endpoint:
POST /relay/set
Legacy HTTP relay routes may remain for compatibility:
GET /relay/relay_1/on
GET /relay/relay_1/off
GET /relay/relay_2/on
GET /relay/relay_2/off
## Response Shape Standard
Success responses should include:
ok: true
Error responses should include:
ok: false
error: "error_code"
Status/config responses should preserve the generic data model used by `/status`.
+5
View File
@@ -27,3 +27,8 @@ This folder contains project documentation for Overland Controller.
Older or duplicate documents have been moved to `archive/`. Older or duplicate documents have been moved to `archive/`.
Archived documents are kept for history, but the primary documents above should be treated as the current source of truth. Archived documents are kept for history, but the primary documents above should be treated as the current source of truth.
## Parity
- `PARITY_MATRIX.md` - Command parity across USB serial, UART JSON, and HTTP API
+50
View File
@@ -364,3 +364,53 @@ Returns complete runtime status including:
- Alarms - Alarms
- Network state - Network state
- System information - System information
---
# WiFi Serial Commands
## wifi status
Print current WiFi status.
## wifi list
Print saved WiFi networks, priorities, and whether passwords are set.
## wifi clear
Clear saved STA WiFi networks.
## wifi ssid <ssid>
Set primary WiFi SSID.
## wifi pass <password>
Set primary WiFi password.
## wifi add <ssid>|<password>|<priority>
Add a saved WiFi network.
Example:
wifi add Starlink|starlink_password|1
wifi add WardAP|Ward5213|2
wifi save
wifi connect
Lower priority numbers are tried first.
## wifi save
Save WiFi configuration.
## wifi connect
Attempt STA WiFi connection using saved networks by priority.
AP remains available at:
192.168.4.1
+27
View File
@@ -205,3 +205,30 @@ Runtime behavior:
If STA disconnects, the ESP32 retries saved networks by priority every 30 seconds. If STA disconnects, the ESP32 retries saved networks by priority every 30 seconds.
AP mode remains available as a recovery path. AP mode remains available as a recovery path.
---
# UART Parity Notes
UART should use the same generic command model as HTTP.
## Preferred Relay Command
Preferred:
{"type":"set_relay","id":"relay_1","state":true}
Legacy accepted shape:
{"type":"set_relay","relay":"relay_1","enabled":true}
Preferred response:
{"type":"relay_response","ok":true,"id":"relay_1","state":true}
## WiFi Priority Config
{"type":"config_wifi","networks":[{"ssid":"Starlink","password":"password","priority":1},{"ssid":"Home WiFi","password":"password","priority":2}]}
Lower priority numbers are tried first.
@@ -591,8 +591,8 @@ bool setRelayById(const String& relayId, bool enabled) {
void sendRelayResponse(Stream& output, const String& relayId, bool enabled) { void sendRelayResponse(Stream& output, const String& relayId, bool enabled) {
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
doc["type"] = MSG_RELAY_RESPONSE; doc["type"] = MSG_RELAY_RESPONSE;
doc["relay"] = relayId; doc["id"] = relayId;
doc["enabled"] = enabled; doc["state"] = enabled;
doc["ok"] = true; doc["ok"] = true;
serializeJson(doc, output); serializeJson(doc, output);
output.println(); output.println();
@@ -712,8 +712,15 @@ void handleUartMessage(const String& line) {
} }
if (strcmp(type, MSG_SET_RELAY) == 0 || strcmp(type, "set_relay") == 0) { if (strcmp(type, MSG_SET_RELAY) == 0 || strcmp(type, "set_relay") == 0) {
String relayId = doc["relay"] | ""; String relayId = doc["id"] | "";
bool enabled = doc["enabled"] | false; if (relayId.length() == 0) {
relayId = doc["relay"] | "";
}
bool enabled = doc["state"] | false;
if (doc["enabled"].is<bool>()) {
enabled = doc["enabled"].as<bool>();
}
if (!setRelayById(relayId, enabled)) { if (!setRelayById(relayId, enabled)) {
sendError(DashboardSerial, "unknown_relay"); sendError(DashboardSerial, "unknown_relay");
@@ -1631,9 +1638,8 @@ void handleSetRelayPost() {
DynamicJsonDocument response(512); DynamicJsonDocument response(512);
response["type"] = "relay_response"; response["type"] = "relay_response";
response["ok"] = true; response["ok"] = true;
response["relay"] = relayId; response["id"] = relayId;
response["state"] = state; response["state"] = state;
response["enabled"] = state;
String output; String output;
serializeJson(response, output); serializeJson(response, output);