import glob from app.sample import Sample from app.utils import sysfs _PS = "/sys/class/power_supply" def _supplies() -> list[tuple[str, str]]: """List power supplies found under /sys/class/power_supply. Returns: (type, path) pairs sorted by path, where type is the sysfs type ("battery", "mains", "usb", ...) of each supply. """ out: list[tuple[str, str]] = [] for p in sorted(glob.glob(f"{_PS}/*")): t = sysfs.read_str(f"{p}/type") if t: out.append((t.lower(), p)) return out def fill(s: Sample) -> None: """Fill the battery / ac_online fields of a Sample from sysfs. psutil's battery API is unreliable here (power_plugged can be None), so /sys/class/power_supply/* is read directly: the first present battery provides capacity and status, and ac_online becomes True when any mains — or, failing that, USB — supply reports online. Fields stay at their Sample defaults on a desktop without these nodes. Args: s: sample to fill. """ try: supplies = _supplies() for t, p in supplies: if t == "battery" and sysfs.read_str(f"{p}/present") == "1": cap = sysfs.read_int(f"{p}/capacity") if cap is not None: s.battery = cap s.battery_status = sysfs.read_str(f"{p}/status") break for t, p in supplies: if t == "mains" and sysfs.read_str(f"{p}/online") == "1": s.ac_online = True break if s.ac_online is None: for t, p in supplies: if t == "usb" and sysfs.read_str(f"{p}/online") == "1": s.ac_online = True break except OSError: pass