Erster Aufbau auf HAOS
Home Assistant auf einem Raspberry Pi 3, mit eigenem Node.js/Express-Add-on, HA-Automationen und einer ersten Android-Auto-App (Kotlin, GridTemplate). Der Grundstein — funktionierte, war aber zu wackelig.
MG4 · KLEVE
Projektverlauf
Projektverlauf
Der Weg dieses MG4 über viele Arbeits-Chats hinweg - was gebaut wurde, was funktionierte, was in der Sackgasse endete und was bewusst wieder stillgelegt wurde.
Die Anfänge auf einem Raspberry Pi — später komplett abgelöst
Home Assistant auf einem Raspberry Pi 3, mit eigenem Node.js/Express-Add-on, HA-Automationen und einer ersten Android-Auto-App (Kotlin, GridTemplate). Der Grundstein — funktionierte, war aber zu wackelig.
Falsche Ladezähler-Erhöhungen beim Entriegeln, falsche Ø-Ladeleistung, AC/DC-Fehlerkennung. In HA-Automationen nicht sauber lösbar — der Auslöser, alles neu und in eigenem Code zu bauen.
SUPERVISOR_TOKEN-401 → Long-Lived Access Token · Docker-Zeitzone UTC vs. Europe/Berlin · Lade-Fehltrigger beim Aufwachen → Umstieg auf den „charging on→off"-Trigger · negatives Leistungs-Vorzeichen → Math.abs().
Ein eigenes ddclient-Add-on für ein Dyn.com-Konto (dyndns2, alle 10 Min). Mit dem VPS-Umzug obsolet geworden.
Das saubere Fundament, auf dem heute alles läuft
Python-asyncio-Poller (SAIC-Cloud) · PostgreSQL · Node.js/Express-API · Caddy mit TLS — alles in Docker auf einem VPS. Der Bruch mit HA, der sich auszahlte.
30 s beim Fahren, dynamisch beim Laden, 24 h im Ruhezustand. Automatischer Re-Login bei Token-Ablauf, alle drei SAIC-Nachrichtengruppen (Alarm, Command, News) werden geprüft.
Per Test kalibriert: Pack-Strom (×0,05−1000), Spannung (×0,25), SoC (÷10), Reichweite, Reifendruck (×0,04), GPS. Inklusive der Falle, dass realtimePower beim Fahren einfriert → Leistung aus Strom×Spannung rechnen.
Token sterben unvorhersehbar (manchmal nach ~80 s) · ein zweiter Login pausiert 900 s · der Lade-Status-Endpunkt versagt immer (Umweg über rvsChargeStatus) · AC/DC nur über Stecker-Flags zuverlässig · zahlreiche Sentinel-Werte (1023, 0x3FFF).
Aus Rohdaten werden echte Auswertungen
FIFO-Energiekonto zur Fahrt-Zuordnung, Monatsgebühren über geladene kWh amortisiert, vorläufige Kosten mit „~", Ersparnis-Rechnung mit eingefrorenem Referenzpreis zur Finalisierung.
Die echte Netz-CO₂-Intensität zum Ladezeitpunkt (ElectricityMaps), regionalisiert nach Bundesland über co2map.de, NL-Daten über ned.nl. Das Muster „Wert zum Ereigniszeitpunkt speichern", das später Schule machte.
Persönliche Lizenz-Ausnahme von Rohit, täglicher Import, token-geschützter /api/app/stations-Endpunkt, Anzeige im Auto via PlaceListMapTemplate mit Distanzangaben.
Der erste Import feuerte 51/min gegen ein 50/min-Limit → Konto gesperrt. Behoben mit strikter 1,5-s-Drosselung, NL-Frische-Gate und einem ehrlichen Fair-Use-Appeal — von Rohit genehmigt.
Feinschliff an Website und Auto-App
Leere Admin-Statistik-Charts (eine doppelt definierte Funktion überschrieb die andere), Besucher-Cron zum Laufen gebracht, www-Subdomain umgeleitet, responsive Typografie.
Duotone-Kachel-Icons + Blitz-App-Icon in Koralle. Der entscheidende POI-Fix (Head-Unit hielt die App fälschlich für ein IOT-Gerät → keine Karte), plus farbige, nummerierte Ladesäulen-Pins nach Leistung.
Tiefe Batteriedaten direkt aus dem Auto — in drei Log-Runden zum Ziel
In den Handy-Teil der App: ein ELM327-Client für Bluetooth Classic und BLE (mit automatischer Erkennung der Characteristics), auf Basis der OBDb-Definitionen. Dongle: Maclean MCE200 (reines BLE).
Zusammengeklebte Frames → jeden Frame einzeln parsen · Antworten kamen 2 Zyklen zu spät → ATSTFF (langer Timeout, der MG4-BMS ist langsam) · falscher Temperatur-Frame → ATH1 + Filter auf die BMS-Adresse 7ED.
SoH 95,2 % · echter SoC-Puffer (roh 77 % vs. angezeigt 83 %) · Batterie- & Kühlmitteltemperatur ~21 °C · Pack-Spannung 416 V (deckt sich exakt mit der Cloud-Kalibrierung!) · Strom · Rad-Geschwindigkeit.
Die PID (22B045) liefert vom BMS nur den Sentinel 0x3FFF. Aus der Signalliste entfernt, damit keine Fantasiezahl erscheint.
Falls der Maclean je zickt: Vgate vLinker MC+ (~45 €, STN-Chip, Dual-Bluetooth) als Preistipp, OBDLink LX (~60–80 €) als Premium — beide bewältigen die tiefen Mode-22-PIDs zuverlässiger als Billig-Klone.
Vollständig gebaut — und nach ehrlicher Selbstkritik wieder stillgelegt
Ein Ingest-Endpunkt, ein Umschalter (der den Cloud-Poller pausiert), GPS-Übermittlung, ABRP-Fütterung aus OBD-Daten — technisch fertig und lauffähig, liegt aber schlafend.
Ehrlich erkannt: OBD ist ein lokaler Bluetooth-Leser — er loggt sich nie bei SAIC ein, es gibt also gar keinen Token-Konflikt. Die Pause tauschte wertvolle, schnelle Cloud-Daten (Reichweite, Trips) gegen langsame OBD-Werte. Der falsche Handel.
Endstand: OBD nur noch bei Neugier lokal auslesen („An Server senden" aus). Server-Anbindung schläft, die geplante SoH-Dashboard-Kachel wurde gestrichen — eine fast immer leere Kachel wäre nur störend.
Die jüngsten Bausteine
30-Sekunden-Auto-Refresh, damit Liste und Kartenausschnitt nicht mehr auf dem ersten Ladestand kleben. Die „nur 4 Stationen" bleiben — das ist eine harte Grenze des MG4-Displays für diese Ansicht, keine App-Sache.
Live-Position vom Head-Unit mit blauem Anker-Marker, mit sauberem Rückfall. Noch ungetestet: ob der app-projected-Build sauber durchläuft und ob der MG4 die Schnittstelle überhaupt freigibt.
TankPuls-API komplett tot (404) · „Sprit Tracker" nur eine KI-Demo ohne echte Daten · Tankerkönig-Key kam nie an. Gefunden: benzinpreis-aktuell.de (bundesweiter MTS-K-Durchschnitt, kein Key, live getestet).
Pro Ladung werden die echt gefahrene Strecke (aus mileageSinceLastCharge) und der Spritpreis zu diesem Zeitpunkt eingefroren und aufsummiert — genau nach dem CO₂-Muster. Baut sich mit jeder neuen Ladung auf.
Bestätigt, dass die Gratisstufe bewusst nur einen Endpunkt hat (die 401 waren kein Fehler). Das kostenpflichtige Trial für historische/vollständige Daten lohnt sich für ein Hobbyprojekt nicht — die eine CO₂-Kachel reicht.
Gebaut, gefahren — und bewusst wieder stillgelegt
Der Ausgangspunkt war kein Kartendienst, sondern die Frage: Wie viel braucht dieses Auto wirklich? Verbrauch in sechs Tempobändern aus den echten Fahrten, dazu Höhenprofil, Gegenwind zur jeweiligen Ankunftszeit, Wärmepumpe und Zuladung — und ein Kalibrierfaktor, der sich aus dem Vergleich von Prognose und Wirklichkeit selbst nachzieht.
Selbst hosten scheitert am Speicher: Der Deutschland-Graph will 8 bis 16 GB, der VPS hat 1,8. TomTom und Mapbox können Autobahnen meiden, liefern aber kein Höhenprofil — ohne das ist das Energiemodell blind. Google Maps braucht ein Abrechnungskonto ohne harte Kostengrenze. Geblieben: GraphHopper, später openrouteservice.
Nicht der Listenpreis der Säule zählt, sondern der eigene Tarif samt laufendem Abo. Der Planer fährt die Reichweite bis zum Mindest-Ladestand aus, sucht im letzten Abschnitt davor den stärksten Lader, lädt nur so viel wie nötig — und weist für jeden Stopp Ankunfts-Ladestand, Dauer und Kosten aus.
Android Auto verlangt von Navi-Apps, die Karte selbst zu rendern: Kacheln, Routenlinie, Fahrzeugpfeil. Die entscheidende Einsicht kam beim Nachrechnen — die Fahrzeugposition aus der Cloud ist eine halbe bis ganze Minute alt, bei Autobahntempo also ein bis zwei Kilometer. Für „in 300 Metern rechts“ unbrauchbar. Also führt die App selbst: Sie holt die Route einmal mit Streckenkilometern und bestimmt bei jedem GPS-Fix lokal, wo sie ist — und läuft damit auch im Funkloch weiter.
Mitten im Testen: HTTP 429. Der freie GraphHopper-Zugang hat 500 Anfragen am Tag, und jede Neuplanung waren zwei davon — nach gut 40 Minuten war Schluss. Antwort darauf: ein Adapter, der openrouteservice und GraphHopper austauschbar macht und bei Ausfall automatisch umschaltet, dazu ein Takt von einer Minute statt zehn Sekunden. Beides half. Es zeigte aber auch, wie schmal der Grat ist.
Ein rechnerisch passender Ladestopp nützt nichts, wenn die Säule belegt oder das Gelände abends zu ist. Open Charge Map: bei zwei von drei Säulen zuletzt 2021 geprüft. GoingElectric hat die besten Öffnungszeiten, verlangt aber den Abruf direkt vom Endgerät — ein Filter beim Planen auf dem Server ist damit ausgeschlossen. TomTom liefert als einzige echte Live-Belegung, mit 75 bis 90 Prozent Abdeckung an der Strecke, aber 2.500 Abfragen im Monat.
Alles lief: Route, Ladeplan, Navigation im Auto. Was nicht mehr passte, war der Dauerbetrieb — drei fremde Schnittstellen mit drei Kontingenten und drei Regelwerken, dazu ein Freigabezyklus für jede App-Änderung. A Better Routeplanner macht genau das hauptberuflich und bekommt die Live-Telemetrie ohnehin schon. Der Reiter ist aus dem Admin verschwunden, die Schlüssel sind gelöscht, der Code ruht. Der Machbarkeitsnachweis steht — das war der eigentliche Gewinn.
Vom ersten „Frag das Auto" zum Werkzeugkasten mit Fernsteuerung
Eine Frage, ein Fahrzeug-Schnappschuss, eine Antwort. Mehr war es anfangs nicht. Beim Bauen fiel allerdings etwas auf, das seit Monaten unbenutzt im Code lag: die komplette Fernsteuer-Infrastruktur. Befehlstabelle, Cooldown, Prüfung der Parameter, und ein Poller, der anstehende Befehle abholt und über die Hersteller-Schnittstelle ans Auto schickt. Verriegeln, Klima, Laden, Ziel-Ladestand — alles vorhanden, nur ohne Bedienung.
Naheliegend wäre der Assistent im Head-Unit gewesen — die App läuft dort schließlich. Android Auto sperrt während der Fahrt aber jedes freie Tippen, übrig blieben vorgefertigte Fragen. Also bewusst andersherum: ein normaler Chat auf dem Telefon, mit Eingabefeld und Verlauf. Im Auto bleiben die Kacheln.
„Was hat der Monat gekostet?" konnte der Assistent nicht beantworten — er sah nur Ladestand, Reichweite und Kilometerstand. Die Antwort darauf war kein größerer Prompt, sondern ein Werkzeugkasten: Statt alles mitzugeben, holt er sich, was er braucht, und fragt dabei mehrfach nach. Aus vier Werkzeugen wurden über dreißig — Ladehistorie, Ladekurven, Fahrten, Wetter, Verbrenner- und CO₂-Vergleich, sämtliche Admin-Statistiken. Der Kniff dahinter: Die Statistik-Routen der Website melden ihren Auswerter mit an, und der Chat ruft denselben Code über eine Attrappe auf. Eine Quelle, zwei Verbraucher — keine zweite Rechnung, die abweichen könnte.
Die Rechenmaschine aus Phase VIII lag still, aber vollständig da. Sie wurde nicht wiederbelebt, sondern als Werkzeug eingehängt: „Komme ich nach Hamburg?" liefert Entfernung, Ankunfts-Ladestand, Gegenwind, nötige Stopps mit Dauer und Kosten — samt echter Adressen, die aus den Koordinaten nachgeschlagen und zwischengespeichert werden. Kein Reiter, keine Navigation, keine Kontingente. Nur der Teil, der sich bewährt hatte.
Kurz zuvor antwortete die App auf „Kannst du die Klimaanlage einschalten?" noch mit „kann ich nicht". Jetzt kann sie es, und zwar über ein festes Muster: Der erste Aufruf führt nichts aus, er beschreibt nur, was passieren würde, und fragt nach. Erst nach dem Ja wird der Befehl eingereiht. Dasselbe Gate gilt für jedes schreibende Werkzeug — Anbieter anlegen, Ladungen nachpflegen, Fahrten zusammenführen. Beim Entriegeln ist der Assistent ausdrücklich angewiesen, besonders vorsichtig zu sein.
Für Vorführungen tippt der Chat sich selbst: ein Skript aus Fragen und Pausen, Buchstabe für Buchstabe geschrieben, mit echten Aufrufen gegen die laufende Anlage — keine hinterlegten Antworten. Ausgelöst wird es durch langes Drücken auf den Titel, das Skript selbst liegt auf dem Server. Ändern heißt damit nicht: neue App-Version. Dieselbe Vorführung gibt es auch als Seite im Browser.
Eine Aufnahme aus dem laufenden Betrieb: Status abfragen, Route mit Ladestopps planen, Tarife pflegen, Auswertungen erzeugen, das Auto fernsteuern. Nichts nachgestellt, alle Zahlen aus den echten Telemetriedaten, Adressen auf Wunsch im Gespräch zensiert. Dazu eine zwölfseitige Transkription mit den Diagrammen aus dem Gespräch, die sich auf der Seite durchblättern lässt. Das Video liegt bewusst außerhalb des Containers und wird vom Webserver aus einem Host-Ordner ausgeliefert — sonst wäre das Abbild um ein Vielfaches gewachsen. Das Vorschaubild entstand als Standbild aus dem Baukasten, weil auf der Maschine kein Videowerkzeug lag.
Aus dem Chat wird ein Begleiter — Diagramme, Meldungen, Stimme, Widget
Bisher lieferte eine Frage nach der Ladekurve einen Link: antippen, Browser, zurück. Beim Nachsehen zeigte sich, dass die Datenpunkte den Server nie verließen — die Antwort enthielt nur den Link. Jetzt kommen die Punkte mit und die App zeichnet selbst. Der naheliegende Weg, den vorhandenen Zeichencode aus der Auto-Ansicht wiederzuverwenden, ging nicht: Der ist fest auf Ladestand und Kilowatt verdrahtet. Also ein eigener Zeichner für freie Beschriftungen, Balken wie Linien — und die Auto-Ansicht blieb unangetastet.
„Befehl ausgeführt" erreichte den Nutzer bisher nur bei offenem Chat. Der erste Anlauf ohne Firebase: ein Hintergrundauftrag, der nach dem Absenden zwei Minuten lang nachfragt. Kam nichts an. Ein eingebautes Laufprotokoll brachte es an den Tag — Android hielt die verzögerten Aufträge zurück und gab sie erst frei, als die App wieder geöffnet wurde. Genau dann aber holt der Chat das Ergebnis selbst, und die Meldung entfiel. Zwei Mechanismen, die sich gegenseitig blockierten. Die Lösung war der zuvor verworfene Vordergrunddienst: die einzige Bauform, für die Android ein Zeitfenster zusichert.
Ein Mikrofon neben dem Eingabefeld, das schon beim Sprechen mitschreibt — der Text bleibt zum Korrigieren stehen, statt sofort loszulaufen. Die eingebaute Vorlesestimme klang allerdings nach Navigationsgerät. Der Blick auf die Preise entschied es: Die natürlichen Stimmen von Google haben eine Million Freizeichen im Monat, bei rund zwanzig vorgelesenen Antworten am Tag bleibt es dauerhaft kostenlos. Der Schlüssel liegt auf dem eigenen Server, ein Zähler deckelt den Verbrauch, und bei jedem Problem — kein Netz, Limit erreicht — fällt die App still auf die Gerätestimme zurück. Aus dreißig deutschen Stimmen wird per Hörprobe ausgewählt.
Alles hatte sich hinter einem einzigen Menüpunkt gestapelt: Meldungen, Sprache, Diagnose. Jetzt gibt es eine eigene Einstellungsseite mit Abschnitten, oben nur noch Titel und ein Punktemenü. Die Farben folgen dem Systemdesign — hell wie dunkel. Kein Umbau auf ein neues Oberflächen-Framework: Diktat, Vorlesen und Diagramm-Blasen funktionieren, das Risiko stand in keinem Verhältnis.
Über dem Eingabefeld eine Reihe antippbarer Vorschläge — ein Tipp schickt sofort ab. Die Liste steht nicht in der App, sondern auf dem Server und wird im Admin gepflegt. Ändern heißt damit: Text tippen, speichern. Keine neue Version, kein Freigabezyklus.
Ladestand, Reichweite, beim Laden die Leistung samt Restzeit, dazu Innen- und Außentemperatur. Einen eigenen Aktualisierungstakt hat es bewusst nicht: Android erlaubt Widgets ohnehin nur halbstündlich, und der Auftrag für die Meldungen läuft alle fünfzehn Minuten — der versorgt es nebenbei mit. Der Klima-Knopf setzt nichts direkt ab, sondern fragt erst nach. Auf einem Startbildschirm ist der Fehltipp zu nah.
Die Monatsgebühr wurde längst korrekt auf den Preis pro Kilowattstunde umgelegt, rückwirkend nach Monatsende — nur sah das niemand, die Zahlen standen in einer Tabelle ohne Anzeige. Jetzt zeigt der Admin je Monat die geladene Menge, den effektiven Preis, den Preis ohne Abo und die Ersparnis. Auch die Monate ohne einzige Ladung, mit der vollen Gebühr als Minus. Ohne die sähe das Abo im Rückblick besser aus, als es war.
Was noch auf eine Testfahrt wartet
Standort erlauben, ins Auto, schauen ob der blaue Marker kommt und die Karte live folgt — und ob der Build sauber baut.
Pro Anbieter gibt es heute genau einen AC- und einen DC-Preis. Getrennte Preise für eigene und fremde Säulen — 0,52 an der eigenen, 0,63 im Roaming — lassen sich damit nicht abbilden. Behelf bisher: ein Stationspreis oder ein zweiter Anbieter-Eintrag.
Der Planer wählt den günstigsten Lader innerhalb des Reichweitenfensters. Eine wirklich andere Route — zwanzig Kilometer Umweg, dafür deutlich billiger laden — rechnet er nicht durch. Das greift in den Kern der Streckenplanung ein.
Mit jeder neuen Ladung wächst der eingefrorene Vergleich. Der Zähler sessions_with_frozen_price zeigt, wann genug Daten für eine belastbare Aussage da sind — und damit auch die Basis für eine Abo-Break-even-Kachel.
Eine verdichtete Chronik aus allen bisherigen Arbeits-Chats - Meilensteine, Sackgassen und Entscheidungen in ihrer Reihenfolge. Kein 1:1-Protokoll, sondern der rote Faden.