204 Commits

Author SHA1 Message Date
tobias f5976e6865 iOS-Optik offiziell machen, Audi-CI-Spezifikation vorher archivieren
Entscheidung nach DESIGN_REVIEW_2026-08-13.md §A, Option 1: die additive
iOS-Auflage (audi-dashboard-ios.css) wird zur verbindlichen Optik erklaert,
statt die App auf reine Audi-CI zurueckzuschneiden. Der bisherige
SPECIFICATION.md-§2-Wortlaut (Audi-CI-Farben, 20px-Radius) ist wortgleich
in AUDI_CI_ARCHIV_2026-08-13.md gesichert, inklusive Anleitung fuer den
Rueckweg - der Code selbst braucht dafuer kein Backup, da die iOS-Auflage
rein additiv ist und die Audi-CI-Basiswerte in audi-dashboard.css
unveraendert erhalten bleiben.

SPECIFICATION.md §2 beschreibt jetzt die tatsaechlichen iOS-Werte aus
audi-dashboard-ios.css. bauauftrag.md §8 bleibt unangetastet (Projekt-
konvention: historisches Dokument), gilt aber ab hier als ueberholt.

Zwei aus demselben Review noch offene Implementierungsfehler (Rot-Semantik
invertiert, 20px/16px-Radius-Inkonsistenz bei Popups) sind unabhaengig von
dieser Richtungsentscheidung und bleiben offen.

Zusaetzlich: Versionsbump nach dem Redeploy in audi_ha_test.
2026-08-13 19:20:28 +02:00
tobias 163efe1392 Merge branch 'umsetzung-datametric360': Companion-App-Phasen 1-10 uebernehmen
Bringt die vollstaendig gebaute DataMetric360-App zusammen (React/Vite,
21 Screens, Audi-Assets, PWA + native Capacitor-Huelle, 90+9 Tests) sowie
die profil_lesen()-Haertung gegen fehlende/kaputte Profildatei zusammen.

Konfliktaufloesung:
- AGENTS.md, INSTALL.md, README.md: main-Fassung war jeweils die
  chronologisch neuere, uebernommen und um die durch den Merge tatsaechlich
  erledigten Punkte ergaenzt (profil_lesen()-Haertung, Audit-Reste-Entscheidung).
- fahrterkennung.py: toten WLAN-Zweig vom Branch verworfen, Zuendungs-
  basierte Erkennung von main behalten.
- homeassistant/FMM003_MAPPING.md (MQTT/Mosquitto-Ansatz vom 2026-08-11,
  vor der Umstellung auf flespi) bewusst nicht uebernommen - main nutzt seit
  2026-08-12 flespi als alleinigen FMM003-Datenweg. UMSETZUNGSPLAN.md Phase 13
  entsprechend als ueberholt markiert, verweist auf AGENTS.md als massgeblich.
- REVIEW_main_2026-08-13.md, ha_install.md (add/add): main-Fassung war die
  spaetere Revision derselben Dokumente, uebernommen.

Die von REVIEW_main_2026-08-13.md befuerchtete Merge-Falle (profil_lesen()
gibt jetzt None zurueck, main-seitige Aufrufer pruefen das nicht) wurde
verifiziert als bereits entschaerft: alle 5 Aufrufstellen im gemergten Stand
(backup.py x2, fahrterkennung.py, frontend_veroeffentlichung.py,
reifenzaehler.py, tankerkennung.py) sind None-sicher.

installationspaket/ nicht Teil dieses Commits (gitignored, wird bei Bedarf
neu zusammengestellt).
2026-08-13 19:03:20 +02:00
Paul Nothaft 6230648f29 Design-Review des main-Stands gegen die Audi-CI-Vorgaben ablegen
Code-Review aller UI-Schichten plus Headless-Browser-Screenshots des
Panels mit Mock-hass. Kernbefunde: die iOS-Auflage ersetzt Palette,
Radien und die Rot-Semantik ohne dokumentierte Entscheidung; das
design-system traegt noch den Vor-Audit-Stand (fg3, Fokus, Feldgroessen);
vier im Browser nachgewiesene Darstellungsfehler. Nur Bericht, keine
Fixes.
2026-08-13 18:15:38 +02:00
Paul Nothaft 2a3c4f2ab5 Zugangswege zum privaten Repository dokumentieren und trennen
Neue Option --update-repo trennt, woher installiert wird, von dem, was als
Updatequelle hinterlegt wird. Damit laesst sich mit vollen Zugangsdaten
installieren, ohne sie abzulegen (--update-repo aus). Enthaelt die hinterlegte
URL Zugangsdaten, weist das Skript darauf hin und maskiert sie in der Ausgabe.

Neuer Abschnitt 1b in ha_install.md beantwortet die drei naheliegenden Fragen
und benennt den Haken dahinter:

- Werkzeuge sind vorhanden. git 2.54, curl, unzip und ssh liegen im
  offiziellen HA-Container bereits vor, an der Instanz nachgesehen.
- Passwort in der URL funktioniert genauso wie ein Token - es ist aber das
  Kontopasswort, im Klartext in /config und in jeder Sicherung, und bei
  Zwei-Faktor-Anmeldung verweigert Gitea es ohnehin.
- Ein vorher im Terminal eingerichteter Anmeldehelfer hilft der
  Selbstaktualisierung NICHT. Sie klont aus dem Home-Assistant-Prozess und
  allein anhand von UPDATE_REPO_URL; _git() setzt keine Umgebung. Unter HA OS
  laeuft das Terminal-Add-on ausserdem in einem eigenen Container, geteilt ist
  nur /config. Fuer die Installation selbst genuegt der Helfer dagegen.

Dazu eine Optionstabelle mit Bewertung, der Hinweis dass auch curl fuer das
Skript selbst Zugang braucht, und was sich nach der Umstellung auf die
Integration daran aendert: der Zugang wandert in den Konfigurationsdialog und
Home Assistants eigene Ablage statt in eine Python-Datei.
2026-08-13 17:21:19 +02:00
Paul Nothaft 1afcad25d3 install.sh in ha_install.md aufnehmen
Das Dokument beschrieb bisher nur die kuenftige Integration und liess offen,
wie eine Installation heute ablaeuft. Neuer Abschnitt 1a: was install.sh
abnimmt, die drei Eigenschaften, auf die es dabei ankommt (mehrfach
ausfuehrbar, vorhandene Daten unangetastet, Sicherung der
configuration.yaml), und eine Tabelle, was danach von Hand bleibt - jeweils
mit der Spalte, was davon die Integration aufloest.

Dazu zwei Stellen nachgezogen: die Erstinstallation der Integration laesst
sich genauso automatisieren, das Skript schrumpft dann auf einen
Kopiervorgang; und der erste Punkt der Reihenfolge (die drei Setup-Fehler)
ist seit dem 13.08. erledigt. Ausserdem ein toter Verweis auf
UMSETZUNGSPLAN.md korrigiert - die Datei liegt nur im Feature-Branch.
2026-08-13 16:52:13 +02:00
Paul Nothaft c11c492d86 Installationsskript: eine Zeile statt dreissig Minuten Handarbeit
homeassistant/install.sh richtet das Panel samt Backend auf einer
Home-Assistant-Instanz ein und verdrahtet dabei die Selbstaktualisierung, so
dass danach alles Weitere ueber die Weboberflaeche laeuft: Sensoren zuordnen,
nach Updates suchen, einspielen.

