Templating - Can you have a default dictionary in a for loop?

I am passing a script a dictionary list which it then uses to look at Input Booleans in a for loop. I want to be able to have a default for this dictionary list but the catch is that I need to build it dynamically.

I can create the default list but using it doesn’t work whereas if I use a literal string in exactly the same format as the one I create it does work.

I’m guessing I somehow have to set the dynamic list as something other than a string but I don’t know what or how.

So, (it might look complicated but I have highlighted what I believe to be the relevant bits…)

This doesn’t work:

{# THIS SECTION CREATES MY DYNAMIC LIST #}
{%- set ns = namespace(current_rooms = "['") %}
{%- for room in states.input_boolean
       if 'announcement_on_' in room.entity_id and
          is_state(room.entity_id, 'on') -%}
  {% set ns.current_rooms = ns.current_rooms + room.entity_id.split('.')[1].split('announcement_on_')[1].split('_media_player')[0] + "" %}
  {%- if not loop.last %}
    {%- set ns.current_rooms = ns.current_rooms + "', '" %}
  {%- endif %}
{%- endfor %}
{%- set ns.current_rooms = ns.current_rooms + "']" %}

{# THIS IS THE RESULTING DYNAMIC LIST #}
ns.current_rooms = {{ ns.current_rooms }}

{# HERE IS THE BIT THAT DOESN'T WORK #}
{%- for x in room | default(ns.current_rooms) if is_state('input_boolean.announcement_on_' + x + '_media_player', 'on') %}
  input_boolean.announcement_on_{{ x }}_media_player{%- if not loop.last %},
{%- endif %}
{%- endfor -%}

But if I add a line to statically set the list it does:

{# THIS IS THE RESULTING DYNAMIC LIST #}
ns.current_rooms = {{ ns.current_rooms }}
{% set ns.current_rooms = ['kitchen', 'sitting_room'] %}

Can anyone help please?


Where are you planning on using this? Template sensor or something?

So your issue is that you are making a string look like a list, but its not a list. So we have to get inventive to get around that.

In this macro, I’ll make the same thing. A string that looks like a list without the quotes wrapping each entity and without the brackets.

Then i’ll split the string into a list of strings by splitting off the comma.

A macro makes this possible.

{%- macro getrooms() %}
{%- for room in states.input_boolean 
       if 'announcement_on_' in room.entity_id and
           is_state(room.entity_id, 'on') %}
    {{- room.entity_id.split('.')[-1].replace('announcement_on_','').replace('_media_player','') }}{{- '' if loop.last else ',' }}
{%- endfor %}
{%- endmacro %}

{# YOUR NEW DYNAMIC LIST #}
{% set rooms = getrooms().split(',') %}
{{ rooms }}

Now I have no idea what youa re trying to do in your next part because I don’t know where this ‘room’ variable you are using is coming from.

1 Like

That’s great thanks. It certainly works in the templating tool. I hope to have time to test properly later today.

The reason for all this is my quest for a robust notifications engine which is a rabbit hole I went down many months ago and has now become more an intellectual challenge than anything which has a value anything close to commensurate with the hours I’ve put into writing and rewriting it or the functionality it will provide.

I’m trying, amongst other things, to write it in as modular way as possible given the limitations of yaml etc.

This section is to allow me to set which rooms (sonos) the notifications are played in from the UI overriding anything set dynamically in the config. Initially I wanted this for testing purposes but it could also be used for ad-hoc announcements via the UI.

Like I said it has all become more of an intellectual challenge than a proportionate solution.

Thanks for this, I appreciate it.

1 Like