FEAT-DEEPSLEEP: Display-Refresh-Timer + CPU-Throttle + Admin Power-Tab

DeepSleep-Modus fuer das ePaper-Display:
- dashboard.py: _is_deepsleep(), _next_wake(), _seconds_until_wake(),
                _apply_cpu_throttle() (Pi auf 600MHz im Sleep)
- 60s sleep-chunks in main loop statt festes Intervall
- render_full() mit deepsleep_active + next_wake params
- ZZZ-Indikator + CPU-Throttle-Badge wenn schlafend
- load_config() auto-filled 'power' defaults aus POWER_DEFAULTS

Admin UI (templates/power.html + admin.py):
- /power (GET+POST): DeepSleep-Toggle, Wake-Times, CPU-Throttle-Settings
- /api/power (JSON): live status polling fuer Sidebar-Badge
- /api/wake (POST): manuelles Display-Aufwecken aus dem Admin
- templates/index.html: Energie-Sidebar-Link + Live-Status-Badge
  (Zz / wach / an / aus) via refreshPowerStatus()
This commit is contained in:
Patrik
2026-08-31 00:47:46 +02:00
parent 5a83826aa5
commit 5de086e1b1
4 changed files with 472 additions and 15 deletions
+31
View File
@@ -939,6 +939,11 @@
<span class="icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>
Settings
</button>
<a class="sidebar-item" href="/power" style="text-decoration:none">
<span class="icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18.36 6.64a9 9 0 1 1-12.73 0"/><line x1="12" y1="2" x2="12" y2="12"/></svg></span>
Energie
<span class="badge" id="sbPower">—</span>
</a>
<button class="sidebar-item" data-tab="network" onclick="switchTab('network')">
<span class="icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/></svg></span>
Network
@@ -2042,6 +2047,32 @@
};
document.getElementById('netHint').textContent = hints[s.mode] || '';
}
// ---- Power-Status (DeepSleep) ----
async function refreshPowerStatus() {
try {
const r = await fetch('/api/power');
const d = await r.json();
const sb = document.getElementById('sbPower');
if (sb) {
if (d.deepsleep_enabled && d.is_deepsleep) {
sb.textContent = 'Zz';
sb.style.background = '#fef3c7';
sb.style.color = '#92400e';
} else if (d.deepsleep_enabled) {
sb.textContent = 'an';
sb.style.background = '';
sb.style.color = '';
} else {
sb.textContent = 'aus';
sb.style.background = '';
sb.style.color = '';
}
}
} catch (e) {}
}
refreshPowerStatus();
setInterval(refreshPowerStatus, 30000);
async function refreshScan() {
const r = await netFetch('/api/network/scan'); if (!r) return;
const sel = document.getElementById('ssidSelect');