alandtse / alexa_media_player

This is a custom component to allow control of Amazon Alexa devices in Home Assistant using the unofficial Alexa API.
Apache License 2.0
1.53k stars 290 forks source link

YAML macros do not work in HA service call #761

Closed alesoft73 closed 4 years ago

alesoft73 commented 4 years ago

In the documentation the target setup in notify is :

  - service: notify.alexa_media
    data:
      data:
        type: tts
      target: 
        - media_player.downstairs
        - media_player.upstairs

or target

  target: 
    - media_player.downstairs

or target:

target :

Is possible to add a templete in target : ??? Many thanks!

alandtse commented 4 years ago

Please properly quote if you want help. Please also review the wiki.

alesoft73 commented 4 years ago

I would you use a macro into a target: for send a mediaplayer 1 or 2 or 3 mediaplayer. If i pass this target:

But if i pass a macro into target don't work.

target: >-

 {% macro mediaplayer() %}
 {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name .....%}     
"{{ item.entity_id | lower }}" {% if not loop.last %}, {%- endif %}
{%- endfor -%}  
{% endmacro %}
[{{ mediaplayer() }}] 

result in target : target: ["media_player.room1", "media_player.room2".....roomX] Dont work... I have a test in the target this

        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name   -%}     
        - {{ item.entity_id | lower }} {% if not loop.last %}, {%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        {{ mediaplayer() }}

result in target : target:

don't work... I think i have test all option ;)
In log i don't receive any error.

alandtse commented 4 years ago

I honestly don't understand what you're trying to do. If yore asking for helps with yaml macros, I can't help you with that.

Please test without a macro and provide the specific call you're trying to do. If you do not enable logs, I won't have any idea how to help you.

alesoft73 commented 4 years ago

This is a script i use.

script :

  - service: notify.alexa_media
    data_template:
      data:
        type: announce
      target: >- 
        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name  or states('input_text.mediaplayer_alexa_2') in item.name or states('input_text.mediaplayer_alexa_3') in item.name or states('input_text.mediaplayer_alexa_1') in item.entity_id or states('input_text.mediaplayer_alexa_2') in item.entity_id or states('input_text.mediaplayer_alexa_3') in item.entity_id  -%}     
        "{{ item.entity_id | lower }}"{% if not loop.last %},{%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        [{{ mediaplayer()}}]       
      message: "{{ message }}"

I have test 4 macro see image with result in Home assitant test panel:

immagine

All macro into a target: >- don't work..... I think the problem if is i insert a macro in target. In the logs i don't receive any error.

The script work only with this setup:

  - service: notify.alexa_media
    data_template:
      data:
        type: announce
      target:
        - '{{ states("input_text.mediaplayer_alexa_1") }}'
        - '{{ states("input_text.mediaplayer_alexa_2") }}'
        - '{{ states("input_text.mediaplayer_alexa_3") }}'
      message: "{{ message }}"    

Many thanks!

alandtse commented 4 years ago

Are you sure macros work in data_template? This seems like a HA issue. There's no code in the custom_component that I would change to work with the yaml. If you had debug logs on for alexa_media you may be able to get the actual notify call's target.

EDIT: Saw this discussion on the forum.

alesoft73 commented 4 years ago

Are you sure macros work in data_template? This seems like a HA issue. There's no code in the custom_component that I would change to work with the yaml. If you had debug logs on for alexa_media you may be able to get the actual notify call's target.

I use the same macro into media_player google,into volume set ecc.. and work perfect. This is a debug with all macro in the previus message.... ;)

this is a result:

1

2020-06-05 13:54:13 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: La Lavastoviglie è Terminata !!!, kwargs: {'target': ["['media_player.echo_show_8','media_player.echo_show_salotto']"], 'data': {'type': 'announce'}}

2

2020-06-05 13:54:16 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: La Lavastoviglie è Terminata !!!, kwargs: {'target': ["['media_player.echo_show_8','media_player.echo_show_salotto']"], 'data': {'type': 'announce'}}

3

2020-06-05 13:54:19 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: La Lavastoviglie è Terminata !!!, kwargs: {'target': ['[media_player.echo_show_8,media_player.echo_show_salotto]'], 'data': {'type': 'announce'}}

4