Gedacht fuer das Add-on "Terminal & SSH" direkt auf der Instanz:
  bash <(curl -fsSL <ROH-URL>/homeassistant/install.sh)
Alternativ von einem Rechner aus mit --ziel gegen ein eingebundenes
config-Verzeichnis, oder mit --von gegen eine lokale Arbeitskopie.

Was es tut: pyscript installieren (neueste Version von GitHub, falls nicht
vorhanden), pyscript/ und www/ einspielen, den Belegleser mitliefern (er
liegt in data/, ist aber Code), fehlende Datenbestaende aus der Vorlage
anlegen, den Abschnitt in die configuration.yaml eintragen und
UPDATE_REPO_URL setzen.

Drei Eigenschaften, auf die es dabei ankommt:

- Mehrfach ausfuehrbar. Der Abschnitt in der configuration.yaml steht
  zwischen Markern und wird beim zweiten Lauf ersetzt statt angehaengt.
  Stehen pyscript oder panel_custom bereits ausserhalb dieses Abschnitts,
  weist das Skript darauf hin, statt einen doppelten Schluessel zu erzeugen.
- Vorhandene Daten bleiben unangetastet. Fahrzeugprofil, Fahrten,
  Tankvorgaenge und ein bereits hinterlegtes Token werden nie ueberschrieben,
  nur fehlende Dateien angelegt.
- Die configuration.yaml wird vor jeder Aenderung mit Zeitstempel gesichert.

Geprueft gegen eine frische Home-Assistant-Instanz im Container: HA startet
ohne Konfigurationsfehler, alle neun pyscript-Entitaeten werden
veroeffentlicht, das Panel ist als "Mein Audi" mit mdi:car-sports unter
/audi-dashboard-panel registriert und rendert im Browser mit fuenf Tabs. Ein
zweiter Durchlauf laesst Profil und Token unveraendert und den
Konfigurationsabschnitt genau einmal stehen.

Ausserdem den blockierenden Verlaufsabruf in fahrtabschluss_logik.py
uebernommen: urlopen lief direkt statt ueber task.executor, was Home
Assistant seit 2026.8 abbricht - jede Fahrt waere ohne Strecke geblieben.
Der Fix lag bisher nur im Branch umsetzung-datametric360; eine frische
Installation haette den Fehler sonst mitgebracht.

INSTALL.md nennt den schnellen Weg jetzt vor der ausfuehrlichen Anleitung.
2026-08-13 16:20:34 +02:00
Paul Nothaft 78d70fa4ca Review-Dokument als umgesetzt kennzeichnen
Haelt fest, was bewusst anders geloest wurde als vorgeschlagen, welche drei
Fehler beim Umsetzen dazukamen und welcher pyscript-Fallstrick dabei
aufgefallen ist.
2026-08-13 16:10:38 +02:00
Paul Nothaft e1180f8e34 Kleinere Befunde und Dokumentation aus dem Review
Frontend, kleinere Befunde:
- Das Standort-Menue liess sich nur wischen oder ueber den Kartenmarker
  oeffnen. Der Griff ist jetzt ein Knopf mit aria-expanded, damit auch per
  Tastatur erreichbar; der Umschalter Strasse/Satellit hat aria-pressed und
  ein Label, das den Zustand nennt.
- Der Filterschalter "Nur passende Sensoren anzeigen" wirkte nicht, solange
  eine Auswahlliste offen war: der Klick-Handler ersetzte das Overlay-DOM,
  bevor das change-Ereignis des Kontrollkaestchens ausgeliefert wurde. Er
  wird jetzt vor dem Schliessen der Liste behandelt.
- Der Theme-Wechsel zeichnete nicht neu, die Leaflet-Kacheln blieben bis zum
  naechsten Backend-Update im alten Stil - seit der Dauerkarte auf der
  Uebersicht deutlich sichtbar.
- Toter Code entfernt (fahrzeugGlyphPfade, .dot.neutral) und zwei Kommentare
  berichtigt, die Gegenteiliges behaupteten.

Dokumentation:
- AGENTS.md widersprach sich an sechs Stellen. Berichtigt: Fahrterkennung
  laeuft ueber die Zuendung, nicht ueber WLAN; Datenweg ist flespi, nicht
  MQTT; Modulzahl und Zeilenzahl stimmen wieder; Entity-IDs werden im
  Setup-Menue zugeordnet, nicht in einstellungen.py; STANDORT_TRACKER ist
  belegt, nicht leer.
- SPECIFICATION.md beschreibt durchgehend den Stand vor der FMM003-
  Umstellung. Statt es zu Teilen umzuschreiben und dabei Ungenauigkeiten zu
  riskieren, steht jetzt ein datierter Hinweis am Anfang, der die drei
  geaenderten Punkte benennt und auf AGENTS.md verweist. Alles Uebrige des
  Dokuments gilt unveraendert weiter.
- INSTALL.md: Die zirkulaere Schrittfolge (Schritt 4 verweist auf 9, Schritt
  7 auf 4) ist als solche benannt und aufgeloest. Die Override-Datei ist mit
  Pfad genannt, samt dem Hinweis, dass sie gesichert wird. Und die drei mit
  Test-Entitaeten der Entwicklungsinstanz vorbelegten Rollen sind erwaehnt -
  auf einer frischen Installation zeigen sie ins Leere.
- README, Profilvorlage: WLAN-Reste entfernt, zwei Falschaussagen aus dem
  ersten Review nachgezogen (Statistik rechnet echt, die
  97-Prozent-Volltankungsregel wurde entfernt), Dateiuebersicht um die
  fuenf fehlenden pyscript-Dateien und entitaeten.py ergaenzt.
- update.ps1 liefert jetzt auch shell_beleg_parser.py aus. Die Datei liegt in
  data/, ist aber Code - Aenderungen am Belegleser, dem einzigen getesteten
  Teil des Projekts, kamen bisher auf keiner Instanz an.
- design/README: Zwei Dateien der Inhaltstabelle liegen gar nicht in dem
  Ordner, weshalb das Board aus der Repo-Kopie heraus leer bleibt - jetzt
  vermerkt. Ausserdem die Behauptung berichtigt, die Auflage ruehre
  audi-dashboard-app.js nicht an: der Stylesheet-Loader wurde dort ergaenzt.

Geprueft: Panel laedt, alle neun pyscript-Entitaeten werden veroeffentlicht,
Zuordnen und Zuruecksetzen funktionieren, keine neuen Fehler im Protokoll.
2026-08-13 16:10:19 +02:00
Paul Nothaft bc2834e867 Bedienbarkeit, CSS-Robustheit und drei Anzeigefehler
Befund 9: In Telefonbreite blendet die iOS-Auflage das Zahnrad aus, die Ringe
waren dort der einzige Zugang zu den Einstellungen - als div mit
pointer-events:none aber weder fokussierbar noch fuer Sprachausgabe
erreichbar. Sie sind jetzt ein echter Knopf mit aria-label, in jeder Breite
bedienbar und unabhaengig davon, ob die Auflage geladen wurde.

