Admin angepasst
This commit is contained in:
+176
-12
@@ -154,38 +154,156 @@
|
|||||||
<span class="p-lbl">Systemstatus</span>
|
<span class="p-lbl">Systemstatus</span>
|
||||||
<span class="p-tag">Telemetry</span>
|
<span class="p-tag">Telemetry</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="systemstatus-grid">
|
||||||
|
<div class="systemstatus-section">
|
||||||
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">Netzwerk</span><div class="ss-hdr-line"></div></div>
|
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">Netzwerk</span><div class="ss-hdr-line"></div></div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-ok"></span>
|
<span class="sr-led led-ok"></span>
|
||||||
<span class="sr-key">WLAN</span>
|
<span class="sr-key">WLAN</span>
|
||||||
<span class="sr-val" id="info_wifi">-</span>
|
<span class="sr-val" id="info_wifi">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">SSID</span>
|
||||||
|
<span class="sr-val" id="info_wifi_ssid">-</span>
|
||||||
|
</div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-blue"></span>
|
<span class="sr-led led-blue"></span>
|
||||||
<span class="sr-key">Signal</span>
|
<span class="sr-key">Signal</span>
|
||||||
<span class="sr-val" id="info_wifi_signal">-</span>
|
<span class="sr-val" id="info_wifi_signal">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Signal dBm</span>
|
||||||
|
<span class="sr-val" id="info_wifi_signal_dbm">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Kanal</span>
|
||||||
|
<span class="sr-val" id="info_wifi_channel">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Frequenz</span>
|
||||||
|
<span class="sr-val" id="info_wifi_frequency">-</span>
|
||||||
|
</div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-blue"></span>
|
<span class="sr-led led-blue"></span>
|
||||||
<span class="sr-key">IP</span>
|
<span class="sr-key">IP</span>
|
||||||
<span class="sr-val" id="info_ips">-</span>
|
<span class="sr-val" id="info_ips">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="systemstatus-section">
|
||||||
|
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">System</span><div class="ss-hdr-line"></div></div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Pi-Modell</span>
|
||||||
|
<span class="sr-val" id="info_pi_model">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Hostname</span>
|
||||||
|
<span class="sr-val" id="info_hostname">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Kernel</span>
|
||||||
|
<span class="sr-val" id="info_kernel">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Pi-Zeit</span>
|
||||||
|
<span class="sr-val" id="info_system_time">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Zeitzone</span>
|
||||||
|
<span class="sr-val" id="info_system_timezone">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Zeit-Sync</span>
|
||||||
|
<span class="sr-val" id="info_time_sync">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="systemstatus-section">
|
||||||
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">Hardware</span><div class="ss-hdr-line"></div></div>
|
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">Hardware</span><div class="ss-hdr-line"></div></div>
|
||||||
<div class="sr sr-gauge gauge-temp">
|
<div class="sr sr-gauge gauge-temp">
|
||||||
<span class="sr-key">Temp</span>
|
<span class="sr-key">Temp</span>
|
||||||
<div class="gauge"><div class="gauge-fill" id="bar-temp-adm"></div></div>
|
<div class="gauge"><div class="gauge-fill" id="bar-temp-adm"></div></div>
|
||||||
<span class="gauge-num" id="info_temp">--</span>
|
<span class="gauge-num" id="info_temp">--</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">GPU-/SoC-Temp</span>
|
||||||
|
<span class="sr-val" id="info_gpu_temp">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">CPU gesamt</span>
|
||||||
|
<span class="sr-val" id="info_cpu_usage">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">CPU Kerne</span>
|
||||||
|
<span class="sr-val" id="info_cpu_per_core">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">RAM</span>
|
||||||
|
<span class="sr-val" id="info_memory_details">-</span>
|
||||||
|
</div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-off"></span>
|
<span class="sr-led led-off"></span>
|
||||||
<span class="sr-key">Spannung</span>
|
<span class="sr-key">Spannung</span>
|
||||||
<span class="sr-val" id="info_undervoltage">-</span>
|
<span class="sr-val" id="info_undervoltage">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Throttling</span>
|
||||||
|
<span class="sr-val" id="info_throttling">-</span>
|
||||||
|
</div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-blue"></span>
|
<span class="sr-led led-blue"></span>
|
||||||
<span class="sr-key">Uptime</span>
|
<span class="sr-key">Uptime</span>
|
||||||
<span class="sr-val" id="info_uptime">-</span>
|
<span class="sr-val" id="info_uptime">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Load 1/5/15</span>
|
||||||
|
<span class="sr-val" id="info_load_average">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="systemstatus-section">
|
||||||
|
<div class="ss-hdr"><div class="ss-hdr-line"></div><span class="ss-hdr-txt">Speicher & Container</span><div class="ss-hdr-line"></div></div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Root-Dateisystem</span>
|
||||||
|
<span class="sr-val" id="info_disk_root">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Docker-Speicher</span>
|
||||||
|
<span class="sr-val" id="info_disk_docker">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Inodes frei</span>
|
||||||
|
<span class="sr-val" id="info_inode_free">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Container-Uptime</span>
|
||||||
|
<span class="sr-val" id="info_container_uptime">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="sr">
|
||||||
|
<span class="sr-led led-blue"></span>
|
||||||
|
<span class="sr-key">Container-Restarts</span>
|
||||||
|
<span class="sr-val" id="info_container_restarts">-</span>
|
||||||
|
</div>
|
||||||
<div class="sr">
|
<div class="sr">
|
||||||
<span class="sr-led led-blue"></span>
|
<span class="sr-led led-blue"></span>
|
||||||
<span class="sr-key">Disk frei</span>
|
<span class="sr-key">Disk frei</span>
|
||||||
@@ -194,6 +312,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="admin_panel_camera" class="admin-section-panel" role="tabpanel">
|
<section id="admin_panel_camera" class="admin-section-panel" role="tabpanel">
|
||||||
@@ -784,10 +904,31 @@
|
|||||||
function clearAdminApiDisplay() {
|
function clearAdminApiDisplay() {
|
||||||
setText('info_ips', '--');
|
setText('info_ips', '--');
|
||||||
setText('info_wifi', '--');
|
setText('info_wifi', '--');
|
||||||
|
setText('info_wifi_ssid', '--');
|
||||||
setText('info_wifi_signal', '--');
|
setText('info_wifi_signal', '--');
|
||||||
|
setText('info_wifi_signal_dbm', '--');
|
||||||
|
setText('info_wifi_channel', '--');
|
||||||
|
setText('info_wifi_frequency', '--');
|
||||||
|
setText('info_pi_model', '--');
|
||||||
|
setText('info_hostname', '--');
|
||||||
|
setText('info_kernel', '--');
|
||||||
|
setText('info_system_time', '--');
|
||||||
|
setText('info_system_timezone', '--');
|
||||||
|
setText('info_time_sync', '--');
|
||||||
setText('info_temp', '--');
|
setText('info_temp', '--');
|
||||||
|
setText('info_gpu_temp', '--');
|
||||||
|
setText('info_cpu_usage', '--');
|
||||||
|
setText('info_cpu_per_core', '--');
|
||||||
|
setText('info_memory_details', '--');
|
||||||
setText('info_uptime', '--');
|
setText('info_uptime', '--');
|
||||||
setText('info_disk', '--');
|
setText('info_disk', '--');
|
||||||
|
setText('info_disk_root', '--');
|
||||||
|
setText('info_disk_docker', '--');
|
||||||
|
setText('info_inode_free', '--');
|
||||||
|
setText('info_load_average', '--');
|
||||||
|
setText('info_throttling', '--');
|
||||||
|
setText('info_container_uptime', '--');
|
||||||
|
setText('info_container_restarts', '--');
|
||||||
setUndervoltageState('info_undervoltage', '--', 'unknown');
|
setUndervoltageState('info_undervoltage', '--', 'unknown');
|
||||||
setServiceState('service_camera', '-');
|
setServiceState('service_camera', '-');
|
||||||
setServiceState('camera_service_state', '-');
|
setServiceState('camera_service_state', '-');
|
||||||
@@ -2285,20 +2426,43 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderStatus(data) {
|
function renderStatus(data) {
|
||||||
|
var system = data.system || {};
|
||||||
|
var services = data.services || {};
|
||||||
setAdminStatus(data.status || 'Bereit');
|
setAdminStatus(data.status || 'Bereit');
|
||||||
setText('info_ips', data.system && data.system.ips);
|
setText('info_ips', system.ips);
|
||||||
setText('info_wifi', data.system && data.system.wifi);
|
setText('info_wifi', system.wifi);
|
||||||
setText('info_wifi_signal', data.system && data.system.wifi_signal);
|
setText('info_wifi_ssid', system.wifi_ssid);
|
||||||
setText('info_temp', data.system && data.system.cpu_temperature);
|
setText('info_wifi_signal', system.wifi_signal);
|
||||||
|
setText('info_wifi_signal_dbm', system.wifi_signal_dbm);
|
||||||
|
setText('info_wifi_channel', system.wifi_channel);
|
||||||
|
setText('info_wifi_frequency', system.wifi_frequency);
|
||||||
|
setText('info_pi_model', system.pi_model);
|
||||||
|
setText('info_hostname', system.hostname);
|
||||||
|
setText('info_kernel', system.kernel_version);
|
||||||
|
setText('info_system_time', system.system_time);
|
||||||
|
setText('info_system_timezone', system.system_timezone);
|
||||||
|
setText('info_time_sync', 'NTP: ' + (system.ntp_sync || '--') + ' | Uhr: ' + (system.clock_sync || '--'));
|
||||||
|
setText('info_temp', system.cpu_temperature);
|
||||||
|
setText('info_gpu_temp', system.gpu_temperature);
|
||||||
|
setText('info_cpu_usage', system.cpu_usage);
|
||||||
|
setText('info_cpu_per_core', system.cpu_usage_per_core);
|
||||||
|
setText('info_memory_details', system.memory_details || system.memory_usage);
|
||||||
var bar = document.getElementById('bar-temp-adm');
|
var bar = document.getElementById('bar-temp-adm');
|
||||||
if (bar && data.system) bar.style.width = temperatureToWidth(data.system.cpu_temperature);
|
if (bar) bar.style.width = temperatureToWidth(system.cpu_temperature);
|
||||||
setUndervoltageState('info_undervoltage', data.system && data.system.undervoltage, data.system && data.system.undervoltage_state);
|
setUndervoltageState('info_undervoltage', system.undervoltage, system.undervoltage_state);
|
||||||
setText('info_uptime', data.system && data.system.uptime);
|
setText('info_throttling', system.throttling_details);
|
||||||
setText('info_disk', data.system && data.system.disk_free);
|
setText('info_uptime', system.uptime);
|
||||||
setServiceState('service_camera', data.services && data.services.camera);
|
setText('info_load_average', system.load_average);
|
||||||
setServiceState('camera_service_state', data.services && data.services.camera);
|
setText('info_disk', system.disk_free);
|
||||||
setServiceState('service_admin_api', data.services && data.services.admin_api);
|
setText('info_disk_root', system.disk_root);
|
||||||
setServiceState('service_exomy', data.services && data.services.exomy);
|
setText('info_disk_docker', system.disk_docker);
|
||||||
|
setText('info_inode_free', system.inode_free);
|
||||||
|
setText('info_container_uptime', services.exomy_uptime);
|
||||||
|
setText('info_container_restarts', services.exomy_restarts);
|
||||||
|
setServiceState('service_camera', services.camera);
|
||||||
|
setServiceState('camera_service_state', services.camera);
|
||||||
|
setServiceState('service_admin_api', services.admin_api);
|
||||||
|
setServiceState('service_exomy', services.exomy);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchStatus() {
|
async function fetchStatus() {
|
||||||
|
|||||||
+19
@@ -975,6 +975,24 @@ body.page-admin .ss-hdr{
|
|||||||
}
|
}
|
||||||
body.page-admin .ss-hdr-line{ flex:1; height:1px; background:repeating-linear-gradient(90deg, rgba(0,255,145,.22) 0, rgba(0,255,145,.22) 3px, transparent 3px, transparent 6px); }
|
body.page-admin .ss-hdr-line{ flex:1; height:1px; background:repeating-linear-gradient(90deg, rgba(0,255,145,.22) 0, rgba(0,255,145,.22) 3px, transparent 3px, transparent 6px); }
|
||||||
body.page-admin .ss-hdr-txt{ font-size:7px; letter-spacing:4px; color:rgba(210,255,235,.9); text-transform:uppercase; }
|
body.page-admin .ss-hdr-txt{ font-size:7px; letter-spacing:4px; color:rgba(210,255,235,.9); text-transform:uppercase; }
|
||||||
|
body.page-admin .systemstatus-grid{
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns:repeat(2, minmax(0, 1fr));
|
||||||
|
gap:12px;
|
||||||
|
padding:12px;
|
||||||
|
}
|
||||||
|
body.page-admin .systemstatus-section{
|
||||||
|
min-width:0;
|
||||||
|
border:1px solid rgba(0,255,145,.08);
|
||||||
|
background:rgba(0,255,145,.025);
|
||||||
|
}
|
||||||
|
body.page-admin .systemstatus-section .ss-hdr{
|
||||||
|
margin:0;
|
||||||
|
border-top:none;
|
||||||
|
}
|
||||||
|
body.page-admin .systemstatus-section .sr:last-child{
|
||||||
|
border-bottom:none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── GAUGE ──────────────────────────────────────── */
|
/* ── GAUGE ──────────────────────────────────────── */
|
||||||
body.page-admin .sr-gauge{ padding-bottom:6px; }
|
body.page-admin .sr-gauge{ padding-bottom:6px; }
|
||||||
@@ -1595,6 +1613,7 @@ body.page-admin .leaflet-popup-tip{
|
|||||||
body.page-admin .drive-estimator-value{ font-size:28px; }
|
body.page-admin .drive-estimator-value{ font-size:28px; }
|
||||||
body.page-admin .drive-calibration-toolbar{ flex-direction:column; align-items:stretch; }
|
body.page-admin .drive-calibration-toolbar{ flex-direction:column; align-items:stretch; }
|
||||||
body.page-admin .drive-calibration-grid{ grid-template-columns:1fr; }
|
body.page-admin .drive-calibration-grid{ grid-template-columns:1fr; }
|
||||||
|
body.page-admin .systemstatus-grid{ grid-template-columns:1fr; }
|
||||||
body.page-admin .admin-section-grid_map{ grid-template-columns:1fr; }
|
body.page-admin .admin-section-grid_map{ grid-template-columns:1fr; }
|
||||||
body.page-admin .admin-section-grid_gps{ grid-template-columns:1fr; }
|
body.page-admin .admin-section-grid_gps{ grid-template-columns:1fr; }
|
||||||
body.page-admin .map-panel{ min-height:0; }
|
body.page-admin .map-panel{ min-height:0; }
|
||||||
|
|||||||
+276
-17
@@ -7,6 +7,7 @@ import http.server
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import socket
|
||||||
import socketserver
|
import socketserver
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -85,6 +86,14 @@ def read_cpu_temperature():
|
|||||||
return 'unbekannt'
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def read_gpu_temperature():
|
||||||
|
stdout, _, returncode = run_command(['vcgencmd', 'measure_temp'])
|
||||||
|
if returncode != 0 or not stdout or '=' not in stdout:
|
||||||
|
return 'unbekannt'
|
||||||
|
value = stdout.split('=', 1)[1].strip().replace("'C", ' °C')
|
||||||
|
return value or 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
def read_cpu_usage():
|
def read_cpu_usage():
|
||||||
try:
|
try:
|
||||||
with open('/proc/stat', 'r', encoding='utf-8') as handle:
|
with open('/proc/stat', 'r', encoding='utf-8') as handle:
|
||||||
@@ -108,6 +117,41 @@ def read_cpu_usage():
|
|||||||
return 'unbekannt'
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def read_per_core_usage():
|
||||||
|
try:
|
||||||
|
with open('/proc/stat', 'r', encoding='utf-8') as handle:
|
||||||
|
first_lines = [line.split() for line in handle if line.startswith('cpu') and line[3:4].isdigit()]
|
||||||
|
time.sleep(0.12)
|
||||||
|
with open('/proc/stat', 'r', encoding='utf-8') as handle:
|
||||||
|
second_lines = [line.split() for line in handle if line.startswith('cpu') and line[3:4].isdigit()]
|
||||||
|
except (FileNotFoundError, ValueError):
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
if len(first_lines) != len(second_lines) or not first_lines:
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for first, second in zip(first_lines, second_lines):
|
||||||
|
try:
|
||||||
|
name = first[0]
|
||||||
|
first_values = [int(value) for value in first[1:]]
|
||||||
|
second_values = [int(value) for value in second[1:]]
|
||||||
|
idle_first = first_values[3] + first_values[4]
|
||||||
|
idle_second = second_values[3] + second_values[4]
|
||||||
|
total_first = sum(first_values)
|
||||||
|
total_second = sum(second_values)
|
||||||
|
total_delta = total_second - total_first
|
||||||
|
idle_delta = idle_second - idle_first
|
||||||
|
if total_delta <= 0:
|
||||||
|
continue
|
||||||
|
usage = (1 - (idle_delta / total_delta)) * 100
|
||||||
|
results.append(f'{name.upper()}: {usage:.0f}%')
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
return ' | '.join(results) if results else 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
def read_memory_usage():
|
def read_memory_usage():
|
||||||
try:
|
try:
|
||||||
values = {}
|
values = {}
|
||||||
@@ -126,6 +170,27 @@ def read_memory_usage():
|
|||||||
return 'unbekannt'
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def read_memory_details():
|
||||||
|
try:
|
||||||
|
values = {}
|
||||||
|
with open('/proc/meminfo', 'r', encoding='utf-8') as handle:
|
||||||
|
for line in handle:
|
||||||
|
key, raw_value = line.split(':', 1)
|
||||||
|
values[key] = int(raw_value.strip().split()[0])
|
||||||
|
total = values.get('MemTotal')
|
||||||
|
available = values.get('MemAvailable')
|
||||||
|
if not total or available is None:
|
||||||
|
return 'unbekannt'
|
||||||
|
used = total - available
|
||||||
|
total_mb = total / 1024
|
||||||
|
used_mb = used / 1024
|
||||||
|
free_mb = available / 1024
|
||||||
|
percent = (used / total) * 100
|
||||||
|
return f'{used_mb:.0f} MB belegt / {free_mb:.0f} MB frei / {total_mb:.0f} MB gesamt ({percent:.0f}%)'
|
||||||
|
except (FileNotFoundError, ValueError):
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
def read_undervoltage_status():
|
def read_undervoltage_status():
|
||||||
stdout, _, returncode = run_command(['vcgencmd', 'get_throttled'])
|
stdout, _, returncode = run_command(['vcgencmd', 'get_throttled'])
|
||||||
if returncode != 0 or not stdout or '=' not in stdout:
|
if returncode != 0 or not stdout or '=' not in stdout:
|
||||||
@@ -161,6 +226,32 @@ def read_undervoltage_status():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def read_throttling_details():
|
||||||
|
stdout, _, returncode = run_command(['vcgencmd', 'get_throttled'])
|
||||||
|
if returncode != 0 or not stdout or '=' not in stdout:
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
try:
|
||||||
|
throttled_value = int(stdout.split('=', 1)[1].strip(), 16)
|
||||||
|
except ValueError:
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
flags = [
|
||||||
|
(0x1, 'Unterspannung aktuell'),
|
||||||
|
(0x2, 'ARM gedrosselt aktuell'),
|
||||||
|
(0x4, 'aktuell limitiert'),
|
||||||
|
(0x8, 'Soft-Temperaturlimit aktuell'),
|
||||||
|
(0x10000, 'Unterspannung früher'),
|
||||||
|
(0x20000, 'ARM früher gedrosselt'),
|
||||||
|
(0x40000, 'früher limitiert'),
|
||||||
|
(0x80000, 'Soft-Temperaturlimit früher'),
|
||||||
|
]
|
||||||
|
active = [label for bitmask, label in flags if throttled_value & bitmask]
|
||||||
|
if not active:
|
||||||
|
return 'keine Auffälligkeiten'
|
||||||
|
return ' | '.join(active)
|
||||||
|
|
||||||
|
|
||||||
def format_uptime():
|
def format_uptime():
|
||||||
try:
|
try:
|
||||||
with open('/proc/uptime', 'r', encoding='utf-8') as handle:
|
with open('/proc/uptime', 'r', encoding='utf-8') as handle:
|
||||||
@@ -188,6 +279,39 @@ def format_disk_free():
|
|||||||
return f'{free_gb:.1f} GB frei / {total_gb:.1f} GB'
|
return f'{free_gb:.1f} GB frei / {total_gb:.1f} GB'
|
||||||
|
|
||||||
|
|
||||||
|
def format_path_disk_usage(path):
|
||||||
|
try:
|
||||||
|
usage = shutil.disk_usage(path)
|
||||||
|
free_gb = usage.free / (1024 ** 3)
|
||||||
|
used_gb = usage.used / (1024 ** 3)
|
||||||
|
total_gb = usage.total / (1024 ** 3)
|
||||||
|
return f'{used_gb:.1f} GB belegt / {free_gb:.1f} GB frei / {total_gb:.1f} GB'
|
||||||
|
except FileNotFoundError:
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def read_inode_free(path='/'):
|
||||||
|
try:
|
||||||
|
stats = os.statvfs(path)
|
||||||
|
total = stats.f_files
|
||||||
|
free = stats.f_ffree
|
||||||
|
used = total - free
|
||||||
|
if total <= 0:
|
||||||
|
return 'unbekannt'
|
||||||
|
percent_used = (used / total) * 100
|
||||||
|
return f'{free:,} frei / {total:,} gesamt ({percent_used:.0f}% belegt)'.replace(',', '.')
|
||||||
|
except OSError:
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def read_load_average():
|
||||||
|
try:
|
||||||
|
load_1, load_5, load_15 = os.getloadavg()
|
||||||
|
return f'{load_1:.2f} / {load_5:.2f} / {load_15:.2f}'
|
||||||
|
except (AttributeError, OSError):
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
def get_ip_addresses():
|
def get_ip_addresses():
|
||||||
stdout, _, returncode = run_command(['ip', '-4', '-o', 'addr', 'show', 'dev', 'wlan0', 'scope', 'global'])
|
stdout, _, returncode = run_command(['ip', '-4', '-o', 'addr', 'show', 'dev', 'wlan0', 'scope', 'global'])
|
||||||
if returncode == 0 and stdout:
|
if returncode == 0 and stdout:
|
||||||
@@ -235,29 +359,87 @@ def get_wifi_status():
|
|||||||
return 'kein wlan0'
|
return 'kein wlan0'
|
||||||
|
|
||||||
|
|
||||||
def get_wifi_signal():
|
def get_wifi_details():
|
||||||
stdout, _, returncode = run_command(['nmcli', '-t', '-f', 'GENERAL.STATE,AP.SIGNAL', 'device', 'show', 'wlan0'])
|
details = {
|
||||||
|
'ssid': 'unbekannt',
|
||||||
|
'signal_percent': 'unbekannt',
|
||||||
|
'signal_dbm': 'unbekannt',
|
||||||
|
'channel': 'unbekannt',
|
||||||
|
'frequency': 'unbekannt',
|
||||||
|
}
|
||||||
|
stdout, _, returncode = run_command(['nmcli', '-t', '-f', 'ACTIVE,SSID,SIGNAL,CHAN,FREQ,BARS', 'device', 'wifi', 'list', 'ifname', 'wlan0'])
|
||||||
if returncode != 0 or not stdout:
|
if returncode != 0 or not stdout:
|
||||||
return 'unbekannt'
|
return details
|
||||||
|
|
||||||
state = ''
|
|
||||||
signal = ''
|
|
||||||
for line in stdout.splitlines():
|
for line in stdout.splitlines():
|
||||||
if line.startswith('GENERAL.STATE:'):
|
if not line.startswith('yes:'):
|
||||||
state = line.split(':', 1)[1].strip()
|
continue
|
||||||
elif line.startswith('AP[1].SIGNAL:'):
|
parts = line.split(':')
|
||||||
signal = line.split(':', 1)[1].strip()
|
if len(parts) >= 6:
|
||||||
|
ssid = parts[1].strip()
|
||||||
if 'connected' not in state.lower():
|
signal = parts[2].strip()
|
||||||
return 'nicht verbunden'
|
channel = parts[3].strip()
|
||||||
if not signal:
|
frequency = parts[4].strip()
|
||||||
return 'unbekannt'
|
details['ssid'] = ssid or 'unbekannt'
|
||||||
|
details['signal_percent'] = f'{signal} %' if signal else 'unbekannt'
|
||||||
|
details['channel'] = channel or 'unbekannt'
|
||||||
|
details['frequency'] = frequency or 'unbekannt'
|
||||||
try:
|
try:
|
||||||
percent = max(0, min(100, int(float(signal))))
|
dbm = (int(float(signal)) / 2) - 100
|
||||||
|
details['signal_dbm'] = f'{dbm:.0f} dBm'
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
details['signal_dbm'] = 'unbekannt'
|
||||||
|
break
|
||||||
|
return details
|
||||||
|
|
||||||
|
|
||||||
|
def get_wifi_signal():
|
||||||
|
details = get_wifi_details()
|
||||||
|
return details['signal_percent']
|
||||||
|
|
||||||
|
|
||||||
|
def get_hostname():
|
||||||
|
try:
|
||||||
|
return socket.gethostname()
|
||||||
|
except Exception:
|
||||||
return 'unbekannt'
|
return 'unbekannt'
|
||||||
return f'{percent} %'
|
|
||||||
|
|
||||||
|
def get_kernel_version():
|
||||||
|
stdout, _, returncode = run_command(['uname', '-r'])
|
||||||
|
if returncode == 0 and stdout:
|
||||||
|
return stdout
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def get_pi_model():
|
||||||
|
try:
|
||||||
|
with open('/proc/device-tree/model', 'r', encoding='utf-8') as handle:
|
||||||
|
return handle.read().strip('\x00').strip() or 'unbekannt'
|
||||||
|
except (FileNotFoundError, ValueError):
|
||||||
|
return 'unbekannt'
|
||||||
|
|
||||||
|
|
||||||
|
def get_system_time_details():
|
||||||
|
local_time = datetime.datetime.now().astimezone()
|
||||||
|
timedatectl_stdout, _, timedatectl_returncode = run_command(['timedatectl', 'show', '-p', 'NTPSynchronized', '-p', 'SystemClockSynchronized', '-p', 'Timezone'])
|
||||||
|
ntp_sync = 'unbekannt'
|
||||||
|
clock_sync = 'unbekannt'
|
||||||
|
timezone_name = local_time.tzname() or 'unbekannt'
|
||||||
|
if timedatectl_returncode == 0 and timedatectl_stdout:
|
||||||
|
for line in timedatectl_stdout.splitlines():
|
||||||
|
if line.startswith('NTPSynchronized='):
|
||||||
|
ntp_sync = 'ja' if line.split('=', 1)[1].strip().lower() == 'yes' else 'nein'
|
||||||
|
elif line.startswith('SystemClockSynchronized='):
|
||||||
|
clock_sync = 'ja' if line.split('=', 1)[1].strip().lower() == 'yes' else 'nein'
|
||||||
|
elif line.startswith('Timezone='):
|
||||||
|
timezone_name = line.split('=', 1)[1].strip() or timezone_name
|
||||||
|
return {
|
||||||
|
'local': local_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
'timezone': timezone_name,
|
||||||
|
'ntp_sync': ntp_sync,
|
||||||
|
'clock_sync': clock_sync,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_systemd_state(service_name):
|
def get_systemd_state(service_name):
|
||||||
@@ -274,6 +456,59 @@ def get_container_state(container_name):
|
|||||||
return 'unknown'
|
return 'unknown'
|
||||||
|
|
||||||
|
|
||||||
|
def get_container_details(container_name):
|
||||||
|
stdout, _, returncode = run_command(['docker', 'inspect', container_name])
|
||||||
|
if returncode != 0 or not stdout:
|
||||||
|
return {
|
||||||
|
'uptime': 'unbekannt',
|
||||||
|
'restarts': 'unbekannt',
|
||||||
|
'docker_disk': 'unbekannt',
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = json.loads(stdout)
|
||||||
|
info = payload[0] if payload else {}
|
||||||
|
state = info.get('State', {})
|
||||||
|
started_at = state.get('StartedAt')
|
||||||
|
restart_count = info.get('RestartCount', state.get('RestartCount', 'unbekannt'))
|
||||||
|
uptime = 'unbekannt'
|
||||||
|
if started_at and started_at != '0001-01-01T00:00:00Z':
|
||||||
|
started = datetime.datetime.fromisoformat(started_at.replace('Z', '+00:00'))
|
||||||
|
delta = datetime.datetime.now(datetime.timezone.utc) - started
|
||||||
|
uptime = format_duration(int(delta.total_seconds()))
|
||||||
|
return {
|
||||||
|
'uptime': uptime,
|
||||||
|
'restarts': str(restart_count),
|
||||||
|
'docker_disk': get_docker_disk_usage(),
|
||||||
|
}
|
||||||
|
except (ValueError, KeyError, TypeError, IndexError):
|
||||||
|
return {
|
||||||
|
'uptime': 'unbekannt',
|
||||||
|
'restarts': 'unbekannt',
|
||||||
|
'docker_disk': 'unbekannt',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_docker_disk_usage():
|
||||||
|
stdout, _, returncode = run_command(['docker', 'info', '-f', '{{.DockerRootDir}}'])
|
||||||
|
if returncode != 0 or not stdout:
|
||||||
|
return 'unbekannt'
|
||||||
|
return format_path_disk_usage(stdout.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def format_duration(seconds):
|
||||||
|
days, remainder = divmod(max(0, int(seconds)), 86400)
|
||||||
|
hours, remainder = divmod(remainder, 3600)
|
||||||
|
minutes, _ = divmod(remainder, 60)
|
||||||
|
parts = []
|
||||||
|
if days:
|
||||||
|
parts.append(f'{days}d')
|
||||||
|
if days or hours:
|
||||||
|
parts.append(f'{hours}h')
|
||||||
|
parts.append(f'{minutes}m')
|
||||||
|
return ' '.join(parts)
|
||||||
|
|
||||||
|
|
||||||
def get_motor_test_container_status():
|
def get_motor_test_container_status():
|
||||||
state = get_container_state(EXOMY_CONTAINER)
|
state = get_container_state(EXOMY_CONTAINER)
|
||||||
return {
|
return {
|
||||||
@@ -285,25 +520,49 @@ def get_motor_test_container_status():
|
|||||||
|
|
||||||
def collect_status():
|
def collect_status():
|
||||||
undervoltage = read_undervoltage_status()
|
undervoltage = read_undervoltage_status()
|
||||||
|
wifi_details = get_wifi_details()
|
||||||
|
time_details = get_system_time_details()
|
||||||
|
container_details = get_container_details(EXOMY_CONTAINER)
|
||||||
return {
|
return {
|
||||||
'status': 'Bereit',
|
'status': 'Bereit',
|
||||||
'system': {
|
'system': {
|
||||||
'wifi': get_wifi_status(),
|
'wifi': get_wifi_status(),
|
||||||
'wifi_signal': get_wifi_signal(),
|
'wifi_signal': get_wifi_signal(),
|
||||||
|
'wifi_signal_dbm': wifi_details['signal_dbm'],
|
||||||
|
'wifi_ssid': wifi_details['ssid'],
|
||||||
|
'wifi_channel': wifi_details['channel'],
|
||||||
|
'wifi_frequency': wifi_details['frequency'],
|
||||||
'ips': get_ip_addresses(),
|
'ips': get_ip_addresses(),
|
||||||
'undervoltage': undervoltage['text'],
|
'undervoltage': undervoltage['text'],
|
||||||
'undervoltage_state': undervoltage['state'],
|
'undervoltage_state': undervoltage['state'],
|
||||||
|
'throttling_details': read_throttling_details(),
|
||||||
'cpu_temperature': read_cpu_temperature(),
|
'cpu_temperature': read_cpu_temperature(),
|
||||||
|
'gpu_temperature': read_gpu_temperature(),
|
||||||
'cpu_usage': read_cpu_usage(),
|
'cpu_usage': read_cpu_usage(),
|
||||||
|
'cpu_usage_per_core': read_per_core_usage(),
|
||||||
'memory_usage': read_memory_usage(),
|
'memory_usage': read_memory_usage(),
|
||||||
|
'memory_details': read_memory_details(),
|
||||||
'uptime': format_uptime(),
|
'uptime': format_uptime(),
|
||||||
'disk_free': format_disk_free(),
|
'disk_free': format_disk_free(),
|
||||||
|
'disk_root': format_path_disk_usage('/'),
|
||||||
|
'disk_docker': container_details['docker_disk'],
|
||||||
|
'inode_free': read_inode_free('/'),
|
||||||
|
'load_average': read_load_average(),
|
||||||
|
'hostname': get_hostname(),
|
||||||
|
'kernel_version': get_kernel_version(),
|
||||||
|
'pi_model': get_pi_model(),
|
||||||
|
'system_time': time_details['local'],
|
||||||
|
'system_timezone': time_details['timezone'],
|
||||||
|
'ntp_sync': time_details['ntp_sync'],
|
||||||
|
'clock_sync': time_details['clock_sync'],
|
||||||
},
|
},
|
||||||
'services': {
|
'services': {
|
||||||
'camera': get_systemd_state('exomy-camera-stream.service'),
|
'camera': get_systemd_state('exomy-camera-stream.service'),
|
||||||
'camera_settings_version': read_camera_settings_version(),
|
'camera_settings_version': read_camera_settings_version(),
|
||||||
'admin_api': get_systemd_state('exomy-admin-api.service'),
|
'admin_api': get_systemd_state('exomy-admin-api.service'),
|
||||||
'exomy': get_container_state(EXOMY_CONTAINER),
|
'exomy': get_container_state(EXOMY_CONTAINER),
|
||||||
|
'exomy_uptime': container_details['uptime'],
|
||||||
|
'exomy_restarts': container_details['restarts'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user