Add LiPo battery monitoring with ESP-NOW cache and dashboard API.

Slaves report pack voltages every 30s; the master caches them for fast
BATTERY_STATUS reads. goTool exposes REST/WebSocket and shows values in
the dashboard, with a nanopb fix so optional lipo submessages encode.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 20:14:28 +02:00
co-authored by Cursor
parent eb67a46158
commit 3cb0b5bbe9
30 changed files with 1618 additions and 150 deletions
+24 -2
View File
@@ -133,7 +133,8 @@ func (h *accelStreamHub) register(conn *websocket.Conn, portName string) *wsSubs
Serial: portName,
IntervalMs: int(h.defaultInterval / time.Millisecond),
Commands: []string{
"set_stream", "get_stream", "set_accel_stream", "get_accel_stream", "set_led_ring",
"set_stream", "get_stream", "set_accel_stream", "get_accel_stream",
"set_led_ring", "get_battery",
},
}
if data, err := json.Marshal(hello); err == nil {
@@ -319,6 +320,15 @@ func writeStreamStatus(conn *websocket.Conn, msg StreamStatusMessage) {
_ = conn.WriteMessage(websocket.TextMessage, data)
}
func writeBatteryStatus(conn *websocket.Conn, out batteryAPIResponse) {
out.Type = "battery_status"
data, err := json.Marshal(out)
if err != nil {
return
}
_ = conn.WriteMessage(websocket.TextMessage, data)
}
func writeLedRingStatus(conn *websocket.Conn, out ledRingAPIResponse) {
out.Type = "led_ring_status"
data, err := json.Marshal(out)
@@ -416,10 +426,21 @@ func handleAccelWSCommand(conn *websocket.Conn, sub *wsSubscriber, data []byte,
}
writeLedRingStatus(conn, applyLedRing(link, body))
case "get_battery":
var body batteryAPIRequest
if err := json.Unmarshal(data, &body); err != nil {
writeBatteryStatus(conn, batteryAPIResponse{Error: "invalid JSON"})
return
}
if !body.AllClients && body.ClientID == 0 {
body.AllClients = true
}
writeBatteryStatus(conn, applyBatteryStatus(link, body))
default:
writeStreamStatus(conn, StreamStatusMessage{
Type: "stream_status",
Error: "unknown type (set_stream, get_stream, set_accel_stream, get_accel_stream, set_led_ring)",
Error: "unknown type (set_stream, get_stream, set_accel_stream, get_accel_stream, set_led_ring, get_battery)",
})
}
}
@@ -478,6 +499,7 @@ func runAPIServer(portName string, link *managedSerial, addr string, defaultInte
mux := http.NewServeMux()
mountExternalAPI(mux, portName, defaultInterval, hub, link, dash, ctl)
mountLedRingAPI(mux, link)
mountBatteryAPI(mux, link)
srv := &http.Server{Addr: addr, Handler: mux}
go func() {