Automatisches Fahrtenbuch für BMW mit iDrive 6 – komplett in Home Assistant, ohne App und ohne Abo

# Automatisches Fahrtenbuch für BMW mit iDrive 6 – komplett in Home Assistant, ohne App und ohne Abo

Projekt: ein **vollautomatisches Fahrtenbuch für meinen BMW G31 (530d) mit iDrive 6**.

Jede Fahrt landet als eine Zeile in einem Google Sheet, ohne dass ich etwas tun muss:

- Datum, Start- und Endzeit, Fahrtdauer

- Start und Ziel mit **Straße, Hausnummer, PLZ, Ort** und Klarnamen wie „Home“ oder „Büro“

- Kilometerstand am Start und am Ende, gefahrene Kilometer

- Tankinhalt am Start und am Ende, Verbrauch in Litern und l/100 km

Ich brauche dafür keine BMW-App, keinen Fahrtenbuch-Dienst und kein Abo, nur Home Assistant, BMW CarData, ein iPhone und ein Google Sheet.

> :package: **Komplette Anleitung mit allen YAMLs, Helfern, iOS-Kurzbefehl und PDF:**

> :backhand_index_pointing_right: [GitHub: BMW-Fahrtenbuch für iDrive 6]( GitHub - ursubey/Home-Assistant-BMW-CarData-Logbook-iDrive6: Automatic driving logbook (Fahrtenbuch) for BMW iDrive 6 in Home Assistant: BMW CarData (BavarianData), iPhone Bluetooth webhook with start address, Google Sheets · GitHub )

Das klingt einfach. Mit einem iDrive-6-Auto war es das aber nicht. Unten beschreibe ich deshalb ausführlich, **warum** ich es so gebaut habe und in welche **Stolperfallen** ich unterwegs getreten bin.

—

## Das Grundproblem: iDrive 6 meldet nur am Fahrtende

Seit BMW die alte ConnectedDrive-Schnittstelle abgeschaltet hat, führt der offizielle Weg über **BMW CarData**: ein MQTT-Stream plus eine REST-API mit **50 Aufrufen pro Tag**.

Neuere BMW (iDrive 7/8 und Neue Klasse) liefern über den Stream laufend Daten, auch Positionen während der Fahrt. **Ein iDrive 6 macht das nicht.** Mein Auto schickt Kilometerstand, Tankinhalt und Position **nur einmal, am Ende einer Fahrt**. Während der Fahrt kommt nichts. Den Entriegelungsstatus der Türen streamt es überhaupt nicht.

Für ein Fahrtenbuch heißt das:

- Home Assistant weiß **nicht, wann** eine Fahrt beginnt.

- Home Assistant weiß **nicht, wo** sie beginnt.

- Es weiß nur: Irgendwann kommt ein neuer Kilometerstand mit einer neuen Position.

—

## Warum die Trip-Funktion von BavarianData hier nicht greift

[BavarianData]( GitHub - JustChr/BavarianData: BMW CarData for Home Assistant, in the HACS default store: live MQTT stream + REST API for your BMW or MINI, with charging history & cost, trip journal and battery health. The replacement for the Connected Drive / MyBMW integration. · GitHub ) von @JustChr hat eine eigene Fahrten-Erkennung, ein „Trip Journal“. Für neuere Autos ist das eine tolle Funktion. Laut Wiki setzt die Erkennung aber **Live-GPS aus dem Stream** voraus:

- Eine Fahrt beginnt, wenn Positionen eine Bewegung zeigen.

- Sie endet nach fünf Minuten Stillstand.

- Optional hilft der Status der Fahrertür.

Die Integration ist also für Fahrzeuge gebaut, die laufend Positionen streamen, **nicht für iDrive 6**. Bei meinem Auto kommt nur ein einziger Datenpunkt pro Fahrt an. Daraus kann keine Trip-Erkennung eine Fahrt rekonstruieren.

Das ist keine Kritik an der Integration, sondern eine Eigenschaft der älteren Fahrzeuge. Für die eigentlichen Werte (km, Tank, Position) nutze ich BavarianData trotzdem, und die sind sehr gut. Die Fahrtenlogik habe ich selbst gebaut.

—

## Warum BavarianData und nicht „BMW CarData“ (kvanbiesen)?

Es gibt zwei bekannte HACS-Integrationen für BMW CarData:

- [BMW CarData]( GitHub - kvanbiesen/bmw-cardata-ha: Use Free Cardata To Read BMW data in HA (EU only - For now) · GitHub ) von @kvanbiesen, hervorgegangen aus „BimmerData Streamline“

- [BavarianData]( GitHub - JustChr/BavarianData: BMW CarData for Home Assistant, in the HACS default store: live MQTT stream + REST API for your BMW or MINI, with charging history & cost, trip journal and battery health. The replacement for the Connected Drive / MyBMW integration. · GitHub ) von @JustChr

Ich hatte beide im Einsatz und sie verglichen. Am Ende habe ich mich für **BavarianData** entschieden:

