From a868a60935c9cfafd7ee3c4e8c34d27a1158498e Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:27:45 +0200 Subject: [PATCH] fix(companion): flush pending lazy contacts write on shutdown/power-off Contact updates (advert path cache, new/removed contacts, favourites) are lazily debounced (dirty_contacts_expiry, 5s) to avoid wearing flash on every mesh packet. CMD_REBOOT already flushed this before rebooting, but UITask::shutdown() -- the low-battery auto-shutdown and long-press power-off path -- didn't, so under continuous mesh traffic (which keeps re-arming the debounce timer) a pending write could sit unflushed for a whole session and be lost when one of those paths fired. Add MyMesh::flushDirtyContacts() and call it from shutdown() alongside the existing savePrefs()/saveRTCTime() flush. Co-Authored-By: Claude Sonnet 5 --- examples/companion_radio/MyMesh.h | 8 ++++++++ examples/companion_radio/ui-new/UITask.cpp | 1 + 2 files changed, 9 insertions(+) diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 8a4cdd09..86f3f302 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -297,6 +297,14 @@ public: void savePrefs() { _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); } void saveRTCTime() { _store->saveRTCTime(); } + // Contact updates (new adverts, path/lastmod changes) are lazily debounced + // (see dirty_contacts_expiry) to avoid wearing flash on every packet -- + // under regular mesh traffic the timer keeps getting re-armed, so it can + // stay pending for the device's whole uptime. CMD_REBOOT already flushes + // this before rebooting; UITask::shutdown() (low-battery auto-shutdown, + // long-press power-off) needs the same flush or a whole session's worth + // of learned contacts can be lost. + void flushDirtyContacts() { if (dirty_contacts_expiry) { saveContacts(); dirty_contacts_expiry = 0; } } DataStore* getDataStore() const { return _store; } void applyApc(); // (re)initialise Adaptive Power Control from prefs // Adaptive Power Control is suppressed while repeating: a repeater wants full, diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 22b55f26..bdc5c67e 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -2177,6 +2177,7 @@ void UITask::shutdown(bool restart){ // the_mesh.savePrefs() call sites already do without a dirty check. the_mesh.savePrefs(); the_mesh.saveRTCTime(); + the_mesh.flushDirtyContacts(); // Auto-save the live GPS trail before power-off when the user enabled it // (Tools › Trail › Settings › Auto-save). This covers the low-battery