Linux power_supply Sysfs: Interpret Battery and Charger Telemetry Correctly
Read Linux power_supply attributes with correct units and semantics, distinguish charger online state from battery status, and validate telemetry quality.
The Linux power-supply class exposes batteries, chargers, AC adapters, USB power sources, and related devices through sysfs and uevents. It gives userspace a consistent attribute vocabulary, but not every device supports every attribute, and the meaning depends on the property’s documented unit and semantics. A displayed capacity percentage is not the same thing as measured charge, a charger being online is not proof the battery is charging, and a temperature file is not necessarily expressed in whole degrees Celsius.
Diagnose power telemetry by identifying the exact power-supply object, checking which properties it supports, validating units, and comparing the reported state with known charging and discharging transitions. Do not assume all laptops or embedded devices expose the same set of attributes.
Discover power-supply objects
Power supplies appear under /sys/class/power_supply/. There may be multiple batteries, USB inputs, AC adapters, wireless chargers, or aggregate objects. Names such as BAT0, AC, or USB are common conventions but not guaranteed. A name is not enough to decide whether an object is a battery or charger; read its type property and relevant attributes.
Inspect the available attributes without assuming every file exists:
for d in /sys/class/power_supply/*; do
test -d "$d" || continue
printf '\n### %s\n' "$d"
for key in type present online status capacity voltage_now current_now \
charge_now charge_full energy_now energy_full temp; do
test -r "$d/$key" && printf '%s=' "$key" && cat "$d/$key"
done
done
This is a read-only inventory example. Property availability varies by driver, hardware, and kernel. present may be absent or not meaningful for some supplies. A supply that does not expose current_now may still operate correctly; the hardware may not measure it or the driver may not support it.
Use uevent files or udev-monitoring tools to inspect notifications if userspace updates only on change. Do not poll every attribute at a high rate by default; bus-backed fuel gauges may incur I/O and power cost. Choose a bounded interval appropriate to the device and consume change notifications where supported.
Units and property distinctions
The kernel class defines common units: voltage in microvolts, current in microamps, charge in microamp-hours, energy in microwatt-hours, time in seconds, and temperature in tenths of a degree Celsius unless a property states otherwise. Drivers are responsible for converting hardware-native values into the class units. Userspace that interprets raw values as volts, milliamps, or whole degrees can produce errors by factors of a million, a thousand, or ten.
Charge and energy are distinct. CHARGE_* values use microamp-hours; ENERGY_* values use microwatt-hours. They should not be interchanged. CAPACITY is a percentage between 0 and 100, and can be estimated by a fuel gauge rather than directly measured. Charge and energy full values may represent learned thresholds under current battery conditions, while design values describe nominal design information. A percentage can therefore change when a learned full threshold changes, even if the battery’s absolute stored charge did not abruptly change.
Properties with _NOW describe a momentary value; _AVG denotes a hardware-averaged value where supported. CHARGE_COUNTER is a relative charge counter and can be negative; it is not a remaining-capacity field. VOLTAGE_OCV is open-circuit voltage and should not be treated as a loaded terminal measurement. Read the current class documentation for the exact property semantics before building policy around them.
Temperature attributes have separate meanings: battery temperature, ambient temperature, limits, or alerts. A charging controller may expose current and voltage limits that describe programmed settings, not actual instantaneous draw. Record units, property suffixes, and the supply object with every measurement.
Battery state is not charger state
STATUS describes battery operating status, such as charging, full, discharging, or not charging, when the battery driver can determine it. ONLINE on an external supply generally indicates whether that source is connected/available. A charger can be online while the battery remains full or not charging. Conversely, a battery status may remain stale if a fuel-gauge or charger interrupt was missed.
CHARGE_TYPE can distinguish charge rates such as trickle or fast charging if the hardware and driver report them. HEALTH represents a driver-reported health category and is not a detailed cell diagnosis. AUTHENTIC, where implemented, is a hardware or firmware authentication result. Do not convert any single attribute into a broad statement such as “the charger is faulty” without checking the full path.
Systems may have multiple chargers that feed one battery, or a charger manager that aggregates several supplies. The visible object may be a synthesized view rather than one physical connector. Inspect the kernel log and platform configuration to determine whether values come from a fuel gauge, charger IC, USB power-delivery controller, or aggregation driver.
Validate values with controlled transitions
Capture a baseline on battery, connect the documented charger, wait for the hardware’s reporting interval, and observe which object changes. Then test unplug, fully charged, and charge-inhibited states if the platform supports them. Keep temperatures and load reasonable; do not intentionally short, overheat, or deeply discharge a battery as a telemetry test.
Correlate sysfs values with the device’s reported uevents and userspace power manager. If ONLINE changes but the desktop does not update, the issue may be event delivery or userspace policy. If sysfs values never change, check whether the driver reports notifications, the hardware update period, and the kernel logs. If capacity is erratic, compare voltage, current, charge counter, and learned full values over time rather than smoothing away a potentially real fault.
For battery runtime estimates, avoid assuming that capacity percentage changes linearly with time. Load, temperature, cell chemistry, and fuel-gauge estimation affect the curve. Estimate using repeated observations under representative workload and preserve uncertainty. A single TIME_TO_EMPTY or TIME_TO_FULL value is a prediction, not a guarantee.
Common diagnostic mistakes
Reading micro-units as base units. A voltage value of 12000000 is not 12 million volts; apply the documented unit conversion.
Treating capacity as charge. Percentage and microamp-hours are different properties with different estimators and thresholds.
Assuming missing attributes mean hardware failure. Drivers expose only what their hardware and implementation support.
Conflating ONLINE and STATUS. Source presence and battery charging state are not interchangeable.
Treating voltage as a fuel gauge. Voltage may vary with load and chemistry; open-circuit and instantaneous readings differ.
Polling aggressively. Sysfs reads can reach a slow bus-backed gauge. Prefer appropriate polling intervals or change notifications.
Changing charge-control attributes without a platform procedure. Writable charge limits can alter battery behavior. Validate the exact driver contract and use only supported ranges.
Production monitoring and acceptance
For telemetry pipelines, record the object name, type, kernel release, driver, units, sample time, and property availability. Normalize values only after unit validation. Distinguish “not supported,” “temporarily unavailable,” “unknown,” and an actual zero. Alert on impossible values and stale readings, but do not misclassify unsupported files as zero charge or zero volts.
For a driver or firmware change, test battery-only, charger-attached, full, and suspend/resume states. Verify uevents reach userspace and that charge-control changes, if any, are read back. Compare results against the hardware’s documented tolerances and a known-good unit, not another model with different cells.
The power_supply class is a stable vocabulary over diverse hardware, not a promise of complete telemetry. Correct interpretation starts with the property definition and unit, then checks the physical source and update path. Keeping those boundaries clear prevents UI bugs from being mistaken for charger faults and prevents real hardware anomalies from being hidden by simplistic percentage logic.
Related:
- Linux System Suspend: Compare s2idle, Standby, and Deep Sleep
- Linux Powercap and RAPL: Read Energy Counters Without Misleading Yourself
Sources: