checkin: report an unreachable secondary-sdr as null, never keep stale 'Running'

QA blocker: when the secondary-sdr container was down, the checkin
omitted secondary_sdr_running / sdr_devices / op25_sdr_serial, and C2
only overwrites keys that are present, so the dashboard kept the last
'Running' forever. Send explicit nulls. The local card also says 'not
reported' rather than 'not plugged in' for a pin it can't check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-09-27 14:41:27 -04:00
co-authored by Claude Opus 5.5
parent 9b50ba8114
commit 575a99feb5
2 changed files with 9 additions and 2 deletions
@@ -236,6 +236,12 @@ class MQTTManager:
} }
payload["sdr_pins"] = config.sdr_pins payload["sdr_pins"] = config.sdr_pins
secondary = await secondary_sdr_client.status() secondary = await secondary_sdr_client.status()
# Unreachable secondary-sdr: say so with explicit nulls. C2 only
# overwrites keys present in the checkin, so omitting them would leave
# a dead decoder showing "Running" forever.
payload["secondary_sdr_running"] = None
payload["sdr_devices"] = None
payload["op25_sdr_serial"] = None
if secondary is not None: if secondary is not None:
payload["secondary_sdr_running"] = [r["mode"] for r in secondary.get("running", [])] payload["secondary_sdr_running"] = [r["mode"] for r in secondary.get("running", [])]
if secondary.get("devices") is not None: if secondary.get("devices") is not None:
+3 -2
View File
@@ -568,7 +568,8 @@
return `<option value="">${esc(autoLabel)}</option>` + return `<option value="">${esc(autoLabel)}</option>` +
devs.map(d => `<option value="${esc(d.serial)}" ${d.serial === selected ? 'selected' : ''}>` + devs.map(d => `<option value="${esc(d.serial)}" ${d.serial === selected ? 'selected' : ''}>` +
`SDR ${d.index + 1} · serial ${esc(d.serial)}${d.duplicate_serial ? ' (shared serial!)' : ''}</option>`).join('') + `SDR ${d.index + 1} · serial ${esc(d.serial)}${d.duplicate_serial ? ' (shared serial!)' : ''}</option>`).join('') +
(selected && !known ? `<option value="${esc(selected)}" selected>serial ${esc(selected)} (not plugged in)</option>` : ''); (selected && !known ? `<option value="${esc(selected)}" selected>serial ${esc(selected)} ` +
`(${sdr.devices === null ? 'not reported' : 'not plugged in'})</option>` : '');
} }
function renderSdr() { function renderSdr() {
@@ -585,7 +586,7 @@
const running = sdr.running || []; const running = sdr.running || [];
sdrRows.forEach((row, i) => { sdrRows.forEach((row, i) => {
const [name, hint] = SDR_LABELS[row.mode] || [row.mode, '']; const [name, hint] = SDR_LABELS[row.mode] || [row.mode, ''];
const pinMissing = row.pin && !(sdr.devices || []).some(d => d.serial === row.pin); const pinMissing = row.pin && sdr.devices !== null && !sdr.devices.some(d => d.serial === row.pin);
const state = !row.enabled ? 'Off' const state = !row.enabled ? 'Off'
: sdrDirty ? 'Unsaved' : sdrDirty ? 'Unsaved'
: sdr.running === null ? 'Unknown' : sdr.running === null ? 'Unknown'