Bauauftrag: Fahrzeug-Dashboard in Home Assistant

Stand 05.08.2026 · privates Projekt, keine Veröffentlichung

Überarbeitung: §10 vollständig geklärt; Änderungen in §4.2, §5.6, §6.1, §7.1, §7.2, §7.4, §7.5, §7.7, §9, §10, §13, §14.


1. Der Auftrag in einem Satz

Zu bauen ist ein Fahrzeug-Dashboard in Home Assistant, das die Ende 2026 abgeschaltete App Audi connect plug & play ersetzt: Fahrzeugstatus, Fahrtenbuch, Tankmonitor, Service, Kosten und Versicherung für einen Audi RS 4 Avant competition — in einer Oberfläche, die sich an der Audi-App orientiert.


2. Was mitgeliefert wird

Datei Inhalt
dashboard-muster-ohne-bilder.html Dieselbe Anwendung mit referenzierten statt eingebetteten Bildern, 184 statt 770 KB — die Fassung, mit der gearbeitet wird
bilder/ Die aufbereiteten Bilddateien, elf Stück, zusammen 435 KB
dashboard-muster.html Vollständig bedienbarer Prototyp. Eine einzelne HTML-Datei, alle Ansichten, alle Interaktionen, Beispieldaten. Das ist die verbindliche Vorlage für Aufbau, Verhalten und Gestaltung
audi-connect-nach-homeassistant.md Projektbeschreibung mit allen Entscheidungen und ihren Begründungen
shell_beleg_parser.py Getesteter Parser für Shell-Tankbelege, gegen zwei echte Belege geprüft
Schriften, Ringe, Typenschild, Fahrzeugbilder im Prototyp eingebettet, separat verfügbar

Der Prototyp ist keine Skizze. Er läuft, alle Wege sind begehbar. Wo dieser Auftrag und der Prototyp voneinander abweichen, gilt der Prototyp — außer bei den unter §10 genannten Punkten.


3. Systemumgebung


4. Datenquellen

4.1 EU-Data-Act-Portal über die HACS-Integration

Liefert Kilometerstand, Tankfüllstand, Reichweite, Serviceintervalle, Türen- und Fensterstatus, Verriegelung. Kein GPS. Aktualisierung im 15-Minuten-Takt und nur, wenn das Fahrzeug in diesem Fenster Daten hochgeladen hat. Leere Zyklen sind normal.

Konsequenzen, die im Entwurf bereits berücksichtigt sind:

4.2 iPhone

Positionen über die Companion App. Fahrtstart und Fahrtende über die WLAN-Verbindung zum Fahrzeug (Companion-App-Sensor für das verbundene Netz), nicht über CarPlay — CarPlay ist nicht immer verbunden. Bluetooth wurde verworfen: iOS meldet Bluetooth-Verbindungswechsel im Hintergrund über Region-Monitoring, das mehrere Minuten verzögern kann; die WLAN-Verbindung zum Fahrzeug baut sich nach bisheriger Erfahrung zuverlässig sofort auf und ab. Der WLAN-Name (Audi_MMI_2804_5GHz) ist fahrzeugspezifisch, liegt im Fahrzeugprofil (§6.1) und ist in den Einstellungen änderbar (§5.6).

4.3 Shell-Tankbelege

PDF per Upload in der App (§5.5, §7.7) — kein Postfachzugriff. Parser liegt bei. Belegnummer ist nicht eindeutig; Schlüssel ist der minutengenaue Zeitstempel aus der Belegkopfzeile.

4.4 Manuelle Eingaben

Stammdaten, Versicherung, Steuer, Reifendaten, Servicebuch, Werkstatt, Fahrten und Tankvorgänge ohne Beleg.


5. Aufbau der Oberfläche

Fünf Menüpunkte in einer festen Leiste unten, Symbole mit Beschriftung:

Übersicht · Mein Audi · Fahrten · Statistik · Tanken

Einstellungen liegen hinter den Audi-Ringen oben rechts.

5.1 Übersicht

Fahrzeugbild (Frontansicht, fest), Typenschild mit Kennzeichen, Zustandszeile „Sicher abgestellt" mit grünem oder rotem Punkt, Reichweite als große Zahl mit Balken und Prozentwert, Kilometerstand und nächster Service als Kachelpaar, darunter letzte Fahrt und letzter Tankvorgang als Anrisse.

5.2 Mein Audi

Bildergalerie zum Durchtippen, Typenschild, dann Kacheln mit Sprung auf eigene Seiten:

