PSA: Turn on/off all lights in Home Assistant 0.104+ (group.all_* changes)

I propose this enhanced version:

domain = data.get('domain', '')
group = data.get('group', '')
icon = data.get('icon', '')

if not isinstance(domain, str) or not isinstance(group, str) or not domain or not group:
    logger.warning("bad domain or group! Not executing.")
else:
    if domain == "switch":
        name = "All switches"
    elif domain == "binary_sensor":
        name = "All binary sensors"
    else:
        name = "All "+domain+"s"
    if not icon:
        service_data = {"object_id": group, "entities": hass.states.entity_ids(domain), "name": name}
    else:
        service_data = {"object_id": group, "entities": hass.states.entity_ids(domain), "name": name, "icon": icon}
    hass.services.call("group", "set", service_data, False)

In automation:

      - service: python_script.create_all_group
        data:
          domain: fan
          group: all_fans
          icon: mdi:fan

Thanks @petro for the pyhton script - it helped me a lot. I extended it - with my NO knowledge in python - to optionally provide prefixes and suffixes to just group the entities whose entity_ids which match it.

If wanted to do it with re and filter but i didnt find a way to import these in HA python scripts.

domain = data.get('domain', '')
group = data.get('group', '')
prefixes_or_suffixes = data.get('prefixes_or_suffixes', '')

def filter_by_pattern(entity_id):
    return bool(re.search(entity_id_pattern, entity_id, flags=re.IGNORECASE))

if not isinstance(domain, str) or not isinstance(group, str) or not domain or not group:
    logger.warning("bad domain or group! Not executing.")
else:
    if not isinstance(prefixes_or_suffixes, str) or not prefixes_or_suffixes:
        entities = hass.states.entity_ids(domain)
    else:
        prefixes_or_suffixes = prefixes_or_suffixes.split(",")
        entities = []
        for entity_id in hass.states.entity_ids(domain):
            for prefix_or_suffix in prefixes_or_suffixes:
                if entity_id.find(prefix_or_suffix) != -1:
                    if entity_id not in entities:
                        entities.append(entity_id)

    service_data = {"object_id": group, "entities": entities}
    hass.services.call("group", "set", service_data, False)

Use it like this:

service: python_script.create_all_group
data:
  domain: light
  group: deko_licht
  prefixes_or_suffixes: light.deko_licht_,light.demo_licht_

I found your response while looking for a way to create a light group in an automation. The group.set service creates a regular group, and although that works when used with scene.apply in the automation, it does not work when I try to get any of the color / brightness attributes.

I have the first part working, where I dynamically create a group of lights that can be used in a scene.apply call to set color, etc., but that same group does not work when trying to access the color properties of the group in another automation. If there was a light_group.set service, that would solve my problem.

Alternatively, do you know if it is possible to use a template to create a light_group using a regular group of all light entities?

Is there some way to group lights that are on AND in a specific area?

EDIT:
I found this that somehow looks at the area even though Iā€™ve seen many stating that area cantā€™t be pulled from entities. Can this be used/tweaked to allow dynamic groups with lights ON and in specific area?

{%- set search_state = 'on' %}
{%- set search_area = 'Vardagsrum' %}
{%- set ns = namespace(lights=[]) %}
{%- for light in states.light | selectattr('state','eq', search_state) | rejectattr('attributes.entity_id', '!=', undefined) if area_name(light.entity_id) == search_area %}
  {%- set ns.lights = ns.lights + [ light.entity_id ] %}
{%- endfor %}
{{ ns.lights }}

EDIT: 2 nvm I did not tink of that a group can not be updated without a service call/restart.

I donā€™t have an answer because I have never experimented with Light Groups that way.

Is this not what you are trying to do?

- service: group.set
  data:
    object_id: lights_grp
    entities: >
      {%- set search_state = 'on' %}
      {%- set search_area = 'Vardagsrum' %}
      {%- set ns = namespace(lights=[]) %}
      {%- for light in states.light | selectattr('state','eq', search_state) | rejectattr('attributes.entity_id', '!=', undefined) if area_name(light.entity_id) == search_area %}
        {%- set ns.lights = ns.lights + [ light.entity_id ] %}
      {%- endfor %}
      {{ ns.lights }}

