55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
"""Battery presence + percentage via sysfs — no upower dependency (that daemon
|
|
isn't guaranteed running; sysfs always is on real hardware). Mirrors the icon
|
|
tiers already established in scripts/batteryperc (the eww bar's battery poll)
|
|
so a laptop that switches between hyprlua and hyprdrive sees the same glyphs.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import NamedTuple, Optional
|
|
|
|
_POWER_SUPPLY = Path("/sys/class/power_supply")
|
|
|
|
# (floor percentage, glyph) — first match wins, checked high to low.
|
|
_DISCHARGING_TIERS = [
|
|
(95, ""), (90, ""), (80, ""), (70, ""), (60, ""),
|
|
(50, ""), (40, ""), (30, ""), (20, ""), (10, ""), (0, ""),
|
|
]
|
|
_CHARGING_ICON = ""
|
|
|
|
|
|
class BatteryState(NamedTuple):
|
|
percent: int
|
|
charging: bool
|
|
icon: str
|
|
|
|
|
|
def _find_battery() -> Optional[Path]:
|
|
if not _POWER_SUPPLY.is_dir():
|
|
return None
|
|
for entry in sorted(_POWER_SUPPLY.iterdir()):
|
|
if entry.name.startswith("BAT"):
|
|
return entry
|
|
return None
|
|
|
|
|
|
def read() -> Optional[BatteryState]:
|
|
"""Returns None when no battery is present (desktop machine) — callers
|
|
should hide the widget entirely in that case, per spec."""
|
|
bat = _find_battery()
|
|
if bat is None:
|
|
return None
|
|
try:
|
|
percent = int((bat / "capacity").read_text().strip())
|
|
status = (bat / "status").read_text().strip().lower()
|
|
except (OSError, ValueError):
|
|
return None
|
|
|
|
charging = status == "charging"
|
|
if charging:
|
|
icon = _CHARGING_ICON
|
|
else:
|
|
icon = next(g for floor, g in _DISCHARGING_TIERS if percent >= floor)
|
|
return BatteryState(percent=percent, charging=charging, icon=icon)
|