From 1c5eab14b69b1529ac5139be283671acc864af09 Mon Sep 17 00:00:00 2001 From: Otto Date: Sun, 14 Jun 2026 15:38:11 +0200 Subject: [PATCH] UI-003: show prediction evaluation feedback --- CHANGELOG.md | 6 ++++++ addon/config.yaml | 2 +- app/static/index.html | 19 +++++++++++++++---- tests/test_dashboard.py | 4 ++++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebcbb3d..ad89a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.6.1 - 2026-06-14 +- Manuelle Prüfung als `Aktuelle Situation auswerten` eindeutig von Simulation + oder Aktorschaltung abgegrenzt +- Sichtbare Rückmeldung mit Prüfzeitpunkt, vorhergesagtem Zustand und Sicherheit + oder klarem Hinweis auf einen fehlenden frischen Sensorwechsel + ## 0.6.0 - 2026-06-14 - Kausales Shadow-Lernen erkennt frische Kontextwechsel unmittelbar vor einer Aktorhandlung, etwa `Tür geschlossen → offen` vor `Licht aus → an` diff --git a/addon/config.yaml b/addon/config.yaml index 87f9a6d..2e11fbd 100644 --- a/addon/config.yaml +++ b/addon/config.yaml @@ -1,5 +1,5 @@ name: SillyHome Next -version: "0.6.0" +version: "0.6.1" slug: sillyhome_next description: Lernt automatisch aus deinem Verhalten und steuert freigegebene Aktoren url: http://192.168.6.31:3000/pino/sillyhome-next diff --git a/app/static/index.html b/app/static/index.html index c396181..3245e70 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -225,7 +225,7 @@ async function loadConfiguredActuators() { } } -async function showActuator(actuatorId) { +async function showActuator(actuatorId, evaluationMessage = "") { currentActuatorId = actuatorId; const box = document.getElementById("actuator-detail"); try { @@ -273,7 +273,9 @@ async function showActuator(actuatorId) {

Letztes Training: ${escapeHtml(record.behavior.last_trained_at || "noch nicht")}

Was noch passiert: ${escapeHtml(record.behavior.reason)}

${activationButton} - + +

Die Prüfung simuliert keinen Sensorwechsel und schaltet keinen Aktor.

+ ${evaluationMessage ? `

${escapeHtml(evaluationMessage)}

` : ""}

Was SillyHome aktuell vorhersagt

@@ -290,9 +292,18 @@ async function showActuator(actuatorId) { async function evaluateActuator(actuatorId) { try { - await api(`v1/actuators/${encodeURIComponent(actuatorId)}/evaluate`, {method: "POST"}); + const record = await api( + `v1/actuators/${encodeURIComponent(actuatorId)}/evaluate`, + {method: "POST"}, + ); + const checkedAt = new Date( + record.behavior.last_evaluated_at || Date.now(), + ).toLocaleString("de-DE"); + const message = record.behavior.prediction + ? `Prüfung ${checkedAt}: ${record.behavior.prediction.target_state} mit ${Math.round(record.behavior.prediction.confidence * 100)} % vorhergesagt.` + : `Prüfung ${checkedAt}: Kein frischer passender Sensorwechsel erkannt; aktuell ist keine Aktion fällig.`; await loadConfiguredActuators(); - await showActuator(actuatorId); + await showActuator(actuatorId, message); } catch (error) { alert(error.message); } diff --git a/tests/test_dashboard.py b/tests/test_dashboard.py index 6f8fad5..5cf84a4 100644 --- a/tests/test_dashboard.py +++ b/tests/test_dashboard.py @@ -17,6 +17,10 @@ def test_dashboard_is_served_at_root() -> None: assert "Freigabe noch gesperrt" in response.text assert "Bediene das Licht dafür direkt über Home Assistant" in response.text assert "Davon erkannte HA-Automationen" in response.text + assert "Aktuelle Situation auswerten" in response.text + assert "Die Prüfung simuliert keinen Sensorwechsel" in response.text + assert "Kein frischer passender Sensorwechsel erkannt" in response.text + assert "Vorhersage jetzt prüfen" not in response.text assert 'record.behavior.status === "trained" && missingUserActions === 0' in response.text assert "Automation-Entwurf" not in response.text assert "Manuelle Overrides" not in response.text