diff --git a/docs/cli_commands.md b/docs/cli_commands.md index fe329a04b..b81b3323e 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -1086,11 +1086,11 @@ get clock.sync.status - `on`: enable power saving - `off`: disable power saving -**Default:** `off` +**Default:** `off` for infrastructure roles; `on` for Companion firmware **Note:** Infrastructure firmware enters sleep between radio transmissions. It refuses to enable power saving from the local serial console or while an active USB serial data connection is detected; USB power alone does not block power saving. -Full Companion firmware accepts the command from its local USB terminal and exposes the same setting in WebConfig. On ESP32, it lowers the CPU clock to 80 MHz, enables idle yielding, and enables the configured GPS duty cycle. USB, BLE, and WiFi remain available. `powersaving off` restores the board's normal CPU clock and disables the GPS duty cycle. This device setting is separate from LoRa RXPS (`radio.rxps`) and WiFi modem power save (`wifi.powersave`). +Companion firmware defaults this setting to `on`. Full Companion accepts the command from its local USB terminal and exposes the same setting in WebConfig. On ESP32, it lowers the CPU clock to 80 MHz, enables idle yielding, and enables the configured GPS duty cycle. USB, BLE, and WiFi remain available. `powersaving off` restores the board's normal CPU clock and disables the GPS duty cycle. This device setting is separate from LoRa RXPS (`radio.rxps`) and WiFi modem power save (`wifi.powersave`). --- diff --git a/docs/companion_radio_full.md b/docs/companion_radio_full.md index fc16d0276..7b4f69eed 100644 --- a/docs/companion_radio_full.md +++ b/docs/companion_radio_full.md @@ -74,6 +74,11 @@ powersaving on powersaving off ``` +Companion firmware defaults device power saving to on. Version 1.17.1.2 also +turns it on once when upgrading an older Companion preference file, including +one written by the short-lived default-off regression. After that one-time +migration, an explicit `powersaving off` selection remains persistent. + On ESP32, enabling it lowers the CPU clock to 80 MHz, enables idle yielding, and enables the configured GPS duty cycle. Disabling it restores the normal CPU clock and keeps GPS awake. Full Companion transports remain available in both diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 1099e485e..eef54d241 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -339,6 +339,10 @@ void DataStore::loadPrefsInt(const char *filename, CompanionNodePrefs& _prefs, d if (file.available() >= (int)sizeof(_prefs.wifi_enabled)) { file.read((uint8_t *)&_prefs.wifi_enabled, sizeof(_prefs.wifi_enabled)); // 138 + if (file.available() >= (int)sizeof(_prefs.powersaving_policy_version)) { + file.read((uint8_t *)&_prefs.powersaving_policy_version, + sizeof(_prefs.powersaving_policy_version)); // 139 + } } } } @@ -407,6 +411,9 @@ bool DataStore::savePrefs(const CompanionNodePrefs& _prefs, double node_lat, dou sizeof(_prefs.powersaving_enabled)) == sizeof(_prefs.powersaving_enabled); // 137 success = success && file.write((uint8_t *)&_prefs.wifi_enabled, sizeof(_prefs.wifi_enabled)) == sizeof(_prefs.wifi_enabled); // 138 + success = success && file.write((uint8_t *)&_prefs.powersaving_policy_version, + sizeof(_prefs.powersaving_policy_version)) + == sizeof(_prefs.powersaving_policy_version); // 139 #if defined(NRF52_PLATFORM) success = file.commit(success); diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index fc5a5d5f0..2f02427b8 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1356,7 +1356,8 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.rx_ps_preamble = RXPS_FIXED_PREAMBLE; _prefs.rx_ps_rx_us = RX_POWERSAVING_DEFAULT_RX_US; _prefs.rx_ps_sleep_us = RX_POWERSAVING_DEFAULT_SLEEP_US; - _prefs.powersaving_enabled = 0; + _prefs.powersaving_enabled = 1; + _prefs.powersaving_policy_version = 0; _prefs.wifi_enabled = 1; recalcRxPowerSavingFromLevel(_prefs.rx_ps_level, _prefs.sf, _prefs.bw, _prefs.rx_ps_preamble, &_prefs.rx_ps_rx_us, @@ -1420,6 +1421,13 @@ void MyMesh::begin(bool has_display, bool radio_available) { // load persisted prefs _store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon); + // v1.17.1.2 repairs the Companion default-off regression for both fresh + // installs and devices that already persisted the regressed value. The + // appended policy marker makes this a one-time migration, so a later + // explicit `powersaving off` choice remains persistent. + const bool power_saving_default_migrated = + migrateCompanionPowerSavingDefault(_prefs); + // sanitise bad pref values _prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f); _prefs.airtime_factor = constrain(_prefs.airtime_factor, 0, 9.0f); @@ -1443,6 +1451,9 @@ void MyMesh::begin(bool has_display, bool radio_available) { _prefs.radio_fem_txgain = constrain(_prefs.radio_fem_txgain, 0, 1); _prefs.rx_powersaving_enabled = constrain(_prefs.rx_powersaving_enabled, 0, 1); _prefs.powersaving_enabled = constrain(_prefs.powersaving_enabled, 0, 1); + _prefs.powersaving_policy_version = constrain( + _prefs.powersaving_policy_version, 0, + COMPANION_POWERSAVING_POLICY_VERSION); _prefs.wifi_enabled = constrain(_prefs.wifi_enabled, 0, 1); _prefs.rx_ps_level = constrain(_prefs.rx_ps_level, 0, 10); if (_prefs.rx_ps_preamble != 16 && _prefs.rx_ps_preamble != 32) { @@ -1452,6 +1463,9 @@ void MyMesh::begin(bool has_display, bool radio_available) { recalcRxPowerSavingFromLevel(_prefs.rx_ps_level, _prefs.sf, _prefs.bw, _prefs.rx_ps_preamble, &_prefs.rx_ps_rx_us, &_prefs.rx_ps_sleep_us); + if (power_saving_default_migrated) { + _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); + } #ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index e95e0df2c..b75c7e6d4 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -9,6 +9,12 @@ #define ADVERT_LOC_NONE 0 #define ADVERT_LOC_SHARE 1 +// Increment when a release must migrate the persisted Companion device-power +// policy. Version 1 corrects the short-lived default-off regression: old +// preference files are upgraded to power saving on exactly once, after which +// an explicit user choice remains persistent. +#define COMPANION_POWERSAVING_POLICY_VERSION 1 + struct CompanionNodePrefs { // persisted to file float airtime_factor; char node_name[32]; @@ -46,9 +52,20 @@ struct CompanionNodePrefs { // persisted to file uint8_t rx_ps_preamble; // 0=auto from SF, otherwise 16 or 32 uint8_t powersaving_enabled; // device CPU/GPS idle power saving uint8_t wifi_enabled; // Companion WiFi radio and services + uint8_t powersaving_policy_version; // one-time default migration marker // Keep the upstream repeat API while retaining the existing binary prefs // layout used by this branch. bool isRepeatEn() const { return client_repeat != 0; } void setRepeatEn(bool enabled) { client_repeat = enabled ? 1 : 0; } }; + +inline bool migrateCompanionPowerSavingDefault(CompanionNodePrefs& prefs) { + if (prefs.powersaving_policy_version == COMPANION_POWERSAVING_POLICY_VERSION) { + return false; + } + + prefs.powersaving_enabled = 1; + prefs.powersaving_policy_version = COMPANION_POWERSAVING_POLICY_VERSION; + return true; +} diff --git a/test/test_companion_node_prefs/test_companion_node_prefs.cpp b/test/test_companion_node_prefs/test_companion_node_prefs.cpp index ffc2cf060..f2cbe9450 100644 --- a/test/test_companion_node_prefs/test_companion_node_prefs.cpp +++ b/test/test_companion_node_prefs/test_companion_node_prefs.cpp @@ -80,6 +80,23 @@ TEST(CompanionNodePrefs, WiFiStateIsIndependentFromPowerSaving) { EXPECT_EQ(1, prefs.powersaving_enabled); } +TEST(CompanionNodePrefs, MigratesRegressedPowerSavingDefaultOnce) { + CompanionNodePrefs prefs = {}; + prefs.powersaving_enabled = 0; + prefs.powersaving_policy_version = 0; + + EXPECT_TRUE(migrateCompanionPowerSavingDefault(prefs)); + EXPECT_EQ(1, prefs.powersaving_enabled); + EXPECT_EQ(COMPANION_POWERSAVING_POLICY_VERSION, + prefs.powersaving_policy_version); + + // Once migrated, an explicit user choice to turn power saving off remains + // untouched on later boots. + prefs.powersaving_enabled = 0; + EXPECT_FALSE(migrateCompanionPowerSavingDefault(prefs)); + EXPECT_EQ(0, prefs.powersaving_enabled); +} + #if 0 // Re-enable test once we can SET fem_ values in companion TEST(CompanionNodePrefs, RxGainSettingsRoundTripIndependently) {