refactor: sane-sysinfo: split out a BatteryInfo class

This commit is contained in:
2024-06-15 09:46:58 +00:00
parent a4f5343fb5
commit df0a8cf900

View File

@@ -70,6 +70,9 @@ class Formatter:
@dataclass @dataclass
class ParsedPowerSupply: class ParsedPowerSupply:
"""
near-direct values from /sys/class/power_supply API endpoints
"""
percent_charged: int | None = None percent_charged: int | None = None
# unitless: could be joules, could be something else # unitless: could be joules, could be something else
charge_full: int | None = None charge_full: int | None = None
@@ -81,25 +84,30 @@ class ParsedPowerSupply:
self.charge_full is not None and \ self.charge_full is not None and \
self.charge_rate is not None self.charge_rate is not None
@property class BatteryInfo:
def percent_discharged(self) -> int | None: """
if self.percent_charged is not None: higher-level battery info derived from the underlying power supply
return 100 - self.percent_charged """
percent_charged: int #< always available
minutes_to_charged: int | None = None
minutes_to_discharged: int | None = None
@property def __init__(self, p: ParsedPowerSupply):
def discharge_rate(self) -> int | None: assert p.percent_charged is not None
if self.charge_rate is not None: self.percent_charged = p.percent_charged
return -self.charge_rate
@property if p.charge_rate is not None and p.charge_rate < 0:
def minutes_to_charged(self) -> int | None: self.minutes_to_discharged = int(
if self.percent_discharged is not None and self.charge_full and self.charge_rate > 0: 60
return int(self.charge_full * self.percent_discharged/100 / self.charge_rate * 60) * p.charge_full * self.percent_charged/100
/ -p.charge_rate
@property )
def minutes_to_discharged(self) -> int | None: if p.charge_full is not None and p.charge_rate is not None and p.charge_rate > 0:
if self.percent_charged is not None and self.charge_full and self.charge_rate < 0: self.minutes_to_charged = int(
return int(self.charge_full * self.percent_charged/100 / self.discharge_rate * 60) 60
* p.charge_full * (100-self.percent_charged)/100
/ p.charge_rate * 60
)
def render_icon(direction: ChargeDirection, percentage: float) -> str: def render_icon(direction: ChargeDirection, percentage: float) -> str:
@@ -167,7 +175,7 @@ def try_path(p: str) -> ParsedPowerSupply | None:
return state if state.percent_charged is not None else None return state if state.percent_charged is not None else None
def try_all_paths() -> ParsedPowerSupply | None: def try_all_paths() -> BatteryInfo | None:
p = try_path("/sys/class/power_supply/axp20x-battery") # Pinephone p = try_path("/sys/class/power_supply/axp20x-battery") # Pinephone
if p is None: if p is None:
p = try_path("/sys/class/power_supply/BAT0") # Thinkpad p = try_path("/sys/class/power_supply/BAT0") # Thinkpad
@@ -176,7 +184,8 @@ def try_all_paths() -> ParsedPowerSupply | None:
logger.debug(f"full: {p.charge_full if p else None}, rate: {p.charge_rate if p else None}") logger.debug(f"full: {p.charge_full if p else None}, rate: {p.charge_rate if p else None}")
logger.debug(" rate > 0 means charging, else discharging") logger.debug(" rate > 0 means charging, else discharging")
return p if p.percent_charged is not None:
return BatteryInfo(p)
def fmt_minutes(f: Formatter, icon: str, if_indefinite: str, minutes: int | None) -> str: def fmt_minutes(f: Formatter, icon: str, if_indefinite: str, minutes: int | None) -> str:
logger.debug(f"charge/discharge time: {minutes} min") logger.debug(f"charge/discharge time: {minutes} min")
@@ -189,19 +198,19 @@ def fmt_minutes(f: Formatter, icon: str, if_indefinite: str, minutes: int | None
logger.debug("charge/discharge duration > 1d") logger.debug("charge/discharge duration > 1d")
return f"{icon}{f.suffix_icon}{if_indefinite}" return f"{icon}{f.suffix_icon}{if_indefinite}"
def pretty_output(f: Formatter, p: ParsedPowerSupply) -> str: def pretty_output(f: Formatter, p: BatteryInfo) -> str:
if p.charge_rate > 0: if p.minutes_to_charged != None:
logger.debug("charging") logger.debug("charging")
icon = render_icon(ChargeDirection.Charging, p.percent_charged) icon = render_icon(ChargeDirection.Charging, p.percent_charged)
duration = p.minutes_to_charged duration = p.minutes_to_charged
else: else:
logger.debug("discharging") logger.debug("discharging")
icon = render_icon(ChargeDirection.Discharging, p.percent_discharged) icon = render_icon(ChargeDirection.Discharging, p.percent_charged)
duration = p.minutes_to_discharged duration = p.minutes_to_discharged
return fmt_minutes(f, icon, f"{p.percent_charged}{f.suffix_percent}", duration) return fmt_minutes(f, icon, f"{p.percent_charged}{f.suffix_percent}", duration)
def main(): def main() -> None:
logging.basicConfig() logging.basicConfig()
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)