Node SDRs: pin OP25 and each service to a dongle by serial (node-26#11)
Pairs with node-26 feat/sdr-pins. NodeRecord gains sdr_pins
(service -> serial), sdr_devices and op25_sdr_serial, mirrored from the
node's checkin. PATCH /nodes/{id} validates pins (known services, one
dongle per service) and sends priority/pins as a 'set_sdr_config'
command, never a config re-push. The node restarts OP25 only when OP25's
own dongle changes. The node page's section becomes 'SDRs' with an OP25
SDR dropdown ('Automatic (first SDR)' + detected dongles) and a
per-service dongle dropdown ('Any spare SDR'), plus duplicate-serial and
double-pin warnings.
Verified: c2-core pytest 490 passed; frontend tsc --noEmit clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c95498e7fe
commit
fb2d737d6f
@@ -40,7 +40,7 @@ def _patch(body):
|
||||
def test_priority_only_sends_command_and_never_repushes_config():
|
||||
resp, update, command, push = _patch({"secondary_sdr_priority": ["ais", "adsb"]})
|
||||
assert resp.status_code == 200
|
||||
command.assert_called_once_with("n1", {"action": "set_secondary_priority", "priority": ["ais", "adsb"]})
|
||||
command.assert_called_once_with("n1", {"action": "set_sdr_config", "priority": ["ais", "adsb"]})
|
||||
push.assert_not_called()
|
||||
(_, _, updates), _ = update.await_args
|
||||
assert updates == {"secondary_sdr_priority": ["ais", "adsb"], "secondary_sdr_mode": "ais"}
|
||||
@@ -49,7 +49,7 @@ def test_priority_only_sends_command_and_never_repushes_config():
|
||||
def test_empty_priority_turns_secondaries_off():
|
||||
resp, update, command, push = _patch({"secondary_sdr_priority": []})
|
||||
assert resp.status_code == 200
|
||||
command.assert_called_once_with("n1", {"action": "set_secondary_priority", "priority": []})
|
||||
command.assert_called_once_with("n1", {"action": "set_sdr_config", "priority": []})
|
||||
(_, _, updates), _ = update.await_args
|
||||
assert updates["secondary_sdr_mode"] == "none"
|
||||
|
||||
@@ -57,3 +57,20 @@ def test_empty_priority_turns_secondaries_off():
|
||||
def test_unknown_or_duplicate_modes_are_rejected():
|
||||
assert _patch({"secondary_sdr_priority": ["adsb", "sonar"]})[0].status_code == 400
|
||||
assert _patch({"secondary_sdr_priority": ["adsb", "adsb"]})[0].status_code == 400
|
||||
|
||||
|
||||
def test_pins_send_every_service_with_nulls_for_automatic():
|
||||
resp, update, command, push = _patch({"sdr_pins": {"op25": "00000001", "adsb": "69420", "ais": ""}})
|
||||
assert resp.status_code == 200
|
||||
push.assert_not_called()
|
||||
command.assert_called_once_with("n1", {
|
||||
"action": "set_sdr_config",
|
||||
"pins": {"op25": "00000001", "adsb": "69420", "ais": None},
|
||||
})
|
||||
(_, _, updates), _ = update.await_args
|
||||
assert updates == {"sdr_pins": {"op25": "00000001", "adsb": "69420"}}
|
||||
|
||||
|
||||
def test_two_services_on_one_dongle_or_unknown_service_rejected():
|
||||
assert _patch({"sdr_pins": {"op25": "69420", "adsb": "69420"}})[0].status_code == 400
|
||||
assert _patch({"sdr_pins": {"sonar": "1"}})[0].status_code == 400
|
||||
|
||||
Reference in New Issue
Block a user