2020-04-19 14:27:56 +02:00
|
|
|
# UPowerManger Class Copyright (C) 2017 Oscar Svensson (wogscpar) under MIT licence from upower-python
|
|
|
|
|
|
|
|
"""Displays battery status, remaining percentage and charging information.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
* battery-upower.warning : Warning threshold in % of remaining charge (defaults to 20)
|
|
|
|
* battery-upower.critical : Critical threshold in % of remaining charge (defaults to 10)
|
|
|
|
* battery-upower.showremaining : If set to true (default) shows the remaining time until the batteries are completely discharged
|
2020-05-08 20:58:35 +02:00
|
|
|
|
|
|
|
contributed by `martindoublem <https://github.com/martindoublem>`_ - many thanks!
|
2020-04-19 14:27:56 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
import dbus
|
|
|
|
import logging
|
|
|
|
|
2020-04-19 14:32:51 +02:00
|
|
|
import core.module
|
|
|
|
import core.widget
|
|
|
|
import core.input
|
2020-04-19 14:27:56 +02:00
|
|
|
|
2020-04-19 14:32:51 +02:00
|
|
|
import util.format
|
2020-04-19 14:27:56 +02:00
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
|
|
|
|
class UPowerManager:
|
2020-04-19 14:27:56 +02:00
|
|
|
def __init__(self):
|
|
|
|
self.UPOWER_NAME = "org.freedesktop.UPower"
|
|
|
|
self.UPOWER_PATH = "/org/freedesktop/UPower"
|
|
|
|
|
|
|
|
self.DBUS_PROPERTIES = "org.freedesktop.DBus.Properties"
|
|
|
|
self.bus = dbus.SystemBus()
|
|
|
|
|
|
|
|
def detect_devices(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME)
|
|
|
|
|
|
|
|
devices = upower_interface.EnumerateDevices()
|
|
|
|
return devices
|
|
|
|
|
|
|
|
def get_display_device(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME)
|
|
|
|
|
|
|
|
dispdev = upower_interface.GetDisplayDevice()
|
|
|
|
return dispdev
|
|
|
|
|
|
|
|
def get_critical_action(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME)
|
|
|
|
|
|
|
|
critical_action = upower_interface.GetCriticalAction()
|
|
|
|
return critical_action
|
|
|
|
|
|
|
|
def get_device_percentage(self, battery):
|
|
|
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
|
|
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
|
|
|
return battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Percentage")
|
|
|
|
|
|
|
|
def get_full_device_information(self, battery):
|
|
|
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
|
|
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
hasHistory = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "HasHistory"
|
|
|
|
)
|
|
|
|
hasStatistics = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "HasStatistics"
|
|
|
|
)
|
|
|
|
isPresent = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "IsPresent"
|
|
|
|
)
|
|
|
|
isRechargable = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "IsRechargeable"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
online = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Online")
|
2020-05-03 11:15:52 +02:00
|
|
|
powersupply = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "PowerSupply"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
capacity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Capacity")
|
|
|
|
energy = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Energy")
|
2020-05-03 11:15:52 +02:00
|
|
|
energyempty = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "EnergyEmpty"
|
|
|
|
)
|
|
|
|
energyfull = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "EnergyFull"
|
|
|
|
)
|
|
|
|
energyfulldesign = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "EnergyFullDesign"
|
|
|
|
)
|
|
|
|
energyrate = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "EnergyRate"
|
|
|
|
)
|
|
|
|
luminosity = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "Luminosity"
|
|
|
|
)
|
|
|
|
percentage = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "Percentage"
|
|
|
|
)
|
|
|
|
temperature = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "Temperature"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
voltage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Voltage")
|
2020-05-03 11:15:52 +02:00
|
|
|
timetoempty = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "TimeToEmpty"
|
|
|
|
)
|
|
|
|
timetofull = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "TimeToFull"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
iconname = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IconName")
|
|
|
|
model = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Model")
|
2020-05-03 11:15:52 +02:00
|
|
|
nativepath = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "NativePath"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
serial = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Serial")
|
|
|
|
vendor = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Vendor")
|
|
|
|
state = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State")
|
2020-05-03 11:15:52 +02:00
|
|
|
technology = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "Technology"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
battype = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Type")
|
2020-05-03 11:15:52 +02:00
|
|
|
warninglevel = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "WarningLevel"
|
|
|
|
)
|
|
|
|
updatetime = battery_proxy_interface.Get(
|
|
|
|
self.UPOWER_NAME + ".Device", "UpdateTime"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
information_table = {
|
2020-05-03 11:15:52 +02:00
|
|
|
"HasHistory": hasHistory,
|
|
|
|
"HasStatistics": hasStatistics,
|
|
|
|
"IsPresent": isPresent,
|
|
|
|
"IsRechargeable": isRechargable,
|
|
|
|
"Online": online,
|
|
|
|
"PowerSupply": powersupply,
|
|
|
|
"Capacity": capacity,
|
|
|
|
"Energy": energy,
|
|
|
|
"EnergyEmpty": energyempty,
|
|
|
|
"EnergyFull": energyfull,
|
|
|
|
"EnergyFullDesign": energyfulldesign,
|
|
|
|
"EnergyRate": energyrate,
|
|
|
|
"Luminosity": luminosity,
|
|
|
|
"Percentage": percentage,
|
|
|
|
"Temperature": temperature,
|
|
|
|
"Voltage": voltage,
|
|
|
|
"TimeToEmpty": timetoempty,
|
|
|
|
"TimeToFull": timetofull,
|
|
|
|
"IconName": iconname,
|
|
|
|
"Model": model,
|
|
|
|
"NativePath": nativepath,
|
|
|
|
"Serial": serial,
|
|
|
|
"Vendor": vendor,
|
|
|
|
"State": state,
|
|
|
|
"Technology": technology,
|
|
|
|
"Type": battype,
|
|
|
|
"WarningLevel": warninglevel,
|
|
|
|
"UpdateTime": updatetime,
|
2020-04-19 14:27:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return information_table
|
|
|
|
|
|
|
|
def is_lid_present(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
is_lid_present = bool(upower_interface.Get(self.UPOWER_NAME, "LidIsPresent"))
|
2020-04-19 14:27:56 +02:00
|
|
|
return is_lid_present
|
|
|
|
|
|
|
|
def is_lid_closed(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
is_lid_closed = bool(upower_interface.Get(self.UPOWER_NAME, "LidIsClosed"))
|
2020-04-19 14:27:56 +02:00
|
|
|
return is_lid_closed
|
|
|
|
|
|
|
|
def on_battery(self):
|
|
|
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
on_battery = bool(upower_interface.Get(self.UPOWER_NAME, "OnBattery"))
|
2020-04-19 14:27:56 +02:00
|
|
|
return on_battery
|
|
|
|
|
|
|
|
def has_wakeup_capabilities(self):
|
2020-05-03 11:15:52 +02:00
|
|
|
upower_proxy = self.bus.get_object(
|
|
|
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
has_wakeup_capabilities = bool(
|
|
|
|
upower_interface.Get(self.UPOWER_NAME + ".Wakeups", "HasCapability")
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
return has_wakeup_capabilities
|
|
|
|
|
|
|
|
def get_wakeups_data(self):
|
2020-05-03 11:15:52 +02:00
|
|
|
upower_proxy = self.bus.get_object(
|
|
|
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
|
|
|
)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + ".Wakeups")
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
data = upower_interface.GetData()
|
|
|
|
return data
|
|
|
|
|
|
|
|
def get_wakeups_total(self):
|
2020-05-03 11:15:52 +02:00
|
|
|
upower_proxy = self.bus.get_object(
|
|
|
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
|
|
|
)
|
|
|
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + ".Wakeups")
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
data = upower_interface.GetTotal()
|
|
|
|
return data
|
|
|
|
|
handle missing battery case
I run the same bumblebee-status configuration on my laptop and my
workstation. On my laptop, the upower module works fine: it says "ac"
when plugged in, charging, all that stuff is great.
But on my workstation, it's completely broken: it thinks there's a
battery (which is a mistake: there is no battery at all, apart maybe
from the CMOS battery, but that's not covered by upower), and it
thinks it's discharged, which makes a very noisy warning in the bar.
Now maybe there's something wrong with dbus, Debian, the kernel,
Linux, or some thing else in the stack. All I know is that
`self.power.get_display_device()` returns something like a valid
dbus object here and from there it confuses the heck out of the
module.
So this just adds a function to check if the actual device we're
talking about is actually present, and bails earlier otherwise.
Before: battery logo and "0% 00:00m!", all marked as critical ("red")
After: "ac" with the plugged in logo, not marked critical ("black")
2022-06-20 17:29:14 +02:00
|
|
|
def is_battery_present(self, battery):
|
|
|
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
|
|
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
|
|
|
return bool(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IsPresent"))
|
|
|
|
|
2020-04-19 14:27:56 +02:00
|
|
|
def is_loading(self, battery):
|
|
|
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
|
|
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
|
|
|
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
if state == 1:
|
2020-04-19 14:27:56 +02:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_state(self, battery):
|
|
|
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
|
|
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
|
|
|
|
|
|
|
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
if state == 0:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Unknown"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 1:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Loading"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 2:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Discharging"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 3:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Empty"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 4:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Fully charged"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 5:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Pending charge"
|
2020-05-03 11:15:52 +02:00
|
|
|
elif state == 6:
|
2020-04-19 14:27:56 +02:00
|
|
|
return "Pending discharge"
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
|
2020-04-19 14:32:51 +02:00
|
|
|
class Module(core.module.Module):
|
2020-04-26 16:39:24 +02:00
|
|
|
def __init__(self, config, theme):
|
|
|
|
super().__init__(config, theme, core.widget.Widget(self.capacity))
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
self.power = UPowerManager()
|
|
|
|
self.device = self.power.get_display_device()
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("unable to get battery display device: {}".format(str(e)))
|
2020-05-03 11:15:52 +02:00
|
|
|
core.input.register(
|
|
|
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-power-statistics"
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
self._showremaining = util.format.asbool(self.parameter("showremaining", True))
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
def capacity(self, widget):
|
|
|
|
widget.set("capacity", -1)
|
|
|
|
widget.set("ac", False)
|
|
|
|
output = "n/a"
|
handle missing battery case
I run the same bumblebee-status configuration on my laptop and my
workstation. On my laptop, the upower module works fine: it says "ac"
when plugged in, charging, all that stuff is great.
But on my workstation, it's completely broken: it thinks there's a
battery (which is a mistake: there is no battery at all, apart maybe
from the CMOS battery, but that's not covered by upower), and it
thinks it's discharged, which makes a very noisy warning in the bar.
Now maybe there's something wrong with dbus, Debian, the kernel,
Linux, or some thing else in the stack. All I know is that
`self.power.get_display_device()` returns something like a valid
dbus object here and from there it confuses the heck out of the
module.
So this just adds a function to check if the actual device we're
talking about is actually present, and bails earlier otherwise.
Before: battery logo and "0% 00:00m!", all marked as critical ("red")
After: "ac" with the plugged in logo, not marked critical ("black")
2022-06-20 17:29:14 +02:00
|
|
|
if not self.power.is_battery_present(self.device):
|
|
|
|
widget.set("ac", True)
|
|
|
|
widget.set("capacity", 100)
|
|
|
|
output = "ac"
|
|
|
|
return output
|
2020-04-19 14:27:56 +02:00
|
|
|
try:
|
|
|
|
capacity = int(self.power.get_device_percentage(self.device))
|
|
|
|
capacity = capacity if capacity < 100 else 100
|
|
|
|
widget.set("capacity", capacity)
|
|
|
|
output = "{}%".format(capacity)
|
|
|
|
widget.set("theme.minwidth", "100%")
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("unable to get battery capacity: {}".format(str(e)))
|
|
|
|
|
|
|
|
if self._showremaining:
|
|
|
|
try:
|
2020-05-03 11:15:52 +02:00
|
|
|
p = self.power # an alias to make each line of code shorter
|
2020-04-19 14:27:56 +02:00
|
|
|
proxy = p.bus.get_object(p.UPOWER_NAME, self.device)
|
|
|
|
interface = dbus.Interface(proxy, p.DBUS_PROPERTIES)
|
2020-05-03 11:15:52 +02:00
|
|
|
state = int(interface.Get(p.UPOWER_NAME + ".Device", "State"))
|
2020-04-19 14:27:56 +02:00
|
|
|
# state: 1 => charging, 2 => discharging, other => don't care
|
2020-05-03 11:15:52 +02:00
|
|
|
remain = int(
|
|
|
|
interface.Get(
|
|
|
|
p.UPOWER_NAME + ".Device",
|
|
|
|
["TimeToFull", "TimeToEmpty"][state - 1],
|
|
|
|
)
|
|
|
|
)
|
2020-04-19 14:32:51 +02:00
|
|
|
remain = util.format.duration(remain, compact=True, unit=True)
|
2020-04-19 14:27:56 +02:00
|
|
|
output = "{} {}".format(output, remain)
|
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
except Exception as e:
|
2020-05-03 11:15:52 +02:00
|
|
|
logging.exception(
|
|
|
|
"unable to get battery remaining time: {}".format(str(e))
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
def state(self, widget):
|
|
|
|
state = []
|
|
|
|
capacity = widget.get("capacity", -1)
|
|
|
|
if capacity < 0:
|
|
|
|
return ["critical", "unknown"]
|
|
|
|
|
|
|
|
if capacity < int(self.parameter("critical", 10)):
|
|
|
|
state.append("critical")
|
|
|
|
elif capacity < int(self.parameter("warning", 20)):
|
|
|
|
state.append("warning")
|
|
|
|
|
|
|
|
if widget.get("ac"):
|
|
|
|
state.append("AC")
|
|
|
|
else:
|
|
|
|
charge = "Unknown"
|
|
|
|
try:
|
|
|
|
charge = self.power.get_state(self.device)
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("unable to get charge value: {}".format(str(e)))
|
|
|
|
if charge == "Discharging":
|
2020-05-03 11:15:52 +02:00
|
|
|
state.append(
|
|
|
|
"discharging-{}".format(
|
|
|
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
|
|
|
)
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
elif charge == "Unknown":
|
2020-05-03 11:15:52 +02:00
|
|
|
state.append(
|
|
|
|
"unknown-{}".format(
|
|
|
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
|
|
|
)
|
|
|
|
)
|
2020-04-19 14:27:56 +02:00
|
|
|
else:
|
|
|
|
if capacity > 95:
|
|
|
|
state.append("charged")
|
|
|
|
else:
|
|
|
|
state.append("charging")
|
|
|
|
return state
|
|
|
|
|
2020-05-03 11:15:52 +02:00
|
|
|
|
2020-04-19 14:27:56 +02:00
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|