Files
PilotVault/API Server/internal/hub/models.go
T
tajniak81andClaude Opus 4.8 afc6952eda Initial commit: PilotVault multi-service project
Add API Server (Go/PocketBase), Web App (Go BFF + Vue), Fly App
(Flutter/DJI MSDK), Adobe Plugin, and Docker/Docker AIO deployment
configs. Design assets and build artifacts are gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 11:43:33 +02:00

113 lines
3.4 KiB
Go

package hub
import "encoding/json"
// Telemetry holds the latest flight-controller / battery values for a device.
// Pointers distinguish "not yet reported" (nil) from a genuine zero value.
type Telemetry struct {
SatelliteCount *int `json:"satelliteCount,omitempty"`
IsFlying *bool `json:"isFlying,omitempty"`
FlightMode *string `json:"flightMode,omitempty"`
Altitude *float64 `json:"altitude,omitempty"`
Latitude *float64 `json:"latitude,omitempty"`
Longitude *float64 `json:"longitude,omitempty"`
VelocityX *float64 `json:"velocityX,omitempty"`
VelocityY *float64 `json:"velocityY,omitempty"`
VelocityZ *float64 `json:"velocityZ,omitempty"`
BatteryPercent *int `json:"batteryPercent,omitempty"`
}
// DeviceState is the server's aggregated view of one app/drone.
type DeviceState struct {
DeviceID string `json:"deviceId"`
Online bool `json:"online"` // app's websocket is connected to the server
Connected bool `json:"connected"` // a drone is connected to the app
Model string `json:"model"`
Registration string `json:"registration"`
Telemetry Telemetry `json:"telemetry"`
LastSeenMs int64 `json:"lastSeenMs"`
}
// TrackPoint is one sample of the drone's GPS track (for the map trail).
type TrackPoint struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
Alt float64 `json:"alt"`
TS int64 `json:"ts"`
}
// ServerToUI is the message a dashboard receives over /ws/ui.
type ServerToUI struct {
Type string `json:"type"` // "snapshot" | "update" | "removed"
Device *DeviceState `json:"device,omitempty"`
Devices []*DeviceState `json:"devices,omitempty"`
DeviceID string `json:"deviceId,omitempty"` // for "removed"
Event map[string]any `json:"event,omitempty"` // the raw device event that triggered this
TS int64 `json:"ts"`
}
// Command is what the server pushes down to a device over /ws/device.
type Command struct {
Type string `json:"type"` // always "command"
Command string `json:"command"`
Payload map[string]any `json:"payload,omitempty"`
TS int64 `json:"ts"`
}
// toFloat coerces a JSON-decoded value into a float64.
func toFloat(v any) (float64, bool) {
switch n := v.(type) {
case float64:
return n, true
case float32:
return float64(n), true
case int:
return float64(n), true
case int64:
return float64(n), true
case json.Number:
f, err := n.Float64()
return f, err == nil
}
return 0, false
}
// toInt coerces a JSON-decoded value into an int.
func toInt(v any) (int, bool) {
if f, ok := toFloat(v); ok {
return int(f), true
}
return 0, false
}
// applyTelemetry copies any present telemetry fields from a raw event map.
func applyTelemetry(t *Telemetry, raw map[string]any) {
if v, ok := toInt(raw["satelliteCount"]); ok {
t.SatelliteCount = &v
}
if v, ok := raw["isFlying"].(bool); ok {
t.IsFlying = &v
}
if v, ok := raw["flightMode"].(string); ok {
t.FlightMode = &v
}
if v, ok := toFloat(raw["altitude"]); ok {
t.Altitude = &v
}
if v, ok := toFloat(raw["latitude"]); ok {
t.Latitude = &v
}
if v, ok := toFloat(raw["longitude"]); ok {
t.Longitude = &v
}
if v, ok := toFloat(raw["velocityX"]); ok {
t.VelocityX = &v
}
if v, ok := toFloat(raw["velocityY"]); ok {
t.VelocityY = &v
}
if v, ok := toFloat(raw["velocityZ"]); ok {
t.VelocityZ = &v
}
}