mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-07-26 19:42:46 +02:00
refactor(daemon): resolve companion max TX power via the core resolver
The daemon's max-TX-power lookup duplicated the core fallback chain and ended in a radio_type string match to know the SX1262's 22 dBm limit -- a driver constant that every new backend name would silently lose. The SX1262 driver class now declares max_tx_power_dbm itself (the CH341 variant instantiates the same class, only the transport differs), so the lookup collapses to the shared resolver over the radio object and the validated deployment settings.
This commit is contained in:
+5
-34
@@ -37,6 +37,7 @@ from repeater.sensors import SensorManager
|
||||
from repeater.utils_packet import create_scoped_advert_packet
|
||||
from repeater.web.http_server import HTTPStatsServer, _log_buffer
|
||||
|
||||
from openhop_core.companion.radio_capabilities import resolve_max_tx_power_dbm
|
||||
from openhop_core.protocol.constants import PAYLOAD_TYPE_RAW_CUSTOM
|
||||
|
||||
logger = logging.getLogger("RepeaterDaemon")
|
||||
@@ -676,42 +677,12 @@ class RepeaterDaemon:
|
||||
def _get_companion_max_tx_power_dbm(self):
|
||||
"""Return the active backend's TX limit when it declares one.
|
||||
|
||||
SX1262 backends have an enforced 22 dBm driver limit. Other backends
|
||||
can expose a ``get_max_tx_power_dbm`` method, a
|
||||
``max_tx_power_dbm`` attribute, or a validated deployment setting.
|
||||
The backend can expose a ``get_max_tx_power_dbm`` method, a
|
||||
``max_tx_power_dbm`` attribute (SX1262 backends declare their 22 dBm
|
||||
driver limit this way), or a validated deployment setting.
|
||||
Returning ``None`` lets Core use its generic protocol fallback.
|
||||
"""
|
||||
radio = self.radio
|
||||
getter = getattr(radio, "get_max_tx_power_dbm", None)
|
||||
if callable(getter):
|
||||
try:
|
||||
value = getter()
|
||||
if value is not None:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
logger.warning("Radio reported an invalid maximum TX power")
|
||||
except Exception as e:
|
||||
logger.warning("Could not get radio maximum TX power: %s", e)
|
||||
|
||||
value = getattr(radio, "max_tx_power_dbm", None)
|
||||
if value is not None:
|
||||
try:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
logger.warning("Radio reported an invalid maximum TX power: %r", value)
|
||||
|
||||
settings = self._get_companion_radio_settings()
|
||||
value = settings.get("max_tx_power_dbm", settings.get("max_tx_power"))
|
||||
if value is not None:
|
||||
try:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
logger.warning("Configured maximum TX power is invalid: %r", value)
|
||||
|
||||
radio_type = str(self.config.get("radio_type", "")).lower().strip()
|
||||
if radio_type in {"sx1262", "sx1262_ch341"}:
|
||||
return 22
|
||||
return None
|
||||
return resolve_max_tx_power_dbm(self.radio, self._get_companion_radio_settings())
|
||||
|
||||
async def _load_companion_identities(self) -> None:
|
||||
"""Load companion identities from config and create CompanionBridge + frame server for each."""
|
||||
|
||||
@@ -4,10 +4,13 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from openhop_core.companion import CompanionBridge
|
||||
from openhop_core.protocol import LocalIdentity
|
||||
|
||||
from repeater.companion.utils import (
|
||||
COMPANION_SETTINGS_ALLOWLIST,
|
||||
CompanionContactCapacityError,
|
||||
@@ -65,12 +68,16 @@ class TestParseCompanionBridgeKwargs:
|
||||
|
||||
class TestCompanionRadioCapabilities:
|
||||
def test_reads_active_radio_state_and_known_sx1262_limit(self):
|
||||
# The SX1262 driver declares its 22 dBm limit as a backend attribute
|
||||
# (SX1262Radio.max_tx_power_dbm); the daemon no longer string-matches
|
||||
# radio_type to recover it.
|
||||
radio = SimpleNamespace(
|
||||
frequency=868_000_000,
|
||||
bandwidth=125_000,
|
||||
spreading_factor=7,
|
||||
coding_rate=8,
|
||||
tx_power=14,
|
||||
max_tx_power_dbm=22,
|
||||
)
|
||||
daemon = RepeaterDaemon.__new__(RepeaterDaemon)
|
||||
daemon.config = {"radio_type": "sx1262", "radio": {"frequency": 915_000_000}}
|
||||
@@ -102,6 +109,28 @@ class TestCompanionRadioCapabilities:
|
||||
|
||||
assert RepeaterDaemon._get_companion_max_tx_power_dbm(daemon) == 15
|
||||
|
||||
def test_backend_class_attribute_reaches_self_info_max_tx_power(self):
|
||||
# A driver declares its limit as a class attribute (as SX1262Radio
|
||||
# does); no radio_type string match is involved.
|
||||
class _FakeRadio:
|
||||
max_tx_power_dbm = 20
|
||||
|
||||
daemon = RepeaterDaemon.__new__(RepeaterDaemon)
|
||||
daemon.config = {"radio_type": "sx1262_ch341"}
|
||||
daemon.repeater_handler = SimpleNamespace(radio_config={})
|
||||
daemon.radio = _FakeRadio()
|
||||
|
||||
assert RepeaterDaemon._get_companion_max_tx_power_dbm(daemon) == 20
|
||||
|
||||
# The daemon getter is what a bridge is wired with at load time; the
|
||||
# value must surface through the companion SELF_INFO max-tx-power path.
|
||||
bridge = CompanionBridge(
|
||||
LocalIdentity(),
|
||||
AsyncMock(return_value=True),
|
||||
max_tx_power_getter=daemon._get_companion_max_tx_power_dbm,
|
||||
)
|
||||
assert bridge.get_max_tx_power_dbm() == 20
|
||||
|
||||
|
||||
class TestEffectiveMaxContacts:
|
||||
def test_default(self):
|
||||
|
||||
Reference in New Issue
Block a user