Kachel Unterseite
Identität Fahrzeugdaten, technische Daten, Ausstattung
Zustand Kilometerstand, Tankfüllung, Batteriespannung
Service Termine, Servicebuch, Autohaus, Terminvereinbarung
Kosten Jahreskosten, Aufteilung, je Kilometer
Versicherung und Steuer Beitrag, Vertrag, Notruf, Schutzbrief, Kfz-Steuer
Reifen beide Sätze, Umschalter, Wechseltermin, Anzugsmoment

5.3 Fahrten

Dreistufig aufklappbar: Jahr → Monat → Fahrt. Detailseite mit Karte, Start, Ziel, Start- und Endkilometer, Distanz, Dauer, Ø-Geschwindigkeit, Kraftstoffkosten, Art der Fahrt. Erfassung von Hand über eine Schaltfläche unter der Liste.

5.4 Statistik

Aufklappbare Kacheln: Distanz und Fahrzeit, getankte Menge und Kosten, Durchschnittsverbrauch, Tag/Nacht, Art der Fahrten. Aufschlüsselung je Jahr, Monat, Woche, Tag.

5.5 Tanken

Jahr → Monat → Tankvorgang, mit mengengewichtetem Durchschnittspreis je Ebene. Detailseite mit Karte der Tankstelle, Kosten, Preis je Liter, SmartDeal-Ersparnis, abgeleiteter Volltankung und Verbrauch. Erfassung von Hand und Beleg-Upload.

5.6 Einstellungen

Tag- und Nachtmodus, Beschriftung der Menüleiste, Fahrbahn unter dem Fahrzeug, Übersichtsbild, WLAN-Name des Fahrzeugs (Textfeld mit Übernehmen-Knopf für das aktuell verbundene Netz), Fahrten-Pausenzeit, SmartDeal mit Ablaufdatum, Ölwechsel-Intervall, Fahrzeugprofil sichern und laden, CSV-Ausgabe, Sicherung, Versionsangaben.


6. Datenhaltung

6.1 Drei getrennte Bestände

Bestand Form Begründung
Fahrzeugprofil eine JSON-Datei alles Fahrzeugspezifische an einem Ort, für Portierung austauschbar
Fahrten JSON Lines, eine Zeile je Fahrt wächst laufend, überlebt Purge und Neuinstallation
Tankvorgänge JSON Lines dito

Servicebuch, Versicherung, Steuer, Reifen und Werkstatt gehören ins Profil, nicht in die Archive — sie beschreiben das Fahrzeug, nicht seine Bewegung. Der WLAN-Name des Fahrzeugs gehört aus demselben Grund ebenfalls ins Profil.

6.2 Portierbarkeit ist Anforderung, nicht Zugabe

Die Anwendung muss ohne Codeänderung für ein anderes Fahrzeug nutzbar sein. Das heißt: keine fahrzeugbezogene Angabe außerhalb des Profils, auch keine Bezeichnungen in Texten. Bilder werden referenziert, nicht eingebettet.

Drei Wege der Bearbeitung sind zu unterstützen: in der Oberfläche, über Sichern und Laden der Datei, und direkt im Dateisystem.

6.3 Fahrten-Schema

trip_id, ts_start, ts_end, duration_s, distance_km, km_quelle (odometer | gps), odo_start, odo_end, avg_speed_kmh, start_lat/lon, end_lat/lon, start_address, end_address, art (privat | arbeitsweg), route (GeoJSON oder null), pausen, source (ha | manual | audi_connect), status (offen | vollständig).

6.4 Tankvorgang-Schema

tank_id, receipt_key (Zeitstempel, minutengenau), receipt_no, tse_beleg_nr, ts, ts_payment, ts_tse, station_id, station_name, station_address, article_no, product_name, fuel_type, liters, list_price_per_l, discount, discount_per_l, fuel_total_eur, receipt_total_eur, price_per_l, net_eur, vat_eur, odometer_km, level_before_pct, level_after_pct, full_tank, source, status, receipt_file, edited_fields.


7. Kernlogik

Diese sieben Punkte sind der eigentliche Auftrag. Die Oberfläche ist im Prototyp gelöst; hier liegt die Arbeit.

7.1 Fahrterkennung

7.2 Zweistufiger Fahrtabschluss

  1. Bei Fahrtende (WLAN-Verbindung länger als die Pausenzeit weg, §7.1): Datensatz aus GPS und Uhrzeit, Status offen
  2. Screening: In der Recorder-Historie des Kilometerstand-Sensors wird nach dem Wert gesucht, dessen Zeitstempel am nächsten am Verbindungsabbruch liegt — auch aus während der Fahrt gemeldeten Werten, nicht nur aus dem letzten vor Fahrtende. Wird ein passender Wert gefunden: Start- und Endkilometer nachtragen, Status vollständig
  3. Wird keiner gefunden, bleibt der Status offen. Das Screening läuft erneut, sobald ein neuer Kilometerstand eintrifft — auch wenn das erst mit der nächsten Fahrt geschieht, da der Kilometerstand laut Datenquelle nicht sicher mit Fahrtende, sondern teils erst mit Beginn oder während der folgenden Fahrt übermittelt wird