Befund 10: .navmarke{display:none} stand nur in der iOS-Auflage. Ohne sie
waere der Markenklon ein sechstes Element im fuenfspaltigen Raster und die
Menueleiste zerfiele. Die Regel steht jetzt in der Basis-CSS, die
Sichtbarkeit in der Auflage - genau andersherum als bisher.

Befund 13: Das Setup-Fenster deklariert role=dialog aria-modal=true, hielt den
Vertrag aber nicht ein. Escape schliesst jetzt (Reihenfolge: Auswahlliste,
dann Fenster), der Tabulator wandert im Fenster im Kreis statt in den
verdeckten Hintergrund, und der Filterschalter hat einen zugaenglichen Namen.

CSS-Spezifitaet: main{padding} in der Auflage verlor gegen main#view in der
Basis - auf grossen Bildschirmen blieb der Seitenrand bei 20px statt 44px.
Der Rand liegt jetzt in einer Variablen, die auch der negative Rand der
randlosen Standortkarte benutzt; sonst haette deren Ausgleich nach dem Fix
nicht mehr gepasst.

Drei Anzeigefehler, im Browser gegen die Testinstanz gefunden und behoben:
ein unlesbares Datum ergab NaN/N statt eines Strichs (das Profil wird laut
INSTALL.md von Hand gepflegt, ein ISO-Datum genuegt), ein fehlender
Tanksensor ergab 0 Prozent statt unbekannt, und neben dem Typenschild stand
die Ausfuehrung doppelt, wenn sie schon im Modellnamen steckt.

Alles im echten Panel geprueft: #marke ist ein BUTTON mit aria-label, der
Markenklon ist ohne die Auflage versteckt, der Seitenrand folgt der
Variablen, und die drei Anzeigen zeigen jetzt Striche statt Rechenreste.
2026-08-13 16:04:05 +02:00
Paul Nothaft 7a43be9764 Standort: Dauerabfrage, abgebrochene Gesten, Aufraeumen
Befund 8: USER_POS_TS wurde nur im Erfolgsfall gesetzt. Lehnt der Nutzer die
Standortfreigabe ab, griff die 30-Sekunden-Drossel damit nie - bei einem
GPS-Tracker als Quelle waren das dutzende Hochgenauigkeits-Abfragen pro
Stunde. Der Fehlschlag zaehlt jetzt als Versuch, und die Drossel prueft auf
den Zeitstempel statt auf ein Ergebnis.

Befund 11: Das Standort-Menue hatte als einzige der vier Zeigergesten keinen
pointercancel-Handler. Uebernimmt das System die Beruehrung, blieb der
Startpunkt gesetzt und preventDefault() blockierte das Scrollen in der
ganzen App. Zuruecksetzen jetzt gemeinsam fuer pointerup und pointercancel.

Befund 12: Ein fehlgeschlagener Adressabruf setzte trotzdem den
Cache-Schluessel - fuer diese Zelle blieb es danach die ganze Sitzung bei den
blossen Koordinaten, auch wenn das Netz laengst wieder da war.

Befund 15: disconnectedCallback raeumte nur eine von drei Karten ab.

Nicht umgesetzt, mit Begruendung im Code: die Karte nur bei echtem
Ansichtswechsel neu aufzubauen. Ich hatte das zunaechst geaendert und wieder
zurueckgenommen - render() ersetzt den Inhalt per innerHTML, eine
ueberlebende Leaflet-Instanz zeigte danach auf ein abgehaengtes Element und
bliebe leer. Der Neuaufbau haengt am 20-Sekunden-Takt des Backends; das
liesse sich nur durch einen Umbau der Render-Architektur aendern.
2026-08-13 15:56:35 +02:00
Paul Nothaft 4c62b9b529 Setup-Menue: Datenverlust verhindern, Vorbelegung korrigieren
Befund 1 (Datenverlust): Solange pyscript.audi_dashboard_entitaeten nicht
veroeffentlicht ist, liefert setupKatalog() eine leere Liste. Das Fenster ging
trotzdem auf - ohne eine Zeile, ohne Meldung - und ein Klick auf Speichern
schrieb {}. Weil overrides_schreiben() die Datei vollstaendig ersetzt, waren
damit alle Zuordnungen weg, sichtbar erst beim naechsten Neustart. Jetzt drei
Riegel: das Setup laesst sich ohne Katalog gar nicht oeffnen, Speichern bricht
bei leerer Zuordnung ab, und die Entitaet wird im Nachlade-Pfad mitgeholt -
der sie bisher als einzige der sechs ausliess.

Befund 3 (gleiche Sensoren): Der Vorschlag haengt nicht vom Index ab, also
bekamen alle vier Positionen einer Liste denselben Sensor. Der
Sicherheitscheck haette danach viermal dieselbe Tuer geprueft und Sicher
abgestellt gemeldet, obwohl drei Tueren nie geprueft wurden. Vergebene IDs
werden jetzt mitgefuehrt und uebersprungen.

Befund 4 (beliebige Sensoren): entitaetScore vergibt fuer einen reinen
Domain-Treffer bereits 3 Punkte - die Schwelle 3 war damit immer erfuellt und
belegte jedes leere Feld mit dem erstbesten Sensor der Domain, in willkuer-
licher Reihenfolge. Schwelle jetzt 5, also mindestens ein Stichworttreffer.

Geprueft mit den echten Funktionen aus der Datei: vier Tuerpositionen
erhalten vier verschiedene Sensoren, ein Bewegungsmelder wird der Zuendung
nicht mehr zugeordnet, ein Sensor mit passendem Namen dagegen schon.

Ausserdem wird die Sensor-Zuordnung jetzt im Browser-Backup mitgesichert und
beim Import wieder eingespielt.
2026-08-13 15:54:04 +02:00
Paul Nothaft 64f457dd87 Setup-Zuordnung: Zuruecksetzen wirkt, Sicherung, Absicherung
Drei Befunde aus REVIEW_main_2026-08-13.md, alle an der Testinstanz geprueft.

Zuruecksetzen (Befund 2 und 5): overrides_anwenden() uebersprang leere Werte
und setzte nur belegte. Weil setattr das Modul-Attribut dauerhaft veraendert,
blieb ein einmal gesetzter Wert danach fuer immer stehen - bei 15 von 17
Feldern hatte Zuruecksetzen keine Wirkung, und die Oberflaeche zeigte wieder
den alten Wert, als sei das Speichern fehlgeschlagen. Umgekehrt wurde eine
Liste aus leeren Eintraegen gesetzt statt uebersprungen, was den
Sicherheitscheck mit zwoelf unbekannt-Zeilen fuellte. Jetzt wird fuer jedes
bekannte Feld geschrieben: der Override, wenn belegt, sonst der eingebaute
Standardwert. Damit ist der Vorgang zugleich wiederholbar.

Sicherung (Befund 6): entitaeten.json war weder in backup.py noch in der
Wiederherstellung noch im Browser-Export enthalten - die gesamte Zuordnung
waere nach einem Rueckspielen still weg gewesen. Jetzt ueberall dabei; fehlt
der Abschnitt in aelteren Sicherungen, bleibt die aktuelle Zuordnung stehen.

