home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
74.06k stars 31.08k forks source link

Waze_travel_time.get_travel_times origin not accepting templates #131350

Closed jbrazio closed 4 days ago

jbrazio commented 6 days ago

The problem

- variables:
    coords: |-
      {%- if is_state("person.bart_simpson", "home") -%}
        {%- set latitude = state_attr('zone.home', 'latitude') -%}
        {%- set longitude = state_attr('zone.home', 'longitude') -%}
      {%- else  -%}
        {%- set latitude = state_attr(state_attr('person.bart_simpson', 'source'), 'latitude') -%}
        {%- set longitude = state_attr(state_attr('person.bart_simpson', 'source'), 'longitude') -%}
      {%- endif -%}
      {{ latitude ~ "," ~ longitude }}
- action: waze_travel_time.get_travel_times
  metadata: {}
  data:
    region: eu
    units: metric
    vehicle_type: car
    origin: "{{ coords }}"
    destination: "{{ repeat.item.location }}"
    realtime: true
  response_variable: travel

{{ repeat.item.location }} works fine and it's coming from calendar.get_events. Using "{{ coords }}" as the origin, I get the following error:

Executed: 21 November 2024 at 19:38:53
Error: expected str for dictionary value @ data['origin']
Result:

params:
  domain: waze_travel_time
  service: get_travel_times
  service_data:
    region: eu
    units: metric
    vehicle_type: car
    origin:
      - 11.111
      - -1.111
    destination: Some random street
    realtime: true
  target: {}
running_script: false

What version of Home Assistant Core has the issue?

core-2024.11.3

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Container

Integration causing the issue

Waze Travel Time

Link to integration documentation on our website

https://www.home-assistant.io/integrations/waze_travel_time

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

No response

Additional information

No response

home-assistant[bot] commented 6 days ago

Hey there @eifinger, mind taking a look at this issue as it has been labeled with an integration (waze_travel_time) you are listed as a code owner for? Thanks!

Code owner commands Code owners of `waze_travel_time` can trigger bot actions by commenting: - `@home-assistant close` Closes the issue. - `@home-assistant rename Awesome new title` Renames the issue. - `@home-assistant reopen` Reopen the issue. - `@home-assistant unassign waze_travel_time` Removes the current integration label and assignees on the issue, add the integration domain after the command. - `@home-assistant add-label needs-more-information` Add a label (needs-more-information, problem in dependency, problem in custom component) to the issue. - `@home-assistant remove-label needs-more-information` Remove a label (needs-more-information, problem in dependency, problem in custom component) on the issue.

(message by CodeOwnersMention)


waze_travel_time documentation waze_travel_time source (message by IssueLinks)

eifinger commented 6 days ago

The request_data should look like:

service_data:
    region: eu
    units: metric
    vehicle_type: car
    origin: 11.111,-1.111
    destination: Some random street
    realtime: true

I do currently not understand why your code doesn't do this. Your variables: section looks okay to me

HausnerR commented 6 days ago

It interprets origin as a list, not as string. Try to find a way to force it to be string.

I have similar issue:


params:
  domain: waze_travel_time
  service: get_travel_times
  service_data:
    region: eu
    units: metric
    vehicle_type: car
    origin: person.jakub
    destination: |-
      Lidl
      Planetarna 20, 62-020 Zalasewo, Poland
    realtime: true
  target: {}
running_script: false

And got: Failed to process the returned action response data, expected a dictionary, but got <class 'NoneType'>

action: waze_travel_time.get_travel_times
data:
  region: eu
  units: metric
  vehicle_type: car
  origin: person.jakub
  destination: '{{ state_attr(''calendar.kuba_pachciarek_pl'', ''location'') }}'
  realtime: true
response_variable: travel

Only coordinates works for me, can't use entities, nor addresses..

jbrazio commented 6 days ago

It seems the parser on the integration is somehow broken..

