Solid color mode fills all ring LEDs; master routes UART commands to slaves via ESPNOW_LED_RING. goTool exposes POST /api/led-ring, WebSocket set_led_ring, and a dashboard LED panel with master/slave/all targets. Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"powerpod/gotool/pb"
|
|
)
|
|
|
|
const (
|
|
ledRingModeClear = 0
|
|
ledRingModeProgress = 1
|
|
ledRingModeDigit = 2
|
|
ledRingModeBlink = 3
|
|
ledRingModeFindMe = 4
|
|
ledRingModeColor = 5
|
|
)
|
|
|
|
type ledRingAPIRequest struct {
|
|
Mode string `json:"mode"`
|
|
ClientID uint32 `json:"client_id"`
|
|
AllClients bool `json:"all_clients"`
|
|
SlavesOnly bool `json:"slaves_only"`
|
|
Progress uint32 `json:"progress"`
|
|
Digit uint32 `json:"digit"`
|
|
R uint32 `json:"r"`
|
|
G uint32 `json:"g"`
|
|
B uint32 `json:"b"`
|
|
Intensity uint32 `json:"intensity"`
|
|
BlinkMs uint32 `json:"blink_ms"`
|
|
BlinkCount uint32 `json:"blink_count"`
|
|
}
|
|
|
|
type ledRingAPIResponse struct {
|
|
Type string `json:"type,omitempty"` // led_ring_status (WebSocket)
|
|
Success bool `json:"success"`
|
|
Mode uint32 `json:"mode,omitempty"`
|
|
Progress uint32 `json:"progress,omitempty"`
|
|
Digit uint32 `json:"digit,omitempty"`
|
|
ClientID uint32 `json:"client_id,omitempty"`
|
|
SlavesUpdated uint32 `json:"slaves_updated,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func ledRingModeFromString(s string) (uint32, error) {
|
|
switch strings.ToLower(strings.TrimSpace(s)) {
|
|
case "clear", "":
|
|
return ledRingModeClear, nil
|
|
case "color", "solid", "fill":
|
|
return ledRingModeColor, nil
|
|
case "progress":
|
|
return ledRingModeProgress, nil
|
|
case "digit":
|
|
return ledRingModeDigit, nil
|
|
case "blink":
|
|
return ledRingModeBlink, nil
|
|
case "find-me", "find_me", "findme":
|
|
return ledRingModeFindMe, nil
|
|
default:
|
|
return 0, fmt.Errorf("unknown mode %q (clear, color, progress, digit, blink, find-me)", s)
|
|
}
|
|
}
|
|
|
|
func ledRingPBFromAPI(in ledRingAPIRequest) (*pb.LedRingProgressRequest, error) {
|
|
mode, err := ledRingModeFromString(in.Mode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &pb.LedRingProgressRequest{
|
|
Mode: mode,
|
|
Progress: in.Progress,
|
|
Digit: in.Digit,
|
|
R: in.R,
|
|
G: in.G,
|
|
B: in.B,
|
|
Intensity: in.Intensity,
|
|
BlinkMs: in.BlinkMs,
|
|
BlinkCount: in.BlinkCount,
|
|
ClientId: in.ClientID,
|
|
AllClients: in.AllClients,
|
|
SlavesOnly: in.SlavesOnly,
|
|
}, nil
|
|
}
|
|
|
|
func applyLedRing(link *managedSerial, in ledRingAPIRequest) ledRingAPIResponse {
|
|
req, err := ledRingPBFromAPI(in)
|
|
if err != nil {
|
|
return ledRingAPIResponse{Error: err.Error()}
|
|
}
|
|
resp, err := link.LedRing(req)
|
|
if err != nil {
|
|
return ledRingAPIResponse{Error: err.Error()}
|
|
}
|
|
out := ledRingAPIResponse{
|
|
Success: resp.GetSuccess(),
|
|
Mode: resp.GetMode(),
|
|
Progress: resp.GetProgress(),
|
|
Digit: resp.GetDigit(),
|
|
ClientID: resp.GetClientId(),
|
|
SlavesUpdated: resp.GetSlavesUpdated(),
|
|
}
|
|
if !out.Success && out.Error == "" {
|
|
out.Error = "led ring command rejected"
|
|
}
|
|
return out
|
|
}
|