Absicherung (Befund 7): overrides_lesen() fing kaputtes JSON nicht ab. Der
Aufruf steht in beim_start() vor alles_veroeffentlichen() - eine unlesbare
Zeile liess das Panel komplett leer bleiben. Geprueft: es folgt jetzt eine
verstaendliche Meldung, alle sechs Entitaeten werden trotzdem veroeffentlicht.

Dabei ein pyscript-Fallstrick gefunden und im Code vermerkt: Generator-
ausdruecke sind nicht implementiert (not implemented ast ast_generatorexp),
Mengen-, Listen- und Dict-Comprehensions dagegen schon.
2026-08-13 15:52:05 +02:00
Paul Nothaft 12418a3d52 Review des aktuellen Stands und Plan fuer die native HA-Integration
Zwei Dokumente, beide reine Analyse - kein Code geaendert.

REVIEW_main_2026-08-13.md: 15 Befunde aus den Commits c66ed82..d5562c7,
nach Schaden sortiert, jeder mit Datei-Zeile und der Kette vom Ausloeser zur
Auswirkung. Die drei schwersten liegen im neuen Setup-Menue:

1. Speichern, solange der Katalog noch nicht geladen ist, ueberschreibt
   entitaeten.json mit {} und loescht alle Zuordnungen. Faellt erst beim
   naechsten Neustart auf, weil die setattr-Werte im Prozess bestehen
   bleiben - und entitaeten.json wird von backup.py nicht gesichert.
2. "Zuruecksetzen" wirkt bei 15 von 17 Feldern nicht, weil
   overrides_anwenden() leere Werte ueberspringt und der Standardwert bei
   fast allen Feldern leer ist. Isoliert nachgestellt.
3. Alle vier Listenpositionen bekommen denselben Sensor, weil der
   Vorschlag den Index nicht auswertet. Folge: der Sicherheitscheck prueft
   viermal dieselbe Tuer und meldet "Sicher abgestellt", obwohl drei Tueren
   nie geprueft wurden.

Jeder Befund ist als belegt oder plausibel gekennzeichnet.

ha_install.md: Plan fuer die Umstellung von pyscript auf eine eigene
Integration mit Konfigurationsdialog - Einrichtung komplett ueber die
Oberflaeche, kein YAML, Updates als Knopfdruck. Alle genannten
Schnittstellen sind an der laufenden 2026.8.1-Instanz geprueft, inklusive
Signaturen.

Zur Verteilung: HACS kann ausschliesslich GitHub und scheidet fuer das
Gitea-Repository aus. App-Repositories akzeptieren zwar beliebige Git-URLs,
Apps sind aber Docker-Container und damit der falsche Behaelter fuer eine
Integration. Nativ bleibt eine eigene UpdateEntity, deren Logik in
updateverwaltung.py bereits zu grossen Teilen existiert.

Festgehalten ist ausserdem, welche der Review-Befunde die Umstellung
konstruktionsbedingt aufloest - unter anderem alle drei oben genannten sowie
die Token-Datei im Klartext, weil eine Integration den Recorder direkt
abfragen kann statt sich selbst ueber HTTP.
2026-08-13 13:43:25 +02:00
Paul Nothaft b1f8b71104 Plan fuer die native HA-Integration als Dokument ablegen
Umstellung von pyscript auf eine eigene Integration mit
Konfigurationsdialog: Einrichtung komplett ueber die Oberflaeche, kein YAML,
Updates als Knopfdruck. Alle genannten Schnittstellen sind an der laufenden
2026.8.1-Instanz geprueft, nicht aus der Dokumentation uebernommen -
inklusive Signaturen.

Zur Verteilung festgehalten: HACS kann ausschliesslich GitHub und scheidet
fuer das Gitea-Repository aus; App-Repositories akzeptieren zwar beliebige
Git-URLs, Apps sind aber Docker-Container und damit der falsche Behaelter
fuer eine Integration. Nativ bleibt die eigene UpdateEntity, deren Logik in
updateverwaltung.py bereits zu grossen Teilen existiert.

Dazu festgehalten, welche Befunde aus dem main-Review die Umstellung
konstruktionsbedingt aufloest - vor allem die drei Setup-Menue-Fehler und
die Token-Datei im Klartext.
2026-08-13 13:40:31 +02:00
Paul Nothaft 509de6ef97 Review des main-Branch als Dokument ablegen
15 Befunde aus den 18 neuen Commits, nach Schaden sortiert und mit
Datei-Zeile-Belegen. Die drei schwersten liegen im neuen Setup-Menue:
Speichern bei noch nicht geladenem Katalog ueberschreibt entitaeten.json
mit {} und loescht damit alle Zuordnungen, Zuruecksetzen wirkt bei 15 von
17 Feldern nicht, und alle vier Listenpositionen bekommen denselben Sensor,
wodurch "Sicher abgestellt" gesichert meldet, obwohl drei Tueren nie
geprueft wurden.

Jeder Befund ist als belegt oder plausibel gekennzeichnet; die belegten
sind am Code nachvollzogen, die Zuruecksetz-Regel zusaetzlich isoliert
nachgestellt.
2026-08-13 13:29:06 +02:00
Paul Nothaft 7b9fba04ce Abweichung zu main festhalten samt der Falle beim Zusammenfuehren
main ist 18 Commits voraus (FMM003, Setup-Menue, iOS-Auflage). Zusammenfuehren
ist bewusst aufgeschoben. Festgehalten ist vor allem die eine Stelle, die ein
sauberer Merge nicht auffangen wuerde: profil_lesen() gibt in diesem Branch bei
fehlender Profildatei None zurueck, profil.py ist auf main unveraendert und
geht damit konfliktfrei durch - aber die dortigen Aufrufstellen pruefen das
nicht und wuerden abstuerzen statt eine verstaendliche Meldung zu schreiben.
2026-08-13 13:03:31 +02:00
tobias d5562c71ef Setup-Menü: Wertvorschau, Unavailable-Warnung, Duplikat-Check, Reset, Neustart-Hinweis
Fünf Erweiterungen des bestehenden Setup-Popups: Live-Wert neben jedem
Such-Kandidaten, Warnhinweis bei unavailable/unknown/fehlender Entität,
Duplikat-Check mit Bestätigung vor dem Speichern, Zurücksetzen-Button je
Feld (Standardwerte-Snapshot in entitaeten.py, vor jedem Override
genommen), und ein bestätigter "Jetzt neu starten"-Knopf nach dem
Speichern, falls sich eines der drei trigger-gebundenen Felder geändert
hat (neuer Service audi_dashboard_neustart). Im Docker-Testcontainer
Feld für Feld verifiziert.
2026-08-12 18:48:35 +02:00
tobias 3548f773c9 update.ps1: fehlende ios.css/badges-Kopie fixen, Installationspaket-Konzept
update.ps1 kopierte audi-dashboard-ios.css und www/badges/ nie, obwohl beide
von der laufenden App gebraucht werden - jedes Update seit Einfuehrung dieser
Dateien liess den deployten Stand dort veraltet zurueck. Ausserdem zwei
verwaiste *.bak-before-audit-merge-Dateien aus www/ entfernt (bereits
gitignored, nie versioniert) und installationspaket/ (generiertes,
gitignored Deployment-Bundle fuer eine frische HA-Installation) als neuen
Ignore-Eintrag ergaenzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 17:17:15 +02:00
tobias 7980f9672d Desktop-Sidebar-Markenklon (.navmarke) aus Claude Design nachziehen
audi-dashboard-app.js war bereits mit dem Design-Projekt identisch, aber
audi-dashboard-ios.css war seit einer Weile nicht mehr neu gezogen worden:
Design hatte inzwischen einen Rings-Klon oben in der Desktop-Sidebar
(.navmarke) sowie einen gefuellten Pill-Stil fuer den aktiven Tab ergaenzt.
Nach Byte-Diff-Pruefung (nur additive CSS-Aenderungen) komplett uebernommen,
in Docker deployt und bei 402px/1400px verifiziert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 16:20:19 +02:00
tobias 2c6e8e5ce4 INSTALL.md an Setup-Menü und FMM003 anpassen
Ersetzt die veralteten Installationsschritte (manuelles Eintragen von
WLAN_SENSOR/TommiG1-Entity-IDs in einstellungen.py) durch eine Anleitung
für das neue Setup-Menü in der App und die aktuellen FMM003-Feldnamen
(ZUENDUNG_SENSOR, STANDORT_TRACKER, BATTERIE_SENSOR). AGENTS.md entsprechend
nachgeführt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 16:07:47 +02:00
tobias 9794193803 Setup-Menü für Sensor-Zuordnung + Umstellung von WLAN/VAG-Integration auf FMM003
Setup-Menü (Einstellungen -> Fahrzeug einrichten -> Setup): ordnet alle von
der App genutzten Sensor-Rollen echten HA-Entitäten zu, statt sie in
einstellungen.py von Hand einzutragen - durchsuchbares Dropdown je Feld,
Vorauswahl aus vorhandenen Entitäten, Schalter für "nur passende Sensoren".
Neues Modul entitaeten.py (Katalog + JSON-Override, zur Laufzeit über
setattr() auf einstellungen angewendet, kein Neustart nötig außer für die
drei trigger-gebundenen Felder).

