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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
+10
-4
@@ -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
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user