package protocol import ( "fmt" "time" ) // HubStatusPayload holds a hub snapshot, not house state. ID matches the hub // topic. Status is ready or unavailable. ExpiresAt is required in its envelope. // Address is runtime data and must not be written to logs. type HubStatusPayload struct { ID string `json:"id"` Alias string `json:"alias,omitempty"` Address string `json:"address"` Status string `json:"status"` Error string `json:"error,omitempty"` Model string `json:"model,omitempty"` Firmware string `json:"firmware,omitempty"` EventStream bool `json:"event_stream"` UpdatedAt *time.Time `json:"updated_at,omitempty"` Pairing *HubPairing `json:"pairing,omitempty"` ConfiguredDevices int `json:"configured_devices"` PairedDevices *int `json:"paired_devices,omitempty"` Diagnostics *HubDiagnostics `json:"diagnostics,omitempty"` DiagnosticsError string `json:"diagnostics_error,omitempty"` } // HubPairing describes one request to permit device joining. type HubPairing struct { Status string `json:"status"` DurationSeconds int `json:"duration_seconds"` RequestedAt time.Time `json:"requested_at"` Deadline time.Time `json:"deadline"` Error string `json:"error,omitempty"` } // HubDiagnostics holds a source sample. Repeated publications preserve // ObservedAt and Stale. Optional measurements remain absent when unknown. type HubDiagnostics struct { ObservedAt time.Time `json:"observed_at"` Stale bool `json:"stale"` Hostname string `json:"hostname,omitempty"` IPAddress string `json:"ip_address,omitempty"` MAC string `json:"mac,omitempty"` RadioChip string `json:"radio_chip,omitempty"` RadioFirmware string `json:"radio_firmware,omitempty"` UptimeSeconds *uint64 `json:"uptime_seconds,omitempty"` TemperatureCelsius *float64 `json:"temperature_celsius,omitempty"` RadioTemperatureCelsius *float64 `json:"radio_temperature_celsius,omitempty"` RAMUsedPercent *float64 `json:"ram_used_percent,omitempty"` PSRAMUsedPercent *float64 `json:"psram_used_percent,omitempty"` StorageUsedPercent *float64 `json:"storage_used_percent,omitempty"` EthernetConnected *bool `json:"ethernet_connected,omitempty"` WiFiConnected *bool `json:"wifi_connected,omitempty"` } // HubStatusLifetime bounds retained hub status to two polls plus 50 seconds. A // nonpositive poll interval is invalid. func HubStatusLifetime(pollInterval time.Duration) (time.Duration, error) { if pollInterval <= 0 || pollInterval > (time.Duration(1<<63-1)-50*time.Second)/2 { return 0, fmt.Errorf("hub poll interval is outside the supported range") } return 2*pollInterval + 50*time.Second, nil }