How to toggle all lights in an Area (or Group)?

All of the options you have suggested are possible…

Area-based

You can call your service on an area ID if you want to target all applicable entities in the Area. When using the UI editor, the area_id will be selectable by it’s friendly name, otherwise it can be found using the Template editor: {{area_id("Living Room")}}.

service: light.toggle
data: {}
target:
  area_id: 0352e80e71464487b396c5599c886de0

This will have the same issue when the lights have mixed states

Group-based

A light group’s ‘on’ state is based on whether ‘any’ of it’s component entities’ states are ‘on’.

trigger:
  - platform: mqtt
    topic: "living_room/switch/light"
condition: []
action:
  - service: light.turn_{{ 'on' if is_state('light.living_room_group', 'off') else 'off' ) }}
    data: []
    target:
      entity_id: light.living_room_group

This will turn all lights ‘off’ if any are ‘on’ but only turn them ‘on’ when all are ‘off’.

Proportional toggle

trigger:
  - platform: mqtt
    topic: "living_room/switch/light"
condition: []
action:
  - variables:
      count_on: >
        {{ state_attr('light.living_room_group', 'entity_id') | select('is_state','on') | list | count }}
      count_off: >
        {{ state_attr('light.living_room_group', 'entity_id') | select('is_state','off') | list | count }}
      light_action:  "{{ iif( count_on >= count_off, 'off', 'on' ) }}"
  - service: "light.turn_{{ light_action }}"
    data: []
    target:
      entity_id: light.living_room_group

This will turn all lights in the group ‘off’ when the number of lights which are ‘on’ is greater than or equal to the number of lights that are ‘off’, otherwise it will turn all lights ‘on’.

A similar set of variables could be used to do the same based on the light entities in a given area:

  - variables:
      lights: "{{ area_entities('living room') | select('match', 'light.') | list }}"
      count_on: "{{ lights | select('is_state', 'on') | list | count }}"
      count_off: "{{ lights | select('is_state', 'off') | list | count }}"
      light_action: "{{ 'off' if count_on >= count_off else 'on' }}"

Likewise, you can use the other entity listing functions like device_entities(), integration_entities(), label_entities(), or floor_entities() in the same way shown above for area_entities().

Just be aware that some integrations will classify things in the light domain that you might not expect to be switching on/off with your room lights and you would need to reject those specific entities from the list created for the lights variable. Examples of this include indicator lights on ESPHome devices or screens controlled by the Browser Mod integration. Also, light groups may throw off the true ratio of ‘on’ vs. ‘off’, so you may need to filter those out.

For example, zigbee light groups configured in ZHA have the attribute key group with boolean value true which can be used to reject those groups from the count:

  - variables:
     lights: |
       {{ integration_entities('zha') | select('match', 'light.') 
       | reject('is_state_attr', 'group', true) | list }}
      count_on: "{{ lights | select('is_state', 'on') | list | count }}"
      count_off: "{{ lights | select('is_state', 'off') | list | count }}"
      light_action: "{{ 'off' if count_on >= count_off else 'on' }}"

For other types of groups you might use the entity_id attribute.

EDITS:

2024-04-20: Corrected missing quotes mentioned below and updated templates to exchange expand for preferred select method.

2025-02-20: Templates for counts updated to use more efficient template methods.

2025-05-04: Fixed double-quote issue and added info about entity listing functions.

1 Like