from machine import ADC, Pin class BatteryMonitor: """Utility class for monitoring battery voltage and capacity on ESP32-S3-RLCD-4.2.""" def __init__(self, pin_num=4): import sys self.adc = ADC(Pin(pin_num)) if sys.platform == 'esp32': self.adc.atten(ADC.ATTN_11DB) def read_voltage(self): """Reads the battery voltage in Volts using internal calibration. Returns: float: Battery voltage in Volts (e.g. 4.15) or None on error. """ try: # Try calibrated reading in microvolts first uv = self.adc.read_uv() # 3x voltage divider onboard scales 3.0V-4.2V battery to 1.0V-1.4V voltage = (uv / 1_000_000.0) * 3.0 return round(voltage, 3) except AttributeError: # Fallback if read_uv() is not supported on older MicroPython builds try: # Read 12-bit value (0-4095) raw = self.adc.read() # 3.3V reference at 11dB attenuation, 3x divider voltage = (raw / 4095.0) * 3.3 * 3.0 return round(voltage, 3) except Exception as e: print(f"Error reading battery raw ADC: {e}") return None except Exception as e: print(f"Error reading battery calibrated ADC: {e}") return None def read_percentage(self): """Computes approximate battery percentage based on discharge curve. Assumes linear approximation between 3.0V (0%) and 4.2V (100%). Returns: int: Percentage between 0 and 100. """ voltage = self.read_voltage() if voltage is None: return 0 # Bound typical lithium-ion limits # 3.0V is typically empty for ESP32 systems where the LDO drops out around 3.3V v_min = 3.0 v_max = 4.2 if voltage <= v_min: return 0 if voltage >= v_max: return 100 # Linear scaling pct = (voltage - v_min) / (v_max - v_min) * 100.0 return int(pct) def get_status_summary(self): """Returns a string description of battery status.""" v = self.read_voltage() p = self.read_percentage() if v is None: return "Battery: Error" return f"Battery: {v:.2f}V ({p}%)"