ria-toolkit-oss/src/ria_toolkit_oss/agent/hardware.py

57 lines
1.8 KiB
Python
Raw Normal View History

"""Hardware detection and heartbeat payload construction for the streamer."""
from __future__ import annotations
from ria_toolkit_oss.sdr import detect_available
J
2026-04-16 11:13:43 -04:00
from .config import AgentConfig
def available_devices() -> list[str]:
"""Return a sorted list of device names whose driver modules import cleanly."""
return sorted(detect_available().keys())
J
2026-04-16 11:13:43 -04:00
def heartbeat_payload(
status: str = "idle",
app_id: str | None = None,
*,
cfg: AgentConfig | None = None,
sessions: dict | None = None,
) -> dict:
"""Build the JSON body of a periodic heartbeat frame.
*cfg* drives the ``capabilities`` list and the ``tx_enabled`` flag. If not
supplied, the heartbeat advertises RX-only with ``tx_enabled=False``
matching the pre-TX shape.
"""
c = cfg or AgentConfig()
capabilities = ["rx"]
if c.tx_enabled:
capabilities.append("tx")
payload: dict = {
"type": "heartbeat",
"hardware": available_devices(),
"status": status,
J
2026-04-16 11:13:43 -04:00
"capabilities": capabilities,
"tx_enabled": bool(c.tx_enabled),
}
J
2026-04-16 15:12:56 -04:00
# Surface configured interlock values so the hub can pre-filter UI controls
# before sending a tx_start that would be rejected. Only included when TX
# is opted in AND the operator set a cap.
if c.tx_enabled:
if c.tx_max_gain_db is not None:
payload["tx_max_gain_db"] = float(c.tx_max_gain_db)
if c.tx_max_duration_s is not None:
payload["tx_max_duration_s"] = float(c.tx_max_duration_s)
if c.tx_allowed_freq_ranges:
payload["tx_allowed_freq_ranges"] = [
[float(lo), float(hi)] for lo, hi in c.tx_allowed_freq_ranges
]
if app_id:
payload["app_id"] = app_id
J
2026-04-16 11:13:43 -04:00
if sessions:
payload["sessions"] = sessions
return payload