For the life of me, I can’t figure out how to return an attribute from a list of entities. I can return the entity name that matches the criteria (last sonos player that is playing and is_coordinator: false, but it won’t then go and find the specified attribute, in this case, what song is playing. Anyone know how I can do this?
sonos_group_song:
friendly_name: Group Song
entity_id:
- media_player.sonos_master_bedroom
- media_player.sonos_living_room
- media_player.sonos_guest_room
- media_player.sonos_basement
- media_player.sonos_office
value_template: >-
{%- set players = [
"media_player.sonos_master_bedroom",
"media_player.sonos_office",
"media_player.sonos_living_room",
"media_player.sonos_guest_room",
"media_player.sonos_basement"] -%}
{% for player in players if is_state(player, 'playing') %}
{% if is_state_attr(player, 'is_coordinator', false) %}
{% if loop.last %}
{% set value = player %}
{% endif %}
{% endif %}
{{value|attr('media_title')}}
{% endfor %}
What you are trying to do is not possible for jinja. You cannot perform loops and pull a single result. This is a limitation of jinja. It’s the same reason you cannot create a simple counter in jinja.
The only way you can get what you want here is to use if statements.
If you really don’t want to write nested if statements, i suggest using app daemon or create your own component using python.
Ok thanks. I ended giving up and doing the same with if statements. Was hoping it was possible to do without it but nothing was working. Thanks for the confirmation.
Now that i think about it, this may not be correct and you may actually be able to get this working because you are outputting inside the loop.
Ok, so this should work. 2 things I noticed:
attr() fitler does not work in the template editor. Not sure if its any different during execution, but for safety, i removed it and replaced it by grabbing the domain/device name and getting into the states object.
Setting the value on loop.last has never worked for me, might just be better to output at that moment in time.
Give this a whirl:
{%- set players = [
"media_player.sonos_master_bedroom",
"media_player.sonos_office",
"media_player.sonos_living_room",
"media_player.sonos_guest_room",
"media_player.sonos_basement"] -%}
{% for player in players if is_state(player, 'playing') and is_state_attr(player, 'is_coordinator', false) %}
{% set domain, device = player.split('.') %}
{% set p = states[domain][device] %}
{% if loop.last %}
{{ states[domain][device].attributes.media_title }}
{% endif %}
{% endfor %}
If you don’t want to have a hard coded list you can do the following:
{% for player in states.media_player if player.state == 'playing' and not player.attributes.is_coordinator %}
{% if loop.last %}
{{ player.attributes.media_title }}
{% endif %}
{% endfor %}
One other question for you. I’ve got most of my project working with your help above but this one last one is stumping me. So what I want to do is check all my media_players and see if the corresponding input_boolean is on then return the media_player entity_id. Example, if input_boolean.sonos_office_slave is on then return media_player.sonos_office except in the case it matches my sensor which determines if it’s the master player. The following returns “Unknown”
sonos_join_test:
value_template: >-
{% set master = states.sensor.sonos_group_master.state %}
{% for player in states.media_player -%}
{% set domain, device = player.split('.') %}
{% set new_domain = "input_boolean"%}
{% set new_device = [device, "slave"]|join("_") %}
{% set switch = ["states",new_domain,new_device,"state"]|join(".") %}
{%- if switch == 'off' and player.entity_id != master -%}
{%- if loop.last -%}{{player.entity_id}}
{%- else -%}{{player.entity_id}},
{%- endif -%}
{%- endif -%}
{%- endfor %}
Hmm, i’m not sure. So how I debug these odd kind of things is doing things one by one. So i’ll start with the for loop and print out the player. I’ll verify that works. Then I’ll add each call piece by peice to see what the output is at each step.
I think you’re going to have to do that because nothing stands out to me.