diff --git a/docs/cli_commands.md b/docs/cli_commands.md index e8d7a20a..a5a55e80 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -131,15 +131,23 @@ This document provides an overview of CLI commands that can be sent to MeshCore **Usage:** - `get battery.alert` - `set battery.alert ` +- `get battery.alert.low` +- `set battery.alert.low ` +- `get battery.alert.critical` +- `set battery.alert.critical ` **Parameters:** - `state`: `on` (enable) or `off` (disable) +- `percent`: Battery percentage threshold **Default:** `off` +**Default thresholds:** `20` for `battery.alert.low`, `10` for `battery.alert.critical` + **Notes:** -- When enabled, sends a `#repeaters` flood text warning if voltage is above `1 V` and the battery estimate is below `20%`. -- Warnings repeat every `24` hours, or every `12` hours below `10%`. +- When enabled, sends a `#repeaters` flood text warning if voltage is above `1 V` and the battery estimate is below `battery.alert.low`. +- Warnings repeat every `24` hours, or every `12` hours below `battery.alert.critical`. +- `battery.alert.critical` must be lower than `battery.alert.low`. --- diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 6dc8bb7d..22862518 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -74,8 +74,8 @@ #endif #define LOW_BATTERY_MIN_VALID_MV 1000 -#define LOW_BATTERY_WARN_PERCENT 20 -#define LOW_BATTERY_CRITICAL_PERCENT 10 +#define LOW_BATTERY_WARN_PERCENT_DEFAULT 20 +#define LOW_BATTERY_CRITICAL_PERCENT_DEFAULT 10 #define LOW_BATTERY_CHECK_INTERVAL (60UL * 1000UL) #define LOW_BATTERY_WARN_INTERVAL (24UL * 60UL * 60UL * 1000UL) #define LOW_BATTERY_CRITICAL_INTERVAL (12UL * 60UL * 60UL * 1000UL) @@ -584,6 +584,30 @@ static uint8_t batteryPercentFromMilliVolts(uint16_t batt_mv) { return (uint8_t)pct; } +static bool parseBatteryAlertPercent(const char* value, uint8_t min_value, uint8_t max_value, uint8_t& result) { + if (value == NULL || *value == 0) { + return false; + } + + uint16_t parsed = 0; + while (*value) { + if (*value < '0' || *value > '9') { + return false; + } + parsed = (uint16_t)(parsed * 10 + (*value - '0')); + if (parsed > max_value) { + return false; + } + value++; + } + if (parsed < min_value) { + return false; + } + + result = (uint8_t)parsed; + return true; +} + mesh::Packet* MyMesh::createPacketCopy(const mesh::Packet* packet, const char* caller) { if (packet == NULL) return NULL; @@ -2024,6 +2048,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.flood_retry_bridge_enabled = 0; _prefs.flood_retry_advert_enabled = 0; _prefs.battery_alert_enabled = 0; + _prefs.battery_alert_low_percent = LOW_BATTERY_WARN_PERCENT_DEFAULT; + _prefs.battery_alert_critical_percent = LOW_BATTERY_CRITICAL_PERCENT_DEFAULT; _prefs.direct_retry_cr4_snr_x4 = DIRECT_RETRY_CR4_MIN_SNR_X4_DEFAULT; _prefs.direct_retry_cr5_snr_x4 = DIRECT_RETRY_CR5_MIN_SNR_X4_DEFAULT; _prefs.direct_retry_cr7_snr_x4 = DIRECT_RETRY_CR7_MIN_SNR_X4_DEFAULT; @@ -2198,12 +2224,12 @@ void MyMesh::checkBatteryAlert() { uint16_t batt_mv = board.getBattMilliVolts(); uint8_t batt_pct = batteryPercentFromMilliVolts(batt_mv); - if (batt_mv <= LOW_BATTERY_MIN_VALID_MV || batt_pct >= LOW_BATTERY_WARN_PERCENT) { + if (batt_mv <= LOW_BATTERY_MIN_VALID_MV || batt_pct >= _prefs.battery_alert_low_percent) { battery_alert_sent = false; return; } - unsigned long interval = batt_pct < LOW_BATTERY_CRITICAL_PERCENT + unsigned long interval = batt_pct < _prefs.battery_alert_critical_percent ? LOW_BATTERY_CRITICAL_INTERVAL : LOW_BATTERY_WARN_INTERVAL; if (battery_alert_sent && !millisHasNowPassed(last_battery_alert_sent + interval)) { @@ -2630,6 +2656,10 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, ClientInfo* sender, char * } } else if (strcmp(command, "get battery.alert") == 0) { sprintf(reply, "> %s", _prefs.battery_alert_enabled ? "on" : "off"); + } else if (strcmp(command, "get battery.alert.low") == 0) { + sprintf(reply, "> %u", (uint32_t)_prefs.battery_alert_low_percent); + } else if (strcmp(command, "get battery.alert.critical") == 0) { + sprintf(reply, "> %u", (uint32_t)_prefs.battery_alert_critical_percent); } else if (strncmp(command, "set battery.alert ", 18) == 0) { const char* value = command + 18; if (strcmp(value, "on") == 0) { @@ -2645,6 +2675,30 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, ClientInfo* sender, char * } else { strcpy(reply, "Err - usage: set battery.alert "); } + } else if (strncmp(command, "set battery.alert.low ", 22) == 0) { + uint8_t percent; + if (!parseBatteryAlertPercent(command + 22, 1, 100, percent)) { + strcpy(reply, "Err - usage: set battery.alert.low <1-100>"); + } else if (percent <= _prefs.battery_alert_critical_percent) { + strcpy(reply, "Err - low must be greater than critical"); + } else { + _prefs.battery_alert_low_percent = percent; + next_battery_alert_check = 0; + savePrefs(); + strcpy(reply, "OK"); + } + } else if (strncmp(command, "set battery.alert.critical ", 27) == 0) { + uint8_t percent; + if (!parseBatteryAlertPercent(command + 27, 0, 99, percent)) { + strcpy(reply, "Err - usage: set battery.alert.critical <0-99>"); + } else if (percent >= _prefs.battery_alert_low_percent) { + strcpy(reply, "Err - critical must be less than low"); + } else { + _prefs.battery_alert_critical_percent = percent; + next_battery_alert_check = 0; + savePrefs(); + strcpy(reply, "OK"); + } } else if (strncmp(command, "get recent.repeater", 19) == 0 || strncmp(command, "set recent.repeater", 19) == 0 || strncmp(command, "clear recent.repeater", 21) == 0 diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 3611c05d..7e318c78 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -559,6 +559,12 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { _prefs->battery_alert_enabled = 0; size_t battery_alert_read = file.read((uint8_t *)&_prefs->battery_alert_enabled, sizeof(_prefs->battery_alert_enabled)); // 664 + _prefs->battery_alert_low_percent = 20; + _prefs->battery_alert_critical_percent = 10; + size_t battery_alert_low_read = file.read((uint8_t *)&_prefs->battery_alert_low_percent, + sizeof(_prefs->battery_alert_low_percent)); // 665 + size_t battery_alert_critical_read = file.read((uint8_t *)&_prefs->battery_alert_critical_percent, + sizeof(_prefs->battery_alert_critical_percent)); // 666 // PowerSaving-only prefs stored radio_fem_rxgain at 291, before direct retry timing existed. if (radio_fem_rxgain_read != sizeof(_prefs->radio_fem_rxgain) && legacy_retry_attempts_read == sizeof(legacy_retry_attempts_or_radio_fem_rxgain) @@ -566,7 +572,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { || _prefs->direct_retry_timing_magic[1] != DIRECT_RETRY_TIMING_MAGIC_1)) { _prefs->radio_fem_rxgain = constrain(legacy_retry_attempts_or_radio_fem_rxgain, 0, 1); } - // next: 664 + // next: 667 // sanitise bad pref values _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); @@ -662,6 +668,14 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { } else { _prefs->battery_alert_enabled = constrain(_prefs->battery_alert_enabled, 0, 1); } + if (battery_alert_low_read != sizeof(_prefs->battery_alert_low_percent) + || battery_alert_critical_read != sizeof(_prefs->battery_alert_critical_percent) + || _prefs->battery_alert_low_percent < 1 + || _prefs->battery_alert_low_percent > 100 + || _prefs->battery_alert_critical_percent >= _prefs->battery_alert_low_percent) { + _prefs->battery_alert_low_percent = 20; + _prefs->battery_alert_critical_percent = 10; + } file.close(); } @@ -748,7 +762,9 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write((uint8_t *)&_prefs->direct_retry_cr7_snr_x4, sizeof(_prefs->direct_retry_cr7_snr_x4)); // 662 file.write((uint8_t *)&_prefs->direct_retry_cr8_snr_x4, sizeof(_prefs->direct_retry_cr8_snr_x4)); // 663 file.write((uint8_t *)&_prefs->battery_alert_enabled, sizeof(_prefs->battery_alert_enabled)); // 664 - // next: 665 + file.write((uint8_t *)&_prefs->battery_alert_low_percent, sizeof(_prefs->battery_alert_low_percent)); // 665 + file.write((uint8_t *)&_prefs->battery_alert_critical_percent, sizeof(_prefs->battery_alert_critical_percent)); // 666 + // next: 667 file.close(); } diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 4b7d910c..112c41c0 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -133,6 +133,8 @@ struct NodePrefs { // persisted to file int8_t direct_retry_cr7_snr_x4; int8_t direct_retry_cr8_snr_x4; uint8_t battery_alert_enabled; + uint8_t battery_alert_low_percent; + uint8_t battery_alert_critical_percent; }; class CommonCLICallbacks {