1. **Genauere Werte bei meinem Auto.** Kilometerstand, Tankinhalt und Position am Fahrtende waren mit BavarianData bei mir zuverlässiger und stimmiger. Für ein Fahrtenbuch zählt genau das: Wenn der Kilometerstand nicht stimmt, ist die ganze Zeile wertlos.

2. **Nur ein Stream pro BMW-Konto.** BMW lässt pro Konto nur **eine** gleichzeitige MQTT-Verbindung zu. Steht eine zweite Integration (oder evcc, eine Bridge, …) mit derselben Client-ID daneben, bekommt man „Not authorized“, obwohl die Tokens gültig sind. Beide parallel laufen zu lassen geht also nicht. Man muss sich entscheiden, und ich habe mich für die genaueren Werte entschieden.

3. **Kein Fahrtenbuch in beiden.** „BMW CarData“ ist auf Live-Zustand und Akku-Prognosen ausgelegt und hat laut README keine Logbuch-Funktion. Die Trips von BavarianData helfen bei iDrive 6 nicht (siehe oben). Die Fahrtenbuch-Logik musste ich also so oder so selbst bauen.

Beide Projekte sind gut gepflegt und machen viel richtig. Bei anderen Modellen kann der Vergleich auch anders ausfallen. Probiert es mit eurem Auto aus, aber immer nur **eine** Integration gleichzeitig.

—

## Die Lösung: Start vom iPhone, Ende vom Auto

Weil das Auto den Fahrtbeginn nicht meldet, kommt er vom **iPhone**:

Ausgeschrieben:

```text

iPhone verbindet sich per Bluetooth mit dem BMW

→ iOS-Kurzbefehl (persönliche Automation)

  1\. „Aktuellen Ort abrufen“

  2\. Webhook an Home Assistant (über Nabu Casa) – mit Straße, PLZ, Ort

→ HA merkt sich: Startzeit, Startadresse, km-Stand, Tankinhalt, „Fahrt aktiv“

BMW beendet die Fahrt → CarData-Stream → BavarianData: neuer km-Stand, Tank, Position

→ Places-Integration macht daraus Straße/Hausnummer/PLZ/Ort

→ km-Stand 10 Minuten unverändert = Fahrt zu Ende

→ Skript schreibt eine Zeile in Google Sheets

```

Die **Startadresse** wird in dieser Reihenfolge bestimmt:

1. die Adresse, die der Kurzbefehl im Webhook mitschickt

2. der „Geocoded Location“-Sensor der HA-Companion-App, wenn er höchstens 5 Minuten alt ist

3. das Ziel der vorherigen Fahrt

4. die letzte Position des Autos

So entsteht auch dann eine sinnvolle Zeile, wenn das iPhone mal nicht mitspielt.

**Verwendete Komponenten:**

| Komponente | Wofür |

|—|—|

| [BavarianData]( GitHub - JustChr/BavarianData: BMW CarData for Home Assistant, in the HACS default store: live MQTT stream + REST API for your BMW or MINI, with charging history & cost, trip journal and battery health. The replacement for the Connected Drive / MyBMW integration. · GitHub ) (HACS) | km-Stand, Tankinhalt, Position aus dem CarData-Stream |

| [Places]( GitHub - custom-components/places: Component to integrate with OpenStreetMap Reverse Geocode (places) · GitHub ) (HACS) | Reverse Geocoding (OpenStreetMap) der Auto-Position |

| [Google Sheets]( Google Sheets - Home Assistant ) | `google_sheets.append_sheet`, eine Zeile pro Fahrt |

| iOS-Kurzbefehle | Bluetooth-Automation mit Webhook |

| Nabu Casa (oder andere externe URL) | Webhook aus dem Mobilfunknetz erreichbar |

| HA Companion App | nur als Fallback für die Startadresse |

Alle YAMLs (Helfer, Automation, Skript) und die Einrichtung des Kurzbefehls Schritt für Schritt stehen im [GitHub-Repo]( GitHub - ursubey/Home-Assistant-BMW-CarData-Logbook-iDrive6: Automatic driving logbook (Fahrtenbuch) for BMW iDrive 6 in Home Assistant: BMW CarData (BavarianData), iPhone Bluetooth webhook with start address, Google Sheets · GitHub ).

—

## Die Stolperfallen

Auf diesem Teil liegt der eigentliche Wert des Beitrags. Fast jeder Punkt hat mich mindestens eine Fahrt gekostet.

### BMW CarData und iDrive 6

**1. Die Türentriegelung taugt nicht als Startsignal.**

Meine erste Idee: Auto wird entriegelt, also beginnt eine Fahrt. Bei iDrive 6 bleibt der Status im Stream aber immer „secured“. Den Trigger und den Helfer habe ich wieder gelöscht.

**2. Daten kommen nur am Fahrtende, manchmal mit Verzögerung.**

Die Endzeit im Fahrtenbuch ist der Zeitpunkt, an dem das Auto den neuen km-Stand meldet. Das kann ein paar Minuten nach dem Abstellen sein. Deshalb gilt eine Fahrt erst als beendet, wenn der km-Stand **10 Minuten** stabil ist.

