diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb699d..efc796a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## [3.7.0] - 2026-04-02 + +* Feature: Repeater battery tracking +* Feature: Repeater info pane just like contacts +* Feature: Make repeaters blockable +* Feature: Add new-node advert blocking +* Feature: Add bulk deletion interface +* Feature: Bulk room add on alt+click of new channel button +* Feature: More info in debug endpoint +* Bugfix: Be more conservative around radio load limits and don't exceed radio-reported capacity +* Misc: Default auto-DM decrypt to true +* Misc: Reorganize some settings panes +* Misc: Enable FK pragma +* Misc: Various performance and correctness fixes +* Misc: Correct TCP default port + ## [3.6.7] - 2026-03-31 * Misc: Remove armv7 (for now) diff --git a/app/config.py b/app/config.py index 36ed5a1..a08f836 100644 --- a/app/config.py +++ b/app/config.py @@ -26,6 +26,7 @@ class Settings(BaseSettings): default=False, validation_alias="__CLOWNTOWN_DO_CLOCK_WRAPAROUND", ) + skip_post_connect_sync: bool = False basic_auth_username: str = "" basic_auth_password: str = "" diff --git a/app/services/radio_lifecycle.py b/app/services/radio_lifecycle.py index bdea931..eee9ef5 100644 --- a/app/services/radio_lifecycle.py +++ b/app/services/radio_lifecycle.py @@ -204,35 +204,41 @@ async def run_post_connect_setup(radio_manager) -> None: finally: reader.handle_rx = _original_handle_rx - # Sync contacts/channels from radio to DB and clear radio - logger.info("Syncing and offloading radio data...") - result = await sync_and_offload_all(mc) - logger.info("Sync complete: %s", result) + from app.config import settings as app_settings_config - # Send advertisement to announce our presence (if enabled and not throttled) - if await send_advertisement(mc): - logger.info("Advertisement sent") + if app_settings_config.skip_post_connect_sync: + logger.info("Skipping sync/offload/advert/drain (MESHCORE_SKIP_POST_CONNECT_SYNC)") else: - logger.debug("Advertisement skipped (disabled or throttled)") + # Sync contacts/channels from radio to DB and clear radio + logger.info("Syncing and offloading radio data...") + result = await sync_and_offload_all(mc) + logger.info("Sync complete: %s", result) - # Drain any messages that were queued before we connected. - # This must happen BEFORE starting auto-fetch, otherwise both - # compete on get_msg() with interleaved radio I/O. - drained = await drain_pending_messages(mc) - if drained > 0: - logger.info("Drained %d pending message(s)", drained) - radio_manager.clear_pending_message_channel_slots() + # Send advertisement to announce our presence (if enabled and not throttled) + if await send_advertisement(mc): + logger.info("Advertisement sent") + else: + logger.debug("Advertisement skipped (disabled or throttled)") + + # Drain any messages that were queued before we connected. + # This must happen BEFORE starting auto-fetch, otherwise both + # compete on get_msg() with interleaved radio I/O. + drained = await drain_pending_messages(mc) + if drained > 0: + logger.info("Drained %d pending message(s)", drained) + radio_manager.clear_pending_message_channel_slots() await mc.start_auto_message_fetching() logger.info("Auto message fetching started") finally: radio_manager._release_operation_lock("post_connect_setup") - # Start background tasks AFTER releasing the operation lock. - # These tasks acquire their own locks when they need radio access. - start_periodic_sync() - start_periodic_advert() - start_message_polling() + if not app_settings_config.skip_post_connect_sync: + # Start background tasks AFTER releasing the operation lock. + # These tasks acquire their own locks when they need radio access. + start_periodic_sync() + start_periodic_advert() + start_message_polling() radio_manager._setup_complete = True finally: diff --git a/frontend/package.json b/frontend/package.json index cf95aa4..5fe9c82 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "remoteterm-meshcore-frontend", "private": true, - "version": "3.6.7", + "version": "3.7.0", "type": "module", "scripts": { "dev": "vite", diff --git a/pyproject.toml b/pyproject.toml index 6daf340..abb859c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "remoteterm-meshcore" -version = "3.6.7" +version = "3.7.0" description = "RemoteTerm - Web interface for MeshCore radio mesh networks" readme = "README.md" requires-python = ">=3.10" diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index 58d0840..8870701 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -63,6 +63,7 @@ export default defineConfig({ timeout: 180_000, env: { MESHCORE_DATABASE_PATH: path.join(tmpDir, 'e2e-test.db'), + MESHCORE_SKIP_POST_CONNECT_SYNC: 'true', // Pass through the serial port from the environment ...(process.env.MESHCORE_SERIAL_PORT ? { MESHCORE_SERIAL_PORT: process.env.MESHCORE_SERIAL_PORT } diff --git a/uv.lock b/uv.lock index 58868c0..527bed9 100644 --- a/uv.lock +++ b/uv.lock @@ -1098,7 +1098,7 @@ wheels = [ [[package]] name = "remoteterm-meshcore" -version = "3.6.7" +version = "3.7.0" source = { virtual = "." } dependencies = [ { name = "aiomqtt" },