In a nutshell, I have one input_boolean for each Sonos.
When I do a Sonos Snapshot, Join or Unjoin I want the entity_id to be a list of those input_booleans that are 'on'.
I have successfully done this in other simpler cases by creating the list as a comma separated list and it does work e.g. (the script here is passed a variable room which is a list of room(s))
entity_id: >
{%- for x in room -%}
input_boolean.{{ x }}_media_player{%- if not loop.last %},
{%- endif %}
{%- endfor -%}
but in the case in the OP I can’t find a way to remove the trailing comma.
Played a little
The problem is that it loops over ALL booleans with ‘_media_player’ and prints ONLY the ones that are ‘on’.
So if the last boolean is not ‘on’, the last.loop will not work
Try:
{% for boolean in states.input_boolean if '_media_player' in boolean.entity_id and is_state(boolean.entity_id, 'on') %}
media_player.{{ boolean.entity_id.split('.')[1].split('_media_player')[0] }}{%- if not loop.last %},{%- endif %}
{%- endfor %}
media_players_active:
friendly_name_template: >
{% set count = states.input_boolean
|selectattr('entity_id','in',state_attr('group.activate_media_players','entity_id'))
|selectattr('state','eq','on')|list|length %}
{% set player = 'player' if count in [0,1] else 'players' %}
{% set number = 'No' if count == 0 else count %}
{{number}} Media {{player}} active
entity_id:
- input_boolean.googlehome_woonkamer
- input_boolean.googlehome_hall
- input_boolean.googlehome_master_bedroom
- input_boolean.googlehome_hobbykamer
- input_boolean.googlehome_office
- input_boolean.googlehome_dorm_marte
value_template: >
{% set rooms = states.input_boolean
|selectattr('entity_id','in',state_attr('group.activate_media_players','entity_id'))
|selectattr('state','eq','on') |map(attribute='object_id')|list %}
{% set ns = namespace(speakers = '') %}
{% for i in range(rooms | length) %}
{% if states('input_boolean.' ~ rooms[i]) == 'on' %}
{% set d = ', ' if ns.speakers | length > 0 else '' %}
{% set ns.speakers = ns.speakers ~ d ~ 'media_player.' ~ rooms[i] %}
{% endif %}
{% endfor %}
{% if ns.speakers|length|int == 0 %} None
{% else %}
{{ ns.speakers }}
{% endif %}
but yours is way shorter and seems to render the same result I’ve adapted it to read:
{% for boolean in states.input_boolean if 'googlehome' in boolean.entity_id and is_state(boolean.entity_id, 'on') %}
media_player.{{ boolean.entity_id.split('.')[1] }}{%- if not loop.last %},{%- endif %}
{%- endfor %}
and will test some further, to see what happens…of course, my template has a safeguard for 0 entities, where your template simply shows nothing?
nice to have more ways to do things
Yes it will show nothing but in my case there MUST be something. The script that uses it needs room to be passed to it from the calling automation so there will never (ha ha, yes, I know…) be no rooms.
… but not starting with the same data set. One iterates over the full set whereas the other over a subset (a group). Also, it won’t return ‘None’ if the list is empty (which, as I recall, was one of your requirements) but simply an empty string. Don’t overlook the fact the template I created wasn’t originally for your needs but for someone else (for announcing call to prayers) and was extended to meet your requirements (like ‘None’).
Nevertheless, this version is an elegant way of solving a very similar challenge. Kudos to @klogg and @VDRainer. I’ve bookmarked it for future reference.
sure, that’s what I mentioned in my response. It’s doing its job very nicely. Always keen to see if things can be made more efficient, and if adding a group as a subset can help, maybe I should do that also.