Zusätzlich: Fahrzeug-WLAN-Erkennung und alle Entity-IDs der nicht mehr
genutzten TommiG1/HA_VAG-EU-Data-Act-Integration entfernt. Fahrterkennung
läuft jetzt über den Zündungs-/ACC-Status des neu angebundenen Teltonika
FMM003 (ersetzt die WLAN-Verbindungserkennung); Standort und 12V-
Batteriespannung kommen ebenfalls vom FMM003. Kilometerstand, Tankfüllstand,
Reichweite, Türen/Fenster/Schlösser sowie Ölwechsel-/Inspektionsdaten haben
dadurch vorerst keine Quelle mehr und zeigen "unbekannt" - die Funktionen
selbst bleiben erhalten und lassen sich über das neue Setup-Menü jederzeit
neu zuordnen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 15:55:59 +02:00
tobias 7e979ecfab Standort: Feinschliff aus Claude Design übernehmen + Satellit/Straßenkarte-Umschalter
Übernimmt den in Claude Design überarbeiteten Stand der Standort-Funktion
(echte Audi-CI-Icons statt Platzhalter-SVGs, robustere Abstands-/Adress-
Anzeige, dynamisch gemessene Menü-Zugweg-Höhe) und ergänzt lokal den
Layer-Knopf so, dass er wie gewünscht zwischen Satellit (Esri World
Imagery, kostenlos ohne Key) und Straßenkarte umschaltet statt zwischen
Tag/Nacht-Theme.
2026-08-12 12:32:34 +02:00
tobias dc4c1ff0bf Standort-Kachel: Live-Fahrzeugposition auf der Übersicht
Neue Kachel oberhalb von "Zuletzt" mit echter Leaflet-Mini-Karte,
öffnet per Klick eine Vollbild-Standortansicht (Kartendarstellung
wählen, auf Fahrzeug/User zentrieren, beide zeigen) mit einem
ausziehbaren myAudi-Stil-Menü: Distanz zum Gerät, Adresse (Reverse-
Geocoding via Nominatim), fährt/steht/Letzter-Parkplatz-Status,
Tankfüllstand/Reichweite, Route- und Teilen-Aktionen.

Backend: STANDORT_TRACKER-Einstellung (device_tracker-Entity) plus
_standort()-Veröffentlichung, bewusst leer gelassen bis eine echte
GPS-Quelle (FMM003/flespi) angebunden ist - Kachel zeigt bis dahin
"kein GPS-Signal". Verifiziert in audi_ha_test mit einer manuell
gesetzten Test-Position.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 11:07:49 +02:00
tobias b98d624359 Höhen-Kollaps-Bug in audi-dashboard-ios.css beheben
Die iOS/Großbildschirm-Auflage setzte :host > div{height:100%}
bedingungslos, was die App auch im mobilen Layout brach, da HA die
reale Höhe durch panel_custom nicht zuverlässig durchreicht. Jetzt
bleibt die viewport-verankerte 100dvh-Höhe (mit 880px-Deckel) bei
allen Breiten erhalten; der Deckel entfällt nur noch innerhalb der
@container (min-width:860px)-Desktop-Auflage. Fix lokal in Docker und
im Claude-Design-Board (DataMetric360 Board.dc.html) verifiziert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 22:46:54 +02:00
tobias a84f7c81f4 DuckDNS Let's Encrypt erfolgreich: Ursache war ein falscher aliases-Eintrag
Tatsaechliche Ursache der deploy_challenge-Fehlschlaege gefunden: ein
ueberfluessiger/falscher aliases-Eintrag (alias: datametric360 ohne
.duckdns.org) in der DuckDNS-Add-on-Konfiguration, zusammen mit
accept_terms: false. Nach Entfernen von aliases und accept_terms: true lief
die Zertifikatsanfrage sofort durch. Der DNS-Server war entgegen der
vorherigen Vermutung kein Faktor - Erfolg trat auch mit dem Speedport als
DNS ein.

configuration.yaml's alter http:-Block entfernt, HA migriert SSL-Pfade und
interne/externe URL jetzt ueber die Oberflaeche (Einstellungen > System >
Netzwerk). Dabei eine HA-Eigenheit dokumentiert: Netzwerkaenderungen muessen
innerhalb 5 Minuten per Dialog bestaetigt werden, sonst automatischer
Rollback.

HA ist jetzt per HTTPS mit gueltigem Let's-Encrypt-Zertifikat erreichbar.
2026-08-11 17:13:23 +02:00
tobias 7c57cec92a DuckDNS: Let's Encrypt bewusst fallen gelassen, Portfreigabe erledigt
deploy_challenge (DNS-01) scheiterte reproduzierbar am dig-Aufruf im
DuckDNS-Add-on-Container selbst, obwohl DuckDNS den TXT-Eintrag nachweislich
korrekt setzt und dieser ueberall sonst (PC, HA-SSH-Konsole) sofort sichtbar
war - Ursache innerhalb des Containers blieb trotz gruendlicher Diagnose
ungeklaert. Entscheidung: abschalten statt weiter debuggen, da HA ohnehin
nur ueber Tailscale erreichbar ist. DuckDNS selbst (IP-Update) laeuft
zuverlaessig weiter - das ist der fuer den FMM003-Pfad relevante Teil.

