Initial commit: epaper-dashboard for 7.3" ACeP 7-Color display
- dashboard.py: plugin-based renderer with 4x4 grid layout - admin.py: web UI with layout editor + plugin configs - layout.py: pack algorithm, item placement, grid system - plugins/: clock, weather, system, spotify, strava, gmail, minimax, hello - network_watchdog.py: WiFi AP/client mode management - waveshare_epd_init.py: vendor driver stub
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
"""System-Plugin: CPU-Last, RAM, Uptime. Responsive."""
|
||||
import os, sys
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from plugins.base import Widget
|
||||
from palette import FG, INFO, OK, WARN, ALERT, measure, fit_font, is_small, is_wide, hbar, parse_thresholds, DEFAULT_THRESHOLDS
|
||||
|
||||
|
||||
def _read_loadavg():
|
||||
try:
|
||||
with open("/proc/loadavg") as f:
|
||||
parts = f.read().split()
|
||||
return float(parts[0])
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
|
||||
def _read_mem():
|
||||
try:
|
||||
with open("/proc/meminfo") as f:
|
||||
lines = f.readlines()
|
||||
total = int([l for l in lines if l.startswith("MemTotal")][0].split()[1])
|
||||
avail = int([l for l in lines if l.startswith("MemAvailable")][0].split()[1])
|
||||
return total, total - avail, avail
|
||||
except Exception:
|
||||
return 1, 0, 1
|
||||
|
||||
|
||||
def _read_uptime():
|
||||
try:
|
||||
with open("/proc/uptime") as f:
|
||||
return float(f.read().split()[0])
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
|
||||
def _fmt_uptime(s):
|
||||
days, rem = divmod(int(s), 86400)
|
||||
h, rem = divmod(rem, 3600)
|
||||
m = rem // 60
|
||||
if days: return f"{days}d {h}h"
|
||||
if h: return f"{h}h {m}m"
|
||||
return f"{m}m"
|
||||
|
||||
|
||||
def _system_stats():
|
||||
ncpu = os.cpu_count() or 1
|
||||
la = _read_loadavg()
|
||||
total, used, avail = _read_mem()
|
||||
return {
|
||||
"cpu_pct": min(int((la / ncpu) * 100), 100),
|
||||
"ram_used_mb": used // 1024,
|
||||
"ram_total_mb": total // 1024,
|
||||
"ram_pct": int(used * 100 / total) if total else 0,
|
||||
"uptime_s": _read_uptime(),
|
||||
}
|
||||
|
||||
|
||||
class Widget(Widget):
|
||||
name = "system"
|
||||
label = "System (CPU/RAM)"
|
||||
description = "Live CPU-Last, RAM-Auslastung, Uptime. Responsive Layout fuer 1x1 bis 4x4."
|
||||
category = "system"
|
||||
|
||||
config_schema = [
|
||||
{"key": "show_uptime", "label": "Uptime anzeigen", "type": "bool", "default": True},
|
||||
{"key": "show_load", "label": "Load Average anzeigen", "type": "bool", "default": True},
|
||||
{"key": "compact", "label": "Kompaktmodus (nur Prozent)", "type": "bool", "default": False},
|
||||
{"key": "bar_thresholds", "label": "CPU/RAM-Schwellen (Format: ok,warn,alert oder ok@50,warn@80,alert@95)",
|
||||
"type": "string", "default": "ok@50,warn@80,alert@95",
|
||||
"help": "Legt fest, ab wann eine Bar grün/gelb/rot wird. Mit '@P' setzt du die Schwelle in Prozent."},
|
||||
{"key": "bar_gradient", "label": "Verlaufsmodus (Balken zeigt alle Stufen gleichzeitig)",
|
||||
"type": "bool", "default": True,
|
||||
"help": "Wenn aus, ist die Bar einfarbig in der Farbe der aktuellen Schwelle."},
|
||||
]
|
||||
default_config = {"show_uptime": True, "show_load": True, "compact": False,
|
||||
"bar_thresholds": "ok@50,warn@80,alert@95", "bar_gradient": True}
|
||||
|
||||
def _bar_args(self):
|
||||
return (parse_thresholds(self.cfg("bar_thresholds")),
|
||||
bool(self.cfg("bar_gradient", True)))
|
||||
|
||||
def fetch(self):
|
||||
return _system_stats()
|
||||
|
||||
def render(self, draw, fonts, x, y, w, h):
|
||||
from palette import fill_for, measure
|
||||
pad = 8
|
||||
s = self.fetch()
|
||||
cpu, ram = s["cpu_pct"], s["ram_pct"]
|
||||
thresholds, gradient = self._bar_args()
|
||||
# Im compact/small mode bleiben die Fallback-Farben (Text-Label reicht)
|
||||
|
||||
if self.cfg("compact") or is_small(w, h):
|
||||
# mini/compact: nur CPU + RAM als 2 kleine bars
|
||||
label_font = fit_font(draw, "CPU", fonts, w - 2 * pad, 20)
|
||||
draw.text((x + pad, y + pad), "CPU", font=label_font, fill=FG)
|
||||
bar_y = y + pad + 22
|
||||
bar_w = w - 2 * pad
|
||||
bar_h = max(8, (h - 30) // 4)
|
||||
hbar(draw, x + pad, bar_y, bar_w, bar_h, cpu,
|
||||
thresholds=thresholds, gradient=gradient)
|
||||
ram_y = bar_y + bar_h + 6
|
||||
draw.text((x + pad, ram_y), "RAM", font=label_font, fill=FG)
|
||||
hbar(draw, x + pad, ram_y + 22, bar_w, bar_h, ram,
|
||||
thresholds=thresholds, gradient=gradient)
|
||||
return
|
||||
|
||||
if is_wide(w, h):
|
||||
# Wide strip: CPU% | RAM% | Uptime (each third)
|
||||
col_w = w // 3
|
||||
for i, (label, pct) in enumerate([
|
||||
("CPU", cpu), ("RAM", ram),
|
||||
]):
|
||||
cx = x + i * col_w
|
||||
# Color = passende Schwelle
|
||||
col_color = WARN
|
||||
if thresholds:
|
||||
for max_p, c in thresholds:
|
||||
if pct <= max_p:
|
||||
col_color = c; break
|
||||
label_font = fit_font(draw, label, fonts, col_w - 2 * pad, 22)
|
||||
draw.text((cx + pad, y + pad), f"{label} {pct}%",
|
||||
font=label_font, fill=col_color)
|
||||
if self.cfg("show_uptime"):
|
||||
up_str = "up " + _fmt_uptime(s["uptime_s"])
|
||||
font_up = fit_font(draw, up_str, fonts, col_w - 2 * pad, 22)
|
||||
draw.text((x + 2 * col_w + pad, y + pad), up_str, font=font_up, fill=INFO)
|
||||
return
|
||||
|
||||
# Standard: Header, CPU-Bar, RAM-Bar, Uptime
|
||||
header_font = fonts.get("28") or fonts.get("24")
|
||||
draw.text((x + pad, y + pad), "SYSTEM", font=header_font, fill=INFO)
|
||||
|
||||
# Big numbers + bars
|
||||
cur_y = y + 40
|
||||
# CPU row
|
||||
text = f"CPU: {cpu}%"
|
||||
draw.text((x + pad, cur_y), text, font=fonts.get("32", fonts.get("24")), fill=FG)
|
||||
bar_y = cur_y + 36
|
||||
bar_h = 28
|
||||
hbar(draw, x + pad, bar_y, w - 2 * pad, bar_h, cpu,
|
||||
thresholds=thresholds, gradient=gradient)
|
||||
|
||||
# RAM row
|
||||
cur_y = bar_y + bar_h + 12
|
||||
text = f"RAM: {s['ram_used_mb']}/{s['ram_total_mb']} MB ({ram}%)"
|
||||
font_text = fit_font(draw, text, fonts, w - 2 * pad, 28)
|
||||
draw.text((x + pad, cur_y), text, font=font_text, fill=FG)
|
||||
bar_y2 = cur_y + 30
|
||||
hbar(draw, x + pad, bar_y2, w - 2 * pad, bar_h, ram,
|
||||
thresholds=thresholds, gradient=gradient)
|
||||
|
||||
# Bottom: load + uptime
|
||||
bottom_y = bar_y2 + bar_h + 8
|
||||
if self.cfg("show_load") or self.cfg("show_uptime"):
|
||||
parts = []
|
||||
if self.cfg("show_load"):
|
||||
parts.append(f"load {s['cpu_pct']/100.0 * (os.cpu_count() or 1):.2f}")
|
||||
if self.cfg("show_uptime"):
|
||||
parts.append("up " + _fmt_uptime(s["uptime_s"]))
|
||||
line = " · ".join(parts)
|
||||
font_bot = fit_font(draw, line, fonts, w - 2 * pad, 22)
|
||||
draw.text((x + pad, bottom_y), line, font=font_bot, fill=FG)
|
||||
Reference in New Issue
Block a user