From 5e63a40137d7023deed443f25def669264647171 Mon Sep 17 00:00:00 2001 From: Paul Buckley Date: Mon, 15 Jun 2026 16:20:34 -0700 Subject: [PATCH] feat(api): expose sdr_connected in /api/status Add an sdr_connected boolean to the /api/status response, derived from state.rx_connected, so clients can detect whether the SDR hardware is currently open. With no Pluto attached the RX thread retries the open forever in the background while Flask still serves the API, so callers previously had no way to distinguish 'no hardware' from 'quiet sky'. --- CLAUDE.md | 2 +- src/stream_web/app.py | 1 + tests/test_mock_sdr.py | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8068233..0b8d8ba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,7 +41,7 @@ docker run -p 8050:8050 sdr-docker ## API endpoints ### RX -- `GET /api/status` — system status, RX metrics, peak power +- `GET /api/status` — system status, RX metrics, peak power; includes `sdr_connected` (bool) indicating whether the SDR hardware is currently open - `GET /api/packets` — poll-and-drain decoded packets (NDJSON) ### TX diff --git a/src/stream_web/app.py b/src/stream_web/app.py index 136bd99..baa98c1 100644 --- a/src/stream_web/app.py +++ b/src/stream_web/app.py @@ -300,6 +300,7 @@ def api_status(): cs_stats[chip]["avg_rs_corr_pct"] = round(sum(pcts) / len(pcts), 1) return jsonify( + sdr_connected=state.rx_connected.is_set(), devices=dev_list, stats=stats, td_img=td_b64, td_running=state.td_running, td_device_id=state.td_target_ntw_id, diff --git a/tests/test_mock_sdr.py b/tests/test_mock_sdr.py index 108e905..61b3759 100644 --- a/tests/test_mock_sdr.py +++ b/tests/test_mock_sdr.py @@ -201,3 +201,11 @@ def test_api_status_device_fields(self): assert isinstance(dev["seq_nums"], list) assert isinstance(dev["max_energy_dB"], (int, float)) assert "chipset" in dev + + def test_api_status_reports_sdr_connected(self): + client = self._client() + # rx_connected reflects whether the SDR hardware is currently open. + state.rx_connected.set() + assert client.get("/api/status").get_json()["sdr_connected"] is True + state.rx_connected.clear() + assert client.get("/api/status").get_json()["sdr_connected"] is False