d889353cbede5d0930ff61fb9bef7f4defdaa4d2
12 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
b73a8fb334 |
Meldezeit auch nach hinten prüfen - "Geparkt seit 20698 Tg." war die Unix-Epoche
geraetezeit() prüfte nur, ob die Meldezeit in der Zukunft liegt. Ein Sensor, der 0 meldet, rutschte durch, und fromtimestamp(0) ergibt 1970 - auf der realen Instanz sichtbar als "Geparkt seit 20698 Tg. 9 Std. 39 Min.". Neu geraetezeit_plausibel(): nicht aus der Zukunft und nicht älter als MELDEZEIT_RUECKLAUF (365 Tage). Geprüft wird an drei Stellen - beim Auslesen der Gerätezeit, beim Setzen des Parkbeginns und beim LADEN aus dem Laufzeit-Store, denn ein einmal falsch gespeicherter Wert überlebt sonst jedes Update. Fängt auch eine im Setup falsch zugeordnete ID-Entität ab: das flespi-Gerät hat drei ID-Sensoren, deren Namen dem Zeitstempel ähneln, und deren Werte ergeben als Unix-Zeit ebenfalls 1970. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
d1e3f7230c |
Parkbeginn nach einem Neustart aus der Aufzeichnung holen (2026.9.1.7)
Der Zuhoerer bekommt den Zuendungswechsel nur mit, wenn Home Assistant laeuft. Ging die Zuendung aus, waehrend es unten war - ueber Nacht der Normalfall -, feuerte nichts, und die Registrierung beim Hochfahren wird bewusst ignoriert (sonst begaenne die Parkdauer bei jedem Neustart neu). Ergebnis war "Parkdauer unbekannt", obwohl der Zeitpunkt im recorder steht. _parkbeginn_nachholen() laeuft einmal in _nach_start und schlaegt ihn nach - nur, wenn kein Wert gespeichert ist und die Zuendung auf "aus" steht. Genommen wird der letzte echte Wechsel an -> aus im Fenster von sieben Tagen; gibt es keinen, bleibt es bei "unbekannt" statt den Rand des Fensters zu erfinden. Wieder mit der Meldezeit desselben Datensatzes statt seiner Ankunftszeit - dieselbe Begruendung wie in verlauf.geraetezeit(), hier rueckblickend. VERIFIZIERT in audi_ha_test, der Test trennt genau die beiden Zeiten: Speicher geleert, neu gestartet -> "Parkbeginn aus der Aufzeichnung nachgeholt: 09:04:57". Das ist die Geraetezeit; angekommen war der Datensatz um 09:44. Ein zweiter Neustart ruehrt den Wert nicht an, schreibt keine Zeile und erzeugt keinen Fehler. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
553e128066 |
GNSS-Rollen vorbereitet, "Geparkt seit" von der Zuendung (2026.9.1.5/.6)
GNSS-STRECKENROLLEN, NOCH OHNE VERBRAUCHER 11806 steht seit dem 01.09. auf GNSS. Zwei neue Sensorrollen angelegt, damit nach der ersten echten Fahrt nur noch gemessen und nicht mehr zugeordnet werden muss: GNSS_KM_SENSOR (total_calculated_mileage, der robustere fuer eine Fahrtstrecke - ein verlorener Datensatz verfaelscht die Differenz nicht) und GNSS_TEILSTRECKE_SENSOR (segment_mileage, zeigt WO Strecke fehlt, taugt als Gegenprobe). Kein Code liest sie; die Zuordnung aendert nichts. KM_SENSOR bleibt der Anker - er ist der Tacho des Fahrzeugs und driftet nicht. Der alte Warnhinweis dort zeigt jetzt auf die neue Rolle statt ins Leere. "GEPARKT SEIT" KOMMT VON DER ZUENDUNG Die Anzeige rechnete "jetzt minus ts_end der juengsten Fahrt". Das ist keine Aussage ueber das Parken, sondern ueber die Fahrterkennung: am 01.09. stand dort "Geparkt seit 2 Tg. 16 Std.", waehrend am Vorabend 7 km gefahren wurden - die Fahrt fehlte im Bestand, weil trip_status festhing. Der Koordinator merkt sich jetzt den Zeitpunkt, zu dem die Zuendung zuletzt ausging, in der Zeit des Geraets. Er liegt im Laufzeit-Store neben fahrt_start_ts und ueberlebt einen Neustart. Kein Rueckfall auf die Fahrtenliste: null heisst unbekannt und wird auch so angezeigt - ausdrueckliche Ansage des Eigentuemers, eine falsche Zahl ist schlechter als keine. Beim Ausliefern fiel derselbe Neustart-Fehler auf wie bei der Phantomfahrt: der Zuhoerer las die Registrierung der Entitaet als Wechsel und stempelte den Parkbeginn bei jedem Neustart neu. if alt is None: return behebt es. Merkposten fuer dieses Projekt: jeder neue Zustandszuhoerer braucht diese Pruefung. VERIFIZIERT in audi_ha_test: Neustart laesst 09:34:15 unveraendert; Zuendung an -> null; Zuendung aus mit Geraetezeit von vor 40 Minuten -> 09:04:57 statt jetzt. Companion-App gleichgezogen, tsc --noEmit sauber, 165/165 Tests gruen. NOTIERT, NICHT GEBAUT: der GNSS-Zaehler driftet im Stand. Die 0,034 km waren GPS-Rauschen, nicht Aufloesung - der Dongle lag unbewegt. Die GNSS-Zuwaechse brauchen deshalb ein Bewegungstor, bevor sie summiert werden duerfen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4cc91c461b |
Fahrtzeiten vom Geraet, Trip und Zuendung getrennt (2026.9.1.3)
Enthaelt 2026.9.1.2, das nie einzeln ausgeliefert wurde. FAHRT- UND TANKZEITEN KOMMEN VOM GERAET Fahrtbeginn war datetime.now() - die Uhrzeit, zu der Home Assistant den Wechsel verarbeitet. Hat das Geraet gepuffert (Funkloch, Tiefgarage, Tiefschlaf), liegt die Wahrheit beliebig weit davor. Gemessen: ein Datensatz mit Fahrtende trug die Geraetezeit 07:29:04 und kam um 07:35:23 an. Neue Sensorrolle MELDEZEIT_SENSOR (message_timestamp, Unix-Sekunden). Der Wert ist UTC, keine Ortszeit - nachgemessen lag der Versatz zur UTC-Uhr von HA bei Sekunden, nicht bei zwei Stunden; eine Zeitzonenumrechnung baute einen Zwei-Stunden-Fehler ein. geraetezeit() liegt in verlauf.py, weil Fahrt- und Tankerkennung denselben Zeitstempel bestimmen muessen. tankerkennung._automatisch_anlegen() stempelte bisher ebenfalls mit now(); ein aus einem gepufferten Datensatz erkannter Tankvorgang trug damit die Uhrzeit des Auftauchens. Die flespi-Integration setzt die Entitaeten eines Datensatzes nacheinander - gemessen Zuendung 07:35:23.633, zugehoerige Meldezeit 2 ms spaeter. Wer sofort liest, bekommt den vorigen Datensatz: beim Fahren zehn Sekunden daneben, im Stand Stunden (On Stop Min Period = 43200 s). geraetezeit() wartet deshalb bis zu 2 s auf den passenden Wert. Zwei Notbremsen, beide live ausgeloest: Zeitstempel in der Zukunft und Ende vor dem Beginn. TRIP UND ZUENDUNG SIND ZWEI ROLLEN ZUENDUNG_SENSOR zeigte auf das Trip-Signal; im Setup stand "Zuendung/ACC" ueber einer Trip-Entitaet und die echte Zuendung war nirgends zugeordnet. Neu: TRIP_SENSOR loest Fahrten aus, ZUENDUNG_SENSOR liefert nur noch die Anzeige "faehrt/steht". verlauf.fahrtsignal() ist die eine Stelle, die entscheidet - Trip-Status wenn zugeordnet, sonst Zuendung, damit bestehende Installationen unveraendert weiterlaufen und Livepfad und Rueckblick nicht auseinanderlaufen. VERIFIZIERT in audi_ha_test, jeder Weg einzeln: - Fahrtbeginn 08:30:03 (Geraetezeit) statt 08:38:27 (Ankunft) - Fahrtende 08:04:40 -> 08:09:22 statt 08:11:04 -> 08:11:24 - Tankvorgang 08:18:45 statt 08:38:51 - 20 Minuten frueher - Meldezeit in der Zukunft und Ende vor Beginn: Warnung, Ankunft genommen - Zuendung schalten legt keine Fahrt mehr an, Trip-Signal schon Der Livetest fing dabei einen NameError, den py_compile nicht sehen konnte: der Import von geraetezeit in tankerkennung.py fehlte. Kompiliert ist nicht verifiziert. Alle Testdatensaetze wurden ueber die eigenen Dienste wieder entfernt; Bestand unveraendert 11 Fahrten, 13 Tankvorgaenge, keine offene Fahrt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c0acc836f0 |
Fahrgestellnummer (FIN) automatisch aus den zugeordneten Sensoren ableiten
Neues identitaet.py: durchsucht das Geräte-Register der aktuell im Setup zugeordneten Sensoren (cupra_eu_data_act, FMM003, ...) nach einem VIN-förmigen Geräte-Identifier/Seriennummer, statt ein eigenes Setup-Feld zu verlangen. Mehrere übereinstimmende Quellen werden akzeptiert, abweichende nur geloggt statt geraten; eine bereits von Hand eingetragene FIN wird nie überschrieben. Läuft nach jedem Start und nach jeder Setup-Änderung (koordinator.py/dienste.py). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f4222b715f |
Batteriespannung-Fallback: zeigt letzte Ruhespannungsmessung ueber Neustarts hinweg
Der RAM-only Fallback fuer die Zustand-Kachel wurde bei jedem Neustart geleert und zeigte "unbekannt", solange seit dem Neustart keine echte Live-Messung eintraf (Dongle bei ausgeschaltetem Fahrzeug erwartungsgemaess immer offline). spannung_cache_vorladen() laedt ihn jetzt beim Start aus der gespeicherten Historie vor, begrenzt auf den vereinbarten Bereich 10,0-13,0 V (SPANNUNG_MIN_V bis AGM_RUHE_MAX_V) - eine Generatorspannung (z.B. 15,4 V) soll dort nie als Batteriespannung erscheinen. Version 2026.8.27.21, im Testcontainer verifiziert (12,149 V statt "unbekannt", trotz Dongle weiterhin 0 V live). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
70253e83a5 |
Fahrterkennung: FMM003-Funklöcher reißen keine Fahrt mehr auseinander
Die Zündungs-Entität stammt vom FMM003-Tracker; verliert er unterwegs kurz die Verbindung, meldet Home Assistant "unavailable" statt eines echten Zündungszustands. Die Live-Erkennung wertete das bisher wie "aus" - eine Funklücke über der Pausenzeit teilte eine durchgehende Fahrt in zwei. zuendung_geaendert() ignoriert "unavailable"/"unknown" jetzt vollständig und leitet "fährt gerade" aus dem eigenen Zwischenstand (fahrt_start_ts) statt aus dem letzten Rohwert ab. historienimport.py bekommt zusätzlich eine Plausibilitätsprüfung: eine errechnete Durchschnittsgeschwindigkeit über 300 km/h deutet auf einen Kilometerstand-Ausreißer an der Fahrtgrenze hin, nicht auf eine echte Fahrt - die Strecke wird dann verworfen statt eine unmögliche Fahrt anzuzeigen. Tankerkennung: optionaler zweiter Sensor für das Tankvolumen in Litern (TANK_LITER_SENSOR, direkt vom CAN) neben dem bisherigen Prozent-Füllstand. Ist er zugeordnet, übernimmt er die automatische Tankerkennung vollständig - genauer als der Umweg über das im Fahrzeugprofil hinterlegte Tankvolumen, und der erkannte Anstieg liefert gleich eine grobe Vorbelegung für die getankte Menge statt eines leeren Feldes. Ohne den Sensor bleibt alles beim Alten. Der historische Import zieht mit derselben Präferenz nach. Manifest auf 2026.8.25.2, beide Änderungsrunden live im Testcontainer verifiziert (py_compile, Neustart, sauberes Setup-Log). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
fb251154c7 |
Ölwechsel/Inspektion-Anzeige repariert, Selbst-Update der Integration gebaut
Zwei getrennte Themen in einem Commit, beide in derselben Sitzung entstanden:
1. Ölwechsel/Inspektion wurden komplett ausgeblendet ("kein Eintrag im
Servicebuch"), sobald kein Servicebucheintrag vorlag - selbst wenn der
zugeordnete Sensor eine gültige Fälligkeit meldete. In beiden Frontends
prüfte die Anzeige nur den Servicebuch-Zweig, bevor sie die
Fahrzeugmeldung überhaupt las. Jetzt steht die Fahrzeugmeldung für sich;
fehlt zusätzlich ein Servicebucheintrag, übernimmt eine neue,
fahrtenlog-basierte Prognose (kmProTagAusFahrten()/meldungsPrognose())
die Hochrechnung statt der Servicebuch-Rate - deckelt auf die vom
Fahrzeug selbst gemeldete Zeitgrenze, falls zu wenig gefahren wird.
2. install.ps1 als Update-Weg wird von Windows Smart App Control blockiert,
ohne Umgehungsmöglichkeit. Die Integration lädt sich jetzt auf
Tastendruck selbst von Gitea (aktualisierung.py), verifiziert das
Manifest vor jedem Tausch und tauscht per os.rename mit automatischem
Rollback bei Fehlern - install.ps1 bleibt nur noch für die
Erstinstallation nötig. Zugangstoken über einen neuen OptionsFlow in
entry.options, nie in configuration.yaml.
Nebenbei: mehrere seit der HACS-Ausschluss-Entscheidung liegen gebliebene
falsche HACS-Referenzen in Code-Kommentaren und einem UI-Text korrigiert.
Details, Sicherheitsbegründung und Verifikationsstand in AGENTS.md,
Abschnitte I und J.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
1354ca6b06 |
OTA-Updates für die iOS-App; HACS-Fehlannahme korrigiert
HACS kann laut eigener Dokumentation grundsätzlich nicht mit privaten GitHub-Repositories arbeiten (hacs.xyz/docs/faq/private_repositories) - keine Ausnahme für Tokens oder verbundene Konten. Meine frühere Annahme, HACS käme damit zurecht, wenn es unter dem richtigen Konto angemeldet ist, war falsch. Da das Repository aus Lizenzgründen privat bleiben muss (Audi-Hausschrift, Typenschilder), ist install.ps1 damit nicht die Rückfallebene, sondern der einzige Installationsweg - README, INSTALL.md, ANLEITUNG.md, install.ps1 und VERSIONIERUNG.md korrigiert. Oberflächen-Updates für die iOS-App laufen jetzt ohne Xcode: @capgo/capacitor-updater eingebaut, ein Update-Abschnitt in den Einstellungen lädt ein neues Bündel und tauscht die Oberfläche aus. Kein Selbstlauf (autoUpdate: false) - nur auf Tastendruck, nie während der Benutzung. Das Bündel liegt in der Integration selbst (custom_components/audi_dashboard/frontend/app/), nicht unter /local/: so reist es bei jeder Installation automatisch mit, ohne zweiten Auslieferungsweg. Gebaut von companion-app/scripts/ota-paket.ps1 (neuer Befehl: npm run ota), gemeldet über sensor.audi_dashboard_app_version (neues Feld daten.buendel). Ein echter Bug beim Bauen gefunden: [IO.Compression.ZipFile]::CreateFrom- Directory schreibt unter Windows PowerShell 5.1 Backslashes in die Zip-Einträge - iOS hätte das Archiv falsch entpackt. Behoben, indem die Einträge von Hand mit "/" geschrieben werden. Rückfallebene: notifyAppReady() läuft erst, wenn React nachweislich gerendert hat (App.tsx). Kommt diese Meldung nicht, rollt das Plugin nach 20 Sekunden von selbst auf das vorherige Bündel zurück. Am laufenden Testcontainer verifiziert: die ausgelieferte Zip hasht exakt auf den in bundle.json hinterlegten Wert, 13 Einträge, index.html in der Wurzel, keine Backslashes, keine Beschädigung. tsc sauber, 117/117 Tests (5 davon neu für buendelPasst() - dabei eine echte Lücke gefunden: die Funktion hätte bei unbekannter eigener Version fälschlich ein Update angeboten, jetzt genauso vorsichtig wie versionVergleichen). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
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> |