From 5f5698ccc00777213784002f49162fc2ff147940 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 10 Jul 2025 10:29:33 -0500 Subject: [PATCH 01/17] Explicitly include meshUtils.h --- src/modules/KeyVerificationModule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/KeyVerificationModule.cpp b/src/modules/KeyVerificationModule.cpp index f0ede345f..b1e23e807 100644 --- a/src/modules/KeyVerificationModule.cpp +++ b/src/modules/KeyVerificationModule.cpp @@ -4,6 +4,7 @@ #include "RTC.h" #include "graphics/draw/MenuHandler.h" #include "main.h" +#include "meshUtils.h" #include "modules/AdminModule.h" #include From 6d8c815558f6288b817d8d2c2c53d2c89ce3bbde Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 11:31:40 -0500 Subject: [PATCH 02/17] automated bumps (#7293) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- bin/org.meshtastic.meshtasticd.metainfo.xml | 3 +++ debian/changelog | 7 +++++-- version.properties | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 47082718a..291fe7a7c 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.3 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.2 diff --git a/debian/changelog b/debian/changelog index 42488692b..b5009028a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -meshtasticd (2.7.2.0) UNRELEASED; urgency=medium +meshtasticd (2.7.3.0) UNRELEASED; urgency=medium [ Austin Lane ] * Initial packaging @@ -28,4 +28,7 @@ meshtasticd (2.7.2.0) UNRELEASED; urgency=medium [ ] * GitHub Actions Automatic version bump - -- Fri, 04 Jul 2025 11:58:01 +0000 + [ Ubuntu ] + * GitHub Actions Automatic version bump + + -- Ubuntu Thu, 10 Jul 2025 16:29:27 +0000 diff --git a/version.properties b/version.properties index 69f2d6af5..5de810523 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 2 +build = 3 From 6030bf50e04dc0e7d1c657a5dba50bd5aad0a09f Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 10 Jul 2025 11:39:38 -0500 Subject: [PATCH 03/17] Unbreak the macro --- src/modules/KeyVerificationModule.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/KeyVerificationModule.cpp b/src/modules/KeyVerificationModule.cpp index b1e23e807..3b8225763 100644 --- a/src/modules/KeyVerificationModule.cpp +++ b/src/modules/KeyVerificationModule.cpp @@ -86,9 +86,11 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket & sprintf(message, "Verification: \n"); generateVerificationCode(message + 15); LOG_INFO("Hash1 matches!"); - IF_SCREEN(static const char *optionsArray[] = {"Reject", "Accept"}; graphics::BannerOverlayOptions options; - options.message = message; options.durationMs = 30000; options.optionsArrayPtr = optionsArray; - options.optionsCount = 2; options.notificationType = graphics::notificationTypeEnum::selection_picker; + static const char *optionsArray[] = {"Reject", "Accept"}; + // Don't try to put the array definition in the macro. Does not work with curly braces. + IF_SCREEN(graphics::BannerOverlayOptions options; options.message = message; options.durationMs = 30000; + options.optionsArrayPtr = optionsArray; options.optionsCount = 2; + options.notificationType = graphics::notificationTypeEnum::selection_picker; options.bannerCallback = [=](int selected) { if (selected == 1) { From 57c1c9286b9baa07047300cb0fba1f62d103a1de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:11:00 -0500 Subject: [PATCH 04/17] Update RadioLib to v7.2.1 (#7287) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 89720f0ad..59349139b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -104,7 +104,7 @@ lib_deps = [radiolib_base] lib_deps = # renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib - jgromes/RadioLib@7.2.0 + jgromes/RadioLib@7.2.1 [device-ui_base] lib_deps = From 1aad442ccc253133467c0cb5824445a9887523e1 Mon Sep 17 00:00:00 2001 From: Kongduino Date: Fri, 11 Jul 2025 06:11:19 +0800 Subject: [PATCH 05/17] Update platformio.ini (#7289) The link to the product should point to the vendor's website, not a random distributor. Co-authored-by: Ben Meadors Co-authored-by: Jonathan Bennett --- variants/seeed_xiao_nrf52840_kit/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/seeed_xiao_nrf52840_kit/platformio.ini b/variants/seeed_xiao_nrf52840_kit/platformio.ini index 8c4c5a57b..0e1e94cd5 100644 --- a/variants/seeed_xiao_nrf52840_kit/platformio.ini +++ b/variants/seeed_xiao_nrf52840_kit/platformio.ini @@ -1,4 +1,4 @@ -; Seeed Xiao BLE: https://www.digikey.com/en/products/detail/seeed-technology-co-ltd/102010448/16652893 +; Seeed Xiao BLE: https://wiki.seeedstudio.com/XIAO_BLE/ [env:seeed_xiao_nrf52840_kit] extends = nrf52840_base board = xiao_ble_sense From fe534eae3784dbc5aa89d1cb1b016a332cf70f91 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:12:25 -0500 Subject: [PATCH 06/17] Update Adafruit BusIO to v1.17.2 (#7277) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 59349139b..eb6d4f683 100644 --- a/platformio.ini +++ b/platformio.ini @@ -115,7 +115,7 @@ lib_deps = [environmental_base] lib_deps = # renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO - adafruit/Adafruit BusIO@1.17.1 + adafruit/Adafruit BusIO@1.17.2 # renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor adafruit/Adafruit Unified Sensor@1.1.15 # renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library From 093868f3edb11b71326c882eeab682af2b64e00b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:12:39 -0500 Subject: [PATCH 07/17] Update dorny/test-reporter action to v2.1.1 (#7284) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test_native.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 536d93665..dc05959fd 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -143,7 +143,7 @@ jobs: merge-multiple: true - name: Test Report - uses: dorny/test-reporter@v2.1.0 + uses: dorny/test-reporter@v2.1.1 with: name: PlatformIO Tests path: testreport.xml From be75f111560086e1bef91e49743fb919e287e084 Mon Sep 17 00:00:00 2001 From: Jason P Date: Thu, 10 Jul 2025 19:49:15 -0500 Subject: [PATCH 08/17] Update Screen Wake Default Behavior (#7282) * feat(display): enable screen wake on received messages * feat(menu): add Screen Wakeup option in system menu * feat(ui): update wake on message configuration and refactor save logic * feat(TextMessageModule): conditionally trigger screen wake on received message * Refactoring system menu options for notification and screen. * Fix MUI options in the system menu. * Build out Reboot/Shutdown Menu and consolidate options within it * Trunk fixes * Protobuf ref * Revert generated files * Update plumbing for screen_wakeup_menu * Begin work on crafting a method to stop screen wake for received messages * SharedUIDisplay.cpp doesn't need ExternalNotificationModule.h * Stop screen wake if External Notification is enabled * Removing extra log lines * Add role and battery state checks for not waking screen. Menu updates to resolve some Back options not being linked * Resolve some additional merge conflict related issues * Shouldn't throttle the power menu * Finalize renames of some menus * Flip Flop MUI Menu to avoid accidental clicks * NULL check for powerStatus * Remove "Wakeup" eNum * Update src/graphics/Screen.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * CoPilot was close this should fix the builds --------- Co-authored-by: whywilson Co-authored-by: Ben Meadors Co-authored-by: Jonathan Bennett Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/graphics/Screen.cpp | 79 +++++++---- src/graphics/Screen.h | 4 + src/graphics/draw/MenuHandler.cpp | 229 ++++++++++++++++++++++++------ src/graphics/draw/MenuHandler.h | 14 +- src/modules/TextMessageModule.cpp | 7 +- 5 files changed, 261 insertions(+), 72 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 2bade47b2..f670225c3 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -83,6 +83,29 @@ extern uint16_t TFT_MESH; #include "platform/portduino/PortduinoGlue.h" #endif +bool shouldWakeOnReceivedMessage() +{ + /* + The goal here is to determine when we do NOT wake up the screen on message received: + - Any ext. notifications are turned on + - If role is not client / client_mute + - If the battery level is very low + */ + if (moduleConfig.external_notification.enabled) { + return false; + } + if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT && + config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { + return false; + } + if (powerStatus && powerStatus->getBatteryChargePercent() < 10) { + return false; + } + return true; +} + +bool wake_on_received_message = shouldWakeOnReceivedMessage(); // Master Switch to enable here + using namespace meshtastic; /** @todo remove */ namespace graphics @@ -1257,40 +1280,46 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) devicestate.has_rx_text_message = true; // Needed to include the message frame hasUnreadMessage = true; // Enables mail icon in the header setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view - forceDisplay(); // Forces screen redraw - // === Prepare banner content === - const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); - const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; + // Only wake/force display if the configuration allows it + wake_on_received_message = shouldWakeOnReceivedMessage(); + if (wake_on_received_message) { + setOn(true); // Wake up the screen first + forceDisplay(); // Forces screen redraw - const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); + // === Prepare banner content === + const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); + const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; - char banner[256]; + const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); - // Check for bell character in message to determine alert type - bool isAlert = false; - for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { - if (msgRaw[i] == '\x07') { - isAlert = true; - break; + char banner[256]; + + // Check for bell character in message to determine alert type + bool isAlert = false; + for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { + if (msgRaw[i] == '\x07') { + isAlert = true; + break; + } } - } - if (isAlert) { - if (longName && longName[0]) { - snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName); + if (isAlert) { + if (longName && longName[0]) { + snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName); + } else { + strcpy(banner, "Alert Received"); + } } else { - strcpy(banner, "Alert Received"); + if (longName && longName[0]) { + snprintf(banner, sizeof(banner), "New Message from\n%s", longName); + } else { + strcpy(banner, "New Message"); + } } - } else { - if (longName && longName[0]) { - snprintf(banner, sizeof(banner), "New Message from\n%s", longName); - } else { - strcpy(banner, "New Message"); - } - } - screen->showSimpleBanner(banner, 3000); + screen->showSimpleBanner(banner, 3000); + } } } diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 4deeb7395..19d14ecca 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -26,6 +26,8 @@ struct BannerOverlayOptions { }; } // namespace graphics +bool shouldWakeOnReceivedMessage(); + #if !HAS_SCREEN #include "power.h" namespace graphics @@ -123,6 +125,8 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 +extern bool wake_on_received_message; + /// Convert an integer GPS coords to a floating point #define DegD(i) (i * 1e-7) extern bool hasUnreadMessage; diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index c3a035c4f..f6b250ebc 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -129,11 +129,11 @@ void menuHandler::ClockFacePicker() screen->runNow(); } else if (selected == Digital) { uiconfig.is_clockface_analog = false; - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); + saveUIConfig(); screen->setFrames(Screen::FOCUS_CLOCK); } else { uiconfig.is_clockface_analog = true; - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); + saveUIConfig(); screen->setFrames(Screen::FOCUS_CLOCK); } }; @@ -346,37 +346,28 @@ void menuHandler::homeBaseMenu() void menuHandler::systemBaseMenu() { - // Check if brightness is supported bool hasSupportBrightness = false; #if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || HAS_TFT hasSupportBrightness = true; #endif - enum optionsNumbers { Back, Beeps, Brightness, Reboot, Color, MUI, Test, enumEnd }; + enum optionsNumbers { Back, Notifications, ScreenOptions, PowerMenu, Test, enumEnd }; static const char *optionsArray[enumEnd] = {"Back"}; static int optionsEnumArray[enumEnd] = {Back}; int options = 1; - optionsArray[options] = "Reboot"; - optionsEnumArray[options++] = Reboot; - - optionsArray[options] = "Beeps Action"; - optionsEnumArray[options++] = Beeps; - - if (hasSupportBrightness) { - optionsArray[options] = "Brightness"; - optionsEnumArray[options++] = Brightness; - } - -#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT - optionsArray[options] = "Screen Color"; - optionsEnumArray[options++] = Color; -#endif -#if HAS_TFT - optionsArray[options] = "Switch to MUI"; - optionsEnumArray[options++] = MUI; + optionsArray[options] = "Notifications"; + optionsEnumArray[options++] = Notifications; +#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || \ + defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT + optionsArray[options] = "Screen Options"; + optionsEnumArray[options++] = ScreenOptions; #endif + + optionsArray[options] = "Reboot/Shutdown"; + optionsEnumArray[options++] = PowerMenu; + if (test_enabled) { optionsArray[options] = "Test Menu"; optionsEnumArray[options++] = Test; @@ -388,20 +379,14 @@ void menuHandler::systemBaseMenu() bannerOptions.optionsCount = options; bannerOptions.optionsEnumPtr = optionsEnumArray; bannerOptions.bannerCallback = [](int selected) -> void { - if (selected == Beeps) { - menuHandler::menuQueue = menuHandler::buzzermodemenupicker; + if (selected == Notifications) { + menuHandler::menuQueue = menuHandler::notifications_menu; screen->runNow(); - } else if (selected == Brightness) { - menuHandler::menuQueue = menuHandler::brightness_picker; + } else if (selected == ScreenOptions) { + menuHandler::menuQueue = menuHandler::screen_options_menu; screen->runNow(); - } else if (selected == Reboot) { - menuHandler::menuQueue = menuHandler::reboot_menu; - screen->runNow(); - } else if (selected == MUI) { - menuHandler::menuQueue = menuHandler::mui_picker; - screen->runNow(); - } else if (selected == Color) { - menuHandler::menuQueue = menuHandler::tftcolormenupicker; + } else if (selected == PowerMenu) { + menuHandler::menuQueue = menuHandler::power_menu; screen->runNow(); } else if (selected == Test) { menuHandler::menuQueue = menuHandler::test_menu; @@ -533,22 +518,19 @@ void menuHandler::compassNorthMenu() if (selected == Dynamic) { if (uiconfig.compass_mode != meshtastic_CompassMode_DYNAMIC) { uiconfig.compass_mode = meshtastic_CompassMode_DYNAMIC; - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, - &uiconfig); + saveUIConfig(); screen->setFrames(graphics::Screen::FOCUS_PRESERVE); } } else if (selected == Fixed) { if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) { uiconfig.compass_mode = meshtastic_CompassMode_FIXED_RING; - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, - &uiconfig); + saveUIConfig(); screen->setFrames(graphics::Screen::FOCUS_PRESERVE); } } else if (selected == Freeze) { if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) { uiconfig.compass_mode = meshtastic_CompassMode_FREEZE_HEADING; - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, - &uiconfig); + saveUIConfig(); screen->setFrames(graphics::Screen::FOCUS_PRESERVE); } } else if (selected == Back) { @@ -610,7 +592,7 @@ void menuHandler::BuzzerModeMenu() { static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"}; BannerOverlayOptions bannerOptions; - bannerOptions.message = "Beep Action"; + bannerOptions.message = "Buzzer Mode"; bannerOptions.optionsArrayPtr = optionsArray; bannerOptions.optionsCount = 4; bannerOptions.bannerCallback = [](int selected) -> void { @@ -660,7 +642,7 @@ void menuHandler::BrightnessPickerMenu() #endif // Save to device - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); + saveUIConfig(); LOG_INFO("Screen brightness set to %d", uiconfig.screen_brightness); } @@ -671,13 +653,13 @@ void menuHandler::BrightnessPickerMenu() void menuHandler::switchToMUIMenu() { - static const char *optionsArray[] = {"Yes", "No"}; + static const char *optionsArray[] = {"No", "Yes"}; BannerOverlayOptions bannerOptions; bannerOptions.message = "Switch to MUI?"; bannerOptions.optionsArrayPtr = optionsArray; bannerOptions.optionsCount = 2; bannerOptions.bannerCallback = [](int selected) -> void { - if (selected == 0) { + if (selected == 1) { config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR; config.bluetooth.enabled = false; service->reloadConfig(SEGMENT_CONFIG); @@ -742,6 +724,9 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display) TFT_MESH_r = 255; TFT_MESH_g = 255; TFT_MESH_b = 255; + } else { + menuQueue = system_base_menu; + screen->runNow(); } #if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT @@ -771,7 +756,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display) uiconfig.screen_rgb_color = (TFT_MESH_r << 16) | (TFT_MESH_g << 8) | TFT_MESH_b; } LOG_INFO("Storing Value of %d to uiconfig.screen_rgb_color", uiconfig.screen_rgb_color); - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); + saveUIConfig(); } #endif }; @@ -790,6 +775,29 @@ void menuHandler::rebootMenu() IF_SCREEN(screen->showSimpleBanner("Rebooting...", 0)); nodeDB->saveToDisk(); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; + } else { + menuQueue = power_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::shutdownMenu() +{ + static const char *optionsArray[] = {"Back", "Confirm"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Shutdown Device?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + IF_SCREEN(screen->showSimpleBanner("Shutting Down...", 0)); + nodeDB->saveToDisk(); + power->shutdown(); + } else { + menuQueue = power_menu; + screen->runNow(); } }; screen->showOverlayBanner(bannerOptions); @@ -888,6 +896,117 @@ void menuHandler::wifiToggleMenu() screen->showOverlayBanner(bannerOptions); } +void menuHandler::notificationsMenu() +{ + enum optionsNumbers { Back, BuzzerActions }; + static const char *optionsArray[] = {"Back", "Buzzer Actions"}; + static int optionsEnumArray[] = {Back, BuzzerActions}; + int options = 2; + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Notifications"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == BuzzerActions) { + menuHandler::menuQueue = menuHandler::buzzermodemenupicker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::screenOptionsMenu() +{ + // Check if brightness is supported + bool hasSupportBrightness = false; +#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || HAS_TFT + hasSupportBrightness = true; +#endif + + enum optionsNumbers { Back, Brightness, ScreenColor }; + static const char *optionsArray[4] = {"Back"}; + static int optionsEnumArray[4] = {Back}; + int options = 1; + + // Only show brightness for B&W displays + if (hasSupportBrightness && !HAS_TFT) { + optionsArray[options] = "Brightness"; + optionsEnumArray[options++] = Brightness; + } + + // Only show screen color for TFT displays +#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT + optionsArray[options] = "Screen Color"; + optionsEnumArray[options++] = ScreenColor; +#endif + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Screen Options"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Brightness) { + menuHandler::menuQueue = menuHandler::brightness_picker; + screen->runNow(); + } else if (selected == ScreenColor) { + menuHandler::menuQueue = menuHandler::tftcolormenupicker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::powerMenu() +{ + + enum optionsNumbers { Back, Reboot, Shutdown, MUI }; + static const char *optionsArray[4] = {"Back"}; + static int optionsEnumArray[4] = {Back}; + int options = 1; + + optionsArray[options] = "Reboot"; + optionsEnumArray[options++] = Reboot; + + optionsArray[options] = "Shutdown"; + optionsEnumArray[options++] = Shutdown; + +#if HAS_TFT + optionsArray[options] = "Switch to MUI"; + optionsEnumArray[options++] = MUI; +#endif + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Reboot / Shutdown"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Reboot) { + menuHandler::menuQueue = menuHandler::reboot_menu; + screen->runNow(); + } else if (selected == Shutdown) { + menuHandler::menuQueue = menuHandler::shutdown_menu; + screen->runNow(); + } else if (selected == MUI) { + menuHandler::menuQueue = menuHandler::mui_picker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + void menuHandler::keyVerificationInitMenu() { screen->showNodePicker("Node to Verify", 30000, @@ -941,6 +1060,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case clock_menu: clockMenu(); break; + case system_base_menu: + systemBaseMenu(); + break; case position_base_menu: positionBaseMenu(); break; @@ -970,6 +1092,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case reboot_menu: rebootMenu(); break; + case shutdown_menu: + shutdownMenu(); + break; case add_favorite: addFavoriteMenu(); break; @@ -994,6 +1119,15 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case bluetooth_toggle_menu: BluetoothToggleMenu(); break; + case notifications_menu: + notificationsMenu(); + break; + case screen_options_menu: + screenOptionsMenu(); + break; + case power_menu: + powerMenu(); + break; case throttle_message: screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000); break; @@ -1001,6 +1135,11 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) menuQueue = menu_none; } +void menuHandler::saveUIConfig() +{ + nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); +} + } // namespace graphics #endif \ No newline at end of file diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h index 5846a3c91..2273dbbed 100644 --- a/src/graphics/draw/MenuHandler.h +++ b/src/graphics/draw/MenuHandler.h @@ -23,14 +23,19 @@ class menuHandler tftcolormenupicker, brightness_picker, reboot_menu, + shutdown_menu, add_favorite, remove_favorite, test_menu, number_test, wifi_toggle_menu, + bluetooth_toggle_menu, + notifications_menu, + screen_options_menu, + power_menu, + system_base_menu, key_verification_init, key_verification_final_prompt, - bluetooth_toggle_menu, throttle_message }; static screenMenus menuQueue; @@ -55,12 +60,19 @@ class menuHandler static void resetNodeDBMenu(); static void BrightnessPickerMenu(); static void rebootMenu(); + static void shutdownMenu(); static void addFavoriteMenu(); static void removeFavoriteMenu(); static void testMenu(); static void numberTest(); static void wifiBaseMenu(); static void wifiToggleMenu(); + static void notificationsMenu(); + static void screenOptionsMenu(); + static void powerMenu(); + + private: + static void saveUIConfig(); static void keyVerificationInitMenu(); static void keyVerificationFinalPrompt(); static void BluetoothToggleMenu(); diff --git a/src/modules/TextMessageModule.cpp b/src/modules/TextMessageModule.cpp index f1d01ad16..f0835073b 100644 --- a/src/modules/TextMessageModule.cpp +++ b/src/modules/TextMessageModule.cpp @@ -4,6 +4,7 @@ #include "PowerFSM.h" #include "buzz.h" #include "configuration.h" +#include "graphics/Screen.h" TextMessageModule *textMessageModule; ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp) @@ -17,7 +18,11 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp devicestate.rx_text_message = mp; devicestate.has_rx_text_message = true; - powerFSM.trigger(EVENT_RECEIVED_MSG); + wake_on_received_message = shouldWakeOnReceivedMessage(); + // Only trigger screen wake if configuration allows it + if (wake_on_received_message) { + powerFSM.trigger(EVENT_RECEIVED_MSG); + } notifyObservers(&mp); return ProcessMessage::CONTINUE; // Let others look at this message also if they want From 4bab148e3b75a51bdcd8aaa91ba0f904cf8a4a95 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 10 Jul 2025 22:51:43 -0500 Subject: [PATCH 09/17] Make the shouldWake function always available, and remove the bool (#7300) --- src/graphics/Screen.cpp | 46 ++++++++++++++----------------- src/graphics/Screen.h | 2 -- src/modules/TextMessageModule.cpp | 3 +- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f670225c3..59888c938 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -83,29 +83,6 @@ extern uint16_t TFT_MESH; #include "platform/portduino/PortduinoGlue.h" #endif -bool shouldWakeOnReceivedMessage() -{ - /* - The goal here is to determine when we do NOT wake up the screen on message received: - - Any ext. notifications are turned on - - If role is not client / client_mute - - If the battery level is very low - */ - if (moduleConfig.external_notification.enabled) { - return false; - } - if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT && - config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { - return false; - } - if (powerStatus && powerStatus->getBatteryChargePercent() < 10) { - return false; - } - return true; -} - -bool wake_on_received_message = shouldWakeOnReceivedMessage(); // Master Switch to enable here - using namespace meshtastic; /** @todo remove */ namespace graphics @@ -1282,8 +1259,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view // Only wake/force display if the configuration allows it - wake_on_received_message = shouldWakeOnReceivedMessage(); - if (wake_on_received_message) { + if (shouldWakeOnReceivedMessage()) { setOn(true); // Wake up the screen first forceDisplay(); // Forces screen redraw @@ -1452,3 +1428,23 @@ bool Screen::isOverlayBannerShowing() #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} #endif // HAS_SCREEN + +bool shouldWakeOnReceivedMessage() +{ + /* + The goal here is to determine when we do NOT wake up the screen on message received: + - Any ext. notifications are turned on + - If role is not client / client_mute + - If the battery level is very low + */ + if (moduleConfig.external_notification.enabled) { + return false; + } + if (!meshtastic_Config_DeviceConfig_Role_CLIENT && !meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { + return false; + } + if (powerStatus && powerStatus->getBatteryChargePercent() < 10) { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 19d14ecca..265900131 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -125,8 +125,6 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 -extern bool wake_on_received_message; - /// Convert an integer GPS coords to a floating point #define DegD(i) (i * 1e-7) extern bool hasUnreadMessage; diff --git a/src/modules/TextMessageModule.cpp b/src/modules/TextMessageModule.cpp index f0835073b..970f4429c 100644 --- a/src/modules/TextMessageModule.cpp +++ b/src/modules/TextMessageModule.cpp @@ -18,9 +18,8 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp devicestate.rx_text_message = mp; devicestate.has_rx_text_message = true; - wake_on_received_message = shouldWakeOnReceivedMessage(); // Only trigger screen wake if configuration allows it - if (wake_on_received_message) { + if (shouldWakeOnReceivedMessage()) { powerFSM.trigger(EVENT_RECEIVED_MSG); } notifyObservers(&mp); From 13ac182142ca4f5691aec8aa0c31f8c6b794c7cf Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 10 Jul 2025 23:19:58 -0500 Subject: [PATCH 10/17] Pick up nodedb.h in Screen.cpp regardless of HAS_SCREEN state --- src/graphics/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 59888c938..57ea64fa9 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "Screen.h" +#include "NodeDB.h" #include "PowerMon.h" #include "Throttle.h" #include "configuration.h" @@ -44,7 +45,6 @@ along with this program. If not, see . #endif #include "FSCommon.h" #include "MeshService.h" -#include "NodeDB.h" #include "RadioLibInterface.h" #include "error.h" #include "gps/GeoCoord.h" From 1063ef903495659a769290f36e9b2d1fabb2f4ce Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Fri, 11 Jul 2025 17:30:48 +1200 Subject: [PATCH 11/17] Shorter audio feedback for InkHUD buttons (#7301) --- src/graphics/niche/InkHUD/Events.cpp | 8 ++++---- variants/ELECROW-ThinkNode-M1/nicheGraphics.h | 4 ++-- variants/heltec_vision_master_e213/nicheGraphics.h | 2 +- variants/heltec_vision_master_e290/nicheGraphics.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/graphics/niche/InkHUD/Events.cpp b/src/graphics/niche/InkHUD/Events.cpp index 2abe30793..cdda1638d 100644 --- a/src/graphics/niche/InkHUD/Events.cpp +++ b/src/graphics/niche/InkHUD/Events.cpp @@ -39,8 +39,8 @@ void InkHUD::Events::begin() void InkHUD::Events::onButtonShort() { // Audio feedback (via buzzer) - // Short low tone - playBoop(); + // Short tone + playChirp(); // Cancel any beeping, buzzing, blinking // Some button handling suppressed if we are dismissing an external notification (see below) bool dismissedExt = dismissExternalNotification(); @@ -64,8 +64,8 @@ void InkHUD::Events::onButtonShort() void InkHUD::Events::onButtonLong() { // Audio feedback (via buzzer) - // Low tone, longer than playBoop - playBeep(); + // Slightly longer than playChirp + playBoop(); // Check which system applet wants to handle the button press (if any) SystemApplet *consumer = nullptr; diff --git a/variants/ELECROW-ThinkNode-M1/nicheGraphics.h b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h index b4395114f..f64de9d07 100644 --- a/variants/ELECROW-ThinkNode-M1/nicheGraphics.h +++ b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h @@ -104,11 +104,11 @@ void setupNicheGraphics() buttons->setHandlerDown(1, [backlight]() { backlight->peek(); }); buttons->setHandlerLongPress(1, [backlight]() { backlight->latch(); - playBeep(); + playBoop(); }); buttons->setHandlerShortPress(1, [backlight]() { backlight->off(); - playBoop(); + playChirp(); }); // Begin handling button events diff --git a/variants/heltec_vision_master_e213/nicheGraphics.h b/variants/heltec_vision_master_e213/nicheGraphics.h index 6a75ad90d..1b1291424 100644 --- a/variants/heltec_vision_master_e213/nicheGraphics.h +++ b/variants/heltec_vision_master_e213/nicheGraphics.h @@ -107,7 +107,7 @@ void setupNicheGraphics() buttons->setWiring(1, PIN_BUTTON2); buttons->setHandlerShortPress(1, [inkhud]() { inkhud->nextTile(); - playBoop(); + playChirp(); }); // Begin handling button events diff --git a/variants/heltec_vision_master_e290/nicheGraphics.h b/variants/heltec_vision_master_e290/nicheGraphics.h index f29873c15..61b08c740 100644 --- a/variants/heltec_vision_master_e290/nicheGraphics.h +++ b/variants/heltec_vision_master_e290/nicheGraphics.h @@ -104,7 +104,7 @@ void setupNicheGraphics() buttons->setWiring(1, PIN_BUTTON2); buttons->setHandlerShortPress(1, [inkhud]() { inkhud->nextTile(); - playBoop(); + playChirp(); }); // Begin handling button events From f7ecf141b53428327448b6c5ff80867db307ff43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:45:18 -0500 Subject: [PATCH 12/17] Update meshtastic/device-ui digest to 404c6e0 (#7302) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index eb6d4f683..352d7e8d4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -109,7 +109,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/8c7092c73425adfda1aac8c6960df06cd85f6d92.zip + https://github.com/meshtastic/device-ui/archive/404c6e06ecfda8dd2dc9e6d5fe417ae028f8029f.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 72f3d19d5af3b4b525a5cb5edc7e351be566c08c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:51:33 -0500 Subject: [PATCH 13/17] Upgrade trunk (#7278) Co-authored-by: sachaw <11172820+sachaw@users.noreply.github.com> --- .trunk/trunk.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 0986e6eb0..f0271c856 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -8,8 +8,8 @@ plugins: uri: https://github.com/trunk-io/plugins lint: enabled: - - checkov@3.2.447 - - renovate@41.23.4 + - checkov@3.2.450 + - renovate@41.29.1 - prettier@3.6.2 - trufflehog@3.89.2 - yamllint@1.37.1 From d42bde135f3b6308064b3313f64ef9db6bfd9003 Mon Sep 17 00:00:00 2001 From: Mictronics Date: Fri, 11 Jul 2025 13:54:37 +0200 Subject: [PATCH 14/17] Support native configuration Waveshare Pico LoRa module on Orange Pi Zero3 (#7295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28 * Merge PR #420 * Fixed double and missing Default class. * Use correct format specifier and fixed typo. * Removed duplicate code. * Fix error: #if with no expression * Fix warning: extra tokens at end of #endif directive. * Fix antenna switching logic. Complementary-pin control logic is required on the rp2040-lora board. * Fix deprecated macros. * Set RP2040 in dormant mode when deep sleep is triggered. * Fix array out of bounds read. * Admin key count needs to be set otherwise the key will be zero loaded after reset. * Don't reset the admin key size when loading defaults. Preserve an existing key in config if possible. * Remove log spam when reading INA voltage sensor. * Remove static declaration for admin keys from userPrefs.h. Load hard coded admin keys in case config file has empty slots. * Removed newlines from log. * Fix issue #5665. * Fix build for Pico2 RP2350 platform. * Enable Wifi client on Pico2W. * Use correct processor on Pico2. * Fix deprecated warning. * Update platform and framework for RP2350. * Added Pico2W variant including Wifi support. * Fix typo in used variant. * Remove obsolete define. * Fix for native Linux build. * Simplify RP2350 platform tag reference. Co-authored-by: Austin * Cast user prefs strings. * Update to last successfully building platform package. * Define I2C GPIOs to ensure usage of both ports. Possibly fixes #5361 * RAK11310 support for RAK12002 RTC added. * Update platform and framework packages to 4.4.3. * Use RP2040 base platform and framework package. Use RAK11300 board definition in arduino-pico framework. * Use RAK11300 board definition in arduino-pico framework. * Fix build when MESHTASTIC_EXCLUDE_GPS is defined. * Added configuration for Waveshare Pico LoRa module in combination with Orange Pi Zero3. * Equal to upstream master. --------- Co-authored-by: Ben Meadors Co-authored-by: Thomas Göttgens Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Co-authored-by: Austin Co-authored-by: Tom Fifield --- ...lora-ws-raspberry-pico-to-orangepi-03.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml diff --git a/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml b/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml new file mode 100644 index 000000000..37d7e27d2 --- /dev/null +++ b/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml @@ -0,0 +1,52 @@ +# https://www.waveshare.com/pico-lora-sx1262-868m.htm +# http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-3.html +# +# See Orange Pi Zero3 manual, chapter 3.16, page 124 for 26-pin header pinout +# +# Pin Connection +# Waveshare Orange Pi Zero3 +# 36 3.3V 17 +# 15 MOSI 19 +# 16 MISO 21 +# 14 CLK 23 +# 38 GND 25 +# 4 BUSY 18 +# 20 RESET 22 +# 5 CS 24 +# 26 DIO1/IRQ 26 + +Lora: + Module: sx1262 # Waveshare Raspberry Pico Lora module + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + # Specify either the spidev1_1 or the CS below, not both! + # On DietPi Linux, when using the user overlay dietpi-spi1_1.dtbo, CS will be configured with spidev1.1 + spidev: spidev1.1 # See Orange Pi Zero3 manual, chapter 3.18.3, page 130 +# CS: # CS PIN_24 -> chip 1, line 233 +# pin: 24 +# gpiochip: 1 +# line: 233 + SCK: # SCK PIN_23 -> chip 1, line 230 + pin: 23 + gpiochip: 1 + line: 230 + Busy: # BUSY PIN_18 -> chip 1, line 78 + pin: 18 + gpiochip: 1 + line: 78 + MOSI: # MOSI PIN_19 -> chip 1, line 231 + pin: 19 + gpiochip: 1 + line: 231 + MISO: # MISO PIN_21 -> chip 1, line 232 + pin: 21 + gpiochip: 1 + line: 232 + Reset: # NRST PIN_22 -> chip 1, line 71 + pin: 22 + gpiochip: 1 + line: 71 + IRQ: # DIO1 PIN_26 -> chip 1, line 74 + pin: 26 + gpiochip: 1 + line: 74 From e9a551ae903bdd1269dbce5a1b7ee6dd9357f250 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 11 Jul 2025 09:09:46 -0400 Subject: [PATCH 15/17] Load ringtone from userPrefs (#7298) * Load ringtone from userPrefs * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Meadors Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/modules/ExternalNotificationModule.cpp | 6 +++--- userPrefs.jsonc | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 956508ce5..c17fcc4fa 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -362,9 +362,9 @@ ExternalNotificationModule::ExternalNotificationModule() if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), &meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); - strncpy(rtttlConfig.ringtone, - "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", - sizeof(rtttlConfig.ringtone)); + // The default ringtone is always loaded from userPrefs.jsonc + strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE, sizeof(rtttlConfig.ringtone)); + rtttlConfig.ringtone[sizeof(rtttlConfig.ringtone) - 1] = '\0'; // Ensure null termination } LOG_INFO("Init External Notification Module"); diff --git a/userPrefs.jsonc b/userPrefs.jsonc index fc9e6ed72..c32bc7841 100644 --- a/userPrefs.jsonc +++ b/userPrefs.jsonc @@ -53,5 +53,6 @@ // "USERPREFS_MQTT_ENCRYPTION_ENABLED": "true", // "USERPREFS_MQTT_TLS_ENABLED": "false", // "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME", + "USERPREFS_RINGTONE": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", "USERPREFS_TZ_STRING": "tzplaceholder " } From 9798a91e7b464e92cadd5ae9e1763b5799a1f030 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 11 Jul 2025 08:22:50 -0500 Subject: [PATCH 16/17] Delete ringtone.proto file for factory reset (#7303) --- src/mesh/NodeDB.cpp | 3 +++ src/modules/ExternalNotificationModule.cpp | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a20acfda0..212b0dc33 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -474,6 +474,9 @@ bool NodeDB::factoryReset(bool eraseBleBonds) if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) { LOG_ERROR("Could not remove rangetest.csv file"); } + if (FSCom.exists("/prefs/ringtone.proto") && !FSCom.remove("/prefs/ringtone.proto")) { + LOG_ERROR("Could not remove ringtone.proto file"); + } #endif spiLock->unlock(); // second, install default state (this will deal with the duplicate mac address issue) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index c17fcc4fa..76566d4da 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -364,7 +364,6 @@ ExternalNotificationModule::ExternalNotificationModule() memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); // The default ringtone is always loaded from userPrefs.jsonc strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE, sizeof(rtttlConfig.ringtone)); - rtttlConfig.ringtone[sizeof(rtttlConfig.ringtone) - 1] = '\0'; // Ensure null termination } LOG_INFO("Init External Notification Module"); From 5ae8021aa6d01f1a36ff509c594d0481517f11ec Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 11 Jul 2025 08:28:21 -0500 Subject: [PATCH 17/17] I'm dumb --- src/mesh/NodeDB.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 212b0dc33..a20acfda0 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -474,9 +474,6 @@ bool NodeDB::factoryReset(bool eraseBleBonds) if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) { LOG_ERROR("Could not remove rangetest.csv file"); } - if (FSCom.exists("/prefs/ringtone.proto") && !FSCom.remove("/prefs/ringtone.proto")) { - LOG_ERROR("Could not remove ringtone.proto file"); - } #endif spiLock->unlock(); // second, install default state (this will deal with the duplicate mac address issue)