Benachrichtigung Verkehrslage mit Google Travel Time

Hallo zusammen,
nachdem ich mich eine Weile mit FHEM beschäftigt habe, wage ich nun den Absprung zu Home Assistant. Ich habe hier und da noch ein paar Startschwierigkeiten, z.B. mit dem folgenden Vorhaben:
Ich möchte die Dauer meines Arbeitsweges bei Google abfragen und ab einem gewissen Grenzwert eine Benachrichtigung per Pushover ausgeben.
Die Verknüpfung zur Google API steht, ich habe einen Sensor der mir eine Zeit als Wert ausgibt und diverse Attribute.
Ich habe die folgende Automation geschrieben, bzw. zusammengeklickt:

alias: Stauwarnung Arbeit
description: ""
trigger:
  - platform: time_pattern
    minutes: /15
condition:
  - condition: and
    conditions:
      - condition: numeric_state
        entity_id: sensor.arbeit
        attribute: duration_in_traffic
        above: 15
      - condition: time
        after: "07:00:00"
        before: "09:00:00"
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri
action:
  - action: notify.pushover
    data:
      message: Stau! Fahrzeit {{ state_attr('sensor.arbeit', 'duration_in_traffic') }}
      title: Fahrt zur Arbeit
      target: galaxy
mode: single

Mein Gedanke ist, dass zwischen 7 und 9 Uhr alle 15 min geprüft wird ob die Fahrt länger als 15 min dauert und ich in dem Fall eine Benachrichtigung bekomme (ich habe schon gesehen, dass einige Leute da sehr spannende, deutlich komplexere Sachen geschrieben haben. Aber ich dachte für den Start wäre das schon mal was).
Das Problem ist, dass die Abfrage der Dauer scheinbar nicht funktioniert. Egal was ich für die Grenze einsetze (der Weg zur Arbeit dauert mindestens 19 min), die condition bleibt false. Kann es sein, dass die Angabe “Duration in traffic” ein string ist und deswegen nicht verarbeitet werden kann? Der Wert ist ja schließlich z.B. “19 mins”. Muss ich den Wert irgendwie in Integer oder Float umwandeln?
Die Pushover Benachrichtigung klappt wenn ich manuell auslöse.

Habt ihr einen Tipp für mich?

Zusatzfrage: Zum Unterschied zwischen “Duration in traffic” und “Duration” habe ich im Netz die Info gefunden, das Ersteres die tatsächliche Zeit mit Verkehr ist und “Duration” die ideale Zeit, quasi wenn nichts los ist. Seltsamerweise ist der Wert von “Duration” immer höher als “Duration in traffic”…

Was genau gibt denn das Attribut duration_in_traffic des sensors aus? Wie generierst du diesen Sensor mit den Attributen?

Hier ist ein Screenshot des Sensors mit den Attributen

Generiert wird der Sensor über die Integration “Google Maps Reisezeit” (google_travel_time). Ich gebe Ziel- und Startort ein und erhalte dann die dargestellten Attribute.

edit: Den Namen des Sensors habe ich eben angepasst. Im Beispiel oben entspricht “Arbeit” → “Hinfahrt”. Die Adressen habe ich unkenntlich gemacht.

das sieht mir nach einem Timestamp aus und nicht nur nach einer Zahl.
Dann musst du vermutlich, ich kenn die Integration nicht, die Zeitstempel vergleichen:

  - condition: template
    value_template: >-
      {{ as_timestamp(now(), default=0) >= as_timestamp(state_attr('sensor.arbeit', 'duration_in_traffic'), default=0) - 900 }}
1 „Gefällt mir“

Den String von “Duration in Traffic” kann der state Vergleich nicht verarbeiten.
Mach es mit einem Template

{{ state_attr('sensor.arbeit','duration_in_traffic')[:2] | int > 15}}

Das funktioniert für 1 und 2 stellige Zeiten, da das Leerzeichen bei Umwandlung zu einer Zahl abgeschnitten wird.
Wenn die Zeit auch über 99 Mins steigt, oder wie auch immer die Integration bei Zeiten größer einer Stunde verfährt, müsste man hier noch erweitern um den Fall abzufangen.

