diff --git a/app/routers/health.py b/app/routers/health.py index 1427939..4b38e48 100644 --- a/app/routers/health.py +++ b/app/routers/health.py @@ -40,6 +40,8 @@ class RadioStatsSnapshot(BaseModel): # Core stats battery_mv: int | None = None uptime_secs: int | None = None + queue_len: int | None = None + errors: int | None = None # Radio stats noise_floor: int | None = None last_rssi: int | None = None @@ -155,6 +157,8 @@ async def build_health_data(radio_connected: bool, connection_info: str | None) "timestamp": raw_stats.get("timestamp"), "battery_mv": raw_stats.get("battery_mv"), "uptime_secs": raw_stats.get("uptime_secs"), + "queue_len": raw_stats.get("queue_len"), + "errors": raw_stats.get("errors"), "noise_floor": raw_stats.get("noise_floor"), "last_rssi": raw_stats.get("last_rssi"), "last_snr": raw_stats.get("last_snr"), diff --git a/frontend/src/components/settings/SettingsRadioSection.tsx b/frontend/src/components/settings/SettingsRadioSection.tsx index d0c937b..09a015a 100644 --- a/frontend/src/components/settings/SettingsRadioSection.tsx +++ b/frontend/src/components/settings/SettingsRadioSection.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useMemo } from 'react'; -import { MapPinned } from 'lucide-react'; +import { ChevronDown, MapPinned } from 'lucide-react'; import { Input } from '../ui/input'; import { Label } from '../ui/label'; import { Button } from '../ui/button'; @@ -17,8 +17,116 @@ import type { RadioConfigUpdate, RadioDiscoveryResponse, RadioDiscoveryTarget, + RadioStatsSnapshot, } from '../../types'; +function formatUptime(secs: number): string { + const days = Math.floor(secs / 86400); + const hours = Math.floor((secs % 86400) / 3600); + const minutes = Math.floor((secs % 3600) / 60); + if (days > 0) return `${days}d ${hours}h ${minutes}m`; + if (hours > 0) return `${hours}h ${minutes}m`; + return `${minutes}m`; +} + +function formatAirtime(secs: number): string { + if (secs < 60) return `${secs}s`; + const hours = Math.floor(secs / 3600); + const minutes = Math.floor((secs % 3600) / 60); + if (hours > 0) return `${hours}h ${minutes}m`; + return `${minutes}m`; +} + +function StatRow({ label, value, warn }: { label: string; value: string; warn?: boolean }) { + return ( +
+ Updated {age < 5 ? 'just now' : `${age}s ago`} +
+ )} + + {/* Core */} + {stats.uptime_secs != null && ( +{deviceInfoLabel}
} + + {health?.radio_stats &&