[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 whereBATTERY_PINis-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:
Battery Presence & Voltage Reporting:
- Returns
isBatteryConnect() = true. - Maps estimated remaining capacity to voltage (3300 mV - 4200 mV) and percentage (0% - 100%).
isVbusIn()dynamically tracksHWCDC::isPlugged().
- Returns
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.
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.
Source: meshtastic/firmware