diff --git a/bumblebee/modules/battery.py b/bumblebee/modules/battery.py index 3d47efa..a22c8d8 100644 --- a/bumblebee/modules/battery.py +++ b/bumblebee/modules/battery.py @@ -3,12 +3,14 @@ """Displays battery status, remaining percentage and charging information. Parameters: - * battery.device : The device to read information from (defaults to BAT0) - * battery.warning : Warning threshold in % of remaining charge (defaults to 20) - * battery.critical: Critical threshold in % of remaining charge (defaults to 10) + * battery.device : Comma-separated list of battery devices to read information from (defaults to auto for auto-detection) + * battery.warning : Warning threshold in % of remaining charge (defaults to 20) + * battery.critical : Critical threshold in % of remaining charge (defaults to 10) + * battery.showdevice : If set to "true", add the device name to the widget """ import os +import glob import bumblebee.input import bumblebee.output @@ -16,56 +18,73 @@ import bumblebee.engine class Module(bumblebee.engine.Module): def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.capacity) - widget.set("theme.minwidth", "100%") - super(Module, self).__init__(engine, config, widget) - battery = self.parameter("device", "BAT0") - self._path = "/sys/class/power_supply/{}".format(battery) - self._capacity = 100 - self._ac = False - - def capacity(self, widget): - if self._ac: - return "ac" - if self._capacity == -1: - return "n/a" - return "{}%".format(self._capacity) + widgets = [] + super(Module, self).__init__(engine, config, widgets) + self._batteries = self.parameter("device", "auto").split(",") + if self._batteries[0] == "auto": + self._batteries = glob.glob("/sys/class/power_supply/BAT*") + else: + self._batteries = [ "/sys/class/power_supply/{}".format(b) for b in self._batteries ] + if len(self._batteries) == 0: + self._batteries = [ "/sys/class/power_supply/BAT0" ] + self.update(widgets) def update(self, widgets): - self._ac = False - if not os.path.exists(self._path): - self._ac = True - self._capacity = 100 - return + new_widgets = [] + for path in self._batteries: + widget = self.widget(path) + if not widget: + widget = bumblebee.output.Widget(full_text=self.capacity, name=path) + new_widgets.append(widget) + self.capacity(widget) + while len(widgets) > 0: del widgets[0] + for widget in new_widgets: + widgets.append(widget) + self._widgets = widgets + def capacity(self, widget): + widget.set("capacity", -1) + widget.set("ac", False) + if not os.path.exists(widget.name): + widget.set("capacity", 100) + widget.set("ac", True) + return "ac" + capacity = 100 try: - with open(self._path + "/capacity") as f: - self._capacity = int(f.read()) + with open("{}/capacity".format(widget.name)) as f: + capacity = int(f.read()) except IOError: - self._capacity = -1 - self._capacity = self._capacity if self._capacity < 100 else 100 + return "n/a" + capacity = capacity if capacity < 100 else 100 + widget.set("capacity", capacity) + if self.parameter("showdevice") == "true": + widget.set("theme.minwidth", "100% ({})".format(os.path.basename(widget.name))) + return "{}% ({})".format(capacity, os.path.basename(widget.name)) + widget.set("theme.minwidth", "100%") + return "{}%".format(capacity) def state(self, widget): state = [] + capacity = widget.get("capacity") - if self._capacity < 0: + if capacity < 0: return ["critical", "unknown"] - if self._capacity < int(self.parameter("critical", 10)): + if capacity < int(self.parameter("critical", 10)): state.append("critical") - elif self._capacity < int(self.parameter("warning", 20)): + elif capacity < int(self.parameter("warning", 20)): state.append("warning") - if self._ac: + if widget.get("ac"): state.append("AC") else: charge = "" - with open(self._path + "/status") as f: + with open("{}/status".format(widget.name)) as f: charge = f.read().strip() if charge == "Discharging": - state.append("discharging-{}".format(min([10, 25, 50, 80, 100] , key=lambda i:abs(i-self._capacity)))) + state.append("discharging-{}".format(min([10, 25, 50, 80, 100] , key=lambda i:abs(i-capacity)))) else: - if self._capacity > 95: + if capacity > 95: state.append("charged") else: state.append("charging") diff --git a/tests/modules/test_battery.py b/tests/modules/test_battery.py index 0c86cc9..fb96093 100644 --- a/tests/modules/test_battery.py +++ b/tests/modules/test_battery.py @@ -26,6 +26,7 @@ class TestBatteryModule(unittest.TestCase): self.file = mock.Mock() self.file.__enter__ = lambda x: self.file self.file.__exit__ = lambda x, a, b, c: "" + self.file.read.return_value = "120" self.open.return_value = self.file self.exists.return_value = True @@ -40,9 +41,7 @@ class TestBatteryModule(unittest.TestCase): self.normalValue = "26" self.chargedValue = "96" - for widget in self.module.widgets(): - widget.link_module(self.module) - self.anyWidget = widget + self.module.widgets()[0] def tearDown(self): self._stdout.stop() @@ -56,46 +55,47 @@ class TestBatteryModule(unittest.TestCase): def test_critical(self): self.file.read.return_value = self.criticalValue self.module.update_all() - self.assertTrue("critical" in self.module.state(self.anyWidget)) + self.assertTrue("critical" in self.module.state(self.module.widgets()[0])) def test_warning(self): self.file.read.return_value = self.warningValue self.module.update_all() - self.assertTrue("warning" in self.module.state(self.anyWidget)) + self.assertTrue("warning" in self.module.state(self.module.widgets()[0])) def test_normal(self): self.file.read.return_value = self.normalValue self.module.update_all() - self.assertTrue(not "warning" in self.module.state(self.anyWidget)) - self.assertTrue(not "critical" in self.module.state(self.anyWidget)) + self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) + self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0])) def test_overload(self): self.file.read.return_value = "120" self.module.update_all() - self.assertTrue(not "warning" in self.module.state(self.anyWidget)) - self.assertTrue(not "critical" in self.module.state(self.anyWidget)) - self.assertEquals(self.module.capacity(self.anyWidget), "100%") + self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) + self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0])) + self.assertEquals(self.module.capacity(self.module.widgets()[0]), "100%") def test_ac(self): self.exists.return_value = False + self.file.read.return_value = "120" self.module.update_all() - self.assertEquals(self.module.capacity(self.anyWidget), "ac") - self.assertTrue("AC" in self.module.state(self.anyWidget)) + self.assertEquals(self.module.capacity(self.module.widgets()[0]), "ac") + self.assertTrue("AC" in self.module.state(self.module.widgets()[0])) def test_error(self): self.file.read.side_effect = IOError("failed to read") self.module.update_all() - self.assertEquals(self.module.capacity(self.anyWidget), "n/a") - self.assertTrue("critical" in self.module.state(self.anyWidget)) - self.assertTrue("unknown" in self.module.state(self.anyWidget)) + self.assertEquals(self.module.capacity(self.module.widgets()[0]), "n/a") + self.assertTrue("critical" in self.module.state(self.module.widgets()[0])) + self.assertTrue("unknown" in self.module.state(self.module.widgets()[0])) def test_charging(self): self.file.read.return_value = self.chargedValue self.module.update_all() - self.assertTrue("charged" in self.module.state(self.anyWidget)) + self.assertTrue("charged" in self.module.state(self.module.widgets()[0])) self.file.read.return_value = self.normalValue self.module.update_all() - self.assertTrue("charging" in self.module.state(self.anyWidget)) + self.assertTrue("charging" in self.module.state(self.module.widgets()[0])) def test_discharging(self): for limit in [ 10, 25, 50, 80, 100 ]: @@ -103,6 +103,6 @@ class TestBatteryModule(unittest.TestCase): self.file.read.return_value = str(value) self.module.update_all() self.file.read.return_value = "Discharging" - self.assertTrue("discharging-{}".format(limit) in self.module.state(self.anyWidget)) + self.assertTrue("discharging-{}".format(limit) in self.module.state(self.module.widgets()[0])) # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4