Add live Windows Gaming PC stats with metric bars
- New API /api/windows/stats: SSHes into gamingpc, runs PowerShell for CPU/RAM/Disk/Uptime - Live metric bars on the Windows PC card (CPU/RAM/C:) updating every 30s - Duplicate barColor() removed
This commit is contained in:
@@ -241,6 +241,49 @@ async def docker_stats():
|
||||
return {"error": str(e)[:200], "containers": []}
|
||||
|
||||
|
||||
@app.get("/api/windows/stats")
|
||||
async def windows_stats():
|
||||
"""Get live stats from Windows Gaming PC via PowerShell over SSH."""
|
||||
import subprocess, base64, json as _json
|
||||
|
||||
# PowerShell script: backslash counter paths need single \, Python raw string preserves them
|
||||
ps_script = r'''
|
||||
$cpu=(Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples[0].CookedValue
|
||||
$os=Get-CimInstance Win32_OperatingSystem
|
||||
$disk=Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='C:'"
|
||||
$uptime=(Get-Date)-$os.LastBootUpTime
|
||||
@{
|
||||
'cpu'=[math]::Round($cpu,1)
|
||||
'mem_total_gb'=[math]::Round($os.TotalVisibleMemorySize/1MB,1)
|
||||
'mem_free_gb'=[math]::Round($os.FreePhysicalMemory/1MB,1)
|
||||
'disk_c_total_gb'=[math]::Round($disk.Size/1GB,1)
|
||||
'disk_c_free_gb'=[math]::Round($disk.FreeSpace/1GB,1)
|
||||
'uptime_days'=[math]::Round($uptime.TotalDays,1)
|
||||
} | ConvertTo-Json
|
||||
'''.strip()
|
||||
|
||||
try:
|
||||
encoded = base64.b64encode(ps_script.encode('utf-16le')).decode()
|
||||
result = subprocess.run(
|
||||
["ssh", "gamingpc",
|
||||
"powershell", "-NoProfile", "-EncodedCommand", encoded],
|
||||
capture_output=True, text=True, timeout=30
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return {"error": result.stderr.strip()[:300], "online": False}
|
||||
|
||||
# Filter CLIXML noise from stdout
|
||||
clean = "\n".join(l for l in result.stdout.split("\n")
|
||||
if l.strip() and not l.startswith("#<") and not l.startswith("<"))
|
||||
data = _json.loads(clean)
|
||||
data["online"] = True
|
||||
data["mem_used_gb"] = round(data["mem_total_gb"] - data["mem_free_gb"], 1)
|
||||
data["disk_c_used_gb"] = round(data["disk_c_total_gb"] - data["disk_c_free_gb"], 1)
|
||||
return data
|
||||
except Exception as e:
|
||||
return {"error": str(e)[:300], "online": False}
|
||||
|
||||
|
||||
@app.get("/{path:path}")
|
||||
async def index(path: str = ""):
|
||||
"""Serve static files, fallback to index.html."""
|
||||
|
||||
Reference in New Issue
Block a user