ZUENDUNG_SENSOR liegt jetzt auf dem Trip-Signal des FMM003 statt auf dem rohen,
prellenden Zuendungseingang. Damit kommt die Pausentoleranz vom Geraet - eine
Fahrt beginnt erst bei Zuendung UND Bewegung UND Start Speed.
MINDESTDAUER_S wandert nach verlauf.py und gilt jetzt auch im Livepfad. Vorher
verwarf nur der Import Zuendphasen unter 60 s; live entstanden daraus am 31.08.
elf Fahrten mit 0 km, zwei davon mit null Sekunden Dauer.
Das Panel erfand einen Literpreis von 0,00 EUR, wenn die Kosten noch nicht
feststanden (null/liter ist 0 in JavaScript) - neue Hilfsfunktion literpreis()
prueft beides, wie die App seit jeher. schnittpreis() teilte ohne Nennerpruefung
und konnte "NaN" oder "unendlich" anzeigen.
Der Setup-Dialog ist wirklich modal: die Tab-Leiste hatte einen eigenen Zuhoerer
vor der Sperre und liess einen Tabwechsel bei offenem Fenster zu.
Verwaister Code entfernt: drei Funktionen und vier Regeln im Panel, 20 Regeln in
der App.
Offen bleibt allein die leere Erstzulassung - eine Angabe, keine Aenderung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die App blieb nach einem Neustart von Home Assistant auf dem alten Stand
stehen, mit einer 502-Fehlerzeile, die erst ein Beenden der App wegbekam.
Zwei Ursachen: 502/503/504 galten als harter Ladefehler statt als "Server
faehrt gerade hoch", und nach dem Wiederverbinden wurde genau einmal
nachgeladen - schlug das fehl, kam nie wieder ein Versuch. Beides behoben,
vier Regressionstests dazu.
OTA: das Buendel ist von HEAD ueber die Platte bis zu den ausgelieferten
Bytes nachweislich deckungsgleich. Die Fassung haengt jetzt trotzdem als
?v= an der Adresse (der statische Pfad kommt ohne Cache-Control, aber mit
ETag), und ein Pruefsummenfehler wird erklaert statt durchgereicht.
Statistik: der Gesamtwert steht jetzt als grosse Zahl in der Kopfzeile,
darunter bleiben vier Spalten - fuenf passen auf dem Telefon nachweislich
nicht in eine Zeile.
Fahrzeugfoto ohne Beschnitt und ohne Bodenschatten, damit auch ohne den
Schalter dafuer. Setup filtert zusaetzlich nach dem Signalnamen aus dem
Katalog.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Share-Erweiterung: ein PDF aus Mail landet ueber Teilen -> DataMetric360 als
Tankbeleg. Alles Native liegt versioniert unter companion-app/native/, weil
ios/ gitignored ist und npx cap add ios es sonst wieder frisst;
scripts/ios-teilen-einrichten.mjs haengt es bei jedem Bau ins Xcode-Projekt
und ist in ios-signieren.sh eingehaengt. Der pbxproj-Teil ist auf keinem Mac
erprobt - er bricht vor dem Schreiben ab, und docs/SHARE_EXTENSION.md
beschreibt dieselben Handgriffe fuer Xcode.
"In den Kalender uebernehmen" ging in der App nie: WKWebView ignoriert das
download-Attribut, der Klick lief ins Leere. Auf dem Geraet jetzt
@capacitor/filesystem plus @capacitor/share.
useTheme/useBoden legten je Aufrufer eigenen Zustand an - fuenf Kopien. Der
Schalter aenderte nur seine eigene, data-theme in App.tsx blieb stehen, die
Tag/Nacht-Umschaltung wirkte erst nach einem Neustart. Jetzt ein Speicher je
Einstellung ueber useSyncExternalStore. Zwei Regressionstests, gegen den
alten Stand als fehlschlagend nachgewiesen.
Alle Popups nach Apple HIG: neue Bausteine Sheet und ActionSheet, blickdicht
und mit abgedunkeltem Schleier, in beiden Codebasen. Popup portalierte nach
document.body - ausserhalb von [data-theme] - und war deshalb im Tagmodus
fast unsichtbar; Portal zielt jetzt auf .ads-root.
ImagePlaceholder merkte sich "fehlgeschlagen" ohne die Adresse: nach einem
leeren Galerieplatz zeigten auch die mit Foto nur noch den Platzhalter.
Vier Regressionstests, ebenfalls gegen den alten Stand geprueft.
Bildadressen tragen jetzt einen Cache-Brecher - HA liefert /local/ mit 31
Tagen Cache-Vorgabe aus, im Panel eingefuegte Radfotos erschienen in der App
deshalb nicht.
uebersichtsbild: Panel speichert den Namen, die App verglich gegen den
Dateinamen - der Vergleich traf nie zu. Kanonisch ist der Name.
Weiter: Navigationspfeil statt gleichschenkligem Dreieck auf der Streckenlinie
(die Kerbe unterscheidet Kopf und Ende), CI-Symbol tour-s als Fahrten-Icon,
Datumsfelder zeigen ihren Wert ohne erstes Antippen, feste Beispielnamen im
Setup, Kopf-Gegengewicht fuer mittige Titel, Standort-Blatt mit festem
Fussabstand, NSLocationWhenInUseUsageDescription, watchPosition fuer die
Live-Ortung, Art-Pille wieder als Knopf, Zwischenablage fuer Tankbelege.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Aufgezogen wurde das Blatt exakt so hoch wie sein Inhalt - die Knoepfe Route
und Teilen schlossen dadurch unten buendig mit der Menueleiste ab.
Apple benennt dafuer das passende Konzept: Blaetter rasten auf "detents" ein,
Hoehen, auf denen ein Blatt natuerlich zur Ruhe kommt; large ist das voll
ausgefahrene Blatt, medium etwa die Haelfte davon (Human Interface
Guidelines, Sheets - nachgelesen, nicht aus dem Gedaechtnis zitiert). Unser
Blatt hatte im aufgezogenen Zustand ueberhaupt keine Rasthoehe, sondern nur
seine Inhaltshoehe.
Jetzt min-height: 50% im aufgezogenen Zustand. Der Ueberschuss liegt unter
den Knoepfen und haelt sie von der Leiste frei. Die eingeklappte Hoehe bleibt
unberuehrt, weil die Verschiebung mit 100% der jeweiligen Blatthoehe minus
dem Guckwert rechnet.
Gemessen: Panel 311px auf 622px Karte, App 298 auf 595 - beide exakt 50%,
Luft unter den Knoepfen 89 bzw. 76px statt zuvor 18.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim "Zuendung an"-Patch habe ich den Begruendungskommentar in den
${...}-Ausdruck gesetzt statt in den Markup-Text. Dort ist <!-- kein
HTML-Kommentar, sondern JavaScript. Folge: audi-dashboard-app.js liess sich
nicht mehr als Modul parsen, connectedCallback() brach ab, das Panel hatte
keinen Shadow Root - der Bildschirm blieb leer.
Betroffen sind .14 bis .18, also alles, was seit dem auf Gitea lag. Wer in
dieser Zeit aktualisiert und neu gestartet hat, bekam ein totes Panel.
Warum es durchrutschte - und das ist der eigentliche Befund: "node --check"
prueft eine .js-Datei als SCRIPT, und dort sind HTML-artige Kommentare per
Annex B ausdruecklich erlaubt. Der Browser laedt dieselbe Datei als MODUL,
wo sie verboten sind. Die Pruefung, auf die sich dieses Projekt bei jeder
Panel-Aenderung verlaesst, kann diesen Fehler grundsaetzlich nicht finden.
Ab sofort gilt: die Datei vor dem Ausliefern als Modul pruefen, also unter
.mjs kopieren und node --check darauf laufen lassen. Rueckwirkend ueber alle
heutigen Commits geprueft - .14 ist der erste kaputte.
Erschwerend kam dazu, dass ich den Panel-Tab nach .14 nie neu geladen habe.
Alle spaeteren "live geprueft"-Aussagen zur Panel-Seite liefen gegen das noch
im Speicher stehende alte Skript und waren damit wertlos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die angezeigte "Verfuegbare Version" ist das gespeicherte Ergebnis der letzten
Pruefung, nicht der Live-Stand - version_pruefen() laeuft ausschliesslich auf
Tastendruck. Im Zweig "Integration ist aktuell" stand der Zeitpunkt der
Pruefung schon dabei, ausgerechnet im Verfuegbar-Zweig nicht. Eine Wochen alte
Zahl sah dort aus wie eine Tatsache.
Schlimmer: der Knopf "Auf Update pruefen" gab es nur im Zweig "ist aktuell".
Sobald einmal ein Update gefunden war, liess sich die Angabe gar nicht mehr
auffrischen - sie blieb bis zur Installation stehen, auch wenn auf Gitea
laengst eine neuere Fassung lag.
Beides in beiden Codebasen ergaenzt: Zeitstempel als Nebenzeile an der
Version, "Erneut pruefen" als zweiter Knopf unter "Update installieren".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
--tile gehoert auf den Seitenhintergrund und sonst nirgends. Was auf einer
Kachel oder einem Blatt liegt, nimmt --tile-deckend (deckende Flaeche) oder
--ios-fill (Bedienelement). Grund: --tile ist nachts absichtlich
durchscheinend und tags deckend weiss - auf einer anderen Flaeche versagt es
deshalb in genau einem Theme, tags unsichtbar, nachts als doppelter Schleier.
Genau daran sind heute drei Fehler entstanden, jeder in nur einem Theme
sichtbar.
Geprueft zur Laufzeit statt per Textsuche, weil es auf die aufgeloeste Farbe
gegen die des naechsten gefuellten Vorfahren ankommt - beides steht nicht im
Quelltext. Panel 21 Routen, App 18 Seiten, beide Themes. Einziger
verbleibender Treffer ist die Listenzeile auf der Kachel im Tagmodus, wo
beide deckend weiss sind und die Zeile bewusst mit der Kachel verschmilzt.
Die Pruefung selbst ist gegengetestet: der heute behobene Schliessen-Knopf
wurde von Hand auf den alten Wert zurueckgesetzt und sofort erkannt. Eine
Pruefung, die man nie hat scheitern sehen, belegt nichts.
Dabei gefunden und angeglichen: die Kartenflaechen der Detailseiten trugen in
der App --tile-2, im Panel --tile-deckend - nachts ein zweiter Schleier auf
der ohnehin durchscheinenden Kachel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der runde Knopf malte var(--tile) auf ein Blatt, das selbst deckend ist - im
Tagmodus beides #FFFFFF, also weiss auf weiss. Nachts faellt es nicht auf,
weil --tile dort ein Schleier ueber dunklem Grund ist.
Derselbe Fehlertyp wie bei den Wischzeilen von heute, nur andersherum: dort
addierten sich zwei Schleier im Nachtmodus, hier verschwindet eine Flaeche im
Tagmodus. Beide Male, weil eine Flaeche auf einer Flaeche mit --tile gemalt
wurde. Jetzt --ios-fill, in diesem Projekt ohnehin das Zeichen fuer "das hier
laesst sich bedienen"; es traegt in beiden Themes. In beiden Codebasen
geaendert - das Panel hatte den Fehler genauso.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Es gibt keinen Bewegungssensor am Fahrzeug. Der einzige Anhaltspunkt ist
ZUENDUNG_SENSOR, und der meldet on auch bei blosser Zuendung oder in
Zubehoerstellung - "Fahrzeug faehrt" behauptete also mehr, als bekannt ist.
Mein zwischenzeitlicher Vorschlag, zusaetzlich eine laufende Fahrt zu
verlangen, war falsch begruendet: fahrt_start_ts in fahrterkennung.py wird aus
genau demselben Signal abgeleitet und haette nur eine zweite Huelle um
dieselbe Aussage gelegt.
Der umgekehrte Fall bleibt unangetastet: Zuendung aus heisst verlaesslich,
dass gerade nicht gefahren wird - "Fahrzeug steht" und "Geparkt seit ..."
stehen weiter. Zwei Typ-Kommentare, die dieselbe Gleichsetzung
weitertrugen, sind mitkorrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Blatt trug padding-bottom: max(18px, env(safe-area-inset-bottom)). Es
liegt aber nicht am unteren Bildschirmrand, sondern ueber der Tableiste - und
die haelt den Bereich des Home-Indikators bereits frei. Der Einzug wurde also
doppelt gezaehlt: auf dem Geraet war das Blatt rund 16px hoeher als noetig und
schob sich beim Aufziehen entsprechend weiter hoch. Am Rechner faellt das
nicht auf, dort ist der Einzug 0. In beiden Codebasen entfernt.
Ausserdem: der Blatthintergrund der App stand auf --canvas statt auf dem
deckenden Wert, den das Panel dort nimmt - unter dem Blatt liegt die Karte.
Nachgemessen mit frisch gestarteten Panes: Blatt 240px, Unterkante buendig mit
der Karte, in beiden Anwendungen gleich.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Anlaeufe, die ersten beiden mein Fehler. Gemeldet war "Icon falsch im
Knopf platziert". Ich habe die Zeichenflaeche gemessen, sie fuellt 20,9x15,6
des 24er-Rasters gegen 20x20 bis 24x22 bei den Nachbarn, und daraus auf "zu
schwer und aussermittig" geschlossen - also verkleinert. Zwei Fehler darin:
gemessen habe ich das Panel und geaendert habe ich beide, ohne das Symbol der
App je selbst zu messen; und "fuellt weniger Flaeche als die Nachbarn" spricht
fuer "wirkt kleiner", nicht dagegen.
Nach der Ruecknahme im Panel zeigte die Messung der App den echten Fehler
dort: ihr mapLayer-Pfad begann mit grossem M statt kleinem m. Beim ersten
Befehl ist das gleichbedeutend, aendert aber alles danach - nach M gelten
folgende Zahlenpaare als absolute Linien, nach m als relative. Der zweite
Punkt sprang damit auf (-8.97,-5.66), weit aus dem Raster: das Symbol war
verzerrt, nicht bloss falsch dimensioniert. Pfad wortgleich vom Panel
uebernommen, alle vier Steuerungssymbole vergleichen sich jetzt zeichengleich.
Damit stand die urspruengliche Meldung fuer sich und war schlicht richtig: die
flache Form wirkt bei gleicher Kastengroesse kleiner. Beide zeichnen sie jetzt
mit 26px statt 22px - dieselbe Loesung wie beim Oelwechsel-Icon der
Servicebloecke, das aus demselben Grund 26px neben 20px bekommt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ziehen zum Aktualisieren funktionierte auf keinem Geraet, in keiner der
beiden Anwendungen - und der Grund entwertet zugleich, wie es bisher geprueft
wurde. Beide trieben die Geste ueber pointermove und riefen dort
preventDefault(). Das verhindert laut Spezifikation kein Scrollen; darueber
entscheidet allein touch-action. Auf echtem Touch uebernimmt der Browser die
senkrechte Geste, schickt pointercancel und stellt pointermove ein - der Zug
wird zurueckgesetzt, lange bevor er die Schwelle erreicht. Eine Maus kennt
diese Uebernahme nicht, synthetische PointerEvents ebenso wenig: genau
deshalb lief die Geste 2026-08-17 im Test sauber durch und am Geraet nie.
Jetzt laeuft sie auf Touch-Ereignissen, touchmove zwingend mit passive:false
(sonst ist preventDefault() wirkungslos); der Zeigerweg bleibt fuer Maus und
Stift und ignoriert pointerType "touch". Mit echten TouchEvents geprueft,
inklusive defaultPrevented - dem einzigen Signal, das belegt, dass das native
Ueberscrollen wirklich unterbunden ist.
Der zuletzt nicht nachstellbare Befund war nachtmodus-spezifisch: --tile ist
dort ein durchscheinender Schleier, und die Wischzeilen malten ihn ein
zweites Mal auf die Kachel, auf der sie ohnehin liegen. Am Tag sind beide
deckend weiss, deshalb war nichts zu sehen. Das Panel nutzt an dieser Stelle
--tile-deckend; dieses Token fehlte im Design-System und ist jetzt da.
Ausserdem: steht das Auto auf einem benannten Platz, zeigen beide dessen
Namen statt der naechsten Hausnummer - Nominatim liefert ihn mit, die
Pruefung auf die Art der Flaeche verhindert, dass irgendein benanntes
Gebaeude die Anschrift verdraengt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fahrzeug-Pin auf der Standortkarte fehlte: die Marker-Effekte lesen Refs,
die erst im asynchronen Leaflet-Import gesetzt werden. Beim ersten Lauf leer,
Effekt steigt aus - und weil die Koordinaten sich danach nicht mehr aendern,
lief er nie wieder. Ein Bereitschaftsschalter in den Abhaengigkeiten behebt
das fuer Marker, Kachelebene und eigene Position zugleich.
Kachelpfeil auf "Mein Audi" sass auf halber Kachelhoehe statt oben neben der
Ueberschrift; Auswahlfelder hatten nach appearance:none ueberhaupt keinen
Aufklapp-Pfeil mehr.
SmartDeal: das Datumsfeld war fehlerhaft und die Abfrage, bis wann der Rabatt
gilt, fehlte ganz. Das Panel fragt beim Einschalten und zeigt danach nur an -
genau daran haengt, dass der Rabatt von selbst auslaufen kann. Portiert.
Adressen statt Koordinaten: Nominatim drosselt uns inzwischen. Beide Apps
fielen korrekt zurueck, merkten sich Treffer aber nur bis zum Neuladen. Jetzt
dauerhaft im selben Cache wie die Tankstellensuche.
Ziehen zum Aktualisieren auf dem Geraet: dem Scrollbehaelter fehlte
overscroll-behavior, das native Overscroll nahm die Geste weg - derselbe
Befund, den das Panel am 2026-08-17 hatte.
Ausserdem: Platzhalter wieder in voller Groesse, FIN statt Fahrgestellnummer,
Details als Hinweiszeile, Chevron an der Batteriespannung, Reifenzeile
"aktuell montiert:", Zahnrad statt Stift am Anzugsmoment, Radkilometer in der
Zahlenschrift, Layer-Icon zentriert, share-s beim Teilen, Schliessen-Knopf nur
bei aufgezogener Karte.
Nicht nachstellbar und zurueckgemeldet: "Fahrten/Tanken, grauer Hintergrund" -
Panel und App sind dort deckungsgleich.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei zusammenhaengende Runden, alle live bei 375x812 gegen audi_ha_test
geprueft und in beiden Codebasen angewandt.
Paritaetsrunde 2: der gemeinsame Rahmen war das eigentliche Problem -
Seitenrand, Kachelabstaende, Kopfleiste, Tableiste und vier Bausteine des
Design-Systems trugen noch den Stand vor der iOS-Entscheidung. Dazu sieben
Bildschirme neu aufgebaut. Zwei Panel-Fehler dabei mitbehoben: teaser()
zeigte unter "Letzte Fahrt" den aeltesten Datensatz, und "Daten bearbeiten"
war ein toter Knopf.
Paritaetsrunde 3: das Panel hat nie Audi Type gerendert. @font-face in einem
Shadow Root wird ignoriert - Schriftschnitte registriert der Browser pro
Dokument, nie pro Shadow Tree. Die drei Schnitte liegen jetzt in
audi-dashboard-schriften.css und werden ins Dokument gehaengt. Damit erledigt
sich eine ganze Reihe von "die Schrift sieht anders aus"-Eindruecken: die
beiden Anwendungen zeigten tatsaechlich verschiedene Schriften.
Ausserdem "Daten bearbeiten" im Panel gebaut und portiert, das Zeilenmenue
entfernt und die letzten neun Bildschirme angeglichen.
Designpruefung: die fuenf Punkte der Reihenfolge. Beim vierten hat das Messen
den Befund veraendert - gezaehlt waren die deklarierten Groessen, wirksam war
laengst eine saubere Sieben-Schritt-Skala mit 27 Ausreissern; die sind jetzt
auf den naechsten Schritt gezogen, keiner verschiebt sich um mehr als 1px.
Zuletzt: die Standortvorschau zeichnete die falsche Nadel (das Panel wechselt
den Icon-Satz ab 34px, die App nahm immer den grossen), und der Kopfabstand
der App ist auf den sicheren Bereich reduziert - die 56px des Panels liegen
dort unter der Kopfleiste von Home Assistant, in der nativen Huelle steht
darueber nichts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Systematischer Bildvergleich der companion-app gegen das HA-Panel (companion-app/AGENTS.md
Kapitel 1-11): Farbtoken/Radien aus dem falschen Stylesheet gelesen (iOS-Overlay statt Basis-CSS,
betraf fast jede Kachel/Farbe/Radius app-weit), vier app-weite @audi-dash/ui-Bugs (Switch/Seg/Feld
rot statt neutral bzw. falsche Feldbreite), Reifen-Seite strukturell neu gebaut (beide Radsätze
gleichzeitig statt Umschalter, editierbare Felder, Anzugsmoment-/km-Korrektur), Standort-Feature
komplett neu (fehlte bisher ganz), sowie diverse Struktur-/Typografie-/Datenlücken in
MeinAudi/Service/Versicherung/Sicherheit/Fahrten/Tanken/Statistik/Batterie/Einstellungen.
Manifest auf 2026.8.30.2 angehoben, OTA-Bündel neu gebaut und in audi_ha_test verifiziert
(sauberer Neustart, keine Tracebacks).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Erst zwei Zeilen (festes Beispiel + zugeordneter Sensor) versucht, aber die
erfundenen Beispiele waren für Reichweite/Sofort-Aktualisierung schlicht
falsch. Jetzt nur noch eine Zeile mit dem tatsächlich zugeordneten Sensor,
"(z. B. ...)" in Label-Größe/-Farbe, der Sensorname selbst wie die Einheit
daneben ([on/off], [km]); für Listenfelder (Türen/Fenster) ganz entfernt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neues Profilfeld fahrzeug.fin_automatisch (Standard: an).
- identitaet.py: bei "aus" läuft die Ableitung (samt Mehrfach-Sensor-Abgleich)
gar nicht erst; bei "an" überschreibt der abgeleitete Wert auch einen
vorher von Hand eingetragenen - der Schalter selbst entscheidet jetzt, statt
aus einem leeren Feld zu raten.
- dienste.py: profil_schreiben löst die Ableitung jetzt auch aus, damit das
Umschalten des Schalters selbst sofort wirkt.
- Panel: Schalter "automatisch" zwischen Label und Textfeld in der
Fahrgestellnummer-Zeile, Feld wird bei "an" deaktiviert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- .teaser-Klasse auf die Kachel gesetzt (teaser()).
- .teaser .leaf .v: min-width:72px (gleiche Spaltenbreite je Zeile).
- .teaser .leaf .k: flex:1 1 auto, damit unterschiedlich lange Labels nicht
mehr über justify-content:space-between den ganzen Rest der Zeile
verschieben - vorher blieben .v-Boxen zwar gleich breit, saßen aber an
unterschiedlichen X-Positionen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- distanzVorschlag(): liest jetzt zuerst den Live-Wert von TANK_DISTANZ_SENSOR
(wie backendseitig schon in distanz_seit_tankung()), fällt ohne Zuordnung
auf die bisherige FILLS-Berechnung zurück (jetzt distanzVorschlagBerechnet()).
- .leaf .v: gap:3px ergänzt (fehlte im Gegensatz zu .leaf .k) - die zweizeiligen
Werte in der "Zuletzt"-Kachel (Übersicht) berührten sich sonst.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- FELDER-Katalog: "(Datum)"/"(Restkilometer)"/"(Liter)"/"(Knopf)"/"(Fahrertür)"
aus sieben Labels entfernt - die Unterscheidung übernimmt bereits das
[Einheit]-Label neben der Überschrift (feldEinheitAnzeige()).
- .setup-popup auf max-width:760px verbreitert (eigener Wert, getrennt von
.sdpopup/.sheet/.beleg-popup), damit lange Rohsensornamen nicht mehr
umbrechen müssen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- entitaetIdKurz(): Präfix per Stimmenmehrheit über alle zugeordneten Sensoren statt
des einzelnen nächsten Nachbarn - verhindert Über-Kürzung durch zufällig geteilte
Namensteile zwischen verwandten Feldern (can_fuel_volume->fuel_volume,
oil_change_due->due waren falsch).
- .setup-feld-hinweis: Ellipsis-Kürzung entfernt, voller Sensorname sichtbar.
- entitaetKandidaten(): "Nur passende Sensoren anzeigen" filtert jetzt auch nach
device_class für Datum/Timestamp-Felder, nicht nur nach Domain/Einheit.
- tankFelder(): Kilometerstand/Getankte Liter in .mitEinheit gewrappt (wie alle
anderen km/l-Felder im Rest der App).
- distanzVorschlag(): negative Vorschläge (fehlerhafte km-Basis eines vorherigen
Tankvorgangs) werden nicht mehr angezeigt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Zwei weitere Korrekturrunden, beide vom Nutzer live erkannt:
- .6: paarweise Abstimmung statt fortlaufender Verengung - robuster gegen
einen einzelnen Ausreisser, aber grundsaetzlich noch falsch.
- .7: die eigentliche Ursache war, dass diese Installation zwei etwa
gleich grosse Sensorquellen gleichzeitig hat (9 FMM003-Rollen, 18 Rollen
einer zweiten Integration mit "audi_rs_4_avant_"-Praefix) - ein
EINZELNES globales "Sieger"-Praefix kann immer nur eine der beiden
Quellen richtig kuerzen. entitaetIdKurz() sucht jetzt pro Feld den
naechsten Verwandten unter allen zugeordneten Sensoren und kuerzt nur
dessen gemeinsames Praefix - unabhaengig von Anzahl und Groesse der
Quellen.
Diesmal vor dem Deploy anhand der ECHTEN sensor.audi_dashboard_entitaeten-
Zuordnung durchgerechnet statt mit erfundenen Test-IDs (das hatte den
.6-Fehler faelschlich als behoben erscheinen lassen). Version 2026.8.28.7,
live verifiziert: alle 20 Einzelwert-Felder zeigen die richtige, kurze
Kennung, keine installationsspezifischen Reste aus beiden Quellen mehr.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Korrektur zur letzten Aenderung, vom Nutzer live erkannt:
- "fmm003_" war hart einprogrammiert und liess trotzdem noch
installationsspezifisches Rauschen stehen (Geraete-Slug, Instanzname der
Integration). Jetzt wird das laengste gemeinsame Praefix ueber alle
aktuell zugeordneten Sensoren berechnet (setupGemeinsamesPraefix()) -
nichts mehr hartkodiert. Faellt bei einer einzelnen Entitaet aus
anderer Quelle korrekt auf die volle ID zurueck, statt falsch zu kuerzen
(live bestaetigt: TANK_DISTANZ_SENSOR zeigte den vollen Namen, weil er
auf eine andere Integration zeigte).
- Der Live-Wert des Sensors gehoert nicht mehr neben die ID - stattdessen
zeigt das Label selbst jetzt die ERWARTETE Art des Werts an
("Tankfuellstand [%]", "12V-Batteriespannung [V]"), statisch aus dem
FELDER-Katalog abgeleitet, unabhaengig von einer aktuellen Zuordnung.
Version 2026.8.28.5, live im Testcontainer verifiziert (acht echte
Setup-Zeilen gegen die Nutzerbeispiele geprueft).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
companion-app nannte Servicebuch-Feldnamen betrieb/notiz, waehrend Panel und
Backend (profil["service"]["buch"]) werkstatt/kosten/arbeiten verwenden -
ohne Uebersetzung dazwischen zeigten in einer Oberflaeche angelegte
Eintraege in der anderen leere Werkstatt-/Kosten-Werte. werkstatt/kosten/
arbeiten als kanonisch uebernommen (aeltere, bereits etablierte Panel-
Konvention); ServicebuchEintrag, das Bearbeitungsformular (inkl. neuem
Kosten-Feld) und die Ansicht in Service.tsx angepasst, den Workaround-Cast
im CSV-Export (DatensatzPopup.tsx) sowie die Testfixture entsprechend
bereinigt.
Setup-Popup (Panel, Item 11 aus der letzten Sammel-Rueckmeldung): die
statische Beschreibung unter jedem Feldnamen ist jetzt die Kennung und der
aktuelle Wert des tatsaechlich zugeordneten Sensors.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neuer optionaler Sensor TANK_DISTANZ_SENSOR ersetzt die eigene
Kilometerstand-Subtraktion fuer die Tankvorgang-Strecke, wo zugeordnet
(Live-Erkennung, manuelle Erfassung, historischer Import)
- "Fahrzeugprofil" und "Daten ausgeben" zu einer Kachel zusammengelegt:
"Datensatz sichern" (4 Exporte wie bisher) / "Datensatz laden" (neu:
echter CSV-Import fuer Fahrten/Tankvorgaenge/Wartungsplan)
- Import gleicht per ID ab (Fahrten/Tankvorgaenge) bzw. Datum+Art
(Wartungsplan, hat keine eigene ID) und aktualisiert nur die in der CSV
enthaltenen Spalten - alles andere am Datensatz bleibt unangetastet
- Nebenbei gefunden und behoben: belege.tankvorgang_aktualisieren()
ueberschrieb bisher immer alle Felder, auch mit None, wenn irgendeins
geaendert wurde - fuer den CSV-Import gefaehrlich, jetzt nur noch
tatsaechlich uebergebene Felder
- Ebenfalls gefunden und behoben: Panel las das Import-Ergebnis per
HASS.states direkt nach dem Dienstaufruf - ein Wettlauf mit dem
state_changed-Push. Nutzt jetzt denselben HASS.callWS(get_states)-Weg
wie der bestehende historie_importieren-Ablauf.
companion-app-Portierung von "Datensatz sichern/laden" steht noch aus.
Version 2026.8.28.3, live im Testcontainer verifiziert (alle drei
CSV-Datensatztypen: anlegen + aktualisieren per ID/Datum+Art getestet,
Testdaten danach geloescht).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Archiv-Knopf jetzt in Zeile mit "Montiert" (stale margin-top entfernt),
bekommt einen sichtbaren Hintergrund
- companion-app: Wechseltermin-Datumsfeld (appearance-Reset gegen
natives Safari-Chrome, Breite auf Inhalt geschrumpft)
- Mein Audi/Reifen-Box: "montiert: Sommerräder" links statt Marke/Modell,
"offen" durch "-" ersetzt
- "Servicebuch" ueberall in "Wartungsplan" umbenannt (nur Anzeigetext,
beide Codebasen)
- Version-Kachel: tote Fahrzeugdaten-/Position-/Dashboard-Zeilen entfernt
(inkl. der nie aktualisierten CONFIG.version-Konstante)
Version 2026.8.28.1, live im Testcontainer verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.leaf (Panel) und .dm-listenzeile (companion-app) galten fuer echte
Navigations-Buttons UND fuer die reine <div>-Messwertliste gleichermassen -
Hand-Cursor und Tipp-Rueckmeldung suggerierten dort faelschlich Klickbarkeit,
obwohl die Liste nur Wischen-zum-Loeschen unterstuetzt. Beide Regeln jetzt
auf button.leaf/button.dm-listenzeile beschraenkt - echte Zeilen-Buttons
(Fahrten, Tankvorgaenge, Servicebuch) bleiben unveraendert klickbar.
Version 2026.8.27.22, live verifiziert (Cursor auto statt pointer bei der
Messwertliste, pointer weiterhin bei echten Zeilen-Buttons).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- companion-app Batterie.tsx: Generatorspannung zeigte sich faelschlich als
Ruhespannung/verzerrte den SOH-Trend, Panel-Filter (AGM_RUHE_MAX_V) fehlte
- Manuell angelegte Fahrten/Tankvorgaenge trugen naive Zeitstempel und wurden
von der Import-Dublettenpruefung stillschweigend uebersprungen; neue
gemeinsame zeit_normalisiert() in verlauf.py schliesst die Luecke
- Batteriespannungsverlauf fehlte im Backup (sicherung.py)
- Tankvorgangs-Import verlor stillschweigend aeltere Tankvorgaenge vor Beginn
der Litersensor-Historie; laeuft jetzt zweigleisig (Prozent + Liter)
- Panel-Statistikseite behauptete faelschlich, der Verbrauch je Fahrt komme
vom Fahrzeug (OBD) - ist eine Naeherung aus dem Tankfuellstand
- companion-app Statistik.tsx: Arbeitsweg-Segment war noch rot statt neutral
Version 2026.8.27.19, OTA-Buendel neu gebaut, im Testcontainer verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Beim Zurueckbauen von bvPunkte/bvRuhePunkte auf eine einzige gefilterte
Liste (voriger Commit) blieb eine Fundstelle unbeachtet: die SOC-Berechnung
in vBatterieverlauf() las weiterhin aus dem entfernten bvRuhePunkte. Jeder
Klick auf "Batteriespannung" liess render() mit einem ReferenceError
abbrechen, bevor die Zielseite ueberhaupt gezeichnet wurde - von aussen
ununterscheidbar von "Klick tut nichts". Live im Browser gefunden (Konsole
zeigte den echten Fehler), nicht durch Codelesen - node --check haette das
nie gefangen, da es nur Syntax prueft, keine Laufzeitreferenzen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Statistik-Tab-Icon per zentrierter Stauchung an die Fuellflaeche der
anderen Tab-Icons angeglichen (Panel + companion-app), auf Nutzerwunsch
anschliessend 10% groesser.
- Batteriediagramm neu gezeichnet: dynamische viewBox (1 Einheit = 1 Pixel,
kein preserveAspectRatio-Verzerren mehr), ein Punkt je Ruhespannungsmessung
statt Datumsbeschriftung, Tageshoechstwert nur noch im Tooltip. Generator-
spannungen (> AGM_RUHE_MAX_V = 13,0 V, vom Nutzer festgelegt) bleiben aus
dem Diagramm aussen vor; der SOC-Kurve-Eckwert "100% / voll" bleibt bei den
ursprünglich recherchierten 12,8 V. companion-app auf dieselbe lineare
SOC-Interpolation umgestellt (vorher eine abweichende Stufenkurve).
- Außentemperatur wird jetzt auch beim Batterieverlauf-Import nachgetragen
(vorher nur live) - Kopplung an die naechstgelegene Messung innerhalb
NEBENWERT_MAX_ABSTAND_S (verlauf.py), vom Nutzer nach Live-Daten-Analyse
auf 300s festgelegt. Merge-Logik in ablage.py ergaenzt: ein erneuter Import
kann eine zuvor fehlende Temperatur jetzt tatsaechlich nachtragen, auch
wenn sich der Tagesminimalwert selbst nicht aendert.
- "Mein Audi"/Zustand zeigt bei unplausibler Live-Messung (z. B. Dongle
offline) die zuletzt gemessene Spannung statt "unbekannt".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Die aspect-ratio-Lösung für die volle Spaltenbreite ließ auf großen Bildschirmen
die gesamte Koordinatenfläche mitwachsen - Achsenbeschriftungen (fester font-size
in SVG-Einheiten) wurden dadurch auf ~26px zu groß, das Diagramm unnötig hoch.
Zurück auf eine feste 170px-Höhe: der Y-Maßstab bleibt immer 1:1, nur die
X-Achse dehnt sich auf die volle Breite - normale Schriftgröße, kompaktes
Diagramm, trotzdem volle Spaltenbreite.
bvSkalaY()/y() klemmen jetzt auf [0,1] statt roh zu extrapolieren - ein Punkt
außerhalb von yMin/yMax (z. B. ein Ausreißer auf einer noch nicht aktualisierten
Instanz) zeichnet sich sonst weit außerhalb der Fläche und reißt die Linie über
den Rand hinaus, statt sichtbar am Achsenrand zu liegen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die Y-Achse beider Batteriespannungs-Diagramme (Panel und companion-app) war bisher
aus den sichtbaren Punkten berechnet - jetzt fest 10-15V, auf Nutzerwunsch (zunächst
8-15V, dann auf 10-15V korrigiert). SPANNUNG_MIN_V (batterie.py) auf denselben Wert
angehoben, damit die Plausibilitätsgrenze zur Achse passt - historienimport.py
übernimmt den Wert automatisch, da er von dort importiert statt dupliziert wird.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Fünf vom Nutzer angeforderte Erweiterungen in einer Runde:
- Batteriespannungs-Kachel bekommt eine Messwertliste (Datum, Uhrzeit,
Spannung, optional Außentemperatur über den neuen AUSSENTEMP_SENSOR),
erreichbar über ein neues list-s-Symbol in der Diagramm-Kachel. Werte
über AGM_RUHE_MAX_V (12,8 V) sind keine Ruhespannung, sondern
Lichtmaschinenspannung - die Zeile markiert das jetzt mit
"Generatorspannung" statt es unkommentiert als Messwert auszugeben.
- Jede Zeile der neuen Liste wischbar zum Löschen (neuer Dienst
batterieverlauf_loeschen), über dieselbe Wisch-Mechanik wie Fahrten/
Tankvorgänge in beiden Oberflächen.
- Batteriespannungs-Diagramm im Panel war auf großen Bildschirmen (≥860px,
Spaltenlayout) stark in die Breite gezogen (preserveAspectRatio="none"
bei fester Höhe) - gedeckelt wie die dort bereits vorhandenen Popups.
- Statistik-Tab-Symbol in beiden Oberflächen durch das Audi-CI-Symbol
polls-s ersetzt.
- Neue Möglichkeit, einen Reifensatz zu archivieren ("Neue Räder
anlegen"): der aktuelle Stand (km, Marke, Modell, DOT, Maße, Solldruck,
Kommentar) wandert in ein Archiv, der laufende Satz beginnt bei 0 km neu.
Archiv als aufklappbare Übersicht mit voller Bearbeitungsmöglichkeit,
über drei neue, bewusst nicht über profilSchreiben laufende Dienste
(reifen_archivieren/-aktualisieren/-loeschen) - aus demselben Grund wie
reifen_wechseln: kein im Browser gehaltener Stand darf einen
zwischenzeitlich fortgeschriebenen km-Wert überschreiben.
Live im Testcontainer geprüft (erstmals über :18123 statt :8123 erreichbar)
und dabei zwei echte Layout-Fehler gefunden, die kein Compile-/Testlauf
sehen konnte: die Archiv-Eingabefelder waren durch ein fälschlich
verwendetes .mitEinheit (feste 96px-Breite, eigentlich für Zahl+Einheit
gedacht) abgeschnitten ("Continenta" statt "Continental"), und die
Kilometerzahl in der eingeklappten Archiv-Zeile war klein an das Datum
gequetscht statt wie der Satzname lesbar. Beides behoben, live erneut
bestätigt.
Backend: py_compile clean, services.yaml ergänzt. Panel: node --check
clean. companion-app: tsc/Testsuite (146/146)/Build/OTA-Bündel alle grün.
Manifest 2026.8.25.2 → .8, jeder Neustart im Testcontainer sauber.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
dauerText() zeigte "1 Std. 15 Min." - der Besitzer wollte exakt die Schreibweise,
die companion-app/src/format.ts' dauer() bereits verwendet: "1 h 15 min", Minuten
zweistellig gepolstert. Betrifft sowohl die Einzelfahrt-Detailansicht als auch die
Dauer-Anzeige im Fahrt-Bearbeiten-Formular (gemeinsamer Helfer).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
vTrip() zeigte "75 min" statt der bereits vorhandenen dauerText()-Formatierung
("1 Std. 15 Min."), die jede andere Dauer im Panel schon verwendet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Zwei Meldungen des Besitzers ("Update installieren" braucht manuelles
Neuladen, um den Neustart-Knopf zu zeigen; die "HA startet neu..."-
Anzeige ebenso) auf denselben Grund zurückgeführt: datenLaden() rief
render() nur bei Änderungen an profil/fahrten/tank/status/batt auf,
nie bei einer reinen Änderung des Versions-Sensors. Dazu ein bereits
im Code kommentiertes, bisher nur per Tab-Klick umgangenes Rennen
beim echten HA-Neustart gefunden und behoben: panel_custom baut das
Element neu auf, aber nichts zeichnete es automatisch, bis der Nutzer
irgendwo klickte. companion-app erhielt den passenden Fix für die
Neustart-Anzeige (Panel-Bug 1 betraf sie nicht, siehe AGENTS.md).
Alle drei Fixes live im Testcontainer über einen echten
homeassistant.restart bestätigt, nicht nur simuliert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auf Update prüfen/Update installieren ließ die Seite im Seitenleisten-Layout
sichtbar nach oben springen - render()s eigene Scroll-Wiederherstellung
reichte hier nicht, vermutlich weil die Zustandsänderung des
Update-Sensors zusätzlich über HAs eigenes set-hass-Durchreichen an das
eingebettete Panel einen zweiten Render-Pfad anstößt. Statt die genaue
Ursache weiter zu jagen: fester Scroll-Merkwert vor dem Klick, per
requestAnimationFrame nach jedem eigenen render()-Aufruf dieses Ablaufs
erneut erzwungen. Live bei 1280x800 verifiziert: kein Sprung mehr.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Türschlösser auf ein Sensor reduziert (Fahrertür genügt, Zentralverriegelung
schließt alle Türen gemeinsam) - Kofferraum-/Motorhauben-Schloss entfernt.
- "Sicherheit" heißt im Panel jetzt "Fahrzeugstatus", wie in der companion-app.
- naechsterTermin() (Panel): sortierte null als Epoch 1970 und ließ dadurch
einen datenlosen Termin (Hauptuntersuchung ohne Eintrag/Erstzulassung) immer
vor einem echten, berechneten Termin (Ölwechsel) gewinnen - Ursache dafür,
dass Übersicht nach dem Leeren des Servicebuchs nichts mehr zeigte.
- "Licht ausgeschaltet" statt "Kein Licht" (Formulierung zurückgenommen).
- Große Bildschirme: Unterseiten (Standort, Service, ...) zeigten ihren Titel
in 26px statt der sonst überall genutzten 17px - wirkte neben dem
durchgängig leichten Fließtext wie Fettschrift, obwohl font-weight nirgends
wechselt. Jetzt dieselbe Standardgröße wie im Telefon-Layout.
Details und Verifikation in AGENTS.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- aktualisierung.py: Backup-Ordner verliert sein manifest.json beim Sichern,
sonst laedt HA ihn nach einem Neustart als zweite audi_dashboard-Integration
(Ursache des raetselhaften "gleicher Pfad"-Umbenennungs-Fehlers).
- service.ts/audi-dashboard-app.js: Uebersicht faellt jetzt wie Service schon
auf die Fahrzeugmeldung zurueck, wenn kein Servicebucheintrag existiert;
eigenes (kuerzeres) Oelwechsel-Intervall wird jetzt auch ohne Servicebuch-
eintrag naeherungsweise aus der Herstellermeldung hochgerechnet, statt
weiterhin unveraendert die Herstellervorgabe zu zeigen.
- Sicherheit neu gestaltet: vier Sammelzeilen (Fahrzeug verriegelt / Tueren
und Klappen geschlossen / Fenster und Dach geschlossen / Kein Licht) statt
einer flachen Liste, mit neuen Tuerschloss-, Dach- und Standlicht-Sensor-
rollen, Kreis-Haekchen-Symbolen und einer Detailseite je Tuer/Motorhaube/
Kofferraum in beiden Frontends.
Details, Verifikation und Sensor-Rollen in AGENTS.md (Abschnitte J/M/N).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Der erste echte Live-Test des Selbst-Updates gegen das private Gitea-Repo
lief erfolgreich (mehrfach im Test-Container bestätigt) - deckte aber zwei
UX-Lücken auf, die der Owner direkt gemeldet hat:
- Prüfen/Installieren gaben während der 15-25 Sekunden dauernden
Netzwerkaktion keine sichtbare Rückmeldung - nicht von einem Hänger zu
unterscheiden. Jetzt ein Ladeindikator (Panel: wiederverwendetes
.lade-spinner; companion-app: neues .dm-spinner-Äquivalent, gab es dort
noch gar nicht).
- Nach erfolgreicher Installation stand nur ein Hinweistext da, kein Weg
zum eigentlich nötigen nächsten Schritt. Der Knopf wechselt jetzt zu
"Installation abschließen - Jetzt neu starten" und stößt
homeassistant.restart direkt an.
Das separat gemeldete "Lädt"-Hängenbleiben war kein Bug: reproduziert durch
Live-Test des neuen Neustart-Knopfs - eine echte HA-Verbindungsunterbrechung
während eines Neustarts zeigt exakt denselben, bereits bestehenden
Bootstrap-Ladebildschirm. Vermutlich derselbe Effekt durch den
Docker-Neustart früher in dieser Sitzung.
Verifiziert im Test-Container per Browser-Automatisierung: Neustart-Knopf
ausgelöst, Verbindungsabbruch beobachtet, per docker logs bestätigt, dass
Home Assistant tatsächlich neu gestartet ist und die neue Version aktiv
wurde.
Details in AGENTS.md, Abschnitt L.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Service -> Autohaus -> Zahnrad hat jetzt einen "vCard importieren"-Knopf
(öffnet den Dateiauswahldialog für .vcf). Liest FN/ORG, TEL, EMAIL, ADR
und befüllt das Formular - in beiden Frontends, jeweils passend zum
bestehenden Speicherverhalten (Panel speichert sofort, companion-app
erst über den vorhandenen "Speichern"-Knopf).
- update_pruefen/update_installieren loggten bisher nur bei einem Fehler -
ein erfolgreicher Aufruf war im Log nicht von "noch nicht ausgeführt" zu
unterscheiden. Jetzt auch eine Erfolgsmeldung.
- Panel: der feste Hinweis auf den fehlenden Gitea-Token stand dauerhaft in
der Integration-Update-Kachel, auch wenn ein Token längst hinterlegt war.
Erscheint jetzt nur noch als Teil einer echten Fehlermeldung.
Details in AGENTS.md, Abschnitte J (Nachtrag) und K.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Der am 2026-08-24 angelegte Spiegel nach github.com/T130B/DM360 hatte keinen
Zweck erfüllt: HACS lehnt private Repositories laut eigener Dokumentation
kategorisch ab, unabhängig davon, ob sie auf Gitea oder GitHub liegen. Ein
GitHub-Konto zusätzlich zu pflegen kaufte also nichts. Auf Wunsch entfernt -
entwickelt wird ausschließlich auf der eigenen Gitea-Instanz.
- hacs.json entfernt: tote Konfiguration ohne GitHub-Ziel, das sie bedienen
könnte.
- manifest.json: documentation/issue_tracker/codeowners zeigen jetzt auf
gitea.nothaft.cloud/paul/audi-app statt auf den abgeschafften Spiegel.
- install.ps1: Kopfkommentar nennt keinen aktiven Spiegel mehr.
- AGENTS.md: die HACS-Ablehnung als endgültig festgehalten (nicht nur "heute
privat"), samt der Begründung, warum ein erneuter GitHub-Anlauf nichts
ändern würde - falls das je wieder aufkommt.
Am laufenden Testcontainer geprüft: Integration lädt mit dem neuen Manifest
fehlerfrei neu, keine Fehler im Protokoll.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>