From 0d9472a4cc37951cdfdf986a9094b0b387ce6e21 Mon Sep 17 00:00:00 2001 From: Nick Dunklee Date: Tue, 2 Jun 2026 20:33:44 -0600 Subject: [PATCH 1/2] fix: contact sync across simple_repeater and companion_radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hasPendingWork() extended so simple_repeater and companion_radio both gate sleep and shutdown for pending contact writes - shutdown loops using hasPendingWork instead of ShutdownHandler idea in previous PR - uiTask shutdown behavior - all three variants (ui-new, ui-tiny, ui-orig) now set a _wants_shutdown flag instead of calling powerOff() directly - "Power off in 5 seconds…" messages added everywhere a shutdown is announced - "all" (hopefully) eInk displays are now tagged together using isEInk() constant - "all" eInk displays will send a final "Shut Down" message so the displays show "Shut Down" after a successful shutdown --- examples/companion_radio/AbstractUITask.h | 4 ++++ examples/companion_radio/main.cpp | 17 +++++++++++++++++ examples/companion_radio/ui-new/UITask.cpp | 11 ++++++++--- examples/companion_radio/ui-orig/UITask.cpp | 10 ++++++++-- examples/companion_radio/ui-tiny/UITask.cpp | 13 +++++++++---- examples/simple_repeater/MyMesh.cpp | 2 +- examples/simple_repeater/main.cpp | 11 +++++++++-- 7 files changed, 56 insertions(+), 12 deletions(-) diff --git a/examples/companion_radio/AbstractUITask.h b/examples/companion_radio/AbstractUITask.h index 0eee45aef3..5413b8017e 100644 --- a/examples/companion_radio/AbstractUITask.h +++ b/examples/companion_radio/AbstractUITask.h @@ -27,12 +27,16 @@ class AbstractUITask { mesh::MainBoard* _board; BaseSerialInterface* _serial; bool _connected; + bool _wants_shutdown = false; + bool _restart_on_shutdown = false; AbstractUITask(mesh::MainBoard* board, BaseSerialInterface* serial) : _board(board), _serial(serial) { _connected = false; } public: + bool wantsShutdown() const { return _wants_shutdown; } + bool isRestart() const { return _restart_on_shutdown; } void setHasConnection(bool connected) { _connected = connected; } bool hasConnection() const { return _connected; } uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); } diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index ef9b6bfca4..965b9bb0bc 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -256,6 +256,23 @@ void loop() { #endif } +#ifdef DISPLAY_CLASS + if (ui_task.wantsShutdown() && !the_mesh.hasPendingWork()) { + if (display.isEink()) { + display.startFrame(); + display.setTextSize(2); + display.setColor(DisplayDriver::LIGHT); + display.drawTextCentered(display.width() / 2, 28, "Powered off."); + display.endFrame(); + } else { + display.turnOff(); + } + radio_driver.powerOff(); + if (ui_task.isRestart()) board.reboot(); + else board.powerOff(); + } +#endif + #if defined(ESP32) && defined(WIFI_SSID) // Safely attempt to reconnect every 10 seconds if flagged if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) { diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 7c84201941..8942dd6c1d 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -697,9 +697,14 @@ void UITask::shutdown(bool restart){ if (restart) { _board->reboot(); } else { - _display->turnOff(); - radio_driver.powerOff(); - _board->powerOff(); + if (_display != NULL) { + _display->startFrame(); + _display->setTextSize(1); + _display->setColor(DisplayDriver::LIGHT); + _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 seconds..."); + _display->endFrame(); + } + _wants_shutdown = true; } } diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 5529046775..87e60b5f16 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -307,8 +307,14 @@ void UITask::shutdown(bool restart){ if (restart) { _board->reboot(); } else { - radio_driver.powerOff(); - _board->powerOff(); + if (_display != NULL) { + _display->startFrame(); + _display->setTextSize(1); + _display->setColor(DisplayDriver::LIGHT); + _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 seconds..."); + _display->endFrame(); + } + _wants_shutdown = true; } } diff --git a/examples/companion_radio/ui-tiny/UITask.cpp b/examples/companion_radio/ui-tiny/UITask.cpp index 0119475e77..c38d0e9217 100644 --- a/examples/companion_radio/ui-tiny/UITask.cpp +++ b/examples/companion_radio/ui-tiny/UITask.cpp @@ -364,7 +364,7 @@ class HomeScreen : public UIScreen { display.setColor(DisplayDriver::GREEN); display.setTextSize(1); if (_shutdown_init) { - display.drawTextCentered(display.width() / 2, 20, "hibernating..."); + display.drawTextCentered(display.width() / 2, 20, "Power off in 5 sec."); } else { display.drawXbm((display.width() - 32) / 2, 8, power_icon, 32, 32); // display.drawTextCentered(display.width() / 2, 40 - 11, "hibernate:" PRESS_LABEL); @@ -566,9 +566,14 @@ void UITask::shutdown(bool restart){ if (restart) { _board->reboot(); } else { - _display->turnOff(); - radio_driver.powerOff(); - _board->powerOff(); + if (_display != NULL) { + _display->startFrame(); + _display->setTextSize(1); + _display->setColor(DisplayDriver::LIGHT); + _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 sec."); + _display->endFrame(); + } + _wants_shutdown = true; } } diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index c24e297cd3..473e58dd7e 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1310,5 +1310,5 @@ bool MyMesh::hasPendingWork() const { #if defined(WITH_BRIDGE) if (bridge.isRunning()) return true; // bridge needs WiFi radio, can't sleep #endif - return _mgr->getOutboundTotal() > 0; + return _mgr->getOutboundTotal() > 0 || dirty_contacts_expiry != 0; } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 2ce056f521..ad34d2ac74 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -137,8 +137,15 @@ void loop() { if (userBtnDownAt == 0) { userBtnDownAt = millis(); } else if ((unsigned long)(millis() - userBtnDownAt) >= USER_BTN_HOLD_OFF_MILLIS) { - Serial.println("Powering off..."); - board.powerOff(); // does not return + if (!the_mesh.hasPendingWork()) { + board.powerOff(); // does not return + } else { + static bool notified = false; + if (!notified) { + Serial.println("Power off in 5 seconds..."); + notified = true; + } + } } } else { userBtnDownAt = 0; From f16c496ad29226113d2d9597134dbd299704860b Mon Sep 17 00:00:00 2001 From: Nick Dunklee Date: Fri, 5 Jun 2026 15:45:27 -0600 Subject: [PATCH 2/2] refactored change to include upstream improvements. - removed display text from ui-orig as none of those paths have displays - changed text formatting/syntax across all strings to match - low power, "!" - user-chosen or otherwise, "..." - removed mention of 5 seconds since it could be 0-5 seconds to shutdown after contact flush --- examples/companion_radio/ui-new/UITask.cpp | 8 ++++---- examples/companion_radio/ui-orig/UITask.cpp | 7 ------- examples/companion_radio/ui-tiny/UITask.cpp | 9 +-------- examples/simple_repeater/main.cpp | 2 +- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 8942dd6c1d..3d772aceac 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -404,7 +404,7 @@ class HomeScreen : public UIScreen { display.setColor(DisplayDriver::GREEN); display.setTextSize(1); if (_shutdown_init) { - display.drawTextCentered(display.width() / 2, 34, "hibernating..."); + display.drawTextCentered(display.width() / 2, 34, "Shutting down..."); } else { display.drawXbm((display.width() - 32) / 2, 18, power_icon, 32, 32); display.drawTextCentered(display.width() / 2, 64 - 11, "hibernate:" PRESS_LABEL); @@ -701,7 +701,7 @@ void UITask::shutdown(bool restart){ _display->startFrame(); _display->setTextSize(1); _display->setColor(DisplayDriver::LIGHT); - _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 seconds..."); + _display->drawTextCentered(_display->width() / 2, 20, "Shutting down..."); _display->endFrame(); } _wants_shutdown = true; @@ -842,8 +842,8 @@ void UITask::loop() { _display->startFrame(); _display->setTextSize(2); _display->setColor(DisplayDriver::RED); - _display->drawTextCentered(_display->width() / 2, 20, "Low Battery."); - _display->drawTextCentered(_display->width() / 2, 40, "Shutting Down!"); + _display->drawTextCentered(_display->width() / 2, 20, "Low battery!"); + _display->drawTextCentered(_display->width() / 2, 40, "Shutting down!"); _display->endFrame(); if (_display->isEink() == false) { delay(3000); } } diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 87e60b5f16..7447a63679 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -307,13 +307,6 @@ void UITask::shutdown(bool restart){ if (restart) { _board->reboot(); } else { - if (_display != NULL) { - _display->startFrame(); - _display->setTextSize(1); - _display->setColor(DisplayDriver::LIGHT); - _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 seconds..."); - _display->endFrame(); - } _wants_shutdown = true; } } diff --git a/examples/companion_radio/ui-tiny/UITask.cpp b/examples/companion_radio/ui-tiny/UITask.cpp index c38d0e9217..8977c296bc 100644 --- a/examples/companion_radio/ui-tiny/UITask.cpp +++ b/examples/companion_radio/ui-tiny/UITask.cpp @@ -364,7 +364,7 @@ class HomeScreen : public UIScreen { display.setColor(DisplayDriver::GREEN); display.setTextSize(1); if (_shutdown_init) { - display.drawTextCentered(display.width() / 2, 20, "Power off in 5 sec."); + display.drawTextCentered(display.width() / 2, 20, "Shutting down..."); } else { display.drawXbm((display.width() - 32) / 2, 8, power_icon, 32, 32); // display.drawTextCentered(display.width() / 2, 40 - 11, "hibernate:" PRESS_LABEL); @@ -566,13 +566,6 @@ void UITask::shutdown(bool restart){ if (restart) { _board->reboot(); } else { - if (_display != NULL) { - _display->startFrame(); - _display->setTextSize(1); - _display->setColor(DisplayDriver::LIGHT); - _display->drawTextCentered(_display->width() / 2, 20, "Power off in 5 sec."); - _display->endFrame(); - } _wants_shutdown = true; } } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index ad34d2ac74..2b2fe78ba4 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -142,7 +142,7 @@ void loop() { } else { static bool notified = false; if (!notified) { - Serial.println("Power off in 5 seconds..."); + Serial.println("Shutting down!"); notified = true; } }