Admin angepasst
This commit is contained in:
+212
-48
@@ -154,42 +154,162 @@
|
||||
<span class="p-lbl">Systemstatus</span>
|
||||
<span class="p-tag">Telemetry</span>
|
||||
</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">
|
||||
<span class="sr-led led-ok"></span>
|
||||
<span class="sr-key">WLAN</span>
|
||||
<span class="sr-val" id="info_wifi">-</span>
|
||||
</div>
|
||||
<div class="sr">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Signal</span>
|
||||
<span class="sr-val" id="info_wifi_signal">-</span>
|
||||
</div>
|
||||
<div class="sr">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">IP</span>
|
||||
<span class="sr-val" id="info_ips">-</span>
|
||||
</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">
|
||||
<span class="sr-key">Temp</span>
|
||||
<div class="gauge"><div class="gauge-fill" id="bar-temp-adm"></div></div>
|
||||
<span class="gauge-num" id="info_temp">--</span>
|
||||
</div>
|
||||
<div class="sr">
|
||||
<span class="sr-led led-off"></span>
|
||||
<span class="sr-key">Spannung</span>
|
||||
<span class="sr-val" id="info_undervoltage">-</span>
|
||||
</div>
|
||||
<div class="sr">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Uptime</span>
|
||||
<span class="sr-val" id="info_uptime">-</span>
|
||||
</div>
|
||||
<div class="sr">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Disk frei</span>
|
||||
<span class="sr-val" id="info_disk">-</span>
|
||||
<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="sr">
|
||||
<span class="sr-led led-ok"></span>
|
||||
<span class="sr-key">WLAN</span>
|
||||
<span class="sr-val" id="info_wifi">-</span>
|
||||
</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">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Signal</span>
|
||||
<span class="sr-val" id="info_wifi_signal">-</span>
|
||||
</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">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">IP</span>
|
||||
<span class="sr-val" id="info_ips">-</span>
|
||||
</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="sr sr-gauge gauge-temp">
|
||||
<span class="sr-key">Temp</span>
|
||||
<div class="gauge"><div class="gauge-fill" id="bar-temp-adm"></div></div>
|
||||
<span class="gauge-num" id="info_temp">--</span>
|
||||
</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">
|
||||
<span class="sr-led led-off"></span>
|
||||
<span class="sr-key">Spannung</span>
|
||||
<span class="sr-val" id="info_undervoltage">-</span>
|
||||
</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">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Uptime</span>
|
||||
<span class="sr-val" id="info_uptime">-</span>
|
||||
</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">
|
||||
<span class="sr-led led-blue"></span>
|
||||
<span class="sr-key">Disk frei</span>
|
||||
<span class="sr-val" id="info_disk">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -784,10 +904,31 @@
|
||||
function clearAdminApiDisplay() {
|
||||
setText('info_ips', '--');
|
||||
setText('info_wifi', '--');
|
||||
setText('info_wifi_ssid', '--');
|
||||
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_gpu_temp', '--');
|
||||
setText('info_cpu_usage', '--');
|
||||
setText('info_cpu_per_core', '--');
|
||||
setText('info_memory_details', '--');
|
||||
setText('info_uptime', '--');
|
||||
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');
|
||||
setServiceState('service_camera', '-');
|
||||
setServiceState('camera_service_state', '-');
|
||||
@@ -2285,20 +2426,43 @@
|
||||
}
|
||||
|
||||
function renderStatus(data) {
|
||||
var system = data.system || {};
|
||||
var services = data.services || {};
|
||||
setAdminStatus(data.status || 'Bereit');
|
||||
setText('info_ips', data.system && data.system.ips);
|
||||
setText('info_wifi', data.system && data.system.wifi);
|
||||
setText('info_wifi_signal', data.system && data.system.wifi_signal);
|
||||
setText('info_temp', data.system && data.system.cpu_temperature);
|
||||
setText('info_ips', system.ips);
|
||||
setText('info_wifi', system.wifi);
|
||||
setText('info_wifi_ssid', system.wifi_ssid);
|
||||
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');
|
||||
if (bar && data.system) bar.style.width = temperatureToWidth(data.system.cpu_temperature);
|
||||
setUndervoltageState('info_undervoltage', data.system && data.system.undervoltage, data.system && data.system.undervoltage_state);
|
||||
setText('info_uptime', data.system && data.system.uptime);
|
||||
setText('info_disk', data.system && data.system.disk_free);
|
||||
setServiceState('service_camera', data.services && data.services.camera);
|
||||
setServiceState('camera_service_state', data.services && data.services.camera);
|
||||
setServiceState('service_admin_api', data.services && data.services.admin_api);
|
||||
setServiceState('service_exomy', data.services && data.services.exomy);
|
||||
if (bar) bar.style.width = temperatureToWidth(system.cpu_temperature);
|
||||
setUndervoltageState('info_undervoltage', system.undervoltage, system.undervoltage_state);
|
||||
setText('info_throttling', system.throttling_details);
|
||||
setText('info_uptime', system.uptime);
|
||||
setText('info_load_average', system.load_average);
|
||||
setText('info_disk', system.disk_free);
|
||||
setText('info_disk_root', system.disk_root);
|
||||
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() {
|
||||
|
||||
+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-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 ──────────────────────────────────────── */
|
||||
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-calibration-toolbar{ flex-direction:column; align-items:stretch; }
|
||||
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_gps{ grid-template-columns:1fr; }
|
||||
body.page-admin .map-panel{ min-height:0; }
|
||||
|
||||
+275
-16
@@ -7,6 +7,7 @@ import http.server
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import socketserver
|
||||
import struct
|
||||
import subprocess
|
||||
@@ -85,6 +86,14 @@ def read_cpu_temperature():
|
||||
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():
|
||||
try:
|
||||
with open('/proc/stat', 'r', encoding='utf-8') as handle:
|
||||
@@ -108,6 +117,41 @@ def read_cpu_usage():
|
||||
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():
|
||||
try:
|
||||
values = {}
|
||||
@@ -126,6 +170,27 @@ def read_memory_usage():
|
||||
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():
|
||||
stdout, _, returncode = run_command(['vcgencmd', 'get_throttled'])
|
||||
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():
|
||||
try:
|
||||
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'
|
||||
|
||||
|
||||
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():
|
||||
stdout, _, returncode = run_command(['ip', '-4', '-o', 'addr', 'show', 'dev', 'wlan0', 'scope', 'global'])
|
||||
if returncode == 0 and stdout:
|
||||
@@ -235,29 +359,87 @@ def get_wifi_status():
|
||||
return 'kein wlan0'
|
||||
|
||||
|
||||
def get_wifi_signal():
|
||||
stdout, _, returncode = run_command(['nmcli', '-t', '-f', 'GENERAL.STATE,AP.SIGNAL', 'device', 'show', 'wlan0'])
|
||||
def get_wifi_details():
|
||||
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:
|
||||
return 'unbekannt'
|
||||
return details
|
||||
|
||||
state = ''
|
||||
signal = ''
|
||||
for line in stdout.splitlines():
|
||||
if line.startswith('GENERAL.STATE:'):
|
||||
state = line.split(':', 1)[1].strip()
|
||||
elif line.startswith('AP[1].SIGNAL:'):
|
||||
signal = line.split(':', 1)[1].strip()
|
||||
if not line.startswith('yes:'):
|
||||
continue
|
||||
parts = line.split(':')
|
||||
if len(parts) >= 6:
|
||||
ssid = parts[1].strip()
|
||||
signal = parts[2].strip()
|
||||
channel = parts[3].strip()
|
||||
frequency = parts[4].strip()
|
||||
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:
|
||||
dbm = (int(float(signal)) / 2) - 100
|
||||
details['signal_dbm'] = f'{dbm:.0f} dBm'
|
||||
except ValueError:
|
||||
details['signal_dbm'] = 'unbekannt'
|
||||
break
|
||||
return details
|
||||
|
||||
if 'connected' not in state.lower():
|
||||
return 'nicht verbunden'
|
||||
if not signal:
|
||||
return 'unbekannt'
|
||||
|
||||
def get_wifi_signal():
|
||||
details = get_wifi_details()
|
||||
return details['signal_percent']
|
||||
|
||||
|
||||
def get_hostname():
|
||||
try:
|
||||
percent = max(0, min(100, int(float(signal))))
|
||||
except ValueError:
|
||||
return socket.gethostname()
|
||||
except Exception:
|
||||
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):
|
||||
@@ -274,6 +456,59 @@ def get_container_state(container_name):
|
||||
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():
|
||||
state = get_container_state(EXOMY_CONTAINER)
|
||||
return {
|
||||
@@ -285,25 +520,49 @@ def get_motor_test_container_status():
|
||||
|
||||
def collect_status():
|
||||
undervoltage = read_undervoltage_status()
|
||||
wifi_details = get_wifi_details()
|
||||
time_details = get_system_time_details()
|
||||
container_details = get_container_details(EXOMY_CONTAINER)
|
||||
return {
|
||||
'status': 'Bereit',
|
||||
'system': {
|
||||
'wifi': get_wifi_status(),
|
||||
'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(),
|
||||
'undervoltage': undervoltage['text'],
|
||||
'undervoltage_state': undervoltage['state'],
|
||||
'throttling_details': read_throttling_details(),
|
||||
'cpu_temperature': read_cpu_temperature(),
|
||||
'gpu_temperature': read_gpu_temperature(),
|
||||
'cpu_usage': read_cpu_usage(),
|
||||
'cpu_usage_per_core': read_per_core_usage(),
|
||||
'memory_usage': read_memory_usage(),
|
||||
'memory_details': read_memory_details(),
|
||||
'uptime': format_uptime(),
|
||||
'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': {
|
||||
'camera': get_systemd_state('exomy-camera-stream.service'),
|
||||
'camera_settings_version': read_camera_settings_version(),
|
||||
'admin_api': get_systemd_state('exomy-admin-api.service'),
|
||||
'exomy': get_container_state(EXOMY_CONTAINER),
|
||||
'exomy_uptime': container_details['uptime'],
|
||||
'exomy_restarts': container_details['restarts'],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user