From 0d9b3113f4decbefd4dad852d15e7f173c7d7dda Mon Sep 17 00:00:00 2001 From: Tobias Witek Date: Sat, 17 Nov 2018 13:38:35 +0100 Subject: [PATCH] [modules/sensors2] Alternate sensor module Show all sensor data reported by sensors -u and color widget with warning/critical if sensor limits are exceeded. fixes #326 --- README.md | 2 +- bumblebee/engine.py | 4 +- bumblebee/modules/sensors2.py | 147 ++++++++++++++++++++++++++++++++ screenshots/sensors2.png | Bin 0 -> 4135 bytes themes/icons/awesome-fonts.json | 5 ++ 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 bumblebee/modules/sensors2.py create mode 100644 screenshots/sensors2.png diff --git a/README.md b/README.md index 194edff..89bb042 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage) [![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status) -**Many, many thanks to all contributors! As of now, 33 of the modules are from various contributors (!), and only 16 from myself.** +**Many, many thanks to all contributors! As of now, 33 of the modules are from various contributors (!), and only 17 from myself.** ![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png) diff --git a/bumblebee/engine.py b/bumblebee/engine.py index 526b629..f515470 100644 --- a/bumblebee/engine.py +++ b/bumblebee/engine.py @@ -56,8 +56,10 @@ class Module(object): if widgets: self._widgets = widgets if isinstance(widgets, list) else [widgets] - def widgets(self): + def widgets(self, widgets=None): """Return the widgets to draw for this module""" + if widgets: + self._widgets = widgets return self._widgets def hidden(self): diff --git a/bumblebee/modules/sensors2.py b/bumblebee/modules/sensors2.py new file mode 100644 index 0000000..ea71aed --- /dev/null +++ b/bumblebee/modules/sensors2.py @@ -0,0 +1,147 @@ +# -*- coding: UTF-8 -*- + +"""Displays sensor temperature and CPU frequency + +Parameters: + + * sensors2.chip: "sensors -u" compatible filter for chip to display (default to empty - show all chips) + * sensors2.showcpu: Enable or disable CPU frequency display (default: true) + * sensors2.showtemp: Enable or disable temperature display (default: true) + * sensors2.showfan: Enable or disable fan display (default: true) + * sensors2.showother: Enable or display "other" sensor readings (default: false) + * sensors2.showname: Enable or disable show of sensor name (default: false) +""" + +import bumblebee.util +import bumblebee.output +import bumblebee.engine + +class Module(bumblebee.engine.Module): + def __init__(self, engine, config): + super(Module, self).__init__(engine, config, None) + self._chip = self.parameter("chip", "") + self._data = {} + self._update() + + self.widgets(self._create_widgets()) + + def update(self, widgets): + self._update() + for widget in widgets: + self._update_widget(widget) + + def state(self, widget): + widget_type = widget.get("type", "") + try: + data = self._data[widget.get("adapter")][widget.get("package")][widget.get("field")] + if "crit" in data and float(data["input"]) > float(data["crit"]): + return ["critical", widget_type] + if "max" in data and float(data["input"]) > float(data["max"]): + return ["warning", widget_type] + except: + pass + return [widget_type] + + def _create_widgets(self): + widgets = [] + show_temp = bumblebee.util.asbool(self.parameter("showtemp", "true")) + show_fan = bumblebee.util.asbool(self.parameter("showfan", "true")) + show_other = bumblebee.util.asbool(self.parameter("showother", "false")) + + if bumblebee.util.asbool(self.parameter("showcpu", "true")): + widget = bumblebee.output.Widget(full_text=self._cpu) + widget.set("type", "cpu") + widgets.append(widget) + + for adapter in self._data: + for package in self._data[adapter]: + if bumblebee.util.asbool(self.parameter("showname", "false")): + widget = bumblebee.output.Widget(full_text=package) + widget.set("data", self._data[adapter][package]) + widget.set("package", package) + widget.set("field", "") + widget.set("adapter", adapter) + widgets.append(widget) + for field in self._data[adapter][package]: + widget = bumblebee.output.Widget() + widget.set("package", package) + widget.set("field", field) + widget.set("adapter", adapter) + if "temp" in field and show_temp: + # seems to be a temperature + widget.set("type", "temp") + widgets.append(widget) + if "fan" in field and show_fan: + # seems to be a fan + widget.set("type", "fan") + widgets.append(widget) + elif show_other: + # everything else + widget.set("type", "other") + widgets.append(widget) + return widgets + + def _update_widget(self, widget): + if widget.get("field", "") == "": + return # nothing to do + data = self._data[widget.get("adapter")][widget.get("package")][widget.get("field")] + if "temp" in widget.get("field"): + widget.full_text(u"{:0.01f}°C".format(data["input"])) + elif "fan" in widget.get("field"): + widget.full_text(u"{:0.0f}RPM".format(data["input"])) + else: + widget.full_text(u"{:0.0f}".format(data["input"])) + + def _update(self): + output = bumblebee.util.execute("sensors -u {}".format(self._chip)) + self._data = self._parse(output) + + def _parse(self, data): + output = {} + package = "" + adapter = None + chip = None + for line in data.split("\n"): + if "Adapter" in line: + # new adapter + line = line.replace("Adapter: ", "") + output[chip + " " + line] = {} + adapter = chip + " " + line + chip = line #default - line before adapter is always the chip + if not adapter: continue + key, value = (line.split(":") + ["", ""])[:2] + if not line.startswith(" "): + # assume this starts a new package + if package in output[adapter] and output[adapter][package] == {}: + del output[adapter][package] + output[adapter][key] = {} + package = key + else: + # feature for this chip + try: + name, variant = (key.strip().split("_", 1) + ["",""])[:2] + if not name in output[adapter][package]: + output[adapter][package][name] = { } + if variant: + output[adapter][package][name][variant] = {} + output[adapter][package][name][variant] = float(value) + except Exception as e: + pass + return output + + def _cpu(self, _): + try: + output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read() + mhz = int(float(output)/1000.0) + except: + output = open("/proc/cpuinfo").read() + m = re.search(r"cpu MHz\s+:\s+(\d+)", output) + mhz = int(m.group(1)) + + if mhz < 1000: + return "{} MHz".format(mhz) + else: + return "{:0.01f} GHz".format(float(mhz)/1000.0) + + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/screenshots/sensors2.png b/screenshots/sensors2.png new file mode 100644 index 0000000000000000000000000000000000000000..f2840d20fda73dbcf959528a41c38e7f7b51e4ef GIT binary patch literal 4135 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 literal 0 HcmV?d00001 diff --git a/themes/icons/awesome-fonts.json b/themes/icons/awesome-fonts.json index ed84f6d..6aaab25 100644 --- a/themes/icons/awesome-fonts.json +++ b/themes/icons/awesome-fonts.json @@ -114,6 +114,11 @@ "sensors": { "prefix": "" }, + "sensors2": { + "temp": { "prefix": "" }, + "fan": { "prefix": "" }, + "cpu": { "prefix": "" } + }, "traffic":{ "rx": { "prefix": "" }, "tx": { "prefix": "" }