My template fails as HA does not recognize difference() from Jinja2 filters?

Hi all,
Please help to figure out what is wrong with my template.
I am trying to get a difference in two lists. my first list “light_remove” is one light that I want to turn on.
At the same time, I want to turn-off all other lights… So I have two lists: light_remove and all_lights.
And the last line: {{ all_lights | difference (light_remove) }} supposed to give me the list of all lights to turn off excluding the one in the first line.

HA gives me error: Error rendering template: TemplateAssertionError: no filter named ‘difference’

But the filter exists in Junja2 documentation: http://ansible-docs.readthedocs.io/zh/stable-2.0/rst/playbooks_filters.html#list-filters

What am I doing wrong?

 {% set light_remove =  [ "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" ] %}
 {{ all_lights | difference (light_remove) }}

Difference is a built-in filter in ansible not in Jinja2 as far as I know http://jinja.pocoo.org/docs/2.9/templates/#builtin-filters

1 Like

found out that difference does not exist in jinja2.
Now trying below… now my != logic goes not work as below template prints ALL elements in the all_lights list and it supposed to remove the one from light_remove. Any idea what is wrong with the below code?

    {% set light_remove =  [ 'light.living_room_ceiling_light_2_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" ] %}
     {% for light in all_lights if (light != light_remove) %}
     {{light }} {{ "," }}
     {% endfor %}

My output is this: (but I am not supposed to get light.living_room_ceiling_light_2_level in the output)

   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 ,

I think the problem is caused by the for loop. I could be wrong but it looks like a simular problem as discussed here

1 Like

its not equality, but set membership that you are looking for. try this:

if (light not in light_remove)
1 Like

This worked! Thank you.
But now I am facing a different problem. I can’t seem to turn off a group of lights that are dynamically generated as above.
in HA, one seem can only turn_on turn_off an individual light/switch or a group.

So my code that generates a list of lights to turn off does not work.

Is there a way to create a template group? i.e.: group.lights (which is programmatically set, rather than under the group: yaml config?

You can turn off a group of lights in an automation by passing them as a list to the light.turn_off service like this:

  action:
    - service: switch.turn_off
      data_template:
        entity_id:  >
         {%your code goes here %}

for this to work you will have to fix your trailing comma like this:

{% if !loop.last %}
  {{ "," }}
{% endif %}
2 Likes

great. Thank you for your advise. I actually went a different direction, which put me into a bind… I’ll come back to this route of just putting together a list of ids… which should work…
I will need to separate my lights and switches though …

I actually put this into my test system, and have some more input.
I tried running the inputs agains the “homassistant.turn_on” service, so you wouldn’t have to separate lights and switches, but that doesn’t work.
There are a couple of details left out from the conversation above, so here is a complete working automation from my test environment.

- alias: listtest
  trigger:
    - platform: state
      entity_id: input_boolean.attic_fan
      from: 'off'
      to: 'on'

  action:
    - service: switch.turn_on        
      data_template: 
        entity_id: >
         {% set list = ['switch.office1', 'switch.sun', 'switch.office2']%}
         {% set ignore = ['switch.office2'] %}
         {%-for l in list if (l not in ignore) -%}
           {{l}}{% if not loop.last %}{{ ", " }}{% endif %}
         {%-endfor-%}
1 Like

Thank you treno.

I will be trying it now…
Got a question, I can’t seem to find an explanation about the difference between : {%- and {%
When to use one or another?

{% set list = [‘switch.office1’, ‘switch.sun’, ‘switch.office2’]%}
and
{%- set list = [‘switch.office1’, ‘switch.sun’, ‘switch.office2’] -%}

Jinja 2 whitespace control.
Documentation is here: http://jinja.pocoo.org/docs/2.9/templates/#whitespace-control

the {%- and -%} prevent the carriage returns that are in your code from creeping into the results.
you can see the difference in if you put this into the template editor

 {% set list = ['switch.office1', 'switch.sun', 'switch.office2']%}
{%for l in list%}
{{l}}
{% endfor %}
{{"SECOND RUN"}}
{% for l in list -%}
{{l}}
{%-endfor %}

It will return a result set that looks like this:

switch.office1

switch.sun

switch.office2

SECOND RUN
switch.office1switch.sunswitch.office2

Something is wrong with my code… Can’t figure it out… It must be somehow related to the {%- vs {%…
HA treats all ids I generate as ONE… instead of interpreting each switch ID as one…

follow_me_lights_on:
  sequence:
   - service: homeassistant.turn_on
     data_template:
       entity_id: >
        {{ light_id }}

   - service: homeassistant.turn_off
     data_template:
       entity_id: >
         {% set light_remove =  [ light_id ]  %}
         {% set all_lights = ['switch.bedroom_ceiling_light_switch' , 'switch.family_room_ceiling_light_switch', 'switch.office_lights_switch_2' ] %}
         {%- for light in all_lights if (light not in light_remove) -%}
         {{light }} {% if not loop.last %}{{ ", " }} {% endif %}
         {%- endfor -%}

My log:

Oct 01 11:04:50 HomeControl hass[19978]: 2017-10-01 11:04:50 INFO (MainThread) [homeassistant.helpers.script] Script follow_me_lights_on: Executing step call service
Oct 01 11:04:50 HomeControl hass[19978]: 2017-10-01 11:04:50 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_off, service_call_id=1973313712-784, service_data=entity_id=switch.bedroom_ceiling_light_switch ,  switch.family_room_ceiling_light_switch ,  switch.office_lights_switch_2, domain=homeassistant>
Oct 01 11:04:50 HomeControl hass[19978]: 2017-10-01 11:04:50 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_off, service_call_id=1973313712-785, service_data=entity_id=['switch.bedroom_ceiling_light_switch ,  switch.family_room_ceiling_light_switch ,  switch.office_lights_switch_2'], domain=switch>
Oct 01 11:04:50 HomeControl hass[19978]: 2017-10-01 11:04:50 ERROR (MainThread) [homeassistant.core] Invalid service data for switch.turn_off: Entity ID switch.bedroom_ceiling_light_switch ,  switch.family_room_ceiling_light_switch ,  switch.office_lights_switch_2 is an invalid entity id for dictionary value @ data['entity_id']. Got ['switch.bedroom_ceiling_light_switch ,  switch.family_room_ceiling_light_switch ,  switch.office_lights_switch_2']

Any idea what is wrong? I am duplicating your code and yet getting different results.
I also tried to put "- " and “\n” and those characters just being appended to the long string of ids and HA thinks its ONE id instead of a list.

Also tried this:

   - service: homeassistant.turn_off
     data_template:
       entity_id: >
        {%- set light_remove =  [ light_id ]  %}
        {%- set all_lights = ['switch.bedroom_ceiling_light_switch' , 'switch.family_room_ceiling_light_switch', 'switch.office_lights_switch_2' ] %}
        {%- for light in all_lights if (light not in light_remove) %}
         - {{light}}
        {%- endfor -%}

Which produces the following YAML:

- service: homeassistant.turn_off
     data_template:
       entity_id: >
         - switch.bedroom_ceiling_light_switch
         - switch.family_room_ceiling_light_switch
         - switch.office_lights_switch_2

And the following error log:

Oct 02 19:40:21 HomeControl hass[19978]: 2017-10-02 19:40:21 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_off, service_call_id=1973313712-1964, service_data=entity_id=- switch.bedroom_ceiling_light_switch
Oct 02 19:40:21 HomeControl hass[19978]: - switch.family_room_ceiling_light_switch
Oct 02 19:40:21 HomeControl hass[19978]: - switch.office_lights_switch_2, domain=homeassistant>
Oct 02 19:40:21 HomeControl hass[19978]: 2017-10-02 19:40:21 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_off, service_call_id=1973313712-1965, service_data=entity_id=['- switch.bedroom_ceiling_light_switch\n - switch.family_room_ceiling_light_switch\n - switch.office_lights_switch_2'], domain=- switch>
Oct 02 19:40:21 HomeControl hass[19978]: 2017-10-02 19:40:21 WARNING (MainThread) [homeassistant.core] Unable to find service - switch/turn_off

Nothing works …

But if I just hardcode this YAML:

  - service: switch.turn_off
     data_template:
       entity_id:
        - switch.bedroom_ceiling_light_switch
        - switch.family_room_ceiling_light_switch
        - switch.office_lights_switch_2

It works perfectly with the following log:

Oct 02 20:13:54 HomeControl hass[19978]: 2017-10-02 20:13:54 INFO (MainThread) [homeassistant.helpers.script] Script follow_me_lights_on: Executing step call service
Oct 02 20:13:54 HomeControl hass[19978]: 2017-10-02 20:13:54 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_off, service_call_id=1973313712-2162, service_data=entity_id=['switch.bedroom_ceiling_light_switch', 'switch.family_room_ceiling_light_switch', 'switch.office_lights_switch_2'], domain=switch>

So the key difference is that in all previous cases, it takes all 3 light_ids as one string… But in the working sample, it sees each switch as separate entity…

Like I said in post 9… I wasn’t able to make this work with the “homeassistant.turn_on” service.

1 Like

Yes!! This was the key… I don’t know how, I read it, but it did not sink in… Just switched to “switch.turn_off” and it works right away… Thank you for pointing it out… Need to read more carefully.

1 Like