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.
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
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/`.
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
- Network state
- 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.
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) {
DynamicJsonDocument doc(256);
doc["type"] = MSG_RELAY_RESPONSE;
doc["relay"] = relayId;
doc["enabled"] = enabled;
doc["id"] = relayId;
doc["state"] = enabled;
doc["ok"] = true;
serializeJson(doc, output);
output.println();
@@ -712,8 +712,15 @@ void handleUartMessage(const String& line) {
}
if (strcmp(type, MSG_SET_RELAY) == 0 || strcmp(type, "set_relay") == 0) {
String relayId = doc["relay"] | "";
bool enabled = doc["enabled"] | false;
String relayId = doc["id"] | "";
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)) {
sendError(DashboardSerial, "unknown_relay");
@@ -1631,9 +1638,8 @@ void handleSetRelayPost() {
DynamicJsonDocument response(512);
response["type"] = "relay_response";
response["ok"] = true;
response["relay"] = relayId;
response["id"] = relayId;
response["state"] = state;
response["enabled"] = state;
String output;
serializeJson(response, output);