2020-06-05 13:54:21 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: La Lavastoviglie è Terminata !!!, kwargs: {'target': ['- media_player.echo_show_8 - media_player.echo_show_salotto'], 'data': {'type': 'announce'}}

I think is enaught ;) The problem is in in a json array add a " or ', in front array and back...

This is another example:

        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name or states('input_text.mediaplayer_alexa_2') in item.name or states('input_text.mediaplayer_alexa_3') in item.name or states('input_text.mediaplayer_alexa_1') in item.entity_id or states('input_text.mediaplayer_alexa_2') in item.entity_id or states('input_text.mediaplayer_alexa_3') in item.entity_id  -%}
        '{{ item.entity_id | lower }}'{% if not loop.last %}, {% endif %}
        {%- endfor -%} 
        {% endmacro %}
        {{ mediaplayer()}}

this is in model HA

immagine

this is in debug : {'target': ["'media_player.echo_show_8', 'media_player.echo_show_salotto'"], 'data': {'type': announce'}}

alandtse commented 4 years ago

I can't tell if you provided a working example. However, the problems with 1-4 is that they resulting in a malformed target. Target expects a list of speakers. Debug is reporting that it's receiving a list of a list. It'd be helpful to know the input you are providing.

While I haven't tested it, the final target if it's a single line should not be a list. It should be a string. Notice the final target does not have [ or ].

  - service: notify.alexa_media
    data_template:
      data:
        type: announce
      target: >- 
        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name  or states('input_text.mediaplayer_alexa_2') in item.name or states('input_text.mediaplayer_alexa_3') in item.name or states('input_text.mediaplayer_alexa_1') in item.entity_id or states('input_text.mediaplayer_alexa_2') in item.entity_id or states('input_text.mediaplayer_alexa_3') in item.entity_id  -%}     
        "{{item.entity_id| lower }}"{% if not loop.last %},{%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        {{ mediaplayer()}}    
      message: "{{ message }}"

It is possible that it's parsing the yaml incorrectly but before I change the code, I'd like it confirmed.

EDIT: Yes, if the targets is determined to be a string, then we will encapsulate it as a list. I'll take a look at how Google may be parsing this. Can you test some other components to see if they also work with the macro? Also, which Google integration are you actually using?

alesoft73 commented 4 years ago

With your macro the result is this in debug (i have test all alternative ;) ) :

{'target': ['"media_player.echo_show_8","media_player.echo_show_salotto"'], 'data': {'type': 'announce'}}

In the google tts translate say service i use this :

  - service: tts.google_translate_say
    data_template: 
      entity_id: >
        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_google_1') in item.name or states('input_text.mediaplayer_google_2') in item.name or states('input_text.mediaplayer_google_3') in item.name or states('input_text.mediaplayer_google_1') in item.entity_id or states('input_text.mediaplayer_google_2') in item.entity_id or states('input_text.mediaplayer_google_3') in item.entity_id  -%}     
        {{ item.entity_id | lower }} {% if not loop.last %}, {%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        {{  mediaplayer() }}
      language: it
      message: "{{ message }}" 

in the service media player volume set i use this....

  - service: media_player.volume_set
    data_template: 
      entity_id: >-
        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if states('input_text.mediaplayer_alexa_1') in item.name or states('input_text.mediaplayer_alexa_2') in item.name or states('input_text.mediaplayer_alexa_3') in item.name or states('input_text.mediaplayer_alexa_1') in item.entity_id or states('input_text.mediaplayer_alexa_2') in item.entity_id or states('input_text.mediaplayer_alexa_3') in item.entity_id  -%}     
        {{ item.entity_id | lower }} {% if not loop.last %}, {%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        {{  mediaplayer() }}          
      volume_level: >-
        {% if is_state('binary_sensor.modalita_day_night', 'on') %}
        {{ (states('input_number.tts_volume_day') | float / 100) | round(1) }}
        {% else %}
        {{ (states('input_number.tts_volume_night') | float / 100) | round(1) }}
        {% endif %}

Google service tts and volume set work perfect. Thanks!

alandtse commented 4 years ago

Please try the PR and report back.

alesoft73 commented 4 years ago

I have correct but don't work... The same problem, the same result in debug. I think the problem is in array, don't divide the entities. In array send a single long entity in json. {'target': ['media_player.echo_show_8, media_player.echo_show_salotto'].... the correct is {'target': ['media_player.echo_show_8', 'media_player.echo_show_salotto']....

Thanks another!

alandtse commented 4 years ago

It no longer will build a list for you. You need to provide a properly formatted list of items.

[media_player.echo_show_8, media_player.echo_show_salotto]

This macro works for me:

        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if item.state != 'unavailable' -%}     
        {{ item.entity_id | lower }}{% if not loop.last %}, {%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        [{{  mediaplayer() }}]     
alesoft73 commented 4 years ago

Now i have test this..

        {% macro mediaplayer() %}
        {%- for item in states['media_player'] if item.state == 'standby' -%}     
        {{ item.entity_id | lower }}{% if not loop.last %}, {%- endif %}
        {%- endfor -%}  
        {% endmacro %}
        [{{  mediaplayer() }}]

result..

{'target': ['[media_player.echo_show_8,media_player.echo_show_salotto,media_player.gruppo_alexa,media_player.ovunque,media_player.this_device_2]'],

and don't work for me ...

alandtse commented 4 years ago

Please confirm you have replaced the notify.py with the correct file.

alesoft73 commented 4 years ago

Yes i have replace notify.py with your commit.

alandtse commented 4 years ago

Can you please verify the macro works for other notify components? While there is a way to parse it, I want to make sure it's consistent with the HA environment. It looks like the problem is using the data_template it's returning the target as one large string. However, trying to fix that use case then breaks the handling with the items are individually listed.

This macro provides a string as the first item of a list.

"1591488918170":
  alias: Test_Macro
  sequence:
    - data_template:
        data:
          type: announce
        message: test
        target: >-
          {% macro mediaplayer() %} {%- for item in states['media_player']
          if item.state == "standby"  -%}
          "{{ item.entity_id | lower }}"{%
          if not loop.last %},{%- endif %} {%- endfor -%}   {% endmacro %} {{ mediaplayer()}}
      service: notify.alexa_media
 2020-06-06 18:55:21 INFO (MainThread) [homeassistant.components.script] Test_Macro: Running script
 2020-06-06 18:55:21 INFO (MainThread) [homeassistant.components.script] Test_Macro: Executing step call service
 2020-06-06 18:55:21 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: test, kwargs: {'target': ['"media_player.alan_s_alexa_apps","media_player.alan_s_fire","media_player.echo_show","media_player.everywhere","media_player.great_room","media_player.guest_room","media_player.kitchen","media_player.master_bedroom","media_player.office","media_player.this_device"'], 'data': {'typ ': 'announce'}}

These properly provide a list of targets.

"159148891817324":
  alias: Test_List
  sequence:
    - data_template:
        data:
          type: announce
        message: test
        target:
          - media_player.office
          - media_player.great_room
      service: notify.alexa_media
"159148891817325":
  alias: Test_List_One_Line
  sequence:
    - data_template:
        data:
          type: announce
        message: test
        target: [media_player.office, media_player.great_room]
      service: notify.alexa_media
 2020-06-06 18:56:27 INFO (MainThread) [homeassistant.components.script] Test_List: Running script
 2020-06-06 18:56:27 INFO (MainThread) [homeassistant.components.script] Test_List: Executing step call service
 2020-06-06 18:56:27 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: test, kwargs: {'target': ['media_player.office', 'media_player.great_room'], 'data': {'type': 'announce'}}

 2020-06-06 18:57:14 INFO (MainThread) [homeassistant.components.script] Test_List_One_Line: Running script
 2020-06-06 18:57:14 INFO (MainThread) [homeassistant.components.script] Test_List_One_Line: Executing step call service
 2020-06-06 18:57:14 DEBUG (MainThread) [custom_components.alexa_media.notify] Message: test, kwargs: {'target': ['media_player.office', 'media_player.great_room'], 'data': {'type': 'announce'}}

It looks like the issue may be templates cannot return lists.

caiosweet commented 4 years ago

The problem is... Jinja template rendered as string and not as list inside service calls (target)

in the past such a thing happened, here the problem, and here the solution

I hope it is useful :0)

alandtse commented 4 years ago

Thanks @caiosweet, yes I eventually figured that out. ;) The PR addresses it.

alesoft73 commented 4 years ago

Now work perfect. Many thanks!