From 8e268f044d718b2126af5563176d7aa6ed7bc638 Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Tue, 11 Aug 2026 10:48:33 +0200 Subject: [PATCH] Phase 2: Doku an Codestand angleichen, profil_lesen haerten Doku-Drift behoben: die Statistik-Seite rechnet laengst echt (Behauptung stand an drei Stellen), INSTALL.md nannte in Schritt 4 vier Variablennamen, die es nie gab, README erwaehnte die entfernte 97-Prozent-Volltankungsregel und liess fuenf pyscript-Dateien in der Uebersicht aus. Obsoleter TODO-Kommentar in belegverarbeitung.py entfernt. profil_lesen() gibt bei fehlender oder beschaedigter Profildatei None zurueck statt zu werfen; alle sieben Aufrufstellen fangen den Fall ab. An der Testinstanz geprueft: Datei entfernt, es folgt eine verstaendliche Fehlermeldung mit Verweis auf INSTALL.md statt eines Tracebacks pro Trigger-Durchlauf, Home Assistant laeuft normal weiter. --- homeassistant/INSTALL.md | 21 +++++++++++++------ homeassistant/README.md | 14 +++++++++---- homeassistant/pyscript/backup.py | 4 ++++ homeassistant/pyscript/belegverarbeitung.py | 2 +- homeassistant/pyscript/fahrterkennung.py | 4 ++++ .../modules/frontend_veroeffentlichung.py | 5 ++++- homeassistant/pyscript/modules/profil.py | 21 ++++++++++++++++++- homeassistant/pyscript/reifenzaehler.py | 2 ++ homeassistant/pyscript/tankerkennung.py | 5 ++++- homeassistant/www/audi-dashboard-app.js | 2 -- 10 files changed, 64 insertions(+), 16 deletions(-) diff --git a/homeassistant/INSTALL.md b/homeassistant/INSTALL.md index 419fc1e..b1a77ea 100644 --- a/homeassistant/INSTALL.md +++ b/homeassistant/INSTALL.md @@ -103,10 +103,18 @@ zeigt die Oberfläche „unbekannt" statt eines Werts — kein Absturz): 3. Ebenfalls in Entwicklerwerkzeuge → Zustände suchen: - Reichweite → `RANGE_SENSOR` - - Türstatus (falls als ein Sammel-Sensor vorhanden) → `DOORS_SENSOR` - - Fensterstatus → `WINDOWS_SENSOR` - - Verriegelung (Domäne `lock.`) → `LOCK_ENTITY` - - Batteriespannung, falls überhaupt vorhanden → `BATTERY_VOLTAGE_SENSOR` + - Türstatus → `TUER_SENSOREN` (Liste mit vier Einzelsensoren: + vorne links/rechts, hinten links/rechts) + - Fensterstatus → `FENSTER_SENSOREN` (ebenfalls vier Einzelsensoren) + - Verriegelung → `TUERSCHLOSS_SENSOREN` (vier Einzelsensoren; die + Integration liefert kein `lock.`-Entity) + - Heckklappe und Motorhaube → `HECKKLAPPE_SENSOR`, + `HECKKLAPPENSCHLOSS_SENSOR`, `HAUBE_SENSOR`, `HAUBENSCHLOSS_SENSOR` + - Service-Fälligkeit → `NAECHSTER_OELWECHSEL_SENSOR`, + `OELWECHSEL_STRECKE_SENSOR`, `NAECHSTE_INSPEKTION_SENSOR`, + `INSPEKTION_STRECKE_SENSOR` + - Batteriespannung, falls überhaupt vorhanden → `BATTERIE_SENSOR` + (bei der aktuellen Integration nicht vorhanden, bleibt leer) 4. Datei `pyscript/modules/einstellungen.py` öffnen (Samba: direkt im Explorer, Studio Code Server: im Editor) und alle gefundenen Werte @@ -201,8 +209,9 @@ Der `panel_custom`-Eintrag aus Schritt 3 zeigt auf Prototyp. Das Gerät braucht dafür zusätzlich zur Tailscale-Verbindung normalen Internetzugang — sonst bleibt die Karte auf der Fahrt- und Tankvorgang-Detailseite leer. -- **Statistik-Seite** zeigt weiterhin Beispielzahlen aus dem Prototyp, - keine echte Auswertung der eigenen Fahrten — eigenes Arbeitspaket. +- **Statistik-Seite** wertet die eigenen Fahrten und Tankvorgänge echt aus + (Zeiträume, Verbrauch, Tag/Nacht, privat/Arbeitsweg). Sie bleibt nur so + lange leer, wie noch keine Fahrten und Tankungen erfasst sind. ## Schritt 10 — künftige Updates einspielen, ohne die App neu zu bauen diff --git a/homeassistant/README.md b/homeassistant/README.md index 04c3a86..de7f604 100644 --- a/homeassistant/README.md +++ b/homeassistant/README.md @@ -96,8 +96,6 @@ Datendateien — nie App-Code oder -Konfiguration. `fahrterkennung.py`. - **Bilder fehlen** (§7a) — Ordner `www/bilder/` ist noch leer. Layout springt nicht (Maße sind reserviert), aber die Flächen bleiben leer. -- **Statistik-Seite** zeigt weiterhin Beispielzahlen aus dem Prototyp, keine - echte Auswertung der erfassten Fahrten. - **Leaflet lädt per CDN**, wie im Prototyp — braucht zusätzlich zu Tailscale echten Internetzugang auf dem Gerät. @@ -107,11 +105,14 @@ Datendateien — nie App-Code oder -Konfiguration. - Zweistufiger Fahrtabschluss per Recorder-Historie-Screening, inklusive Verkettung direkt anschließender Fahrten - Reifenzähler per direkter Subtraktion, kein `utility_meter` -- Belegverarbeitung inklusive 97-%-Volltankungsregel und Duplikatserkennung - über `receipt_key` +- Belegverarbeitung mit Duplikatserkennung über `receipt_key` (die zunächst + geplante 97-%-Volltankungsregel wurde per Änderungswunsch entfernt, siehe + Kopfkommentar in `pyscript/belegverarbeitung.py`) - Manuelle Fallback-Wege für Fahrten und Tankvorgänge ohne Beleg - Frontend: Übersicht, Fahrtenliste, Navigation zwischen allen Ansichten, Datenadapter Profil→Oberfläche, Schreibaktionen über `hass.callService` +- Statistik-Seite mit echter Auswertung aus Fahrten und Tankvorgängen + (Zeiträume, Verbrauch, Tag/Nacht, privat/Arbeitsweg) ## Dateiübersicht @@ -133,8 +134,13 @@ homeassistant/ │ │ └── frontend_veroeffentlichung.py Zustände fürs Frontend (§10 Punkt 7 Ersatz) │ ├── fahrterkennung.py §7.1 │ ├── fahrtabschluss.py §7.2 (Trigger-Registrierung) +│ ├── tankerkennung.py §7.4 (automatische Erkennung am Füllstandsanstieg) │ ├── reifenzaehler.py §7.5 │ ├── belegverarbeitung.py §7.4, §7.7 +│ ├── batterieverlauf.py 12-V-Spannung, Tagesminimum/-maximum +│ ├── bilderverwaltung.py Upload/Löschen der Fahrzeugfotos +│ ├── backup.py tägliche Sicherung und Wiederherstellung +│ ├── updateverwaltung.py Update suchen und installieren │ └── frontend_api.py Lese-/Schreib-Anbindung fürs Frontend ├── www/ │ ├── audi-dashboard-panel.js Lade-Stub (zeigt configuration.yaml hierher), ändert sich kaum diff --git a/homeassistant/pyscript/backup.py b/homeassistant/pyscript/backup.py index 54b658e..e92a70e 100644 --- a/homeassistant/pyscript/backup.py +++ b/homeassistant/pyscript/backup.py @@ -44,6 +44,8 @@ def _backup_jetzt(): def _letztes_backup_vermerken(): p = profil.profil_lesen() + if p is None: + return p.setdefault("einstellungen", {})["letztes_backup"] = datetime.datetime.now().isoformat() profil.profil_schreiben(p) frontend_veroeffentlichung.profil_veroeffentlichen() @@ -60,6 +62,8 @@ def audi_dashboard_backup_jetzt(): @time_trigger("cron(0 4 * * *)") def _automatisches_backup(): p = profil.profil_lesen() + if p is None: + return intervall = p.get("einstellungen", {}).get("backup_intervall", "aus") heute = datetime.date.today() faellig = ( diff --git a/homeassistant/pyscript/belegverarbeitung.py b/homeassistant/pyscript/belegverarbeitung.py index 81b32dc..0abb859 100644 --- a/homeassistant/pyscript/belegverarbeitung.py +++ b/homeassistant/pyscript/belegverarbeitung.py @@ -38,7 +38,7 @@ import einstellungen import frontend_veroeffentlichung import profil -PARSER_SKRIPT = "/config/audi_dashboard/shell_beleg_parser.py" # TODO: Datei ablegen +PARSER_SKRIPT = "/config/audi_dashboard/shell_beleg_parser.py" # --------------------------------------------------------------- Hilfsfunktionen diff --git a/homeassistant/pyscript/fahrterkennung.py b/homeassistant/pyscript/fahrterkennung.py index 78f7928..26f9973 100644 --- a/homeassistant/pyscript/fahrterkennung.py +++ b/homeassistant/pyscript/fahrterkennung.py @@ -34,11 +34,15 @@ _fahrt_start_ts = None def _profil_wlan_name(): p = profil.profil_lesen() + if p is None: + return None return p.get("fahrzeug", {}).get("wlan_name") def _pausenzeit_sekunden(): p = profil.profil_lesen() + if p is None: + return 15 * 60 return p.get("einstellungen", {}).get("fahrten_pausenzeit_min", 15) * 60 diff --git a/homeassistant/pyscript/modules/frontend_veroeffentlichung.py b/homeassistant/pyscript/modules/frontend_veroeffentlichung.py index 521d9d3..ffcd10e 100644 --- a/homeassistant/pyscript/modules/frontend_veroeffentlichung.py +++ b/homeassistant/pyscript/modules/frontend_veroeffentlichung.py @@ -24,7 +24,10 @@ import profil def profil_veroeffentlichen(): - state.set("pyscript.audi_dashboard_profil", "aktuell", new_attributes={"daten": profil.profil_lesen()}) + daten = profil.profil_lesen() + if daten is None: + return + state.set("pyscript.audi_dashboard_profil", "aktuell", new_attributes={"daten": daten}) def fahrten_veroeffentlichen(): diff --git a/homeassistant/pyscript/modules/profil.py b/homeassistant/pyscript/modules/profil.py index 62d7fe7..4631d86 100644 --- a/homeassistant/pyscript/modules/profil.py +++ b/homeassistant/pyscript/modules/profil.py @@ -49,10 +49,29 @@ def ordner_sicherstellen(): # ----------------------------------------------------------- Fahrzeugprofil def profil_lesen(): + """Liest das Fahrzeugprofil, oder None wenn es fehlt bzw. beschädigt ist. + + Ohne diese Prüfung reißt eine fehlende Datei (Installation unvollständig, + siehe INSTALL.md Schritt 2) jeden Trigger und jeden Service mit, der das + Profil braucht — bei laufenden Zeittriggern also im Minutentakt. Jeder + Aufrufer muss den None-Fall abfangen.""" + if not os.path.exists(PROFIL_PFAD): + log.error( + f"audi_dashboard: {PROFIL_PFAD} fehlt. Siehe INSTALL.md Schritt 2 — " + "bis dahin bleiben alle Funktionen aus, die das Profil brauchen." + ) + return None f = task.executor(io.open, PROFIL_PFAD, "r") inhalt = f.read() f.close() - return json.loads(inhalt) + try: + return json.loads(inhalt) + except ValueError as fehler: + log.error( + f"audi_dashboard: {PROFIL_PFAD} ist kein gültiges JSON ({fehler}). " + "Letztes Backup aus audi_dashboard/backups/ zurückspielen." + ) + return None def profil_schreiben(profil): diff --git a/homeassistant/pyscript/reifenzaehler.py b/homeassistant/pyscript/reifenzaehler.py index 95c62f6..6f850c7 100644 --- a/homeassistant/pyscript/reifenzaehler.py +++ b/homeassistant/pyscript/reifenzaehler.py @@ -60,6 +60,8 @@ def _fortschreiben_und_veroeffentlichen(neuer_km, neuer_aktiv=None): Reihenfolge, damit beim Wechseln selbst keine km dem neuen Satz zugerechnet werden, die eigentlich noch auf dem alten gefahren wurden.""" p = profil.profil_lesen() + if p is None: + return reifen = p.setdefault("reifen", {}) saetze = reifen.setdefault("saetze", {}) aktiv = reifen.get("aktiv", "sommer") diff --git a/homeassistant/pyscript/tankerkennung.py b/homeassistant/pyscript/tankerkennung.py index 23c9889..f74fd68 100644 --- a/homeassistant/pyscript/tankerkennung.py +++ b/homeassistant/pyscript/tankerkennung.py @@ -57,7 +57,10 @@ def _als_zahl(wert): def _schwelle_prozent(): p = profil.profil_lesen() - tankvolumen = p.get("fahrzeug", {}).get("tankvolumen_liter") or STANDARD_TANKVOLUMEN_LITER + if p is None: + tankvolumen = STANDARD_TANKVOLUMEN_LITER + else: + tankvolumen = p.get("fahrzeug", {}).get("tankvolumen_liter") or STANDARD_TANKVOLUMEN_LITER liter_als_prozent = (LITER_SCHWELLE / tankvolumen) * 100 return min(liter_als_prozent, PROZENT_SCHWELLE) diff --git a/homeassistant/www/audi-dashboard-app.js b/homeassistant/www/audi-dashboard-app.js index ec44b1e..08a818c 100644 --- a/homeassistant/www/audi-dashboard-app.js +++ b/homeassistant/www/audi-dashboard-app.js @@ -11,8 +11,6 @@ DOM-Anbindung (Shadow DOM statt document, siehe $ weiter unten). Bekannte Lücken in diesem Stand: - - Statistik-Seite (vStat/ST) zeigt weiterhin Beispielzahlen, keine echte - Auswertung aus TRIPS/FILLS - eigenes Arbeitspaket. - Kein Bild-Ordner vorhanden; Bilder fallen auf die im Prototyp bereits vorgesehenen Platzhalter-Maße zurück (§7a), erscheinen aber als gebrochene Bilder, bis bilder/ tatsächlich befüllt ist.