#11916·firmware

[Feature] Add VirtualBatteryLevel fuel gauge for boards without ADC divider (Seeed XIAO ESP32-S3)

Author: imdocwhoCreated Sep 19, 2026Updated Sep 19, 2026
Labelsfirst-contribution

Hardware Target

  • Board: Seeed Studio XIAO ESP32-S3 (seeed-xiao-s3) — extensible to other boards where BATTERY_PIN is -1.
  • Battery: 3.7V LiPo (e.g. PKCELL LP803860 2000mAh) wired to battery pads with no external resistor divider.

Problem

The Seeed Studio XIAO ESP32-S3 has no built-in resistor divider connected to an ADC pin (BATTERY_PIN -1). In standard Meshtastic firmware, the device reports "Powered by USB" or 0% / no battery, leaving users without any battery level or telemetry monitoring unless they manually solder external resistors.

Solution

Introduced VirtualBatteryLevel (inheriting from HasBatteryLevel) enabled via #define VIRTUAL_BATTERY_GAUGE 1 in variant.h:

  1. Battery Presence & Voltage Reporting:

    • Returns isBatteryConnect() = true.
    • Maps estimated remaining capacity to voltage (3300 mV - 4200 mV) and percentage (0% - 100%).
    • isVbusIn() dynamically tracks HWCDC::isPlugged().
  2. Charge & Discharge Tracking:

    • Simulates continuous baseline consumption (~35 mA for ESP32-S3 + SX1262 RX listening + BLE).
    • Simulates charging intake (~400 mA) when USB power is present.
  3. Cycle Learning & NVS Persistence:

    • Detects full discharge cycles (100% -> 0% -> 100%) and recalibrates the battery's true capacity using a 70/30 moving average.
    • Persists state to NVS every 5 minutes and on full charge, preventing loss of percentage when an external power switch is toggled.

meshtastic_patch.txt