configuration.yaml's http:-Block bleibt deshalb dauerhaft auskommentiert.
Portfreigabe 8883 und FMM003-Datenversand sind bestaetigt erledigt.
2026-08-11 16:04:48 +02:00
tobias b10ce7c0a5 iOS/Grossbildschirm-Auflage im HA-Panel scharf schalten
audi-dashboard-app.js laedt jetzt zusaetzlich audi-dashboard-ios.css in
den Shadow-Root (zweiter <link>, rein additiv neben audi-dashboard.css).
Im Docker-Testcontainer bei 375px (Tab-Leiste unten) und 1280px (Grid mit
264px-Seitennavigation) verifiziert.

Zwei Fixes an audi-dashboard-ios.css waren dafuer noetig:
- :host-Selektoren werden von diesem Browser innerhalb von @container
  verworfen (kein Fehler, die Regel fehlt einfach im CSSOM) - die alte
  412px-Zentrierung aus audi-dashboard.css wird deshalb unbedingt statt
  nur ab 860px aufgehoben.
- audi-dashboard-version.json hochgezaehlt, sonst liefert der Browser die
  alte Datei aus dem HTTP-Cache trotz neuem Serverstand.

design/README.md dokumentiert beide Fixes fuer kuenftige Aenderungen an
dieser Datei.
2026-08-11 15:12:51 +02:00
tobias 838ea7f362 DataMetric360 Board aus Claude Design importieren: iOS/Großbildschirm-Optikauflage
Neuer Vergleichsentwurf (Smartphone + Großbildschirm nebeneinander) direkt per
Claude-Design-MCP importiert. Enthaelt die responsive Grossbildschirm-Umsetzung
(Tab-Leiste wird zur Seitennavigation ab 860px) als reine CSS-Auflage.

audi-dashboard-app.js aus dem Export weicht 641 Zeilen vom produktiven Stand ab
(fehlende Vier-Kacheln-Kurzwahl, Balkenfarbe, Resttank-Liter) - deshalb NICHT
uebernommen, nur die CSS-Auflage (audi-dashboard-ios.css) nach homeassistant/www/
kopiert, aber noch nicht in die Panel-Ladelogik eingebunden. Entscheidung zur
Aktivierung und zur Aufloesung der JS-Abweichung steht noch aus.
2026-08-11 14:55:00 +02:00
tobias 619d8247f7 Umsetzungsstand MQTT/FMM003 nachtragen: Zertifikate erzeugt, DuckDNS/Dual-Stack bestätigt, Cloudflare-Frage geklärt
- Eigene CA + Server-/Client-Zertifikate erzeugt und Mosquitto konfiguriert
- Dateinamen-Endungs-Stolperstein am FMM003-Configurator dokumentiert (.pem/.pem.crt/.pem.key)
- Dual-Stack am Router bestaetigt, Portfreigabe-Risiko damit ausgeraeumt
- Klargestellt: Cloudflare ersetzt DuckDNS+Portfreigabe+Mosquitto nicht, sondern ergaenzt sie
  fuer einen anderen Zweck (App-Erreichbarkeit statt Fahrzeug-MQTT)
- AGENTS.md Open-Items-Liste entsprechend abgehakt
2026-08-11 14:21:04 +02:00
Paul Nothaft f7f1a238e5 Stand nach der nativen Huelle in AGENTS.md und Plan nachziehen 2026-08-11 12:44:32 +02:00
Paul Nothaft 4395ff6ac6 Native iOS-Huelle in Betrieb, drei Darstellungsfehler behoben
Xcode ist vorhanden, die Huelle liess sich also wirklich bauen statt nur
vorzubereiten: Capacitor 8 fuer iOS und Android, Build fuer den Simulator
erfolgreich, App laeuft und zeigt echte Daten vom Server.

CapacitorHttp eingeschaltet. Das ist keine Feinheit: die native Huelle
liefert die Oberflaeche unter eigenem Ursprung aus, jede Anfrage an Home
Assistant ist damit ursprungsuebergreifend, und die WebView lehnt sie ohne
CORS-Freigabe ab. Nativ gestellte Anfragen kennen keine CORS-Pruefung -
die App braucht dadurch keine CORS-Einstellung am Server.

Drei Fehler, die erst die Bildschirmfotos zeigten:

1. Der Fahrzeug-Block auf der Uebersicht war unsichtbar. Ursache war der
   Flexbox-Fallstrick: "overflow: hidden" setzt die automatische Mindesthoehe
   auf 0, und sobald die Seite laenger ist als der Bildschirm, quetscht
   flex-shrink den Block auf Hoehe 0. Modellname, Typenschild und Kennzeichen
   waren damit schlicht weg.
2. Neben dem Typenschild stand der Modellname noch einmal komplett, obwohl
   das Schild ihn bereits zeigt. Das alte Panel loest das laengst richtig -
   nur der Zusatz gehoert daneben. Nachgezogen, samt Entdopplung, wenn die
   Ausfuehrung schon im Namen steckt.
3. In der Fotogalerie liefen die Dateinamen ueber den Rand der Miniaturen.

Dazu: Datumszeile in Listen bricht um statt abzuschneiden, Statistik nutzt
auf der Flaeche mehrere Spalten.

Im Backend war das Kilometerstand-Screening kaputt: es rief urlopen direkt
auf, was Home Assistant seit 2026.8 als blockierenden Aufruf abbricht. Jede
Fahrt blieb dadurch ohne Strecke - sichtbar nur als Warnung im Protokoll.
Laeuft jetzt ueber task.executor und rechnet an der Testinstanz wieder echte
Strecken aus dem Verlauf.

Die CORS-Freigabe fuer die Web-Fassung ist in der Testkonfiguration
hinterlegt. Sie greift in Home Assistant 2026.8 allerdings nicht - deshalb
wird die App aus Home Assistant selbst ausgeliefert (gleicher Ursprung, kein
CORS), was ohnehin der geplante Weg ist.

Die erzeugten Ordner ios/ und android/ bleiben ungetrackt; sie entstehen
jederzeit neu aus dem Webbuendel.
2026-08-11 12:44:11 +02:00
tobias 6448c9eea4 Broker-Erreichbarkeit entscheiden: Portfreigabe 8883 statt VPS-Bridge
Owner-Entscheidung: der Mehraufwand einer VPS-Bridge steht in keinem Verhaeltnis zum
zusaetzlichen Schutz, da TLS-Zwang plus Pflicht-Client-Zertifikat den Port bereits
praktisch unangreifbar macht.
2026-08-11 12:14:44 +02:00
tobias 2c79ed445c FMM003 MQTT: "AWS IoT Custom" als bestätigten Weg statt "Custom server" dokumentieren
"Custom server" ist im Configurator des Besitzers nicht auswählbar. Ein zweiter unabhängiger
Praxisbericht (mdworld.nl) bestätigt "AWS IoT Custom" + eigener Server als funktionierenden Weg
und deckt zwei kritische Stolpersteine auf: umgekehrte Zertifikatsketten-Reihenfolge und ein
Topic-Namensschema mit %imei%.
2026-08-11 11:56:54 +02:00
tobias 3e730fdf2b MQTT Client Type "Custom server" bestätigen, FMM003-Warnsignal aus Community-Thread dokumentieren
Configurator-Hilfetext (Screenshot) bestätigt einen vierten, in der offiziellen Doku nicht
beschriebenen Wert für eigene Broker. Ein Community-Thread bestätigt den Ansatz praktisch, zeigt
aber auch einen ungelösten FMM003-spezifischen Fehlerbericht - TCP/Codec8 bleibt der Rückfallplan.
2026-08-11 11:46:20 +02:00
Paul Nothaft 5e4ef2a327 Plan und AGENTS.md auf den erreichten Stand bringen
Elf von dreizehn Phasen sind erledigt oder vorbereitet. AGENTS.md haelt
zusaetzlich die drei Fehler fest, die erst der Betrieb gegen eine echte
Home-Assistant-Instanz zutage brachte - und den verworfenen selbstgebauten
QR-Erzeuger, damit niemand den Versuch wiederholt.
2026-08-11 11:28:34 +02:00
Paul Nothaft f8b877d555 Phase 10-13: PWA fertig, blockierte Phasen vorbereitet
PWA laeuft: Manifest, Symbole in allen noetigen Groessen und die
iOS-Angaben, die Apple statt des Manifests auswertet. Das Startsymbol ist
bewusst neutral - die Vier Ringe auf einem Homescreen waeren nach aussen
sichtbar und fielen nicht mehr unter die private Nutzung.

