Commit Graph

12 Commits

Author SHA1 Message Date
tobias 38e7731a3d Rollende Zeitraeume, zwei Gesten, CI-Symbole und das Screening faellt nach (2026.9.2.8-.12)
Gemeldet vom Eigentuemer an der realen Instanz, in einem Zug abgearbeitet.

STATISTIK. "Monat kleiner als Woche" war kein Rechenfehler, sondern die
Definition: am 02.09. begann die Kalenderwoche am 31.08., der Monat erst am
01.09. Umgestellt auf rollende Fenster (1/7/30/365 Tage), damit 1 ⊂ 7 ⊂ 30 ⊂
365 an jedem Tag gilt. "Jahr" meint damit nicht mehr das Kalenderjahr - so
entschieden. Zwei neue Tests halten die Verschachtelung fest.

Aus dem Langzeitverbrauch sind Herleitung und Erklaerabsatz aus der ANSICHT
genommen, nicht aus der Rechnung; das Datum des letzten Tankstops ebenfalls.

UEBERSICHT. Unter "Letzter Tankvorgang" steht das Datum statt der Tankstelle.

BILDER. Die Draufsicht war der einzige sichtbare Bildplatz ohne Zugang -
bilder.py kannte den Dateinamen, BILDER/BILDPLAETZE nicht. Jetzt ein Platz wie
jeder andere. Die Vorschau in den Einstellungen schneidet Fotos nicht mehr an,
und der Bildbereich der Fahrzeugseite steht eingerueckt statt randlos.

ZAHNRAD. Es lag mit seiner 44px-Trefferflaeche 21px im Kachelinhalt und fing
die obere Haelfte des ersten Knopfes ab (Versicherung, "Inland"). Die Kopfzeile
bekommt jetzt die Hoehe, die es braucht.

SCREENING. Lief ausschliesslich bei einer Aenderung des Kilometerstands, also
nur waehrend der Fahrt - im Stand blieben Ortsnamen und Verbrauch liegen. Jetzt
zusaetzlich einmal nach dem Start, und danach faellt es selbst nach, solange
ein Lauf sein Ortsbudget aufbraucht UND dabei etwas aufloest. Kein Dauertakt:
die Kette endet, sobald ein Lauf mit uebrigem Budget durchkommt.

GESTEN. Zum Loeschen nach links wischen, jetzt auch im Radarchiv (das Panel
hatte die Mechanik, das Archiv war nie angeschlossen; die App hatte sie gar
nicht). Vom linken Rand nach rechts wischen = zurueck, jetzt auch in der App,
mit denselben Zahlen wie im Panel und in beiden mit sichtbarer Rueckmeldung.

CI-SYMBOLE. Das Kachel-Zahnrad ist settings-s - im Panel stand der Pfad
sechsmal wortgleich im Markup, jetzt einmal als CI.settingsS. Das
handgezeichnete Zahnrad der Seitenleiste ist ersetzt und geloescht. Die
Zapfsaeule des Tanken-Reiters ist fuel-station-s, Faktor 0,84 um die
Rastermitte - live per getBBox() gemessen, damit sie auf dieselbe senkrechte
Spanne kommt wie Statistik.

Zurueckgenommen: die Titel der Unterseiten stehen wieder mittig. Zentriert ist
Apples HIG fuer Navigationsleisten; die linksbuendigen Titel sind die der
Hauptbereiche und folgen der anderen Regel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 15:48:24 +02:00
tobias 2af5c469d6 Ortsnamen aus dem Backend, Verbrauchsfaktor aus dem Tankbeleg, Radzaehler ueber Fahrten
Ortsauflösung serverseitig (geokodierung.py): der Ort steht jetzt in der Fahrt
statt im Zwischenspeicher jedes Geräts. Beide Oberflächen fragen nichts mehr ab.

Verbrauchskorrektur (verbrauchskorrektur.py): Faktor = Beleg-Liter / Summe der
Einzelfahrten, voll zu voll. Statt einer Schranke am Faktor wird der Nenner
geprüft - decken die erkannten Fahrten 90-110 % der Tacho-Spanne ab? Ausgelöst
beim Schreiben eines Tankvorgangs, nicht erst bei der nächsten Fahrt.

Radzähler: summiert die Fahrten des montierten Satzes statt Tacho-Deltas. Der
alte Weg hatte Fahrzeugwechsel als gefahrene Strecke verbucht (375.962 km bei
einem Tacho von 61.823).

