From 308e95f159da311d465d102e884ae7281c7294ab Mon Sep 17 00:00:00 2001 From: agessaman Date: Fri, 2 Oct 2026 16:44:22 -0700 Subject: [PATCH] refactor: restore AqiCommand.geolocator and MeshCoreBot.last_clock_sync_time The S1 dead-code slice dropped both because nothing in the tree reads them, but local plugins may (codex review of the dev merge). set_radio_clock records the sync time again after a successful update. Two DEBUG diagnostics S1 removed with dead code stay removed: parse_advert's flags line behind handler.debug and the overwritten contact-path lookup lines. --- modules/commands/aqi_command.py | 5 +++- modules/core.py | 2 ++ tests/unit/test_compat_attributes.py | 35 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_compat_attributes.py diff --git a/modules/commands/aqi_command.py b/modules/commands/aqi_command.py index 9545102..10fc761 100644 --- a/modules/commands/aqi_command.py +++ b/modules/commands/aqi_command.py @@ -24,7 +24,7 @@ from ..location import ( from ..models import MeshMessage from ..utils import ( abbreviate_location, - get_nominatim_geocoder, # noqa: F401 + get_nominatim_geocoder, is_valid_timezone, normalize_us_state, ) @@ -90,6 +90,9 @@ class AqiCommand(BaseCommand): self.logger.warning("Invalid timezone '%s', using system timezone", timezone_str) self.timezone = "America/Los_Angeles" if not timezone_str else "UTC" + # Initialize geocoder (will use rate-limited helpers for actual calls) + self.geolocator = get_nominatim_geocoder() + # Get database manager for geocoding cache self.db_manager = bot.db_manager diff --git a/modules/core.py b/modules/core.py index c9e481c..33a7df0 100644 --- a/modules/core.py +++ b/modules/core.py @@ -311,6 +311,7 @@ class MeshCoreBot(ServiceSupervisorMixin, RadioLinkMixin, RadioOfflineBreaker): self.last_advert_time = None # Clock sync tracking + self.last_clock_sync_time = None # Shutdown event for graceful shutdown self._shutdown_event = threading.Event() @@ -905,6 +906,7 @@ class MeshCoreBot(ServiceSupervisorMixin, RadioLinkMixin, RadioOfflineBreaker): result = await self.meshcore.commands.set_time(current_time) if result.type == EventType.OK: self.logger.info(f"✓ Radio clock updated to: {current_time}") + self.last_clock_sync_time = current_time return True else: self.logger.warning(f"Failed to update radio clock: {result}") diff --git a/tests/unit/test_compat_attributes.py b/tests/unit/test_compat_attributes.py new file mode 100644 index 0000000..47bae71 --- /dev/null +++ b/tests/unit/test_compat_attributes.py @@ -0,0 +1,35 @@ +"""Attributes local plugins may read survive the dead-code cleanup.""" + +import configparser +from unittest.mock import AsyncMock, Mock, patch + +import pytest +from meshcore import EventType + +from modules.commands.aqi_command import AqiCommand +from modules.core import MeshCoreBot + + +def test_aqi_keeps_geolocator(): + config = configparser.ConfigParser() + config.read_dict({"Aqi_Command": {}, "Bot": {}, "Weather": {}}) + bot = Mock() + bot.config = config + bot.db_manager.db_path = "meshcore_bot.db" + with patch("modules.commands.aqi_command.requests_cache.CachedSession"), \ + patch("modules.commands.aqi_command.retry", side_effect=lambda s, **kw: s), \ + patch("modules.commands.aqi_command.openmeteo_requests.Client", return_value=Mock()): + assert AqiCommand(bot).geolocator is not None + + +@pytest.mark.asyncio +async def test_set_radio_clock_records_the_sync_time(): + bot = MeshCoreBot.__new__(MeshCoreBot) + bot.logger = Mock() + bot.last_clock_sync_time = None + bot.meshcore = Mock(is_connected=True) + bot.meshcore.commands.get_time = AsyncMock(return_value=Mock(type=EventType.OK, payload={"time": 100})) + bot.meshcore.commands.set_time = AsyncMock(return_value=Mock(type=EventType.OK)) + assert await bot.set_radio_clock() is True + synced = bot.meshcore.commands.set_time.await_args.args[0] + assert bot.last_clock_sync_time == synced