It creates a group on-the-fly called group.lights_grp which is composed of the entities you seek. I do something very similar in a loop in an automation (although I use input_booleans to determine which lights to include in the group) so that even if the automation is running, if I turn off a boolean, it will be excluded on the next iteration. I also make it immediate by using a wait-for-trigger on a change of any of the booleans I watch.

This little loop you found is very cool, btw.

1 Like

Thanks! Iā€™ll have a look at this in the morning!

As Iā€™m controlling my lights mostly with a group of lights in a room and use a slider for that it can sometimes be annoying that all the lights changes when setting a new brightness or temperature.

So if I could have a dynamic group I could turn all lights on the first time and then just turn the individual lights off and use that updated dynamic group to just control the lights that are actually on.

So can I just make a automation that listens on light turn state changes and just trigger it to update the group with the code above?

Edit: I never seem to make replies tag right on this forumā€¦ can one add them when editing a post?

To tag and respond to a particular post, use the Reply button just below it and to the right, NOT the blue one at the bottom, which replies to the OP (no tag).

I think I understand what you are trying to do. If so, I do something similar. I recently acquired some Hue lights and integrated them into HA via ZHA. I started with buttons for each entity that let me control each individually. That just wasnā€™t cool enough. I then created a light group that included all of them, and created two scripts tied to buttons that would call a scene.apply service to set the entire group (all lights) to either a warm tone or cool tone. All that was easy.

Then I created an automation to do a custom color loop where a color was chosen at random from a predefined set of colors for various color loop themes I created (e.g., cool, sunny, moody, etc.) defined by an input_select. I can also control the transition and hold time of each color from the UI using input_numbers. That all worked great, until I discovered that I may not want all lights to be in the color loop, or to have one stay white bright for reading while the rest looped, or some turned off during the loop.

I could turn individual lights off, but as soon as the loop started over with a new color, and set the GROUP to that color, ALL the lights in the group would turn on with the scene.apply service call (just as they should).

So, I needed a way to filter out certain lights from both my warm/cool scene buttons and my color loop. What I decided to do was create an input_boolean for each Hue light (I have 4 currently), connect them to buttons on my UI, and use the state of those to create my dynamic group.

Hereā€™s the relevant code:

      - service: group.set
        data:
          object_id: lamps_grp
          entities: >
            {% set result = states.light.hue_lr_lights_lgrp.attributes.entity_id -%}
            {%- if is_state('input_boolean.hue_loop_include_go','off') -%}
              {%- set result = result | reject("==",'light.hue_go') | list -%}
            {%- endif %}
            {%- if is_state('input_boolean.hue_loop_include_lr_table','off') -%}
              {%- set result = result | reject("==",'light.hue_100w_lr_table') | list -%}
            {%- endif %}
            {%- if is_state('input_boolean.hue_loop_include_lr_floor','off') -%}
              {%- set result = result | reject("==",'light.hue_75w_lr_floor') | list -%}
            {%- endif %}
            {%- if is_state('input_boolean.hue_loop_include_den_floor','off') -%}
              {%- set result = result | reject("==",'light.hue_75w_den_floor') | list -%}
            {%- endif -%}
            {{ result }}

It works basically by removing entities from the predefined light group I defined in my config, based upon the input_booleans (there are probably 5 better, more effective ways to do this, but Iā€™m still getting up to speed on templates). With my new group defined, I can do whatever I want with it (although reading color attributes from it is not possible like they are with a real light group). Note that I do also pre-define a regular group with these same entities, just so if something happens here, the regular group is still fully populated (so both a light group and a regular group with the same entities - I have a reason for this).

Here is what the Card in the UI looks like:

I really canā€™t see why anyone would use anything other than Home Assistant for home automation!

1 Like