Bleibt der Wert dauerhaft aus, greift ersatzweise die GPS-Strecke, kenntlich über km_quelle. Das betrifft insbesondere Fahrten, die in kurzem Abstand aufeinanderfolgen, bevor ein neuer Kilometerstand eintrifft: nur die erste und letzte Fahrt einer solchen Kette lassen sich über den Kilometerstand abgrenzen, die dazwischenliegenden fallen auf GPS zurück.

Technische Voraussetzung: Zugriff auf die Recorder-Historie (nicht nur den aktuellen Zustand) und eine ausreichende Aufbewahrungsdauer des Recorders.

7.3 Strecke aus dem Kilometerstand

km = Odometer(nach) − Odometer(vor). Das GPS liefert Route und Adressen, nicht die Distanz. Dadurch ist eine lückenhafte Positionsaufzeichnung unschädlich.

7.4 Volltankung ableiten

Nicht abfragen. Füllstand nach dem Tanken ≥ 97 % → Volltankung. Bei Teilbetankung wird kein Verbrauch ausgewiesen. Der Tankgeber meldet den Füllstand bereits unterhalb des Ausdehnungsraums — 100 % sind also tatsächlich 100 %, die Schwelle braucht keine Korrektur dafür. Die Auflösung des Sensors ist ganzzahlig.

7.5 Reifenzähler

Kein utility_meter — stattdessen direkte Berechnung: Zähler = aktueller (absoluter) Kilometerstand − Startwert des aktiven Satzes. Der Startwert je Satz ist als Stammdatum im Fahrzeugprofil hinterlegt. Das vermeidet die Abhängigkeit von total_increasing und von utility_meter-internem Zustand, der bei zeitweise unavailable Quellsensoren (§4.1) Strecke verschlucken kann — die Subtraktion braucht nur den zuletzt bekannten Absolutwert, keinen fortgeschriebenen Zählerstand.

7.6 Serviceprognose

Termine werden nicht gespeichert, sondern berechnet: letzter passender Servicebuch-Eintrag plus Intervall. Gespeichert wird nur der vereinbarte Werkstatttermin.

Die Fahrleistung mischt zwei Zeiträume: den gesamten bekannten Verlauf und den Zeitraum seit dem letzten Service, gewichtet über etwa 180 Tage. Damit wird die Vorhersage genauer, je näher das Ziel rückt, und startet nach jedem Service neu.

Ein eingestelltes Intervall darf die Herstellervorgabe nicht überschreiten.

7.7 Belegverarbeitung

Beleg-Upload in der App (§5.5) → Parser → Datensatz. Ersetzt den in §4.3 ursprünglich vorgesehenen Weg über ein Postfach — kein IMAP, keine Zugangsdaten nötig. Regeln:

  1. Schlüssel ist der Zeitstempel aus der Kopfzeile, minutengenau
  2. Liter, Preis und Betrag kommen vom Beleg, der Kilometerstand vom Fahrzeug
  3. Manuell geänderte Felder werden nie von einem Import überschrieben
  4. Nicht zuordenbare Fahrzeugereignisse bleiben als beleg_fehlt stehen
  5. Der Gesamtbetrag kann Shop-Käufe enthalten — Kraftstoffanteil separat rechnen
  6. Ohne Beleg: manuelle Eingabe von Liter und Preis als Fallback, bereits als Erfassungsweg unter „Tanken" vorgesehen

7a. Bilder

Bilder werden nicht eingebettet, sondern referenziert. Sie kommen am Ende dazu; die Anwendung muss ohne sie vollständig bedienbar sein.

Ordner bilder/, feste Dateinamen:

Datei Verwendung
seitenansicht.webp, front-schraeg.webp, frontansicht.webp, heckansicht.webp, scheinwerfer.webp, cockpit.webp, sitze.webp Galerie in „Mein Audi", eine davon als Übersichtsbild
seitenansicht-winter.webp Seitenansicht mit montierten Winterrädern
rad-sommer.webp, rad-winter.webp Radbilder in der Reifenansicht
fahrbahn-schnee.webp Untergrund bei montierten Winterrädern