Null heißt unbekannt: ein Kilometerstand von 0 oder ein leeres Feld werden zu
None normalisiert, statt an sechs Lesestellen als "Tachostand null" zu gelten.
Momentanwerte der Sensoren gelten nur für einen Tankvorgang von jetzt.

Oberfläche, beide Codebasen: Wertespalte der Fahrtenliste ausgerichtet, Ort ->
Ort in "Zuletzt", "Räder" statt "Reifen", "Termin vereinbart" entfernt,
Markenlogo 20 % größer, Übersicht-Symbol auf volle Rasterbreite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 11:28:37 +02:00
tobias 78a8017e95 Verbrauch: Tankstand ab Fahrtbeginn statt davor (2026.9.1.24)
DER VERBRAUCH WAR SYSTEMATISCH ZU HOCH

Der Startwert kam aus wert_bei(), also dem letzten Literstand VOR der Fahrt -
und das ist im Stand der Wert vom Ende der VORIGEN Fahrt. An der Fahrt
Eichstaett - Adelschlag nachgemessen: 36,4 l um 13:52 (Ende der vorigen Fahrt),
36,2 l um 16:20:49 (erster Datensatz der neuen). In der Standzeit dazwischen
ist niemand gefahren; diese 0,2 l Setzung wurden der neuen Fahrt zugerechnet.

  alt: 36,4 - 35,6 = 0,8 l auf 6,896 km -> 11,6 l/100 km
  neu: 36,2 - 35,6 = 0,6 l auf 6,896 km ->  8,7 l/100 km

Neu wert_ab() in verlauf.py: der erste Wert AB dem Zeitpunkt. Fuer einen
ZAEHLER ist "zuletzt davor" richtig (der Kilometerstand aendert sich im Stand
nicht), fuer einen gemessenen FUELLSTAND nicht - der driftet. Das Fahrtende
bleibt bei wert_bei(). Livepfad und Rueckblick benutzen beide die neue
Funktion.

Bereits gerechnete Fahrten behalten ihren Wert: _verbrauch_screenen() fuellt
nur fehlende. Die Neuberechnung kommt mit dem Korrekturwert aus den
Tankvorgaengen, den der Eigentuemer vorgeschlagen hat.

ANZEIGE

Hoechstgeschwindigkeit ohne Nachkommastelle. Statuswort raus aus der
Fahrtenliste - "vollstaendig" sagt dem Nutzer nichts, und "offen" verspricht
Daten, die bei einer laengst abgeschlossenen Fahrt nie mehr kommen; fehlt ein
Wert, steht dort ein Strich.

Strecke und Verbrauch stehen jetzt in einer Spalte: die Wertspalte wuchs mit
dem Inhalt, gemessen 86px gegen 37px, und die Zahlen standen versetzt. Feste
Mindestbreite in beiden Oberflaechen, nachgemessen alle Zeilen 92px.

Verifiziert: py_compile, Panel als Modul, tsc --noEmit sauber, 165/165 Tests,
wert_ab() gegen vier Randfaelle, im Browser nachgesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 21:13:43 +02:00
tobias 9d70192da3 Audit: Livepfad und Rueckblick messen wieder dasselbe (2026.9.1.17)
BEFUND 1 (behoben): dieselbe Fahrt, zwei Strecken

screening.py las den Verlauf ueber verlauf_lesen(), das den Stand zu Beginn
des Fensters mitliefert. historienimport.py schnitt sein Fenster streng heraus
und verlor genau diesen Punkt. An der echten Fahrt nachgemessen: 6,896 km
gegen 6,816 km fuer denselben Zeitraum.

Neu verlauf.zaehlerstrecke(punkte, start, ende) - der Anker ist der letzte
Datensatz am oder vor dem Beginn, dieselbe Ueberlegung wie bei wert_bei().
Beide Wege schneiden jetzt durch dieselbe Funktion. Nachgewiesen: Rueckblick
6,896, Livepfad 6,896.

Dritter Fall dieser Art nach UNPLAUSIBLE_KMH und MINDESTDAUER_S - und ich
hatte ihn am selben Tag selbst eingebaut.

BEFUND 2 (behoben): STANDARDWERTE gingen unnoetig ueber die Leitung.
zuordnung.py schickte sie mit jeder Katalogantwort; gelesen hat sie seit dem
Entfernen des Zuruecksetzen-Knopfes niemand mehr. Die Konstante bleibt, sie
traegt intern die Vorgabewerte und leitet SCHLUESSEL ab.

