Reworked battery module, should work better now. Or worse. Let's find out...
This commit is contained in:
parent
8ef891cef6
commit
e8191da312
@ -1,28 +1,34 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from . import IntervalModule
|
from . import IntervalModule
|
||||||
from .core.util import PrefixedKeyDict
|
from .core.util import PrefixedKeyDict
|
||||||
from .core.desktop import display_notification
|
from .core.desktop import display_notification
|
||||||
|
|
||||||
class Battery:
|
class UEventParser: # fun-fact: configparser doesn't provide a way to handle files w/o sections
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lchop(string, prefix="POWER_SUPPLY_"):
|
def lchop(string, prefix):
|
||||||
if string.startswith(prefix):
|
if string.startswith(prefix):
|
||||||
return string[len(prefix):]
|
return string[len(prefix):]
|
||||||
return string
|
return string
|
||||||
|
|
||||||
@staticmethod
|
def __init__(self, file, prefix="POWER_SUPPLY_"):
|
||||||
def map_key(key):
|
super().__init__()
|
||||||
return Battery.lchop(key).replace("CHARGE", "ENERGY")
|
self.prefix = prefix
|
||||||
|
self.data = {}
|
||||||
@staticmethod
|
|
||||||
def convert(value):
|
|
||||||
return float(value) if value.isdecimal() else value.strip()
|
|
||||||
|
|
||||||
def __init__(self, file):
|
|
||||||
self.parse(file)
|
self.parse(file)
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
def map_key(self, key):
|
||||||
|
return self.lchop(key, self.prefix)
|
||||||
|
|
||||||
|
def map_value(self, value):
|
||||||
|
return float(value) if value.isdecimal() else value.strip()
|
||||||
|
|
||||||
def parse(self, file):
|
def parse(self, file):
|
||||||
with open(file, "r") as file:
|
with open(file, "r") as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
@ -30,21 +36,73 @@ class Battery:
|
|||||||
|
|
||||||
def parse_line(self, line):
|
def parse_line(self, line):
|
||||||
key, value = line.split("=", 2)
|
key, value = line.split("=", 2)
|
||||||
|
self.data[self.map_key(key)] = self.map_value(value)
|
||||||
|
|
||||||
setattr(self, self.map_key(key), self.convert(value))
|
class Battery:
|
||||||
|
@staticmethod
|
||||||
|
def create(from_file):
|
||||||
|
batinfo = UEventParser(from_file).dict()
|
||||||
|
if "POWER_NOW" in batinfo:
|
||||||
|
return BatteryEnergy(batinfo)
|
||||||
|
else:
|
||||||
|
return BatteryCharge(batinfo)
|
||||||
|
|
||||||
class RemainingCalculator:
|
def __init__(self, batinfo):
|
||||||
def __init__(self, energy, power):
|
self.bat = batinfo
|
||||||
self.remaining_time = (energy / power) * 60
|
self.normalize_µ()
|
||||||
self.hours, self.minutes = map(int, divmod(self.remaining_time, 60))
|
|
||||||
|
def normalize_µ(self):
|
||||||
|
for key, µvalue in self.bat.items():
|
||||||
|
if re.match(r"(VOLTAGE|CHARGE|CURRENT|POWER|ENERGY)_(NOW|FULL|MIN)(_DESIGN)?", key):
|
||||||
|
self.bat[key] = µvalue / 1000000.0
|
||||||
|
|
||||||
|
def percentage(self, design=False):
|
||||||
|
return self._percentage("_DESIGN" if design else "") * 100
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
if self.consumption():
|
||||||
|
if self.bat["STATUS"] == "Discharging":
|
||||||
|
return "Discharging"
|
||||||
|
else:
|
||||||
|
return "Charging"
|
||||||
|
else:
|
||||||
|
return "Full"
|
||||||
|
|
||||||
|
class BatteryCharge(Battery):
|
||||||
|
def consumption(self):
|
||||||
|
return self.bat["VOLTAGE_NOW"] * self.bat["CURRENT_NOW"] # V * A = W
|
||||||
|
|
||||||
|
def _percentage(self, design):
|
||||||
|
return self.bat["CHARGE_NOW"] / self.bat["CHARGE_FULL"+design]
|
||||||
|
|
||||||
|
def remaining(self):
|
||||||
|
if self.status() == "Discharging":
|
||||||
|
return self.bat["CHARGE_NOW"] / self.bat["CURRENT_NOW"] * 60 # Ah / A = h * 60 min = min
|
||||||
|
else:
|
||||||
|
return (self.bat["CHARGE_FULL"] - self.bat["CHARGE_NOW"]) / self.bat["CURRENT_NOW"] * 60
|
||||||
|
|
||||||
|
class BatteryEnergy(Battery):
|
||||||
|
def consumption(self):
|
||||||
|
return self.bat["POWER_NOW"]
|
||||||
|
|
||||||
|
def _percentage(self, design):
|
||||||
|
return self.bat["ENERGY_NOW"] / self.bat["ENERGY_FULL"+design]
|
||||||
|
|
||||||
|
def remaining(self):
|
||||||
|
if self.status() == "Discharging":
|
||||||
|
return self.bat["ENERGY_NOW"] / self.bat["POWER_NOW"] * 60 # Wh / W = h * 60 min = min
|
||||||
|
else:
|
||||||
|
return (self.bat["ENERGY_FULL"] - self.bat["ENERGY_NOW"]) / self.bat["POWER_NOW"] * 60
|
||||||
|
|
||||||
|
def format_remaining(minutes, prefix):
|
||||||
|
hours, minutes = map(int, divmod(minutes, 60))
|
||||||
|
|
||||||
def get_dict(self, prefix):
|
|
||||||
d = PrefixedKeyDict(prefix)
|
d = PrefixedKeyDict(prefix)
|
||||||
d.update({
|
d.update({
|
||||||
"str": "{}:{:02}".format(self.hours, self.minutes),
|
"str": "{}:{:02}".format(hours, minutes),
|
||||||
"hm": "{}h:{:02}m".format(self.hours, self.minutes),
|
"hm": "{}h:{:02}m".format(hours, minutes),
|
||||||
"hours": self.hours,
|
"hours": hours,
|
||||||
"mins": self.minutes,
|
"mins": minutes,
|
||||||
})
|
})
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -63,7 +121,7 @@ class BatteryChecker(IntervalModule):
|
|||||||
* status
|
* status
|
||||||
* battery_ident
|
* battery_ident
|
||||||
"""
|
"""
|
||||||
|
interval=1
|
||||||
settings = (
|
settings = (
|
||||||
"battery_ident", "format",
|
"battery_ident", "format",
|
||||||
("alert", "Display a libnotify-notification on low battery"),
|
("alert", "Display a libnotify-notification on low battery"),
|
||||||
@ -88,34 +146,26 @@ class BatteryChecker(IntervalModule):
|
|||||||
urgent = False
|
urgent = False
|
||||||
color = "#ffffff"
|
color = "#ffffff"
|
||||||
|
|
||||||
battery = Battery(self.path)
|
battery = Battery.create(self.path)
|
||||||
|
|
||||||
status = battery.STATUS
|
|
||||||
energy_now = battery.ENERGY_NOW
|
|
||||||
energy_full = battery.ENERGY_FULL
|
|
||||||
if not hasattr(battery, "POWER_NOW"):
|
|
||||||
battery.POWER_NOW = battery.VOLTAGE_NOW * battery.CURRENT_NOW
|
|
||||||
power_now = battery.POWER_NOW
|
|
||||||
|
|
||||||
fdict = {
|
fdict = {
|
||||||
"battery_ident": self.battery_ident,
|
"battery_ident": self.battery_ident,
|
||||||
"remaining_str": "",
|
"remaining_str": "",
|
||||||
"remaining_hm": "",
|
"remaining_hm": "",
|
||||||
"percentage": (energy_now / energy_full) * 100,
|
"percentage": battery.percentage(),
|
||||||
"percentage_design": (energy_now / battery.ENERGY_FULL_DESIGN) * 100,
|
"percentage_design": battery.percentage(design=True),
|
||||||
"consumption": power_now / 1000000,
|
"consumption": battery.consumption(),
|
||||||
}
|
}
|
||||||
if power_now:
|
|
||||||
|
status = battery.status()
|
||||||
|
if status in ["Discharging", "Charging"]:
|
||||||
|
remaining = battery.remaining()
|
||||||
|
fdict.update(format_remaining(remaining, "remaining_"))
|
||||||
if status == "Discharging":
|
if status == "Discharging":
|
||||||
fdict["status"] = "DIS"
|
fdict["status"] = "DIS"
|
||||||
remaining = RemainingCalculator(energy_now, power_now)
|
if remaining < 15:
|
||||||
if remaining.remaining_time < 15:
|
|
||||||
urgent = True
|
urgent = True
|
||||||
color = "#ff0000"
|
color = "#ff0000"
|
||||||
else: # Charging, Unknown etc. (My thinkpad says Unknown if close to fully charged)
|
|
||||||
fdict["status"] = "CHR"
|
|
||||||
remaining = RemainingCalculator(energy_full-energy_now, power_now)
|
|
||||||
fdict.update(remaining.get_dict("remaining_"))
|
|
||||||
else:
|
else:
|
||||||
fdict["status"] = "FULL"
|
fdict["status"] = "FULL"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user