diff --git a/jsonrpc.go b/jsonrpc.go index 258828a..e930f49 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -681,10 +681,11 @@ func rpcResetConfig() error { } type DCPowerState struct { - IsOn bool `json:"isOn"` - Voltage float64 `json:"voltage"` - Current float64 `json:"current"` - Power float64 `json:"power"` + IsOn bool `json:"isOn"` + Voltage float64 `json:"voltage"` + Current float64 `json:"current"` + Power float64 `json:"power"` + RestoreState int `json:"restoreState"` } func rpcGetDCPowerState() (DCPowerState, error) { @@ -700,6 +701,15 @@ func rpcSetDCPowerState(enabled bool) error { return nil } +func rpcSetDCRestoreState(state int) error { + logger.Info().Int("state", state).Msg("Setting DC restore state") + err := setDCRestoreState(state) + if err != nil { + return fmt.Errorf("failed to set DC restore state: %w", err) + } + return nil +} + func rpcGetActiveExtension() (string, error) { return config.ActiveExtension, nil } @@ -1088,6 +1098,7 @@ var rpcHandlers = map[string]RPCHandler{ "getBacklightSettings": {Func: rpcGetBacklightSettings}, "getDCPowerState": {Func: rpcGetDCPowerState}, "setDCPowerState": {Func: rpcSetDCPowerState, Params: []string{"enabled"}}, + "setDCRestoreState": {Func: rpcSetDCRestoreState, Params: []string{"state"}}, "getActiveExtension": {Func: rpcGetActiveExtension}, "setActiveExtension": {Func: rpcSetActiveExtension, Params: []string{"extensionId"}}, "getATXState": {Func: rpcGetATXState}, diff --git a/serial.go b/serial.go index f4dd5b5..90fed8f 100644 --- a/serial.go +++ b/serial.go @@ -142,6 +142,7 @@ var dcState DCPowerState func runDCControl() { scopedLogger := serialLogger.With().Str("service", "dc_control").Logger() reader := bufio.NewReader(port) + hasRestoreFeature := false for { line, err := reader.ReadString('\n') if err != nil { @@ -151,7 +152,13 @@ func runDCControl() { // Split the line by semicolon parts := strings.Split(strings.TrimSpace(line), ";") - if len(parts) != 4 { + if len(parts) == 5 { + scopedLogger.Debug().Str("line", line).Msg("Detected DC extension with restore feature") + hasRestoreFeature = true + } else if len(parts) == 4 { + scopedLogger.Debug().Str("line", line).Msg("Detected DC extension without restore feature") + hasRestoreFeature = false + } else { scopedLogger.Warn().Str("line", line).Msg("Invalid line") continue } @@ -163,6 +170,17 @@ func runDCControl() { continue } dcState.IsOn = powerState == 1 + if hasRestoreFeature { + restoreState, err := strconv.Atoi(parts[4]) + if err != nil { + scopedLogger.Warn().Err(err).Msg("Invalid restore state") + continue + } + dcState.RestoreState = restoreState + } else { + // -1 means not supported + dcState.RestoreState = -1 + } milliVolts, err := strconv.ParseFloat(parts[1], 64) if err != nil { scopedLogger.Warn().Err(err).Msg("Invalid voltage") @@ -210,6 +228,24 @@ func setDCPowerState(on bool) error { return nil } +func setDCRestoreState(state int) error { + _, err := port.Write([]byte("\n")) + if err != nil { + return err + } + command := "RESTORE_MODE_OFF\n" + if state == 1 { + command = "RESTORE_MODE_ON\n" + } else if state == 2 { + command = "RESTORE_MODE_LAST_STATE\n" + } + _, err = port.Write([]byte(command)) + if err != nil { + return err + } + return nil +} + var defaultMode = &serial.Mode{ BaudRate: 115200, DataBits: 8, diff --git a/ui/src/components/extensions/DCPowerControl.tsx b/ui/src/components/extensions/DCPowerControl.tsx index 3fcb7dc..a13e4ea 100644 --- a/ui/src/components/extensions/DCPowerControl.tsx +++ b/ui/src/components/extensions/DCPowerControl.tsx @@ -8,12 +8,14 @@ import { useJsonRpc } from "@/hooks/useJsonRpc"; import notifications from "@/notifications"; import FieldLabel from "@components/FieldLabel"; import LoadingSpinner from "@components/LoadingSpinner"; +import {SelectMenuBasic} from "@components/SelectMenuBasic"; interface DCPowerState { isOn: boolean; voltage: number; current: number; power: number; + restoreState: number; } export function DCPowerControl() { @@ -43,6 +45,20 @@ export function DCPowerControl() { getDCPowerState(); // Refresh state after change }); }; + const handleRestoreChange = (state: number) => { + // const state = powerState?.restoreState === 0 ? 1 : powerState?.restoreState === 1 ? 2 : 0; + send("setDCRestoreState", { state }, resp => { + if ("error" in resp) { + notifications.error( + `Failed to set DC power state: ${resp.error.data || "Unknown error"}`, + ); + return; + } + getDCPowerState(); // Refresh state after change + }); + }; + + useEffect(() => { getDCPowerState(); @@ -63,7 +79,7 @@ export function DCPowerControl() { ) : ( - +
{/* Power Controls */}
@@ -84,6 +100,21 @@ export function DCPowerControl() { onClick={() => handlePowerToggle(false)} />
+ {powerState.restoreState > -1 ? ( +
+ handleRestoreChange(parseInt(e.target.value))} + options={[ + { value: '0', label: "Power OFF" }, + { value: '1', label: "Power ON" }, + { value: '2', label: "Last State" }, + ]} + /> +
+ ) : null}
{/* Status Display */}