BEFUND 3 und 4 bleiben offen und gehoeren dem Eigentuemer: die vier Tage alte
Reichweite auf der Uebersicht (RANGE_SENSOR besser leer lassen) und die
Nullfahrt-Regel, die nur der Rueckblick kennt - im Livepfad hiesse sie, einen
bereits gespeicherten Datensatz automatisch zu loeschen.

SAUBER: 24 Backend-Dateien py_compile, Panel als Modul geparst, tsc --noEmit
und vite build sauber, 165/165 Tests, 27 Katalogeintraege gegen 27
Dataclass-Felder ohne Abweichung, jedes Listenfeld mit so vielen Beispielen wie
Positionen, keine verwaisten Verweise, in der Konsole nur das bekannte
ServiceWorker-Rauschen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 19:09:59 +02:00
tobias 09c7461892 Rueckblick misst auf Meter, Streckenwahl gemeinsam (2026.9.1.14)
Der erste Wurf (2026.9.1.12) verwarf jedes Importfenster mit distanz == 0. Zu
grob: seit der GNSS-Verfeinerung messen wir Meter, und eine Fahrt von 400
Metern steht im CAN-Wert als Null. Der Eigentuemer hat es auf den Punkt
gebracht - "0,0 moechte ich nicht, ab 0,1 schon".

Der Rueckblick liest jetzt ebenfalls den GNSS-Zaehler und entscheidet auf eine
Nachkommastelle.

Dabei stand die Toleranzlogik kurz doppelt im Code - in screening.py und in
historienimport.py. Genau die Doppelung, die dieses Projekt bei
UNPLAUSIBLE_KMH und MINDESTDAUER_S schon einmal teuer bezahlt hat. Sie liegt
jetzt gemeinsam in verlauf.py:

  strecke_waehlen(grob, fein) - die feine Zahl gilt, solange sie in der
  Rundungsunschaerfe des Ankers liegt, oder wenn es keinen Anker gibt.

  ist_gefahren(distanz) - ab 0,1 km ja. Eine unbekannte Strecke gilt als
  gefahren; nur die gemessene Null ist ein Nein.

VERIFIZIERT: 13 Faelle gegen beide Funktionen, darunter die zwei echten
Fahrten, die 400-Meter-Fahrt, die 100-Meter-Untergrenze, 40 Meter, fehlender
Anker, fehlender GNSS-Wert, gedrifteter Zaehler und beide Seiten der Grenze.
Import live: 1 Fenster uebersprungen, null 0-km-Fahrten im Bestand. Livepfad
live: vier alte Fahrten korrekt abgelehnt.

NICHT live gezeigt: ein Fenster mit 0,1-0,9 km, das der Import nun behaelt -
der Recorder enthaelt kein geschlossenes Fenster dieser Groesse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 18:47:51 +02:00
tobias af83805c34 Fahrtstrecke auf 100 m: CAN als Anker, GNSS als Nachkommastelle (2026.9.1.10)
Zwei echte Fahrten am 01.09.2026 haben die Datenform geliefert, auf die
2026.9.1.5 gewartet hat.

strecke_aus_zaehler() summiert die Zuwaechse des geraeteeigenen
Kilometerzaehlers und behandelt einen Ruecksprung als Ruecksetzung. Weder der
rohe Zaehler noch die Teilstrecken taugen allein: der Zaehler verliert bei
einer Ruecksetzung alles Vorherige (Fahrt 1: 0,415 km), die Teilstrecken
verlieren einzelne Datensaetze (Fahrt 2: 4 von 50 null, 0,2 km zu wenig). An
jedem Datensatz sind beide identisch - sie gehen nur verschieden kaputt.

_gnss_verfeinern() ersetzt die grobe Strecke nur, wenn die feine innerhalb der
Rundungsunschaerfe des Ankers liegt (GNSS_TOLERANZ_KM = 1.0; beide Enden des
CAN-Werts sind auf ganze Kilometer gerundet). Sonst behaelt der Fahrzeugwert
recht.

VERIFIZIERT gegen die echten Fahrten:
- Fahrt 1 (mit Ruecksetzung): 6,958 km, Google Maps sagt 7,1
- Fahrt 2 (sauber): 6,816 km
- live: 'Strecke auf 6.896 km verfeinert (Kilometerstand sagte 7.0 km)'
- drei aeltere Fahrten korrekt abgelehnt (209178 km gegen 21 km Anker)
- sechs Randfaelle: zwei Ruecksetzungen, ein Punkt, leer, unlesbare Werte