Drei Bedingungen, damit das Nachreichen ohne Nacharbeit gelingt:

  1. Die Flächen behalten ihre Maße. Bildfläche 206 px hoch, auf der Übersicht 165 px, Radbilder 78 × 78 px. Platzhalter belegen dieselben Maße. Andernfalls springt das Layout, sobald die Bilder kommen — und zwar in jeder Ansicht gleichzeitig.
  2. Die Namen stehen vorher fest. Das Übersichtsbild wird über seinen Namen ausgewählt, nicht über eine Position. Ein späterer Namenswechsel bricht die Konfiguration.
  3. Die Bildaufbereitung ist ein eigenes Arbeitspaket, kein Nebenprodukt. Sie umfasst: Freistellen des weißen Hintergrunds über eine Flutfüllung vom Rand — nicht über eine Helligkeitsschwelle, sonst verschwinden Kennzeichen und Tagfahrlicht —, Montage der Winterräder in die Seitenansicht, kreisrunde Maskierung der Radbilder und Zuschnitt der Fahrbahn mit ausgeblendeter Oberkante.

Der beiliegende Prototyp enthält alle Bilder bereits aufbereitet; sie können übernommen werden.

8. Gestaltung

Verbindlich ist der Prototyp. Die Regeln dahinter:

Fläche #161b23, Kacheln #1f2733
Text #FFFFFF, sekundär #9aa1ad, Beschriftungen #657081
Akzent Progressive Red #F50537, sparsam
Signalfarben Grün #15da15, Gelb #ffaa00, Rot #fd2c4e (Nachtmodus)
Radien Kacheln 20 px, Schaltflächen vollrund — dazwischen nichts
Schrift Audi Type: Normal für die Oberfläche, Wide Light für Kennzahlen, Extended Italic für den Fahrzeugtitel
Zahlen durchgehend Tausenderpunkt, Tabellenziffern

Tag- und Nachtmodus sind umschaltbar, alle Farben liegen als Rollen vor. Keine Schatten, keine Verläufe außer der Fahrbahn unter dem Fahrzeug.

Rechtlich: Audi Type, Ringe und Typenschild sind lizenz- beziehungsweise markenrechtlich geschützt und ausschließlich für diese private, nicht veröffentlichte Installation freigegeben.


9. Nicht-funktionale Anforderungen


10. Vor Baubeginn zu klären

Diese Punkte waren bewusst offen und betreffen die Umsetzung in Home Assistant. Sie sind inzwischen geklärt; Fragestellung und Entscheidung stehen im Folgenden jeweils zusammen.

  1. Einbindung der Oberfläche. Eigenes Panel, eingebettete Seite, eigene Lovelace-Karte oder Add-on? Der Prototyp ist eine einzelne HTML-Datei — welche Form davon trägt im Dauerbetrieb, und wie kommt die Oberfläche an Zustände und Dienste?
    Entscheidung: panel_custom — Home Assistants eingebaute Panel-Integration, per YAML registriert, kein Add-on und keine eigene Integration nötig. Das JS-Custom-Element aus dem Prototyp bekommt automatisch das hass-Objekt injiziert (Live-Zustände per WebSocket, callService() für Aktionen); die bestehenden Render-Funktionen (vHome(), vTrips() usw.) bleiben erhalten, nur die Datenquelle wechselt von den Beispielarrays auf hass.states.
  2. Zurückschreiben von Daten. Wie schreibt die Oberfläche Dateien im Home-Assistant-Dateisystem? Eigene Integration, AppDaemon, pyscript, Skript im Add-on? Diese Entscheidung bestimmt den gesamten Aufbau.
    Entscheidung: pyscript für die gesamte Logik — Fahrterkennung, Fahrtabschluss, Belegverarbeitung, Dateizugriff. Läuft installationsunabhängig (Core, Container, OS, Supervised), im HA-Python-Kontext, mit @service für aufrufbare Aktionen und @time_trigger/task.sleep für die Wartezeit-Logik aus §7.1.
  3. Bluetooth- und WLAN-Erkennung unter iOS. Meldet die Companion App die Verbindung zum Fahrzeug zuverlässig genug für die Fahrterkennung, oder braucht es Kurzbefehle? Das ist die riskanteste Annahme des Entwurfs — trägt sie nicht, muss die Fahrterkennung anders gelöst werden.
    Entscheidung: WLAN statt Bluetooth, Kurzbefehle entfallen. Die WLAN-Verbindung zum Fahrzeug baut sich nach bisheriger Erfahrung zuverlässig sofort auf und ab; Bluetooth-Region- Monitoring unter iOS wäre dagegen mit mehrminütiger Verzögerung riskant gewesen. Trigger ist der Companion-App-Sensor für das verbundene WLAN (§4.2, §7.1).
  4. Verzögerung des Kilometerstands. Wie lange dauert es nach dem Abstellen tatsächlich, bis der Wert nachkommt? Bestimmt die Wartezeit im zweistufigen Abschluss.
    Entscheidung: kein fester Wartewert — der Kilometerstand kommt nicht sicher mit Fahrtende, sondern teils erst mit Beginn oder während der nächsten Fahrt. Der Fahrtabschluss läuft deshalb ereignisgesteuert über ein Screening der Recorder-Historie statt über einen Timeout (§7.2).
  5. Auflösung des Tankfüllstands. Prozentgenau oder gerastert? Bestimmt, ob die 97-Prozent-Regel für die Volltankung trägt.
    Entscheidung: ganzzahlig. Der Tankgeber meldet den Stand bereits unterhalb des Ausdehnungsraums, 100 % sind also tatsächlich 100 % — die 97-Prozent-Schwelle bleibt unverändert (§7.4).
  6. Meldet die Integration den Kilometerstand als total_increasing? Falls nicht, ist ein vorgeschalteter Template-Sensor nötig, sonst funktioniert der Reifenzähler nicht.
    Entscheidung: Frage erübrigt sich — kein utility_meter, kein Template-Sensor. Der Reifenzähler rechnet direkt mit dem absoluten Kilometerstand gegen den im Profil hinterlegten Startwert je Satz (§7.5).
  7. Abholung der Belege aus dem Postfach. Welcher Weg, und wo läuft der Parser?
    Entscheidung: kein Postfach. Belege werden als PDF direkt in der App hochgeladen (§4.3, §5.5, §7.7); ohne Beleg ersatzweise manuelle Eingabe von Liter und Preis.
  8. Verhalten des Tailscale-Tunnels beim Losfahren. Steht er rechtzeitig für den Fahrtstart?
    Entscheidung: Tailscale „VPN On Demand" mit Regel „Only On", gebunden an das Fahrzeug-WLAN (§9). Der Tunnel baut sich damit zeitgleich mit der Fahrterkennung auf, kein dauerhaft aktiver Tunnel nötig.