**3. 50 API-Aufrufe pro Tag.**

Nicht pollen. Der MQTT-Stream ist die Datenquelle, die API nur die Notreserve.

**4. Der Stream verbindet sich etwa alle 45 Minuten neu.**

Das sieht in der Diagnose wie ein Fehler aus, ist aber nur der Token-Refresh. Dabei gehen keine Daten verloren.

**5. Nur eine Stream-Verbindung pro BMW-Konto.**

Siehe oben: Zwei Integrationen, evcc oder eine Bridge gleichzeitig führen zu „Not authorized“.

### iPhone und Webhook

**6. Der Webhook geht manchmal verloren.**

Beim Wechsel von WLAN auf 5G und mit dauerhaft aktivem VPN scheitert der Kurzbefehl ab und zu. Lösung: Die Fahrt wird am Ende **trotzdem** eingetragen. Als Start gilt dann das Ziel der letzten Fahrt, markiert mit „(no start signal)“.

**7. Die Rückfahrt startet, bevor die Hinfahrt abgeschlossen ist.**

Klassiker: kurz zum Bäcker und wieder zurück. Der Webhook für die Rückfahrt kommt, während HA noch die 10 Minuten bis zum Ende der Hinfahrt abwartet. In der ersten Version wurde dieser Webhook verworfen, und die Rückfahrt hatte keinen Start. Jetzt gilt: Ist beim neuen Webhook noch eine Fahrt offen und der km-Stand gestiegen, wird die alte Fahrt **sofort** abgeschlossen, dann startet die neue.

**8. Doppelte Bluetooth-Ereignisse.**

Das iPhone verbindet sich manchmal zweimal kurz hintereinander. Ein zweiter Webhook innerhalb von 30 Minuten wird ignoriert.

**9. Die Webhook-URL muss `/api/webhook/` enthalten.**

Richtig ist `https:///api/webhook/`. Ohne `/api/webhook/` passiert einfach nichts. Außerdem braucht der Webhook-Trigger `local_only: false`, sonst kommt er aus dem Mobilfunknetz nicht an.

**10. Eine lange, zufällige Webhook-ID verwenden.**

Mit `local_only: false` kann **jeder**, der die ID kennt, Fahrten anlegen. `bmw_fahrt_start` errät man leicht, `openssl rand -hex 16` nicht.

**11. „Standort aktualisieren“ der HA-App funktioniert im Hintergrund nicht.**

Die Kurzbefehl-Aktion der Companion App läuft nur, wenn die App geöffnet ist. Aus einer Bluetooth-Automation heraus klappt sie nicht. Die Lösung ist die eingebaute Aktion **„Aktuellen Ort abrufen“** der Kurzbefehle-App selbst, mit Genauigkeit „Optimal“. Die braucht die HA-App gar nicht.

**12. Der Kurzbefehl schickt die ganze Adresse statt nur der Straße.**

Auch wenn man bei der Variable „Straße“ auswählt, kam bei mir oft die komplette Adresse an: `Musterstraße 12⏎12345 Musterstadt⏎Deutschland`. Außerdem war mir beim Schlüssel `plz` ein Leerzeichen hinten reingerutscht (`"plz "`). Die Automation ist deshalb tolerant: Sie nimmt die erste Zeile, trennt Straße und Hausnummer, holt PLZ und Ort notfalls aus der Adresse und ignoriert Leerzeichen und Groß-/Kleinschreibung in den Schlüsseln.

**13. Die Aktion im Kurzbefehl verschieben.**

„Aktuellen Ort abrufen“ muss **vor** dem Webhook stehen. Zum Verschieben den **Titel** der Aktion gedrückt halten, bis sie sich anhebt, dann ziehen.

### Adressen und Zonen

**14. iPhone und Auto verorten denselben Ort unterschiedlich.**

Mein Auto parkt etwa 20 m vom Haus entfernt. Das iPhone meldet die Hausadresse, Places/OpenStreetMap für das Auto die Nachbarstraße. Beides stimmt, sieht im Fahrtenbuch aber unterschiedlich aus. Der **Klarname** („Home“) kommt deshalb aus der Zone, die Adresse aus der jeweiligen Quelle.

**15. Überlappende Zonen.**

Ein Device Tracker bekommt den Namen der **kleinsten** Zone, in der er steht. Hat man um „Home“ herum eine größere Zone (bei mir „Wohngebiet“) und parkt am Rand, steht als Ziel plötzlich „Wohngebiet“ statt „Home“. Die Zonen also bewusst anlegen.

### Home Assistant

**16. Die Reihenfolge der `variables:` kann sich ändern.**

Beim Speichern über die UI bzw. die Config-API landen die Schlüssel eines `variables:`-Blocks bei mir **alphabetisch sortiert**. Hängt `b` von `a` ab und `a` steht danach weiter unten, ist `a` beim Rendern noch nicht definiert. Lösung: Abhängige Variablen in **mehrere aufeinanderfolgende `variables:`-Schritte** aufteilen.

**17. Kein `initial:` am `input_boolean`.**

