Эх сурвалжийг харах

fix: add battery reporting toggle for Heltec V3 and clean up VS Code metadata

Jared Dohrman 4 сар өмнө
parent
commit
4f4964e454

+ 82 - 0
.github/ISSUE_TEMPLATE/feature-support-request.yml

@@ -0,0 +1,82 @@
+name: Feature / Support Request
+description: Request a feature or report a board-specific support need.
+title: "[Feature/Support]: "
+labels:
+  - enhancement
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Use this form for feature requests and board-specific support needs.
+
+  - type: textarea
+    id: summary
+    attributes:
+      label: Summary
+      description: What do you want to add or what do you need help with?
+      placeholder: Briefly describe the request or issue.
+    validations:
+      required: true
+
+  - type: input
+    id: board
+    attributes:
+      label: Board
+      description: Board model and revision, if known.
+      placeholder: e.g. Heltec WiFi LoRa 32 V3.2
+    validations:
+      required: false
+
+  - type: input
+    id: firmware
+    attributes:
+      label: Firmware Target
+      description: Firmware environment or binary name, if known.
+      placeholder: e.g. Heltec_v3_repeater_mqtt
+    validations:
+      required: false
+
+  - type: input
+    id: power
+    attributes:
+      label: Power Source
+      description: How is the board powered?
+      placeholder: e.g. USB only, LiPo only, USB + LiPo
+    validations:
+      required: false
+
+  - type: textarea
+    id: behavior
+    attributes:
+      label: Current Behavior
+      description: What is happening now?
+      placeholder: Describe the current behavior, readings, LEDs, errors, etc.
+    validations:
+      required: false
+
+  - type: textarea
+    id: expected
+    attributes:
+      label: Expected Behavior
+      description: What did you expect instead?
+      placeholder: Describe the expected result.
+    validations:
+      required: false
+
+  - type: textarea
+    id: comparison
+    attributes:
+      label: Comparison
+      description: If relevant, does upstream MeshCore or another firmware behave differently?
+      placeholder: Include repo/branch/target details if you compared multiple builds.
+    validations:
+      required: false
+
+  - type: textarea
+    id: logs
+    attributes:
+      label: Logs Or Screenshots
+      description: Paste logs or attach screenshots/photos if helpful.
+      placeholder: Add CLI output, boot logs, screenshots, or photos here.
+    validations:
+      required: false

+ 1 - 0
README.md

@@ -145,6 +145,7 @@ uv run --group docs zensical build
 - CLI controls for:
   - WiFi credentials
   - WiFi powersaving
+  - board battery reporting on supported targets
   - MQTT endpoint enablement
   - MQTT packet and raw publishing
   - owner public key and email

+ 10 - 0
docs/custom-cli.md

@@ -102,6 +102,16 @@ Legacy dotted aliases are also accepted:
 - `stats-packets`
   - shows packet receive/send totals, flood/direct breakdown, and receive errors
 
+### Board Battery Reporting
+
+- `get battery.reporting`
+  - shows whether board battery reporting is enabled
+  - support is board-dependent
+- `set battery.reporting on|off`
+  - enables or disables battery voltage reporting on supported boards
+  - currently useful for Heltec V3 boards where USB-only power can produce misleading battery readings
+  - if your board needs this too, open an issue and support can be added board-by-board
+
 ## Web Panel Allowlisted Commands
 
 When the repeater web panel is enabled, it only allows a limited command set.

+ 2 - 0
examples/simple_repeater/MyMesh.cpp

@@ -898,6 +898,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
   _prefs.advert_loc_policy = ADVERT_LOC_PREFS;
 
   _prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier
+  _prefs.battery_reporting_enabled = 1;
 
 #if defined(USE_SX1262) || defined(USE_SX1268)
 #ifdef SX126X_RX_BOOSTED_GAIN
@@ -943,6 +944,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
   updateFloodAdvertTimer();
 
   board.setAdcMultiplier(_prefs.adc_multiplier);