Nebenbei bestaetigt: NACHLAUF_S = 900 (Zuendung aus 16:33:39, Trip-Signal aus
16:48:44, gespeichertes Ende 16:33:36); der Rueckwaertssprung-Schutz griff live
beim Fahrzeugwechsel (-147361 km verworfen, Fahrt blieb offen); die
RPM-Zuendung prellt nicht; das Bewegungstor meldet wieder Stillstand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 17:31:33 +02:00
tobias ff5a334e95 Keine Phantomfahrt beim Neustart, Tankstand auf wert_bei() (2026.9.1.1)
zuendung_geaendert() prueste den neuen Zustand, aber nicht den alten. Beim
Hochfahren taucht die Zuendungs-Entitaet neu auf; das kommt als Wechsel mit
old_state = None an. Steht das Trip-Signal ohnehin auf "an" - beim FMM003 der
Normalfall -, las der Beobachter das als "Zuendung ging gerade an" und legte
eine Fahrt an, deren Beginn schlicht der Zeitpunkt des Neustarts war. Daher
der Eintrag 30.08. 19:43 bis 31.08. 08:37, 12,9 h, 0 km.

Die Pruefung ist "if alt is None: return" - dieselbe, die
_kilometerstand_geaendert() im Koordinator seit jeher hat. Eine wirklich
laufende Fahrt geht nicht verloren: deren Beginn liegt im Store und wird von
nach_neustart_fortsetzen() aufgenommen.

Nachgewiesen: zwei Neustarts hintereinander bei trip_status = on und leerem
Zwischenstand, null "Fahrt gestartet"-Zeilen und fahrt_start_ts bleibt null.
Vorher entstand unter genau diesen Bedingungen jedes Mal eine.

_verbrauch_screenen() liest die Literstaende jetzt ebenfalls mit wert_bei()
statt naechster_wert() - dieselbe Doppelbewertung gegenueber
historienimport.py wie beim Kilometerstand, eine Ebene tiefer.
naechster_wert() bleibt bei Breiten-/Laengengrad: eine Position ist kein
Zaehler.

Auf Anweisung des Eigentuemers ausserdem die zwoelf Fahrten mit
distance_km == 0 geloescht (ueber den Dienst fahrt_loeschen, nach einem
backup_jetzt) und "Open items" in AGENTS.md aufgeraeumt: vier Karteileichen
des MQTT-Wegs entfernt, Cloudflare-Zugang und iPhone-Signatur als erledigt
gebucht, Befund 07 als Nutzereingabe geschlossen, QR-Scanner auf den halben
Umfang gekuerzt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 10:04:55 +02:00
tobias 6f23dfebbf Streckenberechnung: zuletzt davor statt naechstgelegen, keine Rueckwaertsspruenge (2026.8.31.6)
_fahrt_screenen() holte beide Kilometerstaende mit naechster_wert(), also dem
zeitlich naechstgelegenen Wert - gleich ob davor oder danach. Fuer einen
Zaehlerstand ist das falsch, und wert_bei()s eigener Docstring sagt es
woertlich: der Stand bei Fahrtbeginn ist der zuletzt gemeldete, nicht der
naechste, der schon Strecke enthaelt. historienimport.py hat immer wert_bei()
benutzt - dieselbe Fahrt wurde also je nach Weg unterschiedlich bewertet,
genau das, was die gemeinsame Herkunft von UNPLAUSIBLE_KMH und MINDESTDAUER_S
in verlauf.py ausschliesst.

Am echten recorder-Verlauf nachgewiesen: fuer den Fahrtbeginn 16:39:42 UTC
lieferte naechster_wert() 21325 (der Stand von 16:40:53, also 71 s nach dem
Beginn und aus einem anderen Fahrzeug), wert_bei() dagegen 209177.

_vollstaendig() prueft ausserdem nach unten. Bisher galt nur > UNPLAUSIBLE_KMH;
ein Rueckwaertssprung ergab eine negative Strecke und wurde als "vollstaendig"
gespeichert. historienimport.py verlangt odo_end >= odo_start seit jeher. Die
Pruefung sitzt an der Strecke, nicht an der Geschwindigkeit: durchschnitt_kmh()
liefert bei Dauer 0 None, eine Fahrt mit null Sekunden kaeme sonst vorbei.