Sonst ist „Fahrt aktiv“ nach jedem Neustart zurückgesetzt, und eine offene Fahrt geht verloren.

**18. Sicherheitsnetz für Google Sheets.**

Vor dem Schreiben ins Sheet erzeugt das Skript eine **persistente Benachrichtigung** mit allen Werten. Gelöscht wird sie erst, wenn die Zeile im Sheet steht. Scheitert der Sheets-Aufruf, ist die Fahrt nicht verloren.

### Google Sheets

**19. Die PLZ wird zum Datum.**

`append_sheet` übergibt die Werte so, als hätte man sie in die Tabelle eingetippt. Eine PLZ wie `12345` kann so zu einer Zahl oder einem Datum werden. Lösung: die PLZ mit vorangestelltem `'` schreiben.

**20. Die Spaltennamen müssen exakt passen.**

`append_sheet` ordnet die Werte über die **Überschriften** zu. Ein Leerzeichen zu viel in der Kopfzeile, und die Spalte bleibt leer.

**21. Verbrauch bei Kurzstrecken.**

Der Tankinhalt kommt in ganzen Litern. Auf 3 km ändert er sich nicht, also steht dort 0 l. Über einen Monat gerechnet passt der Verbrauch dann wieder.

—

## Testen ohne zu fahren

Den Kurzbefehl kann man in der Kurzbefehle-App mit **:play_button:︎** auch von Hand ausführen. Im Trace der Automation sieht man unter `wj`, was angekommen ist, und unter `w`, was daraus geworden ist. Danach `input_boolean.bmw_fahrt_aktiv` wieder ausschalten. Eine Zeile entsteht bei so einem Test nicht, weil sich der km-Stand nicht ändert.

—

## Fazit

Mit einem iDrive 6 bekommt man kein Fahrtenbuch „out of the box“. Die Kombination funktioniert aber zuverlässig:

- **BavarianData** für saubere Werte

- **iPhone-Bluetooth** als Startsignal mit Adresse

- eine eigene Fahrtenlogik mit mehreren Fallbacks

Seit dem Umbau landen alle Fahrten automatisch mit Start- und Zieladresse im Sheet, inklusive Hin- und Rückfahrt zum Bäcker innerhalb von 10 Minuten.

> :warning: Das ist meine private Aufzeichnung. Ob so ein Fahrtenbuch steuerlich anerkannt wird (Stichwort Manipulationssicherheit), müsst ihr mit eurem Steuerberater klären.

Alles zum Nachbauen, anonymisiert und mit Platzhaltern:

:backhand_index_pointing_right: **[Zum GitHub-Repo]( GitHub - ursubey/Home-Assistant-BMW-CarData-Logbook-iDrive6: Automatic driving logbook (Fahrtenbuch) for BMW iDrive 6 in Home Assistant: BMW CarData (BavarianData), iPhone Bluetooth webhook with start address, Google Sheets · GitHub )**

Ein großes Dankeschön an **@JustChr** für [BavarianData]( GitHub - JustChr/BavarianData: BMW CarData for Home Assistant, in the HACS default store: live MQTT stream + REST API for your BMW or MINI, with charging history & cost, trip journal and battery health. The replacement for the Connected Drive / MyBMW integration. · GitHub ), an **@kvanbiesen** für [BMW CarData]( GitHub - kvanbiesen/bmw-cardata-ha: Use Free Cardata To Read BMW data in HA (EU only - For now) · GitHub ), die ich zum Vergleich getestet habe, und an die Macher von [Places]( GitHub - custom-components/places: Component to integrate with OpenStreetMap Reverse Geocode (places) · GitHub ).

Fragen, Ideen oder eure Erfahrungen mit anderen BMW-Modellen gerne hier im Thread. Mich interessiert besonders, ob jemand mit iDrive 7/8 die Trip-Funktion von BavarianData direkt als Fahrtenbuch nutzt.

Viele Grüße

Chris

Ich würde es zu gerne ausprobieren, aber wegen der Tatsache, dass die Daten nur am Ende der Fahrt übermittelt werden (ist bei meinem 2022-er Countryman auch so) und mein Heimat-Parkplatz eine Tiefgarage mit Funkloch ist, fällt das leider aus. Jede Fahrt, die in der Garage endet, würde somit nicht existieren. (Ich möchte deswegen nicht jedes mal extra den Motor vor der Garage abstellen.)

Gute Frage, aber vielleicht eine Idee für Deinen Fall. Eine Tiefgarage im Mehrfamilienhaus ist für dieses Setup der schwierigste Fall:

- **Das Auto hat dort meist kein GPS und kein Netz.** Kilometerstand, Tankinhalt und Position kommen erst bei der nächsten Ausfahrt an.

- **Das iPhone hat oft auch kein Netz.** Der Webhook beim Einsteigen geht dann ins Leere.

- **Hardware** wie Sensoren, Strom, WLAN oder eine Anbindung des Tors ist in einer Gemeinschaftsgarage meist tabu.

Am realistischsten finde ich eine Lösung **ganz ohne Hardware**:

1. **Das iPhone merkt sich den Zeitpunkt selbst.** Es sendet erst, wenn es wieder Netz hat, also ein paar Sekunden nach der Ausfahrt oder spätestens in der Wohnung im WLAN.

2. **Die Zone „Home“ dient als Anker.** Liegt der übermittelte Ort nah genug am Zuhause, gilt der Start bzw. das Ziel als „Home“.

3. **Die Daten vom Auto dürfen später kommen.** Endzeit und Ziel liefert das iPhone, den Kilometerstand trägt HA nach. Die gefahrenen Kilometer stimmen trotzdem, weil sie aus der Differenz der Kilometerstände berechnet werden.

> :warning: **Ungetestet:** Das ist ein Konzept auf Basis meines [Fahrtenbuchs](GitHub - ursubey/Home-Assistant-BMW-CarData-Logbook-iDrive6: Automatic driving logbook (Fahrtenbuch) for BMW iDrive 6 in Home Assistant: BMW CarData (BavarianData), iPhone Bluetooth webhook with start address, Google Sheets · GitHub). In meinem eigenen Setup läuft es so nicht, weil ich keine Tiefgarage habe. Bitte erst testen und dann ins Fahrtenbuch übernehmen.

—

## 1. iPhone: zwei Automationen in der Kurzbefehle-App

### A) Fahrtbeginn: „Bluetooth verbindet mit “

Einstellungen der Automation: **Sofort ausführen** an, **Bei Ausführung benachrichtigen** aus.

```text

1. Aktuelles Datum
2. Datum formatieren → Benutzerdefiniert: yyyy-MM-dd HH:mm:ss
3. Variable festlegen → Name: zeit
4. Zahl: 0
5. Variable festlegen → Name: gesendet
6. Wiederholen: 20-mal
7. Wenn gesendet ist 0
8. Netzwerkdetails abrufen → Mobilfunk · Anzahl Signalbalken
9. Wenn Anzahl Signalbalken ist größer als 0
10. Aktuellen Ort abrufen (Genauigkeit: Optimal)
11. Inhalte von URL abrufen
URL: https:///api/webhook/
Methode: POST
Anfragetext: JSON
zeit (Text) = zeit
strasse (Text) = Aktueller Ort
plz (Text) = Aktueller Ort › Postleitzahl
ort (Text) = Aktueller Ort › Stadt
lat (Text) = Aktueller Ort › Breitengrad
lon (Text) = Aktueller Ort › Längengrad
12. Zahl: 1
13. Variable festlegen → gesendet
14. Sonst
15. Warten: 15 Sekunden
16. Ende Wenn
17. Ende Wenn
18. Ende Wiederholen
```

Das ergibt maximal 20 × 15 s = 5 Minuten Wartezeit. Sobald wieder Netz da ist, geht der Webhook mit dem **Zeitpunkt des Einsteigens** raus.

Tipp: Wer in der Wohnung WLAN hat, kann in Schritt 9 zusätzlich auf „WLAN · Netzwerkname hat einen beliebigen Wert“ prüfen. Dazu bei „Wenn“ die Option **„Beliebige“** wählen.

### B) Fahrtende: „Bluetooth trennt von “

Der Aufbau ist identisch. Es gibt nur zwei Unterschiede:

- Die URL zeigt auf eine **zweite Webhook-ID**: ``.

- In Schritt 10 liefert „Aktueller Ort“ in der Garage oft keinen neuen Fix. iOS nimmt dann die letzte bekannte Position, und das ist die Einfahrt, also praktisch zu Hause. Genau so ist es gewollt.

—

## 2. Home Assistant: Ergänzungen zum Fahrtenbuch

### 2.1 Neuer Helfer

```yaml

input_text:
bmw_iphone_ende:
name: BMW Fahrtende vom iPhone
max: 255        # speichert Zeit + Ziel als kleines JSON

### 2.2 Automation: zweiter Webhook-Trigger

```yaml

triggers:
\# … bestehende Trigger (webhook_start, fahrt_ende) …
  - trigger: webhook
id: webhook_ende
webhook_id: <zufalls-id-ende>
allowed_methods: \[POST\]
local_only: false

### 2.3 Automation: neuer Zweig im `choose` für das Fahrtende vom iPhone

