Add health check command and panorama control
- New `dwarfctl health` command: checks WebSocket connectivity, device state,
battery, storage, RGB, focus motor, both cameras, motor position status,
and CMOS temperature in one pass with clear OK/FAIL output
- Added `dwarfctl pano start|stop` for panorama grid control
- Added StartPanoramaGrid/StopPanorama to the API client
- Fixed CMOS temperature display (int32 not float64)
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@ -29,6 +29,7 @@ func main() {
|
||||
rootCmd.PersistentFlags().BoolVarP(&flagDebug, "debug", "d", false, "verbose WebSocket traffic log")
|
||||
|
||||
rootCmd.AddCommand(
|
||||
cmdHealth(),
|
||||
cmdState(),
|
||||
cmdCamera(),
|
||||
cmdMotor(),
|
||||
@ -71,6 +72,106 @@ func mustCam(s string) api.Camera {
|
||||
}
|
||||
}
|
||||
|
||||
// --- health ---
|
||||
|
||||
func cmdHealth() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "health",
|
||||
Short: "Full telescope health check (connectivity + device state)",
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
checks := 0
|
||||
passed := 0
|
||||
|
||||
check := func(name string, ok bool, detail string) {
|
||||
checks++
|
||||
if ok {
|
||||
passed++
|
||||
fmt.Printf(" ✅ %-20s %s\n", name, detail)
|
||||
} else {
|
||||
fmt.Printf(" ❌ %-20s %s\n", name, detail)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("DWARF Telescope Health Check")
|
||||
fmt.Println(strings.Repeat("=", 50))
|
||||
|
||||
// 1. Connect
|
||||
scope := api.New(flagClientID)
|
||||
scope.SetDebug(flagDebug)
|
||||
connectStart := time.Now()
|
||||
err := scope.Connect(flagIP)
|
||||
elapsed := time.Since(connectStart)
|
||||
check("WebSocket :9900", err == nil, fmt.Sprintf("%s (%dms)", flagIP+":9900", elapsed.Milliseconds()))
|
||||
if err != nil {
|
||||
fmt.Println("\nCannot connect. Aborting.")
|
||||
os.Exit(1)
|
||||
}
|
||||
defer scope.Close()
|
||||
|
||||
// 2. Device state
|
||||
state, err := scope.GetDeviceState()
|
||||
check("Device state query", err == nil, fmt.Sprintf("%d bytes", len(state.String())))
|
||||
|
||||
if err == nil {
|
||||
di := state.GetDeviceStateInfo()
|
||||
|
||||
// 3. Battery
|
||||
batt := di.GetBatteryInfo().GetPercentage()
|
||||
check("Battery", batt > 0, fmt.Sprintf("%d%%", batt))
|
||||
|
||||
// 4. Storage
|
||||
stor := di.GetStorageInfo()
|
||||
avail := stor.GetAvailableSize()
|
||||
total := stor.GetTotalSize()
|
||||
storOK := total > 0 && avail > 0 && stor.GetIsValid()
|
||||
check("Storage", storOK, fmt.Sprintf("%d/%d GB (%s)", avail, total, func() string {
|
||||
if storOK { return "valid" }
|
||||
return "INVALID"
|
||||
}()))
|
||||
|
||||
// 5. RGB state
|
||||
rgb := di.GetRgbState().GetState()
|
||||
check("RGB ring", true, fmt.Sprintf("state=%d", rgb))
|
||||
|
||||
// 6. Focus position
|
||||
focus := state.GetFocusMotorStateInfo().GetFocusPosition().GetPos()
|
||||
check("Focus motor", focus > 0, fmt.Sprintf("pos=%d", focus))
|
||||
|
||||
// 7. Tele camera
|
||||
tele := state.GetTeleCameraStateInfo()
|
||||
teleRes := fmt.Sprintf("%dx%d", tele.GetResolutionWidth(), tele.GetResolutionHeight())
|
||||
check("Tele camera", tele.GetResolutionWidth() > 0, teleRes)
|
||||
|
||||
// 8. Wide camera
|
||||
wide := state.GetWideCameraStateInfo()
|
||||
wideRes := fmt.Sprintf("%dx%d", wide.GetResolutionWidth(), wide.GetResolutionHeight())
|
||||
check("Wide camera", wide.GetResolutionWidth() > 0, wideRes)
|
||||
|
||||
// 9. Motor position (may be NEED_RESET)
|
||||
pos, posErr := scope.MotorGetPosition(0)
|
||||
if posErr != nil {
|
||||
check("Motor position", false, posErr.Error())
|
||||
} else if pos.GetCode() != 0 {
|
||||
check("Motor position", false, fmt.Sprintf("code=%d (NEED_RESET)", pos.GetCode()))
|
||||
} else {
|
||||
check("Motor position", true, fmt.Sprintf("%.2f", pos.GetPosition()))
|
||||
}
|
||||
|
||||
// 10. Temperature
|
||||
cmosTemp := state.GetWideCameraStateInfo().GetCmosTemperature().GetTemperature()
|
||||
check("CMOS temp", cmosTemp > -270, fmt.Sprintf("%d°C", cmosTemp))
|
||||
}
|
||||
|
||||
fmt.Println(strings.Repeat("=", 50))
|
||||
status := "HEALTHY"
|
||||
if passed < checks {
|
||||
status = "ISSUES DETECTED"
|
||||
}
|
||||
fmt.Printf("Result: %d/%d checks passed — %s\n", passed, checks, status)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// --- state ---
|
||||
|
||||
func cmdState() *cobra.Command {
|
||||
|
||||
Reference in New Issue
Block a user