Dem Fahrzeugwechsel des Dongles waehrend der Testphase steht das nicht im Weg:
verglichen werden Anfang und Ende derselben Fahrt, und jedes Fahrzeug zaehlt
innerhalb seiner eigenen Fahrt aufwaerts. In allen 23 gespeicherten Fahrten
haette die Pruefung nie ausgeloest. Greift sie doch, werden beide Werte
verworfen und die Fahrt bleibt "offen" - der naechste Screening-Lauf versucht
es erneut.

Verifiziert gegen die echte Aufzeichnung in audi_ha_test: sieben Faelle,
darunter drei Regressionen (normale Fahrt, unmoegliches Tempo, echte 0-km-Fahrt
bei stillstehendem Zaehler). py_compile sauber, 2026.8.31.6 sauber gestartet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 23:27:11 +02:00
tobias 4af38d7e65 Fahrten, Statistik, Trip-Timer (2026.8.31.3)
Der 15-Minuten-Timer war doppelt: der FMM003 wartet laut Konfiguration
(Trip \ Odometer, Ignition OFF Timeout) selbst 900 s, die App noch einmal
15 Minuten. Zusammen eine halbe Stunde. Die Pausenregel ist damit entfallen -
in der Live-Erkennung, im Historienimport und in beiden Oberflaechen. Der
Schwellwert "ab wann ist es ein Parkplatz" hing an derselben Einstellung, hat
damit aber nichts zu tun und steht jetzt als eigene Zahl.

Hoechst- und Durchschnittsgeschwindigkeit je Fahrt. Der Durchschnitt folgt aus
Strecke und Dauer, vmax aus der neuen Rolle GESCHWINDIGKEIT_SENSOR - laut
Konfiguration liest das Geraet die Geschwindigkeit vom OBD/CAN. Es ist der
groesste gemeldete Wert, nicht die tatsaechliche Spitze: alle zehn Sekunden
ein Datensatz. So ist es auch beschriftet.

Der Langzeitverbrauch war um einen ganzen Tankinhalt zu hoch. Gemessen wird
die Strecke ZWISCHEN erstem und letztem Tankstop; verbraucht wurde darauf,
was ab dem ZWEITEN hineinkam - der erste fuellte die Strecke davor. Bei 13
Tankvorgaengen rund 8 Prozent, im Testfall 16,7 statt 8,3 l/100 km. Der Test
hatte die falsche Rechnung festgeschrieben und ist mitkorrigiert. Eine
negative Strecke (falscher Kilometerstand an einem Tankvorgang) gilt jetzt
als unplausibel statt als Null ohne Erklaerung.

Verbrauch je Fahrt bekommt Grenzen: am Sensor nachgemessen loest
can_fuel_volume 0,1 l auf, ein Schritt entspricht also 10/Strecke l/100 km
Fehler. Unter 3 km sagt die Differenz nichts mehr, ueber 60 l/100 km ist es
kein Verbrauch.

Statistik: zusaetzlich "Absolut", und die Einheit steht jetzt in eckigen
Klammern an der Rubrik statt vier Mal am Zeitraum. Fuenf Spalten passen auf
einem Telefon nicht nebeneinander, das Raster bricht um.

Radfoto in Reifen war ein reines <Bild> - Ersetzen und Loeschen von dort aus
gar nicht erreichbar. Jetzt BildMitMenue wie im Panel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:03:28 +02:00
tobias 80d73e8afd Fahrten: Verbrauch-Näherung, 0V-Zustandsanzeige gefiltert, Plausibilitätsgrenze für die Live-Vervollständigung
Verbrauch (l/100km) war bislang totes Schema - kein Codepfad füllte
verbrauch_l_100km je. Jetzt aus der Literstand-Differenz (TANK_LITER_SENSOR)
über die Distanz genähert, live und beim Import, in beiden Frontends.

Die "Zustand"-Kachel zeigte die Batteriespannung ungefiltert direkt vom
Sensor, unabhängig von der Plausibilitätsgrenze der Verlaufsaufzeichnung -
ein Sensorausreißer (0V) zeigte sich dort weiterhin, obwohl die Messwertliste
ihn längst verwarf. Dieselbe Grenze gilt jetzt auch für diesen Anzeigepfad.

