Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ data/
*.log
.DS_Store
syncpi.sh
RULES.md
PROBLEM_STATEMENT.md
PR_DESCRIPTION.md
.claude/CORE_FINDINGS.md
GITHUB_PR.md

# Docker
/data
106 changes: 20 additions & 86 deletions repeater/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,6 @@ def _sync_repeater_handler_radio_config(self, radio_cfg: Dict[str, Any]) -> None
}
)

def _kiss_transport_restart_required(self) -> bool:
radio = getattr(self.daemon, "radio", None)
kiss_cfg = self.config.get("kiss", {}) or {}
if radio is None or not kiss_cfg:
return False

runtime_port = getattr(radio, "port", None)
runtime_baudrate = getattr(radio, "baudrate", None)

configured_port = kiss_cfg.get("port")
configured_baudrate = kiss_cfg.get("baud_rate")

if configured_port and runtime_port and str(configured_port) != str(runtime_port):
logger.info("KISS port change detected; service restart required")
return True

if configured_baudrate and runtime_baudrate and int(configured_baudrate) != int(runtime_baudrate):
logger.info("KISS baud rate change detected; service restart required")
return True

return False

def _apply_live_radio_config(self) -> bool:
radio = getattr(self.daemon, "radio", None)
if radio is None:
Expand All @@ -79,64 +57,18 @@ def _apply_live_radio_config(self) -> bool:
radio_cfg = self._get_live_radio_snapshot()

try:
if hasattr(radio, "configure_radio"):
if hasattr(radio, "radio_config") and isinstance(radio.radio_config, dict):
radio.radio_config.update(radio_cfg)
if hasattr(radio, "radio_config") and isinstance(radio.radio_config, dict):
radio.radio_config.update(radio_cfg)

applied = radio.configure_radio(
frequency=radio_cfg["frequency"],
bandwidth=radio_cfg["bandwidth"],
spreading_factor=radio_cfg["spreading_factor"],
coding_rate=radio_cfg["coding_rate"],
)
if not applied:
logger.warning("Live radio reconfiguration failed")
return False
else:
current_frequency = getattr(radio, "frequency", None)
current_bandwidth = getattr(radio, "bandwidth", None)
current_spreading_factor = getattr(radio, "spreading_factor", None)
current_coding_rate = getattr(radio, "coding_rate", None)
current_tx_power = getattr(radio, "tx_power", None)

if (
current_frequency != radio_cfg["frequency"]
and hasattr(radio, "set_frequency")
and not radio.set_frequency(radio_cfg["frequency"])
):
return False

if (
current_tx_power != radio_cfg["tx_power"]
and hasattr(radio, "set_tx_power")
and not radio.set_tx_power(radio_cfg["tx_power"])
):
return False

coding_rate_changed = current_coding_rate != radio_cfg["coding_rate"]
if coding_rate_changed:
setattr(radio, "coding_rate", radio_cfg["coding_rate"])

if current_spreading_factor != radio_cfg["spreading_factor"]:
if not hasattr(radio, "set_spreading_factor"):
return False
if not radio.set_spreading_factor(radio_cfg["spreading_factor"]):
return False

if current_bandwidth != radio_cfg["bandwidth"]:
if not hasattr(radio, "set_bandwidth"):
return False
if not radio.set_bandwidth(radio_cfg["bandwidth"]):
return False
elif coding_rate_changed:
if hasattr(radio, "set_bandwidth"):
if not radio.set_bandwidth(radio_cfg["bandwidth"]):
return False
elif hasattr(radio, "set_spreading_factor"):
if not radio.set_spreading_factor(radio_cfg["spreading_factor"]):
return False
else:
return False
applied = radio.configure_radio(
frequency=radio_cfg["frequency"],
bandwidth=radio_cfg["bandwidth"],
spreading_factor=radio_cfg["spreading_factor"],
coding_rate=radio_cfg["coding_rate"],
)
if not applied:
logger.warning("Live radio reconfiguration failed")
return False

self._sync_repeater_handler_radio_config(radio_cfg)
logger.info("Applied live radio configuration to running daemon")
Expand Down Expand Up @@ -226,7 +158,7 @@ def live_update_daemon(self, sections: Optional[List[str]] = None) -> bool:
logger.info("Reloaded AdvertHelper config")

# Re-apply dispatcher path hash mode when mesh section changed
if 'mesh' in sections and self.daemon and hasattr(self.daemon, 'dispatcher'):
if 'mesh' in sections and self.daemon and hasattr(self.daemon, 'dispatcher') and self.daemon.dispatcher:
mesh_cfg = self.daemon.config.get("mesh", {})
path_hash_mode = mesh_cfg.get("path_hash_mode", 0)
if path_hash_mode not in (0, 1, 2):
Expand All @@ -237,12 +169,14 @@ def live_update_daemon(self, sections: Optional[List[str]] = None) -> bool:
self.daemon.dispatcher.set_default_path_hash_mode(path_hash_mode)
logger.info(f"Reloaded path hash mode: mesh.path_hash_mode={path_hash_mode}")

if 'radio_type' in sections:
logger.info("radio_type change detected; service restart required")
live_update_ok = False

if 'kiss' in sections and self._kiss_transport_restart_required():
live_update_ok = False
if 'radio_type' in sections or 'kiss' in sections:
radio_manager = getattr(self.daemon, "radio_manager", None)
if radio_manager:
logger.info("Radio transport config changed; triggering reconnect")
radio_manager.notify_config_changed()
else:
logger.info("Radio transport config changed; service restart required")
live_update_ok = False

if 'radio' in sections:
live_update_ok = self._apply_live_radio_config() and live_update_ok
Expand Down
10 changes: 10 additions & 0 deletions repeater/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,16 @@ def reload_runtime_config(self):
except Exception as e:
logger.error(f"Error reloading runtime config: {e}")

async def stop(self) -> None:
"""Awaitable teardown — cancels background task and waits for it to finish."""
if self._background_task and not self._background_task.done():
self._background_task.cancel()
try:
await self._background_task
except asyncio.CancelledError:
pass
logger.info("Engine stopped")

def cleanup(self):
if self._background_task and not self._background_task.done():
self._background_task.cancel()
Expand Down
Loading