Voltage lies.

Put a battery under load and its terminal voltage sags. Let it rest and the voltage springs back. A naive fuel gauge watching only voltage will happily tell you a worn-out cell is "fine" right up until it falls off a cliff. The number you actually care about — is this battery still good, or is it time to replace it? — isn't in the instantaneous voltage at all. It's in the capacity: how much charge the cell can still deliver between full and empty.

That quantity fades as a cell ages. Tracking it is called State of Health (SoH), and it's the difference between "the device says 80%" and "the device has 80% of the runtime it had when it was new."

I wanted my open-source battery SDK (ibattery-sdk, Apache-2.0) to learn SoH on the device itself — no cloud model, no floating-point, on MCUs with kilobytes of RAM. This post is the story of getting that working end to end: from a coulomb integral in firmware to a faded value showing up live on a Grafana dashboard.

The idea: learn capacity from one full→empty trip