Vorbereitet, aber nicht ausgefuehrt: Capacitor-Konfiguration, ein
Ablage-Adapter fuer Schluesselbund und Keystore (greift defensiv auf die
Laufzeit zu, damit die App ohne das Plugin unveraendert weiterlaeuft), die
Pfad-Freigabeliste fuer den Reverse Proxy und das Geruest der
FMM003-Zuordnungstabelle.

Die QR-Seite fuer die Einrichtung war zunaechst ein Fehlgriff: Ich hatte den
QR-Erzeuger selbst geschrieben. Der Vergleich gegen eine erprobte
Implementierung zeigte 1239 abweichende Module von 3249 - der Code waere
unlesbar gewesen. Jetzt liegt eine bewaehrte Bibliothek (MIT, 57 KB) neben
der Seite im eigenen Home Assistant. Das erfuellt die eigentliche
Anforderung genauso: kein Netzzugriff, der Token verlaesst das eigene Netz
nicht. Geprueft ueber einen Umlauf - 233 Zeichen hinein, identisch wieder
heraus.
2026-08-11 11:27:20 +02:00
Paul Nothaft a68817065b Phase 9: Tests fuer die portierte Rechenlogik
41 weitere Tests fuer Statistik, Service-Prognose und Formatierung. Die
Faelle sind entlang der Regeln gewaehlt, die beim Portieren wichtig waren:
Wochenbeginn Montag, Nachtspanne ueber Mitternacht, mengengewichteter
Durchschnittspreis statt Mittel der Einzelpreise, Plausibilitaetsfenster beim
Langzeitverbrauch, Neustart der Oelprognose ab dem letzten Wechsel samt
Zeitlimit-Deckelung, BOM und Semikolon in der CSV-Ausgabe.

Ein Test war zunaechst falsch: er verglich das UTC-Datum gegen eine
Ortszeit-Erwartung. Der Code rechnet bewusst lokal - sonst begaenne der
Monat in unserer Zeitzone einen Tag zu frueh.

companion-app/README.md auf den erreichten Stand gebracht.

Gesamt: 90 Unit- und Rendertests plus 9 Pruefungen gegen die laufende
Home-Assistant-Instanz.
2026-08-11 11:21:56 +02:00
Paul Nothaft 571d12310f Phase 8: Audi-Schrift, Vier-Ringe und Typenschilder
Die drei Schriftschnitte stammen aus dem Panel, wo sie als base64 im
Stylesheet lagen - als eigene woff2-Dateien sind sie zwischenspeicherbar
statt bei jedem Laden erneut uebertragen zu werden. Typenschilder und Ringe
wechseln mit dem Erscheinungsbild.

Lizenzgrenze eingehalten und geprueft: design-system bleibt unveraendert und
enthaelt keine Markendateien, weil es nach aussen hochgeladen wird. Die App
darf sie nutzen, weil sie nur seitlich installiert wird.

Dabei noch eine Typungenauigkeit korrigiert: technik und ausstattung im
Profil sind Listen von Gruppen, waren aber wie die uebrigen Abschnitte als
Objekt deklariert.
2026-08-11 11:19:38 +02:00
Paul Nothaft 8e6e5bc2ee Phase 7c: restliche Screens - alle 21 Seiten stehen
Fahrzeugdaten, Batterieverlauf, Service mit Werkstatt und Servicebuch,
Reifen, die ganze Versicherungs- und Steuergruppe, Einstellungen in voller
Tiefe und die Live-Ansicht.

Portiert dazu: die eigene Oelwechsel-Prognose (rechnet ab dem letzten
Wechsel im Servicebuch neu, weil der Langzeitschnitt dafuer zu traege ist),
Kalenderdateien fuer Termine und die CSV-Ausgabe im deutschen Format.

Die Live-Ansicht ist gebaut, aber ueber einen Schalter abgeschaltet: die
Werte dafuer liefert erst der FMM003. Ein Menuepunkt mit lauter Nullen waere
schlechter als keiner.

Zwei Stellen, an denen die App bewusst zurueckhaltend ist: ein unbekannter
Pruefpunkt erscheint als hohler Ring statt als geratenes Gruen, und der
Reifen-Kilometerstand wird nie zurueckgeschrieben, weil ihn der Server
fortschreibt.

49 Tests, darunter ein Rendertest ueber alle 21 Seiten in beiden Layouts
mit Beispieldaten in der Form, die das Backend wirklich liefert.
2026-08-11 11:17:47 +02:00
tobias 12c6ec7970 Merge branch 'main' of https://gitea.nothaft.cloud/paul/audi-app 2026-08-11 11:12:30 +02:00
Paul Nothaft 8b64a808ed Phase 7b: Fahrten, Tanken und Statistik
Listen mit Jahr-Monat-Aufklappung, Detailseiten, manuelles Eintragen und
Beleg-Upload. Statistik rechnet ueber die portierten Regeln.

Zwei offene Audit-Befunde des alten Panels sind hier gleich mit erledigt:

1. Loeschen war ausschliesslich per Wischgeste erreichbar. Wer mit
   Sprachausgabe oder Schaltersteuerung bedient, wischt nicht - Fahrten und
   Tankvorgaenge waren fuer diese Nutzer gar nicht loeschbar. Jede Zeile hat
   jetzt zusaetzlich ein sichtbares Menue, ein richtiger Knopf mit Tastatur.
2. Leaflet kam per CDN und blieb auf einem Handy ohne eigenen Internetzugang
   still leer. Es liegt jetzt im Buendel (eigener Abschnitt, erst bei Bedarf
   geladen).

Bewusst NICHT uebernommen: fakeTrack() aus dem alten Panel, das eine
erfundene Linie zwischen zwei Punkten zeichnete, wenn keine Route vorlag.
Solange das Fahrzeug keine Positionen liefert, sagt die Seite das - statt
eine glaubwuerdig aussehende Erfindung zu zeigen.
2026-08-11 11:11:00 +02:00
Paul Nothaft 4dbf3cb173 Phase 7a: Uebersicht, Fahrzeugstatus und Mein Audi
Erste drei Screens auf der fertigen Datenschicht. Uebersicht mit Fahrzeugbild,
Sicherungsstatus, Reichweite und Tankfuellstand, Kilometerstand samt
Service-Faelligkeit und Vorschau auf letzte Fahrt und Tankung. Fahrzeugstatus
zeigt die 16 Einzelpruefungen, wobei ein unbekannter Sensor als hohler Ring
erscheint statt als gruen geratener Punkt - dieselbe Vorsicht, die schon das
Backend walten laesst. Mein Audi buendelt Fotogalerie und Wege zu den
Unterseiten.

