Iterate Group Entities For Conditional Service Call

I have a script that checks the state of each of my media players and pauses them if they are playing (this is to prevent volume jumps before an announcement is played). Right now I have a separate service call for each media player and have to update the script whenever I add a new media player.
I’d like to change this so new media players are automatically included.

I can obviously get the desired effect by using a group as the entity_id for the service call but this results in warnings in the log for each media player that wasn’t playing when the script is run. I need something like this that outputs a format that can be used for the entity_id in a service call to media_player.media_pause. I must be missing something simple here, but I’m lost.

   service: media_player.media_pause
   data_template:
     entity_id: >
        [{%- for entity_id in states.group.all_media_players.attributes.entity_id -%}
        {%- if states(entity_id) == 'playing' -%}
        {{- entity_id -}},
        {%- endif -%}{% endfor %}]

This template gives me the error.

voluptuous.error.MultipleInvalid: not a valid value for dictionary value @ data[‘entity_id’]

I think because there is an extra comma in the array? This is the output in the template editor with a couple of media players playing.

[media_player.dining_room_speaker,media_player.living_room_tv,]

This is my current script (I left out bunch of the media players).

script:
  pause_media_players:
    sequence:
    - service_template: >
        {% if is_state('media_player.bedroom_speaker','playing') %}
          media_player.media_pause
        {% else %}
          script.null_script
        {% endif %}
      entity_id: media_player.bedroom_speaker

    - service_template: >
        {% if is_state('media_player.broadcast_speakers','playing') %}
          media_player.media_pause
        {% else %}
          script.null_script
        {% endif %}
      entity_id: media_player.broadcast_speakers

    - service_template: >
        {% if is_state('media_player.dining_room_speaker','playing') %}
          media_player.media_pause
        {% else %}
          script.null_script
        {% endif %}
      entity_id: media_player.dining_room_speaker

you can’t use list brackets. Just gotta list them out. This also might not work, it depends on the parser.

Also, it’s gotta be in a templateing section. data_template makes all attributes below it template sections.

 - service: media_player.media_pause
   data_template:
     entity_id: >
       {% set entities = state_attr('group.all_media_players', 'entity_id') %}
       {{ states.media_player | selectattr('entity_id', 'in', entities)
                             | selectattr('state','eq','playing') 
                             | map(attribute='entity_id') | join(', ') }}

Also, for safety, you shouldn’t call this if nothing is playing:

script:
  pause_media_players:
    sequence:
      - condition: template
        value_template: >
          {% set entities = state_attr('group.all_media_players', 'entity_id') %}
          {% set playing = states.media_player | selectattr('entity_id', 'in', entities) 
                                               | selectattr('state','eq','playing') 
                                               | length %}
          {{ playing >= 1 }}
      - service: media_player.media_pause
        data_template:
          entity_id: >
            {% set entities = state_attr('group.all_media_players', 'entity_id') %}
            {{ states.media_player | selectattr('entity_id', 'in', entities)
                                   | selectattr('state','eq','playing') 
                                   | map(attribute='entity_id') 
                                   | join(', ') }}
1 Like

@petro I can’t thank you enough for taking the time to help me out here. I just spent the last couple hours going through your template line by line with the docs to try and understand what was happening and I think a couple of things finally clicked for me (particularly about how the states object works) and how to use the jinja filters with it. (maybe…lol)

Please correct me if I’m wrong here but there an error rendering the template in the templater editor when I tried the condition template you provided above (the service template worked a treat off the hop). I made it my mission to figure out the problem on my own here and I think the issue is the list filter was missing? It seems to work ok now with some quick testing. I’m actually kinda glad, it forced me to understand things a little better!!

      {% set entities = state_attr('group.all_media_players', 'entity_id') %}
      {% set playing = states.media_player | selectattr('entity_id', 'in', entities) 
                                           | selectattr('state','eq','playing') 
                                           | list
                                           | length %}
      {{ playing >= 1 }}

BTW - I am using data_template in my yaml file I had just quickly typed that portion out here and had copied my latest attempt at the template right from the template editor… but good reminder for any one else who stumbles across this!

Anyway, again, thank you for your assistance. You are a jinja wizard my friend.

You may be correct. I don’t have it 100% memorized. I can’t remember if the length filter works on a generator object. Generator objects come from using map, select, selectattr, reject, and rejectattr. It may be required to have the list filter between the length and the generator object.