Am I hitting HA templating limit? My beautiful template/macro script does not work

Hi all,

As part of “follow me lights” automation, I wrote this fully dynamic script that uses both service_template and data_template. But I think I might be hitting the wall imposed by HA, where I can NOT generate the entire sequence of service calls programatically.

The logic of the script I am trying to create is as follows:
As person moves around the house, the script turns on the light in the room where person is in and turns off ALL other lights in the house. Every time the script is called below happens:

  • We pass into the script the light_id that we want to turn_on
  • The script will turn_on that light_id and, at the same time dynamically figures out the list of other lights to turn_off.

Questions:

  1. Do I have some small final errors in understanding on how to put together templates and my code can actually made work with some corrections?
  2. Is it HA templating limitation and this approach just can’t work.
  3. Maybe there is another simple way to achieve what I am trying to do…

Below jinga2 template snippet dynamically generates a list of service calls. It works great and if you were to paste the template macro below into the script editor in HA, you will see it’s output:

{%- set light_id = [ 'light.living_room_ceiling_light_1_level' ] -%}
{%- set all_lights = [ 'light.living_room_ceiling_light_1_level', 'light.living_room_ceiling_light_2_level' , 'switch.bedroom_ceiling_light_switch' , 'switch.family_room_ceiling_light_switch', 'switch.office_lights_switch_2' ] -%}
   
{%- macro dyn_light(onoff='') -%}
  - service_template: >  home-assistant.turn_{{onoff}}
    data_template:
       entity_id: > {{ caller() }}
{%- endmacro -%}
  
{%- for light in all_lights   -%}
{%-if (light not in  light_id ) -%}
{%- call dyn_light(onoff='off') %}{{light}}
{% endcall -%} 
{%- else -%}
{%- call dyn_light(onoff='on') %}{{light}}
{% endcall %}
{% endif %}
{%- endfor -%}  

The above template correctly generates below YAML:

- service_template: >  home-assistant.turn_on
    data_template:
       entity_id: > light.living_room_ceiling_light_1_level

- service_template: >  home-assistant.turn_off
    data_template:
       entity_id: > light.living_room_ceiling_light_2_level
- service_template: >  home-assistant.turn_off
    data_template:
       entity_id: > switch.bedroom_ceiling_light_switch
- service_template: >  home-assistant.turn_off
    data_template:
       entity_id: > switch.family_room_ceiling_light_switch
- service_template: >  home-assistant.turn_off
    data_template:
       entity_id: > switch.office_lights_switch_2

In the template example above, I am hardcoding the value of: light_id in the first line “set light_id…” etc.
This line would later be removed and dynamically passed in by the automation yet to be written.

What I wanted to achieve was to programatically generate a script like below:
(below goes into scripts.yaml file). The script’s resulting “sequence of service calls” would wind-up be different depending on which light is passed into the script.

follow_me_lights_on:
  alias: "Follow Me Lights script"
  sequence:
    - service_template: >  home-assistant.turn_on
      data_template:
        entity_id: > light.living_room_ceiling_light_1_level

    - service_template: >  home-assistant.turn_off
      data_template:
        entity_id: > light.living_room_ceiling_light_2_level
    - service_template: >  home-assistant.turn_off
      data_template:
        entity_id: > switch.bedroom_ceiling_light_switch
    - service_template: >  home-assistant.turn_off
      data_template:
        entity_id: > switch.family_room_ceiling_light_switch
    - service_template: >  home-assistant.turn_off
      data_template:
        entity_id: > switch.office_lights_switch_2

The actual script should look some-what like below before it is rendered dynamically by HA processor into the final version above during the execution of the call:

follow_me_lights_on:
  alias: "Follow Me Lights script"
  sequence:
{%- set light_id = [ 'light.living_room_ceiling_light_1_level' ] -%}
{%- set all_lights = [ 'light.living_room_ceiling_light_1_level', 'light.living_room_ceiling_light_2_level' , 'switch.bedroom_ceiling_light_switch' , 'switch.family_room_ceiling_light_switch', 'switch.office_lights_switch_2' ] -%}
   
{%- macro dyn_light(onoff='') -%}
  - service_template: >  home-assistant.turn_{{onoff}}
    data_template:
       entity_id: > {{ caller() }}
{%- endmacro -%}
  
{%- for light in all_lights   -%}
{%-if (light not in  light_id ) -%}
{%- call dyn_light(onoff='off') %}{{light}}
{% endcall -%} 
{%- else -%}
{%- call dyn_light(onoff='on') %}{{light}}
{% endcall %}
{% endif %}
{%- endfor -%}

But this ^^^^ above template script is not working. Basically You can’t seem to have fully dynamic section for sequence of service calls. Or can you? Since my macro actually generates the entire list, I actually don’t even need to use: service_template tag or data_template … But I am just trying to figure out if I must use them to pass the syntax checking…

Am I just not going to make the above work? Because it is NOT possible or there is still hope for this to work?

Thank you all for your input…

I don’t think you can do things (yet) like this:

It’s my understanding that you can only set values for keys (service_template or entity_id) but can’t affect the flow of YAML with templates. You’ve likely got some errors in home_assistant.log pointing to this kind of issue.