Data source: /opt/sysmetrics/sysmetrics.py for Sentinel
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
import json, time, os, psutil, subprocess, platform
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
data = {
"cpu_percent": psutil.cpu_percent(interval=0.1),
"ram_used": psutil.virtual_memory().used,
"ram_total": psutil.virtual_memory().total,
"disk_used": psutil.disk_usage('/').used,
"disk_total": psutil.disk_usage('/').total,
"uptime": time.time() - psutil.boot_time(),
"load_avg": os.getloadavg(),
"net_io": psutil.net_io_counters()._asdict(),
"temps": self.clean_temps(),
"gpu": self.get_gpu_stats(),
"specs": self.get_specs()
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET")
self.end_headers()
self.wfile.write(json.dumps(data).encode())
def get_specs(self):
specs = {
"cpu": self.get_cpu_model(),
"ram_gb": round(psutil.virtual_memory().total / (1024**3)),
"os": platform.system(),
"gpu": self.get_gpu_model()
}
return specs
def get_cpu_model(self):
try:
with open('/proc/cpuinfo', 'r') as f:
lines = f.readlines()
for line in lines:
if 'model name' in line.lower():
return line.split(':')[1].strip()
for line in lines:
if 'Model' in line and 'Raspberry Pi' in line:
model = line.split(':')[1].strip()
try:
import subprocess
result = subprocess.run(['lscpu'], capture_output=True, text=True)
for lscpu_line in result.stdout.split('\n'):
if 'Model name' in lscpu_line:
core = lscpu_line.split(':')[1].strip()
return f"{model} ({core})"
except:
pass
return model
except:
pass
return "Unknown CPU"
def get_gpu_model(self):
try:
result = subprocess.run(
['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
capture_output=True, text=True, timeout=2
)
if result.returncode == 0:
return result.stdout.strip()
except:
pass
return None
def get_gpu_stats(self):
return None
def clean_temps(self):
raw_temps = psutil.sensors_temperatures() if hasattr(psutil, "sensors_temperatures") else {}
cleaned = {}
for sensor, readings in raw_temps.items():
for reading in readings:
label = reading[0] or sensor
temp = reading[1]
friendly_name = label
if sensor not in cleaned:
cleaned[sensor] = []
cleaned[sensor].append([friendly_name, temp, reading[2], reading[3]])
return cleaned
server = HTTPServer(("0.0.0.0", 9000), Handler)
server.serve_forever()
Data source: /opt/sysmetrics/sysmetrics.py for Server, Hyperion, Legacy
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
import json, time, os, psutil, subprocess, platform
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
data = {
"cpu_percent": psutil.cpu_percent(interval=0.1),
"ram_used": psutil.virtual_memory().used,
"ram_total": psutil.virtual_memory().total,
"disk_used": psutil.disk_usage('/').used,
"disk_total": psutil.disk_usage('/').total,
"uptime": time.time() - psutil.boot_time(),
"load_avg": os.getloadavg(),
"net_io": psutil.net_io_counters()._asdict(),
"temps": self.clean_temps(),
"gpu": self.get_gpu_stats(),
"specs": self.get_specs()
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET")
self.end_headers()
self.wfile.write(json.dumps(data).encode())
def get_specs(self):
specs = {
"cpu": self.get_cpu_model(),
"ram_gb": round(psutil.virtual_memory().total / (1024**3)),
"os": platform.system(),
"gpu": self.get_gpu_model()
}
return specs
def get_cpu_model(self):
try:
with open('/proc/cpuinfo', 'r') as f:
for line in f:
if 'model name' in line:
return line.split(':')[1].strip()
except:
pass
return "Unknown CPU"
def get_gpu_model(self):
try:
result = subprocess.run(
['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
capture_output=True, text=True, timeout=2
)
if result.returncode == 0:
return result.stdout.strip()
except:
pass
return None
def get_gpu_stats(self):
try:
result = subprocess.run(
['nvidia-smi', '--query-gpu=utilization.gpu,memory.used,memory.total,temperature.gpu,fan.speed',
'--format=csv,noheader,nounits'],
capture_output=True, text=True, timeout=2
)
if result.returncode == 0:
parts = result.stdout.strip().split(',')
return {
"util": float(parts[0].strip()),
"mem_used": float(parts[1].strip()) * 1024 * 1024,
"mem_total": float(parts[2].strip()) * 1024 * 1024,
"temp": float(parts[3].strip()),
"fan": float(parts[4].strip()) if parts[4].strip() != '[N/A]' else 0
}
except Exception:
pass
return None
def clean_temps(self):
raw_temps = psutil.sensors_temperatures() if hasattr(psutil, "sensors_temperatures") else {}
cleaned = {}
dimm_counter = 0
for sensor, readings in raw_temps.items():
for reading in readings:
label = reading[0] or sensor
temp = reading[1]
friendly_name = label
if sensor == 'coretemp':
if 'Package' in label:
friendly_name = 'CPU Package'
elif 'Core' in label:
continue
else:
continue
elif 'r8169' in sensor:
friendly_name = 'Network Controller'
elif sensor == 'nvme':
if 'Composite' in label:
friendly_name = 'NVMe Controller'
elif 'Sensor 2' in label:
friendly_name = 'NVMe NAND'
elif 'Sensor 1' in label:
continue
elif sensor == 'acpitz':
friendly_name = 'Motherboard'
elif sensor == 'spd5118':
dimm_counter += 1
friendly_name = f'RAM DIMM {dimm_counter}'
elif sensor == 'k10temp':
if 'Tctl' in label:
friendly_name = 'CPU Package'
elif 'Tccd1' in label:
friendly_name = 'CPU CCD1'
elif 'Tccd2' in label:
friendly_name = 'CPU CCD2'
elif sensor == 'jc42':
dimm_counter += 1
friendly_name = f'RAM DIMM {dimm_counter}'
if sensor not in cleaned:
cleaned[sensor] = []
cleaned[sensor].append([friendly_name, temp, reading[2], reading[3]])
return cleaned
server = HTTPServer(("0.0.0.0", 9000), Handler)
server.serve_forever()