You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.7 KiB
146 lines
3.7 KiB
#!/usr/bin/env python
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import typing
|
|
|
|
__all__ = ["_mem", "_backlight", "_hwtemp"]
|
|
|
|
_BITS: list[tuple[int, str, typing.Callable]] = []
|
|
|
|
|
|
def _bit(idx):
|
|
def wrapper(func):
|
|
_BITS.append((idx, func.__name__.replace("_", ""), func))
|
|
return func
|
|
|
|
return wrapper
|
|
|
|
|
|
@_bit(6)
|
|
def _mem():
|
|
with open("/proc/meminfo") as meminfo_fp:
|
|
attrs = {}
|
|
for line in meminfo_fp.readlines():
|
|
parts = line.split(":", 2)
|
|
attrs[parts[0].strip()] = parts[1].strip()
|
|
avail = int(attrs["MemAvailable"].split()[0])
|
|
total = int(attrs["MemTotal"].split()[0])
|
|
used = int(((total - avail) / total) * 100)
|
|
color = None
|
|
if used > 75:
|
|
color = "#ff0000"
|
|
if used < 25:
|
|
color = "#00ff00"
|
|
return "M:{}%".format(used), color
|
|
|
|
|
|
@_bit(0)
|
|
def _backlight(dev_dir="/sys/class/backlight/intel_backlight"):
|
|
with open("{}/brightness".format(dev_dir)) as br_fp:
|
|
with open("{}/max_brightness".format(dev_dir)) as mb_fp:
|
|
value = int(br_fp.read().strip())
|
|
max_value = int(mb_fp.read().strip())
|
|
pct = int(float(float(value) / float(max_value)) * 100)
|
|
color = None
|
|
if pct >= 75:
|
|
color = "#ffaa00"
|
|
if pct <= 25:
|
|
color = "#5599ff"
|
|
return "☼:{}%".format(pct), color
|
|
|
|
|
|
ACPI_IBM_FAN = "/proc/acpi/ibm/fan"
|
|
|
|
|
|
@_bit(7)
|
|
def _hwtemp(fan=ACPI_IBM_FAN):
|
|
acpi_exe = shutil.which("acpi")
|
|
if acpi_exe is None:
|
|
return None, None
|
|
|
|
raw_temp = subprocess.run(
|
|
[acpi_exe, "-t"],
|
|
text=True,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
if raw_temp.returncode != 0 or raw_temp.stdout is None:
|
|
return None, None
|
|
|
|
temps_by_zone = {}
|
|
for line in raw_temp.stdout.splitlines():
|
|
zone_id, value = line.split(":")
|
|
human_temp = value.split(",")[-1]
|
|
temps_by_zone[zone_id.lower().lstrip("thermal ")] = float(
|
|
human_temp.lower().strip().rstrip("degrees c")
|
|
)
|
|
|
|
temps = list(temps_by_zone.values())
|
|
avg_temp = float(sum(temps)) / len(temps)
|
|
color = "#5599ff"
|
|
if avg_temp > 75:
|
|
color = "#ff0000"
|
|
if avg_temp >= 50:
|
|
color = "#ffaa00"
|
|
|
|
fan_level = "unset"
|
|
try:
|
|
with open(fan) as fan_fp:
|
|
for line in fan_fp.readlines():
|
|
if not line.startswith("level:\t\t"):
|
|
continue
|
|
fan_level = int(line.replace("level:\t\t", ""))
|
|
except (OSError, IOError) as exc:
|
|
sys.stderr.write(str(exc) + "\n")
|
|
|
|
return "T:{:.1f}°C L:{}".format(avg_temp, fan_level), color
|
|
|
|
|
|
def _print_line(message):
|
|
sys.stdout.write(message + "\n")
|
|
sys.stdout.flush()
|
|
|
|
|
|
def _read_line():
|
|
try:
|
|
line = sys.stdin.readline().strip()
|
|
if not line:
|
|
sys.exit(3)
|
|
return line
|
|
except KeyboardInterrupt:
|
|
sys.exit()
|
|
|
|
|
|
def main(bits=_BITS):
|
|
_print_line(_read_line())
|
|
_print_line(_read_line())
|
|
|
|
while True:
|
|
line, prefix = _read_line(), ""
|
|
if line.startswith(","):
|
|
line, prefix = line[1:], ","
|
|
|
|
loaded = json.loads(line)
|
|
for idx, name, func in bits:
|
|
try:
|
|
value, color = func()
|
|
if value is None:
|
|
continue
|
|
|
|
record = dict(full_text=str(value), name=name)
|
|
if color is not None:
|
|
record.update(dict(color=color))
|
|
|
|
loaded.insert(idx, record)
|
|
except Exception as exc:
|
|
sys.stderr.write(str(exc) + "\n")
|
|
sys.stderr.flush()
|
|
|
|
_print_line(prefix + json.dumps(loaded))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|