11. Abnahmekriterien

  1. Eine Fahrt wird ohne Zutun erfasst, mit korrekten Kilometern aus dem Fahrzeug, und erscheint vollständig in der Liste.
  2. Ein Tankstopp mitten in einer Fahrt erzeugt eine Fahrt, nicht zwei.
  3. Ein hochgeladener Shell-Beleg erzeugt einen vollständigen Tankvorgang. Derselbe Beleg ein zweites Mal hochgeladen erzeugt keinen zweiten.
  4. Eine manuelle Korrektur überlebt den nächsten Import.
  5. Ein Eintrag im Servicebuch verschiebt die zugehörige Fälligkeit.
  6. Das Umschalten der Reifen leitet die Kilometer auf den anderen Satz um und verliert bei einem Neustart nichts.
  7. Fällt die Datenquelle aus, zeigt die Oberfläche das an, statt alte Werte als aktuell auszugeben.
  8. Ein Fahrzeugprofil lässt sich ausgeben, in einem Texteditor ändern und wieder einlesen.
  9. Die Oberfläche ist über Tailscale erreichbar, ohne dass Home Assistant öffentlich steht.

12. Ausdrücklich nicht Bestandteil


13. Was noch zu liefern ist

Vom Auftraggeber, vor oder während des Baus:

Entfallen gegenüber der ursprünglichen Liste: Zugangsdaten und Postfach für die Belegabholung (Beleg-Upload statt Mailanbindung, §7.7) und Bestätigung des Bluetooth-Gerätenamens des MMI (Fahrterkennung läuft über WLAN, §7.1) — der WLAN-Name ist bereits bekannt (Audi_MMI_2804_5GHz) und in den Einstellungen hinterlegt (§5.6).


14. Zeitlicher Rahmen

Eine Frist ist hart: Die Alt-App wird Ende 2026 abgeschaltet. Der Export des vorhandenen Fahrtenbuchs muss vorher erfolgen — unabhängig vom Baufortschritt und als Erstes. Was danach verloren ist, ist nicht wiederherstellbar.

Der Import der exportierten Daten in das neue System ist davon unabhängig und wird bewusst zurückgestellt, bis die App sich im laufenden Betrieb bewährt hat. Die Frist betrifft nur die Sicherung der Daten, nicht ihre Weiterverarbeitung.

Alles Übrige lässt sich auch nach der Abschaltung bauen.