1 „Gefällt mir“

Das hat die Lösung gebracht :slight_smile: vielen Dank!
Habe nun ein Entität erstellt die mir true oder false ausgibt, je nach eingestelltem Grenzwert. Die Frage ich nun in meiner Automatisierung ab und jetzt kommt auch die erhoffte Benachrichtigung. Danke auch an @maxe für die Hilfe!

Hallo, klingt spannend. Wie ist das mit den Kosten für die Google Maps API. Kommst du mit dem Volumen aus bzw. muss Du schon etwas dafür bezahlen? Oder wie hast du das gelöst? Ich schaue mir parallel noch WAZE an. Das ist wohl ohne API-Kosten.

Gruß Sascha

1 „Gefällt mir“

Ich habe jetzt 4 Sensoren laufen und, wie in der Doku zur Integration beschrieben, klappt das nicht so einfach kostenlos. Ich bin jetzt nach 10 Tagen im Monat bei 70 € von 200 € Frei-Kontingent.
Mich interessieren jedoch hauptsächlich die Arbeitswege, daher werde ich einfach das Polling an den Nebenzeiten runterdrehen. Das ist auch in der Doku beschrieben und kann einfach per Automatisierung umgesetzt werden.
Die Begrenzung auf 645 Polls pro Tag (um unter den 20000 im Monat zu bleiben) kann man zudem als Sicherheit recht einfach auf der API-Übersicht bei Google einstellen.

Möchte die Funktion nicht mehr missen. Habe es mir jetzt so eingebaut, dass ich morgens eine “Jetzt-starten!”-Nachricht bekomme, wenn ich zum Arbeitsbeginn unter Berücksichtigung des Verkehrs und eines von mir definierten Puffers (brauche ja auch etwas Zeit bis das Auto läuft) rechtzeitig bei der Arbeit sein will

1 „Gefällt mir“

Danke für den Tipp. Habe es mal eingerichtet, gleich morgen/nachher mal testen :+1:t3:

Ist ja interessant, habe von WAZE noch nichts gehört.
Könnte ihr mal schreiben wie eure Erfahrungen damit sind? Pro/Con Google vs. WAZE?

Inzwischen gehört Waze zu Google und liefert seine Infos an Maps.

Bin damals von Waze weg, nachdem ein angeblicher 8 Minuten Stau mich rund 2 Stunden gekostet hat, was zu diesem Zeitpunkt bereits bei anderen Diensten wie Google und TomTom ersichtlich war…

1 „Gefällt mir“

Dann mach ich mal mit Google weiter…

Genau da wollte ich noch mal ansetzen und habe mein Glück mit der split-Funktion (und einem etwas anderen Aufbau des Templates) versucht:

{% set curhour = now().hour %}
{% set estimation = state_attr('sensor.hinweg', 'duration_in_traffic').split(' ')[0] | int %} {# aktuelle Fahrzeit in min #}

{{ now().weekday() in (0,1,2,3,4) and curhour > 6 and curhour < 9 and estimation > 30 }}

Das Interessante ist, dass alles genau so funktioniert wie es soll, ich aber im Home Assistant Protokoll immer eine Fehlermeldung bekomme:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 731, in async_render_to_info
    render_info._result = self.async_render(  # noqa: SLF001
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 621, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: UndefinedError: 'None' has no attribute 'split'
2024-09-13 12:52:03.641 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: 'None' has no attribute 'split' when rendering '{% set curhour = now().hour %}
{% set estimation = state_attr('sensor.hinweg', 'duration_in_traffic').split(' ')[0] | int %}  {# aktuelle Fahrzeit in min #}

{{ now().weekday() in (0,1,2,3,4) and curhour > 6 and curhour < 9 and estimation > 30 }}'
2024-09-13 12:52:03.642 ERROR (MainThread) [homeassistant.components.template.template_entity] TemplateError('UndefinedError: 'None' has no attribute 'split'') while processing template 'Template<template=({% set curhour = now().hour %}
{% set estimation = state_attr('sensor.hinweg, 'duration_in_traffic').split(' ')[0] | int %}  {# aktuelle Fahrzeit in min #}

Kann da jemand was mit anfangen?

Hi, wo genau finde ich die Doku oder den Punkt um die Begrenzung einzustellen?

Ja, der Fehler kommt, weil manchmal die Fahrtdauer keinen Wert hat und dann der Split nicht funktioniert. Du kannst dann aber einen Initialwert wie 0 übergeben mit int(0) am Ende

Ok, das scheint jetzt zu passen. Hab da komischerweise noch weitere Fehler.
Fehler 1:

TemplateError('UndefinedError: 'None' has no attribute 'split'') while processing template 'Template<template=({% set curhour = now().hour %} {% set estimation = state_attr('sensor.ruckweg', 'duration_in_traffic').split(' ')[0] | int(0) %} {# aktuelle Fahrzeit in min #} {{ now().weekday() in (0,1,2,4) and curhour > 11 and curhour < 14 and estimation > 30 }}) renders=4>' for attribute '_state' in entity 'binary_sensor.var_stauruckweg'

das Template dazu:

{% set curhour = now().hour %}
{% set estimation = state_attr('sensor.ruckweg', 'duration_in_traffic').split(' ')[0] | int(0) %}  {# aktuelle Fahrzeit in min #}

{{ now().weekday() in (0,1,2,4) and curhour > 11 and curhour < 14 and estimation > 30 }}

und Fehler 2:

TemplateError('ValueError: could not convert str to datetime: ':00'') while processing template 'Template<template=({% set targettime = today_at(':00') %} {% set estimation = state_attr('sensor.hinweg_2', 'duration_in_traffic').split(' ')[0] | int(0) %} {# aktuelle Fahrzeit in min #} {% set safety = 30 %} {# Puffer in min #} {% set duration = estimation + safety %} {{ now().weekday() in (0,1,2,4,5) and now() >= targettime - timedelta( minutes = duration) and now() <= targettime }} {# Donnerstag nicht #}) renders=4>' for attribute '_state' in entity 'None'

Beim diesem Fehler verstehe ich das ‘:00’ auch nicht. Im Template steht ‘08:00’.
Das Template vom zweiten Fehler:

{% set targettime = today_at('08:00') %}
{% set estimation = state_attr('sensor.hinweg_2', 'duration_in_traffic').split(' ')[0] | int(0) %}  {# aktuelle Fahrzeit in min #}
{% set safety = 30 %}  {# Puffer in min #}
{% set duration = estimation + safety %}

{{ now().weekday() in (0,1,2,4) and now() >= targettime - timedelta( minutes = duration) and now() <= targettime }}
{# Donnerstag nicht #}

Ich frage mich ob sich der Fehler auf eine vorherige Version bezieht? Denn weekday ist ja auch auf 0,1,2,4 und nicht 0,1,2,4,5

Beim ersten Fehler ist es so, dass 0 auch nicht splitten geht. Es müsste als Initialwert etwas wie 0 0 übergeben werden, ist dann aber kein Integer. Man könnte erst einen String damit setzen und erst nach dem Split in ein Integer wandeln.
Das Log würde ich mal löschen, dann kannst du schauen ob nach einem Neustart der zweite Fehler nochmal kommt

Hm ich hätte gedacht es ist zunächst ein string. Der Inhalt des Attributs ‘duration-in-traffic’ ist z.B. “5 mins”. Da mins mit drin steht müsste es doch string sein? Möchte nun mit split " mins" entfernen und es danach in integer umwandeln.
Weiß nicht ganz wie du das meinst mit dem Umwandeln in string.

Edit: hab das Gefühl ich bräuchte eine default Möglichkeit für die Split-Funktion oder? Für den Fall das der Sensor keinen valide Wert liefert. Dazu hab ich grade allerdings nichts finden können. Ggf. Abfangen mit mit einer Abfrage ob der Wert valid ist wenn ja split, wenn nein einen default wert vergeben… kompliziert :smiley:
Edit2: der zweite Fehler ist übrigens jetzt weg

Ja das klingt doch gut dein Vorschlag für den ersten Fehler mit der Abfrage