From c641beabd32f564f9064a520efd90afd1df524fa Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 16:37:10 +0800 Subject: [PATCH 1/8] https://github.com/meshcore-dev/MeshCore/issues/989 - persist GPS enabled state to preferences Add GPS configuration to NodePrefs structure and persist the GPS enabled state when toggled via UI. This ensures GPS settings are retained across device restarts. --- examples/companion_radio/DataStore.cpp | 4 ++++ examples/companion_radio/MyMesh.cpp | 7 +++++++ examples/companion_radio/NodePrefs.h | 2 ++ examples/companion_radio/ui-new/UITask.cpp | 3 +++ 4 files changed, 16 insertions(+) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 00e25cb2a..7f5761f3c 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -222,6 +222,8 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no file.read(pad, 2); // 78 file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 file.read((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84 + file.read((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85 + file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.close(); } @@ -254,6 +256,8 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write(pad, 2); // 78 file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 file.write((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84 + file.write((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85 + file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.close(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 09d866c9e..a94975b3e 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -739,6 +739,8 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.bw = LORA_BW; _prefs.cr = LORA_CR; _prefs.tx_power_dbm = LORA_TX_POWER; + _prefs.gps_enabled = 0; // GPS disabled by default + _prefs.gps_interval = 0; // No automatic GPS updates by default //_prefs.rx_delay_base = 10.0f; enable once new algo fixed } @@ -776,6 +778,7 @@ void MyMesh::begin(bool has_display) { _prefs.sf = constrain(_prefs.sf, 5, 12); _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); + _prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1 #ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { @@ -803,6 +806,10 @@ void MyMesh::begin(bool has_display) { radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_set_tx_power(_prefs.tx_power_dbm); + +#if ENV_INCLUDE_GPS == 1 + sensors.setSettingValue("gps", _prefs.gps_enabled ? "1" : "0"); +#endif } const char *MyMesh::getNodeName() { diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 13c9f8842..e9db5444f 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -25,4 +25,6 @@ struct NodePrefs { // persisted to file uint32_t ble_pin; uint8_t advert_loc_policy; uint8_t buzzer_quiet; + uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled) + uint32_t gps_interval; // GPS read interval in seconds }; \ No newline at end of file diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 59a1b2dee..4cc47e238 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -863,13 +863,16 @@ void UITask::toggleGPS() { if (strcmp(_sensors->getSettingName(i), "gps") == 0) { if (strcmp(_sensors->getSettingValue(i), "1") == 0) { _sensors->setSettingValue("gps", "0"); + _node_prefs->gps_enabled = 0; notify(UIEventType::ack); showAlert("GPS: Disabled", 800); } else { _sensors->setSettingValue("gps", "1"); + _node_prefs->gps_enabled = 1; notify(UIEventType::ack); showAlert("GPS: Enabled", 800); } + the_mesh.savePrefs(); _next_refresh = 0; break; } From 88fb173297d667894df4b21faffab84ddea14d7a Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 17:20:02 +0800 Subject: [PATCH 2/8] add configurable GPS update interval Make GPS update interval configurable via settings instead of using hardcoded 1 second value. The interval is persisted from preferences and can be adjusted at runtime through the sensor manager settings interface --- examples/companion_radio/MyMesh.cpp | 3 +++ src/helpers/sensors/EnvironmentSensorManager.cpp | 11 ++++++++++- src/helpers/sensors/EnvironmentSensorManager.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index a94975b3e..be39b7fa6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -809,6 +809,9 @@ void MyMesh::begin(bool has_display) { #if ENV_INCLUDE_GPS == 1 sensors.setSettingValue("gps", _prefs.gps_enabled ? "1" : "0"); + char interval_str[12]; // Max: 24 hours = 86400 seconds (5 digits + null) + sprintf(interval_str, "%u", _prefs.gps_interval); + sensors.setSettingValue("gps_interval", interval_str); #endif } diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index bb675c276..53c381f7c 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -521,6 +521,15 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val } return true; } + if (strcmp(name, "gps_interval") == 0) { + uint32_t interval_seconds = atoi(value); + if (interval_seconds > 0) { + gps_update_interval_ms = interval_seconds * 1000; + } else { + gps_update_interval_ms = 1000; // Default to 1 second if 0 + } + return true; + } #endif return false; // not supported } @@ -708,7 +717,7 @@ void EnvironmentSensorManager::loop() { } #endif } - next_gps_update = millis() + 1000; + next_gps_update = millis() + gps_update_interval_ms; } #endif } diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 5f1c08e2e..6dd532e6b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -25,6 +25,7 @@ protected: bool gps_detected = false; bool gps_active = false; + uint32_t gps_update_interval_ms = 1000; // Default 1 second #if ENV_INCLUDE_GPS LocationProvider* _location; From 678915ef3b6ad3e9bb398bfa797b5c6f832f73f5 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 17:29:59 +0800 Subject: [PATCH 3/8] add GPS interval validation and bounds checking --- examples/companion_radio/MyMesh.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index be39b7fa6..91bb7358d 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -779,6 +779,7 @@ void MyMesh::begin(bool has_display) { _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); _prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1 + _prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours #ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { @@ -809,9 +810,11 @@ void MyMesh::begin(bool has_display) { #if ENV_INCLUDE_GPS == 1 sensors.setSettingValue("gps", _prefs.gps_enabled ? "1" : "0"); - char interval_str[12]; // Max: 24 hours = 86400 seconds (5 digits + null) - sprintf(interval_str, "%u", _prefs.gps_interval); - sensors.setSettingValue("gps_interval", interval_str); + if (_prefs.gps_interval > 0) { + char interval_str[12]; // Max: 24 hours = 86400 seconds (5 digits + null) + sprintf(interval_str, "%u", _prefs.gps_interval); + sensors.setSettingValue("gps_interval", interval_str); + } #endif } From 4aebc57add0c61a37e31bcf18b8a7c5620539785 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 18:02:08 +0800 Subject: [PATCH 4/8] fixed gps init value --- examples/companion_radio/MyMesh.cpp | 9 --------- examples/companion_radio/main.cpp | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 91bb7358d..035e06a74 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -807,15 +807,6 @@ void MyMesh::begin(bool has_display) { radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_set_tx_power(_prefs.tx_power_dbm); - -#if ENV_INCLUDE_GPS == 1 - sensors.setSettingValue("gps", _prefs.gps_enabled ? "1" : "0"); - if (_prefs.gps_interval > 0) { - char interval_str[12]; // Max: 24 hours = 86400 seconds (5 digits + null) - sprintf(interval_str, "%u", _prefs.gps_interval); - sensors.setSettingValue("gps_interval", interval_str); - } -#endif } const char *MyMesh::getNodeName() { diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 82c8c21d9..15b461f3b 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -216,6 +216,16 @@ void setup() { sensors.begin(); +#if ENV_INCLUDE_GPS == 1 + // Apply GPS preferences after sensors.begin() so gps_detected is set + sensors.setSettingValue("gps", the_mesh.getNodePrefs()->gps_enabled ? "1" : "0"); + if (the_mesh.getNodePrefs()->gps_interval > 0) { + char interval_str[12]; + sprintf(interval_str, "%u", the_mesh.getNodePrefs()->gps_interval); + sensors.setSettingValue("gps_interval", interval_str); + } +#endif + #ifdef DISPLAY_CLASS ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved #endif From 39503ad0b48515e527d38ff2bf477b207b5bd1b5 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 18:35:10 +0800 Subject: [PATCH 5/8] move GPS preference initialization to UITask --- examples/companion_radio/main.cpp | 10 ---------- examples/companion_radio/ui-new/UITask.cpp | 13 +++++++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 15b461f3b..82c8c21d9 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -216,16 +216,6 @@ void setup() { sensors.begin(); -#if ENV_INCLUDE_GPS == 1 - // Apply GPS preferences after sensors.begin() so gps_detected is set - sensors.setSettingValue("gps", the_mesh.getNodePrefs()->gps_enabled ? "1" : "0"); - if (the_mesh.getNodePrefs()->gps_interval > 0) { - char interval_str[12]; - sprintf(interval_str, "%u", the_mesh.getNodePrefs()->gps_interval); - sensors.setSettingValue("gps_interval", interval_str); - } -#endif - #ifdef DISPLAY_CLASS ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved #endif diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 4cc47e238..ebdeb6d3b 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -537,6 +537,19 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no #endif _node_prefs = node_prefs; + +#if ENV_INCLUDE_GPS == 1 + // Apply GPS preferences from stored prefs + if (_sensors != NULL && _node_prefs != NULL) { + _sensors->setSettingValue("gps", _node_prefs->gps_enabled ? "1" : "0"); + if (_node_prefs->gps_interval > 0) { + char interval_str[12]; // Max: 24 hours = 86400 seconds (5 digits + null) + sprintf(interval_str, "%u", _node_prefs->gps_interval); + _sensors->setSettingValue("gps_interval", interval_str); + } + } +#endif + if (_display != NULL) { _display->turnOn(); } From 62e180dc0fa1b5af9e55308bc91d60ec1fc98ba8 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 19:02:00 +0800 Subject: [PATCH 6/8] changed ms to sec --- src/helpers/sensors/EnvironmentSensorManager.cpp | 6 +++--- src/helpers/sensors/EnvironmentSensorManager.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 53c381f7c..2362eda7e 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -524,9 +524,9 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val if (strcmp(name, "gps_interval") == 0) { uint32_t interval_seconds = atoi(value); if (interval_seconds > 0) { - gps_update_interval_ms = interval_seconds * 1000; + gps_update_interval_sec = interval_seconds; } else { - gps_update_interval_ms = 1000; // Default to 1 second if 0 + gps_update_interval_sec = 1; // Default to 1 second if 0 } return true; } @@ -717,7 +717,7 @@ void EnvironmentSensorManager::loop() { } #endif } - next_gps_update = millis() + gps_update_interval_ms; + next_gps_update = millis() + gps_update_interval_sec; } #endif } diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 6dd532e6b..f176a33f5 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -25,7 +25,7 @@ protected: bool gps_detected = false; bool gps_active = false; - uint32_t gps_update_interval_ms = 1000; // Default 1 second + uint32_t gps_update_interval_sec = 1; // Default 1 second #if ENV_INCLUDE_GPS LocationProvider* _location; From df3cb3d192ab655b467ecb22e4fb41c3041c1673 Mon Sep 17 00:00:00 2001 From: csrutil Date: Sat, 29 Nov 2025 20:29:52 +0800 Subject: [PATCH 7/8] _location->loop() should be in the next tick --- src/helpers/sensors/EnvironmentSensorManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 2362eda7e..b072bcb0d 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -695,9 +695,9 @@ void EnvironmentSensorManager::loop() { static long next_gps_update = 0; #if ENV_INCLUDE_GPS - _location->loop(); - if (millis() > next_gps_update) { + _location->loop(); + if(gps_active){ #ifdef RAK_WISBLOCK_GPS if ((i2cGPSFlag || serialGPSFlag) && _location->isValid()) { @@ -717,7 +717,7 @@ void EnvironmentSensorManager::loop() { } #endif } - next_gps_update = millis() + gps_update_interval_sec; + next_gps_update = millis() + (gps_update_interval_sec * 1000); } #endif } From cfb7ed876ca7a424d7d1007ebb271aa08765e77b Mon Sep 17 00:00:00 2001 From: csrutil Date: Sun, 30 Nov 2025 09:45:56 +0800 Subject: [PATCH 8/8] CMD_SET_CUSTOM_VAR will update gps and gps_interval --- examples/companion_radio/MyMesh.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 035e06a74..3aed2da70 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1525,6 +1525,17 @@ void MyMesh::handleCmdFrame(size_t len) { *np++ = 0; // modify 'cmd_frame', replace ':' with null bool success = sensors.setSettingValue(sp, np); if (success) { + #if ENV_INCLUDE_GPS == 1 + // Update node preferences for GPS settings + if (strcmp(sp, "gps") == 0) { + _prefs.gps_enabled = (np[0] == '1') ? 1 : 0; + savePrefs(); + } else if (strcmp(sp, "gps_interval") == 0) { + uint32_t interval_seconds = atoi(np); + _prefs.gps_interval = constrain(interval_seconds, 0, 86400); + savePrefs(); + } + #endif writeOKFrame(); } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG);