Add web dashboard configuration for master and slaves.
Expose deadzone and unicast-test via HTTP API and UI, reusing the same UART commands as the CLI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"powerpod/gotool/pb"
|
||||
)
|
||||
|
||||
type deadzoneAPIResponse struct {
|
||||
Deadzone uint32 `json:"deadzone"`
|
||||
ClientID uint32 `json:"client_id"`
|
||||
Success bool `json:"success"`
|
||||
SlavesUpdated uint32 `json:"slaves_updated"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type deadzoneAPIRequest struct {
|
||||
Write bool `json:"write"`
|
||||
Deadzone uint32 `json:"deadzone"`
|
||||
ClientID uint32 `json:"client_id"`
|
||||
AllClients bool `json:"all_clients"`
|
||||
}
|
||||
|
||||
type unicastAPIRequest struct {
|
||||
ClientID uint32 `json:"client_id"`
|
||||
Seq uint32 `json:"seq"`
|
||||
}
|
||||
|
||||
type unicastAPIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Seq uint32 `json:"seq"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func mountServeAPI(mux *http.ServeMux, link *managedSerial) {
|
||||
mux.HandleFunc("/api/deadzone", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
serveDeadzoneGet(w, r, link)
|
||||
case http.MethodPost:
|
||||
serveDeadzonePost(w, r, link)
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
mux.HandleFunc("/api/unicast-test", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
serveUnicastTest(w, r, link)
|
||||
})
|
||||
}
|
||||
|
||||
func serveDeadzoneGet(w http.ResponseWriter, r *http.Request, link *managedSerial) {
|
||||
clientID, err := parseUintQuery(r, "client_id", 0)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, deadzoneAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
resp, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{
|
||||
Write: false,
|
||||
ClientId: clientID,
|
||||
})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusServiceUnavailable, deadzoneAPIResponse{
|
||||
ClientID: clientID,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, deadzoneAPIResponse{
|
||||
Deadzone: resp.GetDeadzone(),
|
||||
ClientID: resp.GetClientId(),
|
||||
Success: resp.GetSuccess(),
|
||||
})
|
||||
}
|
||||
|
||||
func serveDeadzonePost(w http.ResponseWriter, r *http.Request, link *managedSerial) {
|
||||
var body deadzoneAPIRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, deadzoneAPIResponse{Error: "invalid JSON"})
|
||||
return
|
||||
}
|
||||
resp, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{
|
||||
Write: true,
|
||||
Deadzone: body.Deadzone,
|
||||
ClientId: body.ClientID,
|
||||
AllClients: body.AllClients,
|
||||
})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusServiceUnavailable, deadzoneAPIResponse{
|
||||
ClientID: body.ClientID,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, deadzoneAPIResponse{
|
||||
Deadzone: resp.GetDeadzone(),
|
||||
ClientID: resp.GetClientId(),
|
||||
Success: resp.GetSuccess(),
|
||||
SlavesUpdated: resp.GetSlavesUpdated(),
|
||||
})
|
||||
}
|
||||
|
||||
func serveUnicastTest(w http.ResponseWriter, r *http.Request, link *managedSerial) {
|
||||
var body unicastAPIRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, unicastAPIResponse{Error: "invalid JSON"})
|
||||
return
|
||||
}
|
||||
if body.ClientID == 0 {
|
||||
writeJSON(w, http.StatusBadRequest, unicastAPIResponse{Error: "client_id required"})
|
||||
return
|
||||
}
|
||||
if body.Seq == 0 {
|
||||
body.Seq = 1
|
||||
}
|
||||
resp, err := link.EspnowUnicastTest(body.ClientID, body.Seq)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusServiceUnavailable, unicastAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, unicastAPIResponse{
|
||||
Success: resp.GetSuccess(),
|
||||
Seq: resp.GetSeq(),
|
||||
})
|
||||
}
|
||||
|
||||
func parseUintQuery(r *http.Request, key string, def uint32) (uint32, error) {
|
||||
s := r.URL.Query().Get(key)
|
||||
if s == "" {
|
||||
return def, nil
|
||||
}
|
||||
v, err := strconv.ParseUint(s, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, v any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
_ = json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
Reference in New Issue
Block a user