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 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-08 13:27:45 +02:00
co-authored by Claude Sonnet 5
parent 23ccc06d1d
commit a868a60935
2 changed files with 9 additions and 0 deletions
+8
View File
@@ -297,6 +297,14 @@ public:
void savePrefs() { _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); } void savePrefs() { _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); }
void saveRTCTime() { _store->saveRTCTime(); } 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; } DataStore* getDataStore() const { return _store; }
void applyApc(); // (re)initialise Adaptive Power Control from prefs void applyApc(); // (re)initialise Adaptive Power Control from prefs
// Adaptive Power Control is suppressed while repeating: a repeater wants full, // Adaptive Power Control is suppressed while repeating: a repeater wants full,
@@ -2177,6 +2177,7 @@ void UITask::shutdown(bool restart){
// the_mesh.savePrefs() call sites already do without a dirty check. // the_mesh.savePrefs() call sites already do without a dirty check.
the_mesh.savePrefs(); the_mesh.savePrefs();
the_mesh.saveRTCTime(); the_mesh.saveRTCTime();
the_mesh.flushDirtyContacts();
// Auto-save the live GPS trail before power-off when the user enabled it // Auto-save the live GPS trail before power-off when the user enabled it
// (Tools Trail Settings Auto-save). This covers the low-battery // (Tools Trail Settings Auto-save). This covers the low-battery