Secondary SDR priority: C2 field, node command, dashboard section

Pairs with node-26 feat/secondary-sdr-priority. NodeRecord gains
secondary_sdr_priority (ordered; SDRs beyond OP25's run it top-down) and
secondary_sdr_running, both mirrored from the node's checkin.
PATCH /nodes/{id} accepts the priority, validates it, and sends it as a
'set_secondary_priority' MQTT command. A priority-only change never
re-pushes system config, because that restarts OP25. The node detail page
gets a 'Secondary SDRs' section (admin-editable) with enable, reorder,
save, and live Running / Waiting-for-SDR state from the checkin.

Verified: c2-core pytest 482 passed; frontend tsc --noEmit clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-09-27 14:10:11 -04:00
co-authored by Claude Opus 5.5
parent fa207e494d
commit 3cbb0828ae
8 changed files with 246 additions and 8 deletions
+6 -1
View File
@@ -62,7 +62,12 @@ class NodeRecord(BaseModel):
last_seen: Optional[datetime] = None
assigned_system_id: Optional[str] = None
node_type: str = "fixed" # fixed or portable
secondary_sdr_mode: str = "none" # none | adsb | ais | op25_2 — requires a second physical SDR
secondary_sdr_mode: str = "none" # legacy single-mode field; priority[0] on current nodes
# Ordered decoders for the SDRs beyond op25's (node-26#9): the node runs
# them top-down until it runs out of dongles. Mirrored from the node's own
# checkin, which is the source of truth; set via PATCH /nodes/{id}.
secondary_sdr_priority: List[str] = []
secondary_sdr_running: Optional[List[str]] = None # what the node reports actually running
sdr_count: int = 1 # self-reported by the node's checkin, best-effort
enforce_override_timeout: bool = True
is_overridden: bool = False