Script Templating - turn off only lights that are on

Ah yes. Some services do accept a comma separated list for entity_id, with the light services probably being one of those. So, all you need here is a comma separated list because it doesn’t have to be a list object like some other services.

FYI, I think that loop.last check at the end is probably unnecessary unless I’m missing something (I’m on my phone so maybe I am).

I think I copied your code I found somewhere and tweaked it until I got it to work correctly. I think you do need it otherwise it will put a coma at the end.

This is awesome. Exactly what I was trying to do. I didnt realize the commas were misisng - and also, I didnt realize how Jinja was formatting the output - that was also giving me some grief

1 Like

Glad I could help.

Sorry to resurrect an old thread but I have a related question that I’m hoping someone smarter than I can figure out. First, MediaCowboy’s automation works perfectly and is WAY faster than using a group.light -> off method. I have 60+ ZWave devices, mostly lights. When I tried the group.all_lights -> off it took over a mintue to turn off 6 lights that were on and it renders the Zwave network totally inop during this time for anything else. Turning off only the 6 lights that are on using the automation above is basically instantaneous. This is a huge improvement, thanks MediaCowboy!

To expand on the usefulness of this, I would like to turn off any light, switch, fan, and media player device that is in a specific group that is not presently in the “off” state. The idea is to trigger an automation from a scene command on the Zwave switch at the top of my basement steps to turn off everything in the basement with one click. So is there a way to filter by members of group.basement using the same concept used in the automation example? If not in an automation, then could this be done in a Python script?

@Jeepman

I don’t have a lot of switches or any fans but would it be similar to how I did the lights.

    - service: switch.turn_off
      data_template: 
        entity_id: > 
         {%- for device in dict(states.switch|groupby("state"))["on"] %}{%- if loop.first %}{% else %}, {% endif %}{{device.entity_id | lower }}{%- if loop.last %}{% endif %}{%- endfor  %}

Same for the fans.

    - service: climate.turn_off
      data_template: 
        entity_id: > 
          {%- for device in dict(states.climate|groupby("state"))["on"] %}{%- if loop.first %}{% else %}, {% endif %}{{device.entity_id | lower }}{%- if loop.last %}{% endif %}{%- endfor  %}

These can be simplified and combined.

    - service: homeasisstant.turn_off
      data_template: 
        entity_id: >
          {% set domains = ['light','switch','fan','media_player'] %}
          {% set on_states = ['on'] %}
          {{ states | selectattr('domain','in', domains) | selectattr('state','in',on_states) | map(attribute='entity_id') | join(', ') }} 

Also, @MediaCowboy, your loop can be shortened to:

{{ states.light | selectattr('state','eq','on') | map(attribute='entity_id') | join(', ') }}
3 Likes

i kind of wanted something similar to make a list and have alexa or google tell me which lights are on and ask me to turn them off

Thanka I actually forgot about this automation when my network got compromised. I need to add it back.

1 Like

Yes, you can use this for lights and switches to get the friendly names

          {% set domains = ['light','switch'] %}
          {% set on_states = ['on'] %}
          {{ states | selectattr('domain','in', domains) | selectattr('state','in',on_states) | map(attribute='name') | join(', ') }}

awesome sure does. now just to implement. i have like basement 1 and 2 grouped into a,light group. it shows all three. anyway to only get on or the other?

And for proper english:

{% set domains = ['light','switch'] %}
{% set on_states = ['on'] %}
{% set things_that_are_on = states | selectattr('domain','in', domains) | selectattr('state','in',on_states) | map(attribute='name') | list %}
{% set on_count = things_that_are_on | length %}
{% if on_count == 1 %}
  {{ things_that_are_on[0] }} is on!
{% elif on_count == 2 %}
  {{ things_that_are_on[0] }} and {{ things_that_are_on[1] }} are on!
{% elif on_count > 2 %}
  {{ things_that_are_on[:-1] | join(', ') }}, and {{ things_that_are_on[-1] }} are on!
{% else %}
  Nothing is on!
{% endif %}

Any way this could be filtered by only entities in a group? Back to my example above, I’m trying to turn off everything by floor, not necessarily the entire house. So I think I need to select by members of “group.basement” or something like that. Or maybe there is a completely different way to achieve the same thing?

BTW, I’m kind of lost on how to figure out what the schema of the HA data structure looks like. Coming from the relational database world, I understand how to build a query to do what I want by knowing the database schema. I don’t understand this syntax and I don’t know of any good resources to learn it. How are you figuring this out? Where can I go to learn more?

It’s Jinja2. You can read more about templatinghere.

Yep

{% set group_id = 'group.foo' %}
{% set on_states = ['on'] %}
{{ states | selectattr('entity_id','in', state_attr(group_id, 'entity_id')) | selectattr('state','in',on_states) | map(attribute='entity_id') | join(', ') }}

Wow. Very handy script. My 30 Z-Wave lights were taking around 10-30 seconds to turn off before. With this approach they’re off in 1-2 seconds.

@petro I was very excited when I saw this post. Unfortunately I can’t get the thing to work. I tried putting it in as an Automation and as a Script and neither wants to actually work. Here is what I have in my script:

'turn_things_off_when_away_daytime':
  alias: Turn Things Off When Away Daytime
  sequence:
  - data:
      entity_id: >
        {% set domains = ['light','switch','fan','media_player'] %}
        {% set on_states = ['on'] %}
        {{ states | selectattr('domain','in', domains) | selectattr('state','in',on_states) | map(attribute='entity_id') | join(', ') }}
    service: homeassistant.turn_off

Here is the error I get running it:

image

When I put it in the templates I get this:

'turn_things_off_when_away_daytime':
  alias: Turn Things Off When Away Daytime
  sequence:
  - data:
      entity_id: >
        {% set domains = ['light','switch','fan','media_player'] %}
        {% set on_states = ['on'] %}
        {{ states | selectattr('domain','in', domains) | selectattr('state','in',on_states) | map(attribute='entity_id') | join(', ') }}
    service: homeassistant.turn_off
 'turn_things_off_when_away_daytime':
  alias: Turn Things Off When Away Daytime
  sequence:
  - data:
      entity_id: >
        
        
        light.kitchen_bar_pendant_lights, media_player.receiver, media_player.samsung_tv_remote, switch.kitchen_main_light, switch.master_bedroom
    service: homeassistant.turn_off

(I renamed it from 1555894674612 to ‘turn_things_off_when_away_daytime’ in between my screenshots but the same thing happens with both names.)

It’s not data it’s data_template.

  - data_template:
      entity_id: >-

The data supplied to the service is entity_id. However a template is used to produce the value for entity_id therefore the heading is not data but data_template.

what @123 said

That was exactly it. Thanks a ton. I have been jumping between using the Script Editor and just editing the yaml files directly. Is there an option in the Script Editor to use a data_template? It looks like this in the UI when I edit that script.

image

1 Like