Dazu die geteilte Rechenlogik der Statistik portiert (Zeitraeume,
Langzeitverbrauch mit Plausibilitaetsfenster, Gruppierung nach Jahr und
Monat) und Formatierung im deutschen Format.

Bild-Komponente kapselt eine Reibung zwischen App und Bibliothek: die App
laeuft mit exactOptionalPropertyTypes, ein undefined an einem optionalen Prop
waere sonst an jeder Aufrufstelle einzeln zu behandeln.
2026-08-11 11:07:03 +02:00
Paul Nothaft 0103508cea Phase 6: Datenanbindung, Ersteinrichtung und Offline-Anzeige
Die App spricht jetzt echt mit Home Assistant. Ein Datenkontext buendelt die
vier Datentoepfe, haengt sich an den WebSocket-Ereignisstrom und reicht
Verbindungszustand und Warteschlange nach aussen; die Screens kennen weder
REST noch WebSocket. Ersteinrichtung prueft die Zugangsdaten, bevor sie sie
speichert, und unterscheidet in der Fehlermeldung zwischen abgelehntem Token
und nicht erreichbarem Server - zwei Faelle, die voellig verschiedene
Reaktionen verlangen.

Zwei echte Fehler, die erst der Test gegen die laufende Instanz zutage
brachte:

1. Die Typen der Datenschicht deklarierten tank_prozent, sicher_abgestellt
   und sicherheit. Das Backend schreibt tankprozent, gesichert und
   sicherheitscheck - die Oberflaeche haette still ueberall undefined
   gelesen, ohne dass irgendetwas fehlgeschlagen waere.
2. Der Profil-Adapter reichte lebende Verweise ins Rohprofil durch. Ein
   Formular haette damit den Rohstand mitveraendert und die Zusage gebrochen,
   den vom Backend fortgeschriebenen Reifen-Kilometerstand nie zu
   ueberschreiben. Abschnitte werden jetzt kopiert.

Ausserdem zwei Parameter-Eigenschaften in der Datenschicht aufgeloest, weil
Node sie im Strip-Modus nicht uebersetzt und genau darueber die Rauchtests
laufen.

Belegt durch neun Pruefungen gegen die laufende Instanz (Lesen, Dienstaufruf,
vollstaendiger Warteschlangenumlauf, WebSocket-Anmeldung) und 21 Unit-Tests.
2026-08-11 11:02:44 +02:00
Paul Nothaft 5c0c2d1898 Phase 5: App-Shell mit responsivem Layout, Navigation und Theme
Zwei Layouts aus derselben Zusammensetzung: unter 1000px Tab-Leiste unten,
darueber Seitenleiste links mit Brotkrume statt Zurueck-Pfeil. Navigation
ist wie im alten Panel ein flacher Zustand mit fester ZURUECK-Tabelle statt
eines Router-Pakets - die Verschachtelung ist hoechstens dreistufig.

Theme und Tab-Beschriftung ueberleben einen Neustart (localStorage,
abgesichert fuer den Privatmodus), Startwert folgt der Systemeinstellung.
Symbole aus dem alten Panel uebernommen, damit App und Panel gleich aussehen.

Neun Rendertests belegen die Abnahmekriterien: Layoutwechsel in beide
Richtungen, Zurueck-Ziel ueber die Tabelle, Zahnrad statt Tab-Leiste fuer
die Einstellungen, Theme-Persistenz.
2026-08-11 10:55:10 +02:00
Paul Nothaft 2fe3576682 Phase 4: Vite-React-Geruest und Workspace-Anbindung
npm-Workspace im Repo-Root verbindet companion-app mit @audi-dash/ui, so
dass die App die Komponentenbibliothek als echte Abhaengigkeit nutzt statt
nur in der Doku. Dazu Vite, React 18, Einstiegsdateien und eine schlanke
Grundlage-CSS, die nur enthaelt was eine App braucht und eine Bibliothek
nicht mitbringt: Vollbild, sichere Bereiche, Scrollverhalten.

Zwei Audit-Befunde des alten Panels sind hier von Anfang an beruecksichtigt:
Formularfelder mit 16px (sonst zoomt iOS Safari beim Fokus) und ein
globaler :focus-visible-Ring.

Nebenbei im design-system den Kontrastwert --fg3 nachgezogen: dort stand
noch #657081 mit 3,0:1 auf --tile, das Panel hatte den Wert laengst auf
#8a94a3 korrigiert. Ohne das haette die neue App den bereits behobenen
WCAG-Verstoss geerbt.
2026-08-11 10:50:51 +02:00
Paul Nothaft 8e268f044d 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.
2026-08-11 10:48:33 +02:00
Paul Nothaft 982bb04c1a Phase 1: reproduzierbare HA-Testumgebung als Skript
Die urspruengliche Wegwerf-Testinstanz war verloren, weil sie nur als
Anleitung existierte. testumgebung/aufsetzen.sh baut sie jetzt vollstaendig
neu auf: Container, Nutzer, langlebiges Token, pyscript als Custom Component,
Projektdateien und nachgebildete Fahrzeugsensoren als Template-Entitaeten,
die ueber Helfer zur Laufzeit steuerbar sind.

Verifiziert: pyscript veroeffentlicht alle acht Entitaeten, Fahrzeugsensoren
liefern Werte, beide Smoke-Tests gruen.
2026-08-11 10:44:50 +02:00
Paul Nothaft ab2c3db679 Umsetzungsplan mit 13 Phasen anlegen und in AGENTS.md verlinken
Schrittweiser Plan fuer alle offenen Punkte inkl. Abnahmekriterien je
Schritt, Nachschlagereferenz und Definition of Done. Ergaenzt die
Entscheidungen vom 2026-08-11: kein Electron (Capacitor bzw. PWA) und
kein eigenes Backend (HA-API direkt).
2026-08-11 10:39:45 +02:00
tobias a310c1e6f2 Design-Brief um Marken-Assets-Erlaubnis und Fernsteuerungs-Ausschluss ergänzen
Zwei Punkte aus COMPANION_APP_ARCHITECTURE.md fehlten bisher im Design-Brief für Claude Design.
2026-08-11 10:31:08 +02:00
Paul Nothaft c66ed82ee1 AGENTS.md mit Projektstand, Review-Befunden und Arbeitsregeln anlegen
Englischsprachiger Einstiegspunkt für Agent-Sessions: Statusübersicht der
drei Teilprojekte, Review-Befunde vom 2026-08-11, offene Punkte als
Checklisten, Karpathy-Regeln und Claude-Code-Praktiken als verbindlicher
Standard, plus Pflicht zur Aktualisierung bei Änderungen. CLAUDE.md
importiert die Datei per @AGENTS.md (Claude Code liest AGENTS.md nicht
nativ).
2026-08-11 10:14:33 +02:00