I also got Failed to process the returned action response data, expected a dictionary, but got <class 'NoneType'> multiple times when trying to force the list to be a string.

By now I guess I already tried everything.. no avail. @eifinger can you have a look at the parsing function ? This is easy to reproduce at your side.

HausnerR commented 6 days ago

I can confirm, it's impossible to make proper service call if you want to use template to generate string with coordinates. Jinja always interprets comma separated string as list and list is not supported as input for waze origin nor destination.

HausnerR commented 6 days ago

Also it's impossible to use entity_id as origin or destination for service call but it looks more like feature request than bug :)

HausnerR commented 6 days ago

Found parsing code in pywaze, coords are checked by this regexp: https://github.com/eifinger/pywaze/blob/b81ebbf342afd4f710df97d31bc45d5064907554/src/pywaze/route_calculator.py#L68

There is no way to provide string like this because HA templating engine convert it to list before service call.

jbrazio commented 6 days ago

Before going trough the regex and after being parsed by the template engine, if it's a list why not join it with "," between ? Not pretty but could work.

Other route would be to make origin and dest accept a list for the cords field.. I'm not a python expert but 'coords_string_parser' seems to be doing this already.

HausnerR commented 5 days ago

As a PoC I modified component and use ; instead of ,. It works as it should. But in my opinion proper solution should allow for lists and strings as service input.

waze_travel_time.zip

eifinger commented 5 days ago

@jbrazio can you try with {{ ",".join([latitude | string, longitude | string]) }} instead of {{ latitude ~ "," ~ longitude }}?

eifinger commented 5 days ago

To be clear: The issue is not with waze_travel_time here but with the templates. The input must be a string.

HausnerR commented 5 days ago

I tried that, still the same. Even HA template editor returns list.

eifinger commented 5 days ago

Can you show your input for the template editor please?

HausnerR commented 5 days ago
{{ ",".join([state_attr('person.jakub', 'latitude') | string, state_attr('person.jakub', 'longitude') | string]) }}

Result:

image
jbrazio commented 4 days ago

@eifinger

can you try with {{ ",".join([latitude | string, longitude | string]) }} instead of {{ latitude ~ "," ~ longitude }}?

Is not working.. still a list when the automation executes. I even tried with origin: '{{ coords | string }}'.

To be clear: The issue is not with waze_travel_time here but with the templates. The input must be a string.

This is clear.. my point is: Why don't we update the extension to accept a list of coords as and input for origin and destination ? This should be faster to solve than fixing whatever the bug is at the current HA template engine.

Petro31 commented 4 days ago

FYI this is not a bug. The template engine assigns types to templates after a template is executed. To get around this, @jbrazio needs to template the entire data: field.

The template resolver will attempt to assign a type to a template result. e.g. If the template outputs the value '5', the template resolver will identify that it's an integer and convert it. The same thing occurs for the following python types: int, float, bool, None, list, and dict. The resolver is not recursive, so it does not resolve values inside dictionary values, nor does it resolve complex object types like datetimes or timedeltas.

What's happening here is the resolver is detecting the response value -11.111, 1.111 as a list of floats.

This functionality will not change as it will likely break many things down the road, blueprints, automations, scripts, etc.

I highlighted what OP should do in this post on the forums and this issue should be closed.

To get around this, you have to template the entire data section.

- action: waze_travel_time.get_travel_times
  metadata: {}
  data: >
    {{ dict(
      region='eu',
      units='metric',
      vehicle_type='car',
      origin=coords | join(', '),
      destination=repeat.item.location,
      realtime=True,
    ) }}
  response_variable: travel

If anything were to come out of this Issue, I would recommend that @eifinger make the service validation accept a list or a string for origin: and handle both accordingly.

eifinger commented 4 days ago

This will be solved in the feature by having separate inputs for latitude and longitude like here_travel_time has

eifinger commented 4 days ago

@home-assistant close

jbrazio commented 4 days ago

Your workaround works flawlessly. @eifinger, @Petro31 Thanks for the support