```yaml

\- conditions:
    - condition: trigger
id: webhook_ende
sequence:
    - variables:
wj: "{{ trigger.json if trigger.json is mapping else {} }}"
    - variables:
lat: "{{ wj.get('lat', 0) | float(0) }}"
lon: "{{ wj.get('lon', 0) | float(0) }}"
zeit: "{{ wj.get('zeit') or now().strftime('%Y-%m-%d %H:%M:%S') }}"
zeile1: "{{ ((wj.get('strasse', '') | string).split('\\n') | first | default('')) | trim }}"
plz: "{{ wj.get('plz', '') | string | trim }}"
ort: "{{ wj.get('ort', '') | string | trim }}"
    - variables:
zuhause: "{{ lat != 0 and distance(lat, lon, 'zone.home') < 0.3 }}"   # 300 m um Home
m: "{{ zeile1 | regex_findall('^(.\*?)\\\\s+(\\\\d+\\\\s\*\[a-zA-Z\]?)$') }}"
    - action: input_text.set_value
target:
entity_id: input_text.bmw_iphone_ende
data:
value: >-
          {{ {'zeit': zeit,
              'anzeige': state_attr('zone.home', 'friendly_name') if zuhause else zeile1,
              'strasse': m\[0\]\[0\] if m else zeile1,
              'hnr': m\[0\]\[1\] if m else '',
              'plz': plz, 'ort': ort} | to_json }}

### 2.4 Automation: Ergänzungen im Zweig `webhook_start`

**a) Startzeit vom iPhone übernehmen.** Den Schritt, der `input_text.bmw_fahrt_start_zeit` setzt, ersetzen durch:

```yaml

\- action: input_text.set_value
target:
entity_id: input_text.bmw_fahrt_start_zeit
data:
value: "{{ wj.get('zeit') or now().strftime('%Y-%m-%d %H:%M:%S') }}"

**\*\*b) „Home“ als Anker für den Start.\*\*** Im Schritt, der \`input_text.bmw_fahrt_start_zone\` setzt, als erste Bedingung einfügen:

\`\`\`jinja

{%- set la = wj.get('lat', 0) | float(0) -%}{%- set lo = wj.get('lon', 0) | float(0) -%}
{%- if la != 0 and distance(la, lo, 'zone.home') < 0.3 -%}{{ state_attr('zone.home', 'friendly_name') }}
{%- elif … bestehende Logik … -%}

**c) Verspäteten km-Stand abwarten.** Das ist der wichtigste Punkt für die Tiefgarage: Bei der Ausfahrt kommen der neue Webhook und der km-Stand der **letzten** Fahrt fast gleichzeitig an, oft der Webhook zuerst. Ganz an den Anfang des Zweigs `webhook_start` gehört deshalb:

```yaml

\- if:
    - condition: state
entity_id: input_boolean.bmw_fahrt_aktiv
state: "on"
    - condition: template
value_template: "{{ states('input_text.bmw_iphone_ende') | length > 2 }}"   # iPhone hat Ende gemeldet
    - condition: template
value_template: >-
        {{ states('sensor.my_bmw_mileage') | float(0)
           <= states('input_number.bmw_fahrt_start_km') | float(0) }}
then:
    - wait_for_trigger:
        - trigger: state
entity_id: sensor.my_bmw_mileage
timeout:
minutes: 5
continue_on_timeout: true
alias: "Auto meldet den km-Stand der letzten Fahrt erst nach der Ausfahrt"

Danach greift die bestehende Logik: Die offene Fahrt wird abgeschlossen, und die neue beginnt.

### 2.5 Skript `bmw_fahrt_abschliessen`: Ende vom iPhone bevorzugen

Im ersten `variables`-Schritt ergänzen:

```yaml

ie: >-
  {% set s = states('input_text.bmw_iphone_ende') %}
  {{ s | from_json if s.startswith('{') else {} }}

In den späteren Schritten jeweils die iPhone-Werte bevorzugen:

```yaml

ende_zeit: >-
  {{ ie.zeit if ie.zeit is defined
     else as_local(states.sensor.my_bmw_mileage.last_changed).strftime('%Y-%m-%d %H:%M:%S') }}
ziel_strasse: "{{ ie.strasse if ie.strasse is defined else states('sensor.my_bmw_places_street') }}"
ziel_hausnummer: "{{ ie.hnr if ie.hnr is defined else <bisherige Logik> }}"
ziel_plz: "{{ ie.plz if ie.plz is defined else states('sensor.my_bmw_places_postal_code') }}"
ziel_ort: "{{ ie.ort if ie.ort is defined else states('sensor.my_bmw_places_city') }}"
\# ziel_anzeige: ie.anzeige verwenden, wenn vorhanden

Ganz am Ende des Skripts den Helfer wieder leeren:

