Skip to main content

Battery Management

Overview​

MyStation supports battery voltage monitoring and percentage reporting. The BatteryManager class handles ADC reading, voltage conversion, and capacity estimation.

âš ī¸ Battery monitoring is only available when the SHOW_BATTERY_STATUS build flag is enabled and the board is an ESP32-S3 variant with the dedicated ADC circuit.


Hardware Configuration​

ParameterValueDescription
ADC PinGPIO1 (A0) — BAT_ADCBattery voltage sense input
ADC Enable PinGPIO6 (A5) — ADC_ENControls power to the ADC circuit
ADC Resolution12-bit (0 – 4095)—
ADC Reference Voltage3.6 VActual reference for ESP32-S3
Voltage Divider Ratio2 : 1Onboard resistor divider halves voltage
Calibration Factor0.968From OG DIY Kit reference

Voltage formula:

V_bat = (ADC_raw / 4095) × 3.6 V × 2.0 × 0.968

Readings are averaged over 10 samples to reduce ADC noise. The ADC enable pin is driven HIGH only during a reading and immediately returned LOW to save power.


Voltage Thresholds​

ThresholdVoltageCapacityNotes
Fully charged4.120 V100 %BATTERY_VOLTAGE_MAX constant
Nominal3.643 V~50 %BATTERY_VOLTAGE_NOMINAL constant
âš ī¸ Low battery warning≈ 3.252 V5 %Trigger warning UI; prompt user to recharge
⚡ ESP32 instability zone< 3.0 V< 0 %WiFi & Bluetooth become unreliable below this point
🔒 Hardware power cut-off3.0 V0 %BATTERY_VOLTAGE_MIN; onboard circuit cuts power

Why 3.252 V as the Warning Threshold?​

The discharge curve (see below) maps 5 % capacity to approximately 3.252 V. At this level the battery still has enough energy for one more update cycle, giving the user actionable time to recharge before the hardware cut-off at 3.0 V.

ESP32 Stability Below 3.0 V​

Although an ESP32 may remain partially functional below 3.0 V, RF peripherals (WiFi, Bluetooth) become unstable. Running the chip at such low voltages is not recommended and may cause:

  • Failed WiFi associations or dropped connections
  • Corrupted NVS write operations
  • Unpredictable deep-sleep wake behaviour
  • Accelerated battery wear

Li-ion Discharge Curve​

The values below are measured from a typical Li-ion cell and are used internally for capacity estimation.

Capacity (%)Voltage (V)Notes
1004.111Discharge curve top (measured)
904.020
803.950
703.840
603.750
503.643Nominal voltage
403.580
303.500
203.420
103.350
53.252âš ī¸ Low battery warning trigger
23.120
12.795Discharge curve bottom (measured)

📝 Current implementation uses a linear interpolation between BATTERY_VOLTAGE_MIN (3.010 V) and BATTERY_VOLTAGE_MAX (4.120 V). The table above documents the real non-linear Li-ion discharge curve and can be used to implement a look-up-table (LUT) approach in a future improvement.


Battery Percentage Calculation​

Current Implementation (Linear)​

// voltageToPercentage() in battery_manager.cpp
float percentage = ((voltage - BATTERY_VOLTAGE_MIN) / (BATTERY_VOLTAGE_MAX - BATTERY_VOLTAGE_MIN)) * 100.0f;
  • Simple and fast, but underestimates capacity in the flat mid-range (~3.6 – 3.9 V)
  • Overestimates capacity near the knee of the curve (< 3.3 V)

A look-up table based on the measured discharge curve (1 % → 2.795 V, 100 % → 4.111 V) would provide significantly more accurate readings:

// Example LUT approach (not yet implemented)
static const float VOLTAGE_LUT[] = {
2.795f, // 1%
3.120f, // 2%
3.252f, // 5% ← low-battery warning threshold
3.350f, // 10%
3.420f, // 20%
3.500f, // 30%
3.580f, // 40%
3.643f, // 50% ← nominal
3.750f, // 60%
3.840f, // 70%
3.950f, // 80%
4.020f, // 90%
4.111f, // 100%
};

Battery Icon Levels​

The icon level maps the percentage to one of five visual states:

Icon LevelPercentage RangeMeaning
580 – 100 %Full
460 – 79 %High
340 – 59 %Medium
220 – 39 %Low
10 – 19 %Critical
0N/ANot available

Charging Detection​

Charging is inferred by comparing voltage against BATTERY_VOLTAGE_MAX + 0.1 V (4.22 V). This is a heuristic — no dedicated charge-status pin is read.

return voltage > (BATTERY_VOLTAGE_MAX + 0.1f); // > 4.22 V → likely charging

Usage Example​

BatteryManager::init(); // Call once in setup()

if (BatteryManager::isAvailable()) {
float voltage = BatteryManager::getBatteryVoltage(); // e.g. 3.72 V
int percentage = BatteryManager::getBatteryPercentage(); // e.g. 63
int iconLevel = BatteryManager::getBatteryIconLevel(); // e.g. 4
bool charging = BatteryManager::isCharging();

if (percentage <= 5) {
// Trigger low battery warning on display
}
}

Temperature Management​

Battery temperature is managed autonomously by the SY6974B PMIC via the **NTC (Negative Temperature Coefficient) pin ** — no firmware intervention is required.

The SY6974B features integrated hardware comparators that continuously monitor the NTC thermistor resistance. If the battery temperature exceeds safe thresholds, the PMIC will automatically suspend charging without any software involvement.

EventBehaviour
Temperature within safe rangeCharging proceeds normally
Temperature too high / too lowCharging is automatically suspended by hardware
Temperature returns to safe rangeCharging resumes automatically

â„šī¸ Because this is handled entirely in hardware, there is no temperature API in BatteryManager and no firmware action needed. The firmware does not need to read or react to battery temperature.


FileDescription
include/util/battery_manager.hClass declaration and constants
src/util/battery_manager.cppADC reading, voltage conversion, icons
include/config/pins.hBATTERY_ADC and ADC_EN pin mapping
include/build_config.hSHOW_BATTERY_STATUS compile flag

References​