Reale Fahrtendaten zeigten eine Fahrt mit 22km in 67s (~1180 km/h) - die
Live-Vervollständigung (screening.py) hatte anders als der Import keine
Plausibilitätsprüfung der Durchschnittsgeschwindigkeit. Jetzt gemeinsam in
verlauf.py (UNPLAUSIBLE_KMH/durchschnitt_kmh) für beide Pfade. Dabei einen
zweiten echten Bug gefunden: _fahrt_screenen() zog sein Ergebnis nie ins
In-Memory-Objekt nach (nur in die Ablage) - eine im selben Durchlauf gerade
erst ermittelte Distanz blieb für spätere Schritte (z. B. Verbrauch) bis zum
nächsten Screening unsichtbar. Beide Stellen jetzt behoben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 21:01:57 +02:00
tobias f337820fc8 Batteriespannung: 8V-Plausibilitätsgrenze; Fahrten: echte Start-/Zielposition und Streckenlinie
Batteriespannung: Werte unter 8V (Sensor-/Verbindungsfehler, nicht physikalisch
plausibel für eine 12V-Bleibatterie) werden nicht mehr erfasst - live und beim
Import. "Neue Räder anlegen"-Knopf sitzt jetzt auf derselben Zeile wie "Montiert".

Fahrten: start_lat/-lon, end_lat/-lon und route wurden bisher nur beim
rückwirkenden Import befüllt, nie bei live erkannten Fahrten (dem Normalfall) -
Screening trägt sie jetzt aus dem GPS-Verlauf nach, unabhängig vom
Kilometerstand-Status. fakeTrack() (eine erfundene Linie) ist entfernt, die
Karte zeichnet jetzt die echte Route oder eine ehrliche Gerade zwischen den
bekannten Punkten. CARTOs anonyme Kartenkacheln verlangen inzwischen einen
API-Schlüssel ("API key required" auf jeder Karte in beiden Apps) - auf
schlüssellose OpenStreetMap-Kacheln umgestellt. Start/Ziel zeigen jetzt Datum
und Uhrzeit über der Adresse; die fehlerhafte "Status"-Zeile ist entfernt.
Batteriespannungs-Diagramm nutzt auf großen Bildschirmen die volle
Spaltenbreite statt einer festen 400px-Deckelung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 17:23:32 +02:00
tobias d8b12da36d pyscript-Backend zur echten HA-Integration umgebaut (HACS-fähig)
Das Backend liegt jetzt als custom_components/audi_dashboard/ vor - eine
normale Home-Assistant-Integration mit Config-Flow, einer sensor-Plattform
und 18 Diensten. Damit ist die App über HACS installierbar; bis das Repo auf
GitHub gespiegelt ist (HACS spricht ausschließlich mit GitHub), installiert
homeassistant/installationspaket/install.ps1 denselben Ordner ohne HACS.

Fünf Installationsschritte entfallen ersatzlos: der pyscript:-Block, der
panel_custom:-Block, das Kopieren der Oberfläche nach www/, das langlebige
Zugriffstoken (der Verlauf wird direkt über die recorder-API gelesen) und
"pip install pypdf" (steht in manifest.json). Das Fahrzeugprofil legt die
Integration beim ersten Start aus ihrer Vorlage an.

Drei alte Schwächen sind dabei mit erledigt:
- Die Nutzlast landet nicht mehr in der Recorder-Datenbank
  (_unrecorded_attributes - das kann nur eine echte Entität).
- Eine laufende Fahrt überlebt einen Neustart (Store statt Arbeitsspeicher);
  fiel sie während eines Ausfalls ins Ende, schließt
  nach_neustart_fortsetzen() sie beim letzten aufgezeichneten Zeitpunkt.
- Sensor-Zuordnungen wirken sofort - die Zustandsbeobachter werden neu
  gebunden, der Neustart-Hinweis und der Neustart-Dienst sind weg.

Namensvertrag geändert, beide Oberflächen mitgezogen:
pyscript.audi_dashboard_x -> sensor.audi_dashboard_x,
pyscript.audi_dashboard_y -> audi_dashboard.y. Eine Companion-App vom alten
Stand findet nach dem Umstieg nichts mehr und muss neu gebaut werden; das
Panel liegt in der Integration und kann nicht driften.

Der selbstgebaute Updater entfällt - HACS ist die Update-Mechanik, die Home
Assistant kennt. Die Versionierung schrumpft auf eine Quelle: manifest.json.

Geprüft am laufenden Testcontainer (Container byteweise identisch mit dem
Repo): alle 18 Dienste, Panel, Config-Entry neu laden, Historienimport,
echter Shell-Beleg in-process, Neuinstallation im Wegwerf-Container blank mit
automatisch nachinstalliertem pypdf. Companion-App: tsc sauber, 112/112
Tests, beide Rauchtests gegen das laufende Backend grün. Belegparser 8/8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 23:53:56 +02:00