Waze Travel Time Sensor, Next event from Calendars

Hello everyone;

I have been trying for some time to create a Waze Travel Time Sensor that sniffs events from my calendar and updates to the next event. Not for notifications, just to sit on the front end. I have gotten it to find the events, but I am having a difficult time getting it to handle the Waze integration afterward. Here is what I have so far:

template:
  - triggers:
      - platform: time_pattern
        minutes: /1
    actions:
      - service: calendar.get_events
        target:
          entity_id:
            - calendar.finley
            - calendar.family_calendar
            - calendar.work
        data:
          # Fetch events for the next 12 hours
          duration:
            hours: 12
        response_variable: next_events_data

    sensor:
      # sensor to combine events from multiple calendars
      - name: "Next Event Location Sensor"
        unique_id: next_event_location_sensor
        state: >
          {% set events = next_events_data.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
          {% if events %}
            {{ events[0].summary }}
          {% else %}
            Home
          {% endif %}
        attributes:
          summary: >
            {% set events = next_events_data.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
            {% if events %}
              {{ events[0].summary }}
            {% else %}
              Home
            {% endif %}
          location: >
            {% set events = next_events_data.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
            {% if events %}
              {{ events[0].location }}
            {% else %}
              zone.home
            {% endif %}
          start_time: >
            {% set events = next_events_data.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
            {% if events %}
              {{ events[0].start }}
            {% endif %}
          friendly_start_time: >
            {% set events = next_events_data.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
            {% if events %}
            {{ as_datetime(events[0].start).strftime('%-I:%M %p') }}
            {% endif %}


### This part doesn't work: ###
  - triggers:
      - platform: time_pattern
        minutes: /1
    actions:
      - action: waze_travel_time.get_travel_times
        data:
          origin: person.stiofan
          destination: "{{ state_attr('sensor.next_event_location_sensor', 'location') }}"
          region: na
        response_variable: waze_eta_result
        continue_on_error: true
      - variables:
          wiggle_room: "{{ 5 }}"
          waze_duration: "{{ waze_eta_result['routes'][0].duration | round(0) }}"
          start_time: "{{ state_attr('sensor.next_event_location_sensor', 'friendly_start_time') }}"
          start_time_friendly: "{{ as_datetime(start_time).strftime('%-I:%M %p') }}"
          location: "{{ state_attr('sensor.next_event_location_sensor', 'location') }}"
          summary: "{{ state_attr('sensor.next_event_location_sensor', 'summary') }}"
          departure_time: >-
            {{ as_datetime(start_time) - timedelta(minutes=waze_duration) -
            timedelta(minutes=wiggle_room) }}
          departure_time_friendly: "{{ as_datetime(departure_time).strftime('%I:%M %p') }}"
          reminder_time: "{{ as_datetime(departure_time) - timedelta(minutes=30) }}"
          sensor_window: "{{ as_datetime(start_time) + timedelta(minutes=30) }}"
    sensor:
      - name: "Next Event Travel Time"
        unique_id: next_event_travel_time
        state: waze_duration
        #state: "{{ state_attr('sensor.waze_travel_time_next_event', 'duration') | round() }}"
        unit_of_measurement: "minutes"
        attributes:
          destination: "{{ state_attr('sensor.next_event_location_sensor', 'location') }}"
          last_update: "{{ state_attr('sensor.travel_time_to_work', 'last_update') }}"
          event_name: "{{ state_attr('sensor.next_event_location_sensor', 'summary') }}"
          start_time: "{{ state_attr('sensor.next_event_location_sensor', 'friendly_start_time') }}"

There are some remnants of attributes from some testing, as well as some other bits I am still working on - just in case anyone is wondering… like “sensor_window” - this will eventually be used to filter out events that are ongoing and to display the next one… Once of course I get the sensor working in the first place.

Any help is greatly appreciated.

Anybody???

I don’t know anything about the Waze integration, but you could simplify your calendar event sensor by using merge_reponse:

template:
  - triggers:
      - platform: time_pattern
        minutes: /1
    actions:
      - service: calendar.get_events
        target:
          entity_id:
            - calendar.finley
            - calendar.family_calendar
            - calendar.work
        data:
          # Fetch events for the next 12 hours
          duration:
            hours: 12
        response_variable: next_events_data
      - variables:
          next_event: |
           {{ merge_response(next_events_data) | sort(attribute='start') | first }}
    sensor:
      # sensor to combine events from multiple calendars
      - name: "Next Event Location Sensor"
        unique_id: next_event_location_sensor
        state: "{{ next_event.summary | default('Home', true) }}"
        attributes:
          summary: "{{ next_event.summary | default('Home', true) }}"
          location: "{{ next_event.location | default('zone.home', true) }}"
          start_time: "{{ next_event.start }}"
          friendly_start_time: "{{ as_datetime(next_event.start).strftime('%-I:%M %p') }}"

Issues:

  • You have the state set to a static string, “waze_duration”… but you have defined a unit_of_measurement which requires that the sensor returns a numeric output.

  • You’ve set your action to continue on error, but the variables that are set in the next block need that data. At a minimum, you need to provide defaults for all those variables if you are going to use continue on error in the waze_travel_time.get_travel_times action.

  • Only one of those variable are being used for anything. I know you said there were some “remnants from testing”, but you’re making it hard for us to help when you leave confounding junk in there.

If you need help with the response variable that is being returned from Waze, then you should post it. You can obfuscate the data, but leave the structure intact.

Hey Drew!

Thanks for your reply. This one is proving to be a bit of a challenge. I’m gonna play with that simplified sensor you suggested - elegant to say the least. I should be able to get Waze to check in another action following that first action, i gotta play some more. Thanks for your help. I will post any progress as it happens.

Hey there!

So I finally got it all working. It was a lot of trial and error, the new template sensor configuration format doesn’t like “variables”, I seemed to have gotten it working with attributes. Thanks for your suggestion/solution with the merge function. That is a new one for me. Elegant. I do now need to figure out how to strip found items containing specified text strings from the merged items.

Anyhow, here is the finished, working code:

template:
  - triggers:
      - platform: time_pattern
        minutes: /1
    actions:
      - service: calendar.get_events
        target:
          entity_id:
            - calendar.finley
            - calendar.family_calendar
            - calendar.work
        data:
          # Fetch events for the next 12 hours
          duration:
            hours: 12
        response_variable: next_events_data
      - variables:
          next_event: |
           {{ merge_response(next_events_data) | sort(attribute='start') | first }}
      - service: waze_travel_time.get_travel_times
        data:
          region: na
          units: metric
          vehicle_type: car
          origin: person.stiofan
          destination: "{{ next_event.location | default('zone.home', true) }}"
        response_variable: waze_eta_result
    sensor:
      # sensor to find next event from multiple calendars.
      - name: "Next Event Location Sensor"
        unique_id: next_event_location_sensor
        state: "{{ next_event.summary | default('Home', true) }}"
        attributes:
          summary: "{{ next_event.summary | default('Home', true) }}"
          location: "{{ next_event.location | default('zone.home', true) }}"
          start_time: "{{ next_event.start }}"
          friendly_start_time: "{{ as_datetime(next_event.start).strftime('%-I:%M %p') }}"
      - name: "Next Event Travel Time"
        unique_id: next_event_travel_time
        icon: mdi:car-clock
        state: "{{ waze_eta_result['routes'][0].duration | default('0', true) | round(0) }}"
        #state: "{{ this.attributes.waze_duration }}"
       # For some reason, this didn't work and state was always '0', the above code does work though.
        unit_of_measurement: "minutes"
        attributes:
          wiggle_room: "{{ 5 }}"
          waze_duration: "{{ waze_eta_result['routes'][0].duration | default('0', true) | round(0) }}"
          start_time: "{{ next_event.start }}"
          departure_time: "{{ as_datetime(start_time) - timedelta(minutes=waze_duration) - timedelta(minutes=wiggle_room) }}"
          departure_time_friendly: "{{ as_datetime(departure_time).strftime('%-I:%M %p') }}"
          reminder_time: "{{ as_datetime(departure_time) - timedelta(minutes=30) }}"
          sensor_window: "{{ as_datetime(start_time) + timedelta(minutes=30) }}"
          reminder_time_friendly: "{{ as_datetime(reminder_time).strftime('%-I:%M %p') }}"
          sensor_window_friendly: "{{ as_datetime(sensor_window).strftime('%-I:%M %p') }}"