aboutsummaryrefslogtreecommitdiffstats
path: root/modules/desktop/eww/system-stats.py
diff options
context:
space:
mode:
authorArpit Chakladar <arpitchakladar+git@gmail.com>2026-08-27 01:55:13 +0530
committerArpit Chakladar <arpitchakladar+git@gmail.com>2026-08-29 03:50:30 +0530
commit9a6f21b65da927fb064773bd83e92151c50b6823 (patch)
tree897de5d11ba347529e0f16fe554eac0d5d908fd1 /modules/desktop/eww/system-stats.py
parentf3407d3d21c29eb4a59732d02f8f309b113fa480 (diff)
downloadhome-manager-config-9a6f21b65da927fb064773bd83e92151c50b6823.tar.gz
home-manager-config-9a6f21b65da927fb064773bd83e92151c50b6823.zip
desktop: added some of basic system information in the system section
- added date, time, memory used (percent), cpu usage (percent), network status (icons for up or down)
Diffstat (limited to 'modules/desktop/eww/system-stats.py')
-rw-r--r--modules/desktop/eww/system-stats.py91
1 files changed, 91 insertions, 0 deletions
diff --git a/modules/desktop/eww/system-stats.py b/modules/desktop/eww/system-stats.py
new file mode 100644
index 0000000..380dc25
--- /dev/null
+++ b/modules/desktop/eww/system-stats.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+"""system-stats: emit {cpu, ram, net} as JSON. CPU/RAM sample on an interval
+inside one long-lived process (no per-tick spawn)"""
+import json
+import subprocess
+import threading
+import time
+
+STATE_LOCK = threading.Lock()
+STATE = {"cpu": 0, "ram": 0, "net": "down"}
+
+
+def read_cpu_times():
+ with open("/proc/stat") as f:
+ parts = f.readline().split()[1:]
+ vals = list(map(int, parts))
+ idle = vals[3] + vals[4] # idle + iowait
+ total = sum(vals)
+ return idle, total
+
+
+def cpu_ram_loop(interval=2.0):
+ prev_idle, prev_total = read_cpu_times()
+ while True:
+ time.sleep(interval)
+ idle, total = read_cpu_times()
+ d_idle = idle - prev_idle
+ d_total = total - prev_total
+ prev_idle, prev_total = idle, total
+ cpu_pct = round((1 - d_idle / d_total) * 100) if d_total else 0
+
+ with open("/proc/meminfo") as f:
+ meminfo = {}
+ for line in f:
+ k, v, *_ = line.split()
+ meminfo[k.rstrip(":")] = int(v)
+ total_kb = meminfo["MemTotal"]
+ avail_kb = meminfo["MemAvailable"]
+ ram_pct = round((1 - avail_kb / total_kb) * 100) if total_kb else 0
+
+ with STATE_LOCK:
+ STATE["cpu"] = cpu_pct
+ STATE["ram"] = ram_pct
+ emit()
+
+
+def check_net_status() -> str:
+ try:
+ with open("/run/systemd/netif/state") as f:
+ state = dict(
+ line.strip().split("=", 1) for line in f if "=" in line
+ )
+ except FileNotFoundError:
+ return "down"
+
+ oper = state.get("OPER_STATE", "off")
+ if oper == "routable":
+ return "up"
+ if oper in ("degraded", "carrier", "degraded-carrier"):
+ return "limited"
+ return "down"
+
+
+def net_loop():
+ with STATE_LOCK:
+ STATE["net"] = check_net_status()
+ emit()
+
+ proc = subprocess.Popen(
+ ["inotifywait", "-m", "-e", "modify", "/run/systemd/netif/state"],
+ stdout=subprocess.PIPE, text=True, bufsize=1,
+ )
+ for _ in proc.stdout:
+ with STATE_LOCK:
+ STATE["net"] = check_net_status()
+ emit()
+
+
+def emit():
+ with STATE_LOCK:
+ print(json.dumps(STATE), flush=True)
+
+
+def main():
+ threading.Thread(target=cpu_ram_loop, daemon=True).start()
+ threading.Thread(target=net_loop, daemon=True).start()
+ threading.Event().wait() # keep main thread alive
+
+
+if __name__ == "__main__":
+ main()