```yaml

\- action: input_text.set_value
target:
entity_id: input_text.bmw_iphone_ende
data:
value: ""

> Wichtig: `ie` steht in einem **früheren** `variables`-Schritt als die Werte, die es nutzen. Die Schlüssel innerhalb eines Blocks können beim Speichern alphabetisch sortiert werden (siehe Stolperfalle 16 im Hauptbeitrag).

—
## Ergebnis

Situation Startzeit Start Endzeit Ziel km
Ausfahrt aus der Tiefgarage iPhone (Einsteigen) Home (Anker) – – Stand vom letzten Fahrtende
Einfahrt in die Tiefgarage – – iPhone (Aussteigen) Home (letzter Ort = Einfahrt) kommt bei der nächsten Ausfahrt
Nächste Ausfahrt – – – – HA wartet bis zu 5 Min., schließt die alte Fahrt ab, startet die neue

**Fazit:** Der Kurzbefehl, der den Zeitstempel merkt und später sendet, zusammen mit der Zone „Home“ als Anker, ist in einer Tiefgarage im Mehrfamilienhaus am realistischsten. Er braucht keine Hardware und keine Genehmigung. Dass die Daten vom Auto verspätet kommen, spielt für die Berechnung keine Rolle, weil Zeiten und Orte vom iPhone kommen und die Kilometer aus der Differenz berechnet werden.

**Grenzen:**

- iOS kann lang laufende Kurzbefehle im Hintergrund abbrechen. Die 5 Minuten Warteschleife müsste man in der Praxis testen.
- Fährt jemand ohne das iPhone, greift wie bisher der Fallback „(no start signal)“.

Wenn du es ausprobierst, sag gern, ob es klappt. Dann nehme ich es als Variante „Tiefgarage“ ins Repo auf.

:crayon:by HarryP: Post formatiert

Vielen Dank für deine Mühe und die super Anleitung.
Sobald meine Erkältung auskuriert ist und mein Gehirn wieder zu 100% arbeitet, werde ich das mal angehen. Die größte Herausforderung werden sicher die iOS Befehle sein, ich find die Kurzbefehle-Einrichtung extrem anwenderfeindlich.
Meine Heimatgarage liegt übrigens nicht unter dem Block, in dem ich wohne, sondern unter dem Block auf der anderen Straßenseite. Würd es was erleichtern, wenn ich in HA eine Zone für die Garageneinfahrt speichere?

Danke dir, und gute Besserung! :face_with_thermometer:
ich habe dein case bei dem Entwickler von bavariandata, das HACS, das ich nutze platziert, mal schauen was rauskommt, schau Dir die Diskussion an:

aber noch eine Idee für Dich:
Wenn die Garage nur etwa ca. 20 m (andere Strassebseite in D) von deiner Wohnung entfernt ist, würde ich auf iOS ganz verzichten und Bluetooth (BLE) nehmen: einen kleinen Beacon im Auto und einen Empfänger in deiner Wohnung. Du brauchst dafür keine Kurzbefehle, keine Hardware in der Gemeinschaftsgarage und keine Genehmigung.

Hardware (ca. 10–15 €)

Teil Wo Wofür
ESP32 als Bluetooth-Proxy (idealerweise mit externer Antenne) in deiner Wohnung am Fenster zur Straße empfängt den Beacon
BLE-Beacon im Auto sendet „ich bin hier“

Als Beacon reicht ein fertiges iBeacon mit Batterie. Eleganter ist ein ESP32-C3 am USB-Port des Autos, der sich per ESPHome selbst als Beacon ausgibt. Bekommt der USB-Port nur bei Zündung Strom, hast du nebenbei ein „Auto läuft“-Signal. Ob dein Auto den USB-Port nach dem Abschließen weiter versorgt, musst du ausprobieren.

Proxy in der Wohnung:

yaml

esphome:
  name: ble-proxy-strasse
esp32:
  board: esp32dev
  framework:
    type: esp-idf
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
api:
logger:
esp32_ble_tracker:
  scan_parameters:
    active: false
bluetooth_proxy:

Beacon im Auto (ESP32-C3, kein WLAN nötig):

yaml

esphome:
  name: bmw-beacon
esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf
logger:
esp32_ble_beacon:
  type: iBeacon
  uuid: "<eigene-uuid>"      # z. B. mit uuidgen erzeugen

In HA erkennt die eingebaute Integration iBeacon Tracker (oder Bermuda) den Beacon automatisch. Es entsteht ein device_tracker.bmw_beacon, der home meldet, wenn der Proxy ihn sieht.

Schritt 1: eine Woche beobachten

Schau im Verlauf von device_tracker.bmw_beacon nach, welcher Fall bei dir eintritt:

  • Fall A: Der Beacon ist auch in der Garage zu sehen, das Signal ist schwach, aber dauerhaft.
  • Fall B: In der Garage gibt es keinen Empfang, Beton schirmt ab. Der Beacon ist nur kurz bei der Ein- und Ausfahrt zu sehen.

Schritt 2: passende Automation

Als Basis dienen die Helfer aus meinem Fahrtenbuch und der Helfer input_text.bmw_iphone_ende aus meiner Tiefgaragen-Antwort, mit der Skript-Ergänzung „Ende bevorzugen“. Trag die Garagenadresse einmal fest ein.

Fall A: verschwindet = Start, taucht auf = Ende

yaml

alias: BMW Garage Beacon (Fall A)
mode: queued
triggers:
  - trigger: state
    entity_id: device_tracker.bmw_beacon
    to: not_home
    for: { minutes: 1 }
    id: start
  - trigger: state
    entity_id: device_tracker.bmw_beacon
    to: home
    for: { minutes: 1 }
    id: ende
actions:
  - choose:
      - conditions:
          - condition: trigger
            id: start
          - condition: state
            entity_id: input_boolean.bmw_fahrt_aktiv
            state: "off"
        sequence: &start
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_zone }
            data: { value: "Garage" }
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_strasse }
            data: { value: "<Garagen-Straße>" }
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_hausnummer }
            data: { value: "<Nr.>" }
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_plz }
            data: { value: "<PLZ>" }
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_ort }
            data: { value: "<Ort>" }
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_fahrt_start_zeit }
            data: { value: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}" }
          - action: input_number.set_value
            target: { entity_id: input_number.bmw_fahrt_start_km }
            data: { value: "{{ states('sensor.my_bmw_mileage') | float(0) }}" }
          - action: input_number.set_value
            target: { entity_id: input_number.bmw_fahrt_start_tank }
            data: { value: "{{ states('sensor.my_bmw_fuel_level') | float(0) }}" }
          - action: input_boolean.turn_on
            target: { entity_id: input_boolean.bmw_fahrt_aktiv }
      - conditions:
          - condition: trigger
            id: ende
          - condition: state
            entity_id: input_boolean.bmw_fahrt_aktiv
            state: "on"
        sequence: &ende
          - action: input_text.set_value
            target: { entity_id: input_text.bmw_iphone_ende }
            data:
              value: >-
                {{ {'zeit': now().strftime('%Y-%m-%d %H:%M:%S'), 'anzeige': 'Garage',
                    'strasse': '<Garagen-Straße>', 'hnr': '<Nr.>',
                    'plz': '<PLZ>', 'ort': '<Ort>'} | to_json }}

Fall B: kurz sichtbar = abwechselnd Start und Ende

Hier gibt es nur einen Trigger. Ob Start oder Ende, entscheidet der Zustand von „Fahrt aktiv“. Eine Sperre von 5 Minuten verhindert, dass eine einzelne Ein- oder Ausfahrt doppelt zählt.

yaml

alias: BMW Garage Beacon (Fall B)
mode: single
triggers:
  - trigger: state
    entity_id: device_tracker.bmw_beacon
    to: home
conditions:
  - condition: template
    value_template: >-
      {{ this.attributes.last_triggered is none
         or (now() - this.attributes.last_triggered).total_seconds() > 300 }}
actions:
  - if:
      - condition: state
        entity_id: input_boolean.bmw_fahrt_aktiv
        state: "off"
    then:
      # gleiche Start-Schritte wie in Fall A
    else:
      # gleiche Ende-Schritte wie in Fall A

Die YAML-Anker &start und &ende aus Fall A funktionieren nur innerhalb derselben YAML-Datei. Am einfachsten kopierst du die beiden Blöcke von oben in then: und else:.

Was danach passiert

  • Die Startzeit und die Endzeit kommen vom Beacon, also von zu Hause, ganz ohne GPS und Handynetz in der Garage.
  • Kilometerstand und Tank schickt das Auto, sobald es wieder Netz hat, oft erst bei der nächsten Ausfahrt. Die Fahrt wird dann mit den Zeiten vom Beacon abgeschlossen. Die Strecke stimmt, weil sie aus der Differenz berechnet wird.
  • Für Fahrten woanders hin liefert weiter das Auto am Ziel Ort und Zeit, wie in der Anleitung.

Wie immer ungetestet für deine Situation.

Die Bluetooth-Sache ist ne coole Alternative, aber ich muss es mit der Reichweite auf der Straße testen, in der Garage wird es keinesfalls gehen. Zwei ESP32 hab ich zu hause.

…, war nur so eine Idee, denke an die Antenne für den ESP in der Wohnung wegen der Reichweite

LG

Nutze eine Modifizierte Version von https://community.home-assistant.io/t/car-travel-log-car-mileage-log-blueprint/907903

für meine Autos … die diese keinerlei Integrationsmöglichkeit bieten, rein über die HA App und ggf. ein Paar Helfer.

Ja, sie hat mehrere Fallstricke … z.B. das die Waze Integration mal wieder nicht funktioniert, das manche Ereignisse nicht ankommen, oder überlappend, … aber in der Regel funzts.

…, sehr cool, das hatte ich nicht vorher gekannt, Nutzt Du Android, oder IOS?

Android. Die Bluetooth-Verbinding für das Auto was eine Freisprecheinrichtung hat und Template-Sensoren für “ist jemand in Auto A” (via Bluetooth) bzw “Ist jemand in Auto B” (input) und Automation welche letztere automatisch anhand von “detected activity”, “ist jemand in Auto A” und so für das nicht Smarte Auto umschaltet falls man es mal wieder vergessen hat. :slight_smile:

Nutze das Log dann um Helfer für Kilometerstand, Tankfüllstand und Verbrauch zu aktualisieren mit manuellen Korrekturen falls mal was verloren gegangen ist.

Ich kenne das Problem von unserem i3. Im Gegensatz zu unserem iX1 wird auch beim i3 die Position/Fahrt nur am Fahrtende gemeldet. In meiner DriveLoom Integration löse ich das über das Erkennen eines Smarthone im Zuge seiner Verbindung mit Carplay (der Carplay WLAN SSID), oder alternativ über einen Binärsensor bei z.B. Android Auto. Das Tracking läuft nun seit Tagen absolut zuverlässig - sobald ich losfahre weiß HA im 10-Sekundentakt, dass der i3 in Bewegung ist.