+  board.setBatteryReporting(_prefs.battery_reporting_enabled);
 
 #if ENV_INCLUDE_GPS == 1
   applyGpsPrefs();

+ 2 - 0
examples/simple_room_server/MyMesh.cpp

@@ -631,6 +631,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
   _prefs.gps_enabled = 0;
   _prefs.gps_interval = 0;
   _prefs.advert_loc_policy = ADVERT_LOC_PREFS;
+  _prefs.battery_reporting_enabled = 1;
 
   next_post_idx = 0;
   next_client_idx = 0;
@@ -654,6 +655,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
   updateFloodAdvertTimer();
 
   board.setAdcMultiplier(_prefs.adc_multiplier);
+  board.setBatteryReporting(_prefs.battery_reporting_enabled);
 
 #if ENV_INCLUDE_GPS == 1
   applyGpsPrefs();

+ 2 - 0
examples/simple_sensor/SensorMesh.cpp

@@ -729,6 +729,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
   _prefs.gps_enabled = 0;
   _prefs.gps_interval = 0;
   _prefs.advert_loc_policy = ADVERT_LOC_PREFS;
+  _prefs.battery_reporting_enabled = 1;
 }
 
 void SensorMesh::begin(FILESYSTEM* fs) {
@@ -746,6 +747,7 @@ void SensorMesh::begin(FILESYSTEM* fs) {
   updateFloodAdvertTimer();
 
    board.setAdcMultiplier(_prefs.adc_multiplier);
+   board.setBatteryReporting(_prefs.battery_reporting_enabled);
 
 #if ENV_INCLUDE_GPS == 1
   applyGpsPrefs();

+ 3 - 0
src/MeshCore.h

@@ -44,6 +44,9 @@ namespace mesh {
 class MainBoard {
 public:
   virtual uint16_t getBattMilliVolts() = 0;
+  virtual bool supportsBatteryReporting() const { return false; }
+  virtual bool setBatteryReporting(bool enabled) { (void)enabled; return false; }
+  virtual bool isBatteryReportingEnabled() const { return true; }
   virtual float getMCUTemperature() { return NAN; }
   virtual bool setAdcMultiplier(float multiplier) { return false; };
   virtual float getAdcMultiplier() const { return 0.0f; }

+ 26 - 4
src/helpers/CommonCLI.cpp

@@ -87,8 +87,13 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
     file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
     file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier));                 // 166
     file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info));                          // 170
-    file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain));              // 290
-    // next: 291
+    if (file.available() >= (int)sizeof(_prefs->battery_reporting_enabled)) {
+      file.read((uint8_t *)&_prefs->battery_reporting_enabled, sizeof(_prefs->battery_reporting_enabled)); // 290
+    }
+    if (file.available() >= (int)sizeof(_prefs->rx_boosted_gain)) {
+      file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain));            // 291
+    }
+    // next: 292
 
     // sanitise bad pref values
     _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@@ -112,6 +117,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
     _prefs->bridge_channel = constrain(_prefs->bridge_channel, 0, 14);
 
     _prefs->powersaving_enabled = constrain(_prefs->powersaving_enabled, 0, 1);
+    _prefs->battery_reporting_enabled = constrain(_prefs->battery_reporting_enabled, 0, 1);
 
     _prefs->gps_enabled = constrain(_prefs->gps_enabled, 0, 1);
     _prefs->advert_loc_policy = constrain(_prefs->advert_loc_policy, 0, 2);
@@ -178,8 +184,9 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
     file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
     file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier));                 // 166
     file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info));                          // 170
-    file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain));              // 290
-    // next: 291
+    file.write((uint8_t *)&_prefs->battery_reporting_enabled, sizeof(_prefs->battery_reporting_enabled)); // 290
+    file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain));              // 291
+    // next: 292
 
     file.close();
   }
@@ -421,6 +428,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
         } else {
           sprintf(reply, "> %.3f", adc_mult);
         }
+      } else if (memcmp(config, "battery.reporting", 17) == 0) {
+        if (_board->supportsBatteryReporting()) {
+          sprintf(reply, "> %s", _board->isBatteryReportingEnabled() ? "on" : "off");
+        } else {
+          strcpy(reply, "Error: unsupported by this board");
+        }
       // Power management commands
       } else if (memcmp(config, "pwrmgt.support", 14) == 0) {
 #ifdef NRF52_POWER_MANAGEMENT
@@ -717,6 +730,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
           _prefs->adc_multiplier = 0.0f;
           strcpy(reply, "Error: unsupported by this board");
         };
+      } else if (memcmp(config, "battery.reporting ", 18) == 0) {
+        bool enabled = memcmp(&config[18], "on", 2) == 0;
+        if (_board->setBatteryReporting(enabled)) {
+          _prefs->battery_reporting_enabled = enabled ? 1 : 0;
+          savePrefs();
+          sprintf(reply, "OK - battery reporting %s", enabled ? "on" : "off");
+        } else {
+          strcpy(reply, "Error: unsupported by this board");
+        }
       } else {
         sprintf(reply, "unknown config: %s", config);
       }

+ 1 - 0
src/helpers/CommonCLI.h

@@ -57,6 +57,7 @@ struct NodePrefs { // persisted to file
   uint32_t discovery_mod_timestamp;
   float adc_multiplier;
   char owner_info[120];
+  uint8_t battery_reporting_enabled; // boolean
   uint8_t rx_boosted_gain; // power settings
   uint8_t path_hash_mode;   // which path mode to use when sending
   uint8_t loop_detect;

+ 30 - 2
variants/heltec_v3/HeltecV3Board.h

@@ -19,11 +19,14 @@
 class HeltecV3Board : public ESP32Board {
 private:
   bool adc_active_state;
+  bool battery_reporting_enabled;
 
 public:
   RefCountedDigitalPin periph_power;
 
-  HeltecV3Board() : periph_power(PIN_VEXT_EN) { }
+  HeltecV3Board() : adc_active_state(false),
+                    battery_reporting_enabled(true),
+                    periph_power(PIN_VEXT_EN) { }
 
   void begin() {
     ESP32Board::begin();
@@ -77,6 +80,10 @@ public:
   }
 
   uint16_t getBattMilliVolts() override {
+    if (!battery_reporting_enabled) {
+      return 0;
+    }
+
     analogReadResolution(10);
     digitalWrite(PIN_ADC_CTRL, adc_active_state);
 
@@ -88,7 +95,28 @@ public:
 
     digitalWrite(PIN_ADC_CTRL, !adc_active_state);
 
-    return (5.42 * (3.3 / 1024.0) * raw) * 1000;
+    uint16_t mv = (5.42 * (3.3 / 1024.0) * raw) * 1000;
+
+    // Heltec V3 USB-powered boards without a battery can bias or float the
+    // VBAT sense rail, which shows up as an impossible LiPo voltage.
+    if (mv > 4400) {
+      return 0;
+    }
+
+    return mv;
+  }
+
+  bool supportsBatteryReporting() const override {
+    return true;
+  }
+
+  bool setBatteryReporting(bool enabled) override {
+    battery_reporting_enabled = enabled;
+    return true;
+  }
+
+  bool isBatteryReportingEnabled() const override {
+    return battery_reporting_enabled;
   }
 
   const char* getManufacturerName() const override {

+ 1 - 1
variants/heltec_v3/platformio.ini

@@ -376,4 +376,4 @@ build_flags =
 build_src_filter = ${Heltec_lora32_v3.build_src_filter}
   +<../examples/kiss_modem/>
 lib_deps =
-  ${Heltec_lora32_v3.lib_deps}
+  ${Heltec_lora32_v3.lib_deps}