Single automation for all lights

My goal is that I want to have the lights have a transition when they’re turned on (so they’re not immediately at full brightness when turned on). The old way I used was to have an automation per light, but that was heavy for maintenance/set up.

I sorta found a way to have a single automation but I wonder if it’s inefficient since the way I found is checking against all state_changed events, not just for lights. So what is the efficient way to do it?

Here’s the full yaml for the automation:

alias: 'TEST: Tell which light bulbs turned on'
description: ''
trigger:
  - platform: event
    event_type: state_changed
condition:
  - condition: and
    conditions:
      - condition: template
        value_template: '{{ trigger.event.data.entity_id.split(''.'')[0] == ''light'' }}'
      - condition: template
        value_template: '{{ trigger.event.data.old_state.state == ''off'' }}'
      - condition: template
        value_template: '{{ trigger.event.data.new_state.state == ''on'' }}'
action:
  - service: light.turn_on
    target:
      entity_id: '{{trigger.event.data.entity_id}}'
    data:
      brightness_pct: 1
      color_temp: >
        {% if is_state("sun.sun", "above_horizon") -%}
          300
        {%- else -%}
          425
        {%- endif %}
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - service: light.turn_on
    target:
      entity_id: '{{trigger.event.data.entity_id}}'
    data:
      transition: 10
      brightness_pct: >
        {% if is_state("sun.sun", "above_horizon") -%}
          100
        {%- else -%}
          50
        {%- endif %}
  - service: notify.notify
    data:
      message: 'This light was turned on: {{trigger.event.data.entity_id}}'
mode: parallel
max: 10

Have you seen Light Profiles? Light - Home Assistant

I think you can use group.all_lights.default and add a default transition to all lights this way

1 Like

Thanks for the suggestion! I thought about it but came to the conclusion that it would be a little weird for the lights since they’re Tradfri light bulbs paired with Tradfri motion detectors.

Basically, when they’re turned on by the motion detector (the motion detector communicates directly with the light), the lights use the last settings from when it was previously turned off. So if the light was turned off at 100% brightness, it would turn on with 100% brightness.

So I think the light would briefly be at 100% brightness before it is transitioned toward the profile’s brightness, which is what I don’t want (I’d want the light to start with a low brightness before transitioning toward the new brightness, basically). Also, profiles doesn’t support color temperature, which my bulbs do.

Anyhow, my current solution works, but it’s triggered way too often, which makes the useful trace feature near impossible to use since it’s firing up so often that the previous traces aren’t available anymore by the time I click the next button…

Use a State Trigger.

alias: 'TEST: Tell which light bulbs turned on'
description: ''
trigger:
  - platform: state
    entity_id:
      - light.first
      - light.second
      - light.third
      - light.fourth
      - light.fifth
      - light.etc
    from: 'off'
    to: 'on'
condition: []
action:
  - variables:
      is_above: '{{ is_state("sun.sun", "above_horizon") }}'
  - service: light.turn_on
    target:
      entity_id: '{{ trigger.entity_id }}'
    data:
      brightness_pct: 1
      color_temp: '{{ 300 if is_above else 425 }}'
  - delay: '00:00:01'
  - service: light.turn_on
    target:
      entity_id: '{{ trigger.entity_id }}'
    data:
      transition: 10
      brightness_pct: '{{ 100 if is_above else 50 }}'
  - service: notify.notify
    data:
      message: 'This light was turned on: {{ trigger.entity_id }}'
mode: parallel
max: 10

Is there a way to use a template in entity_id to get all lights? My solution doesn’t require me to list all lights, which is what I like about it. A while ago, I had to pair an existing light again because the Tradfri bridge didn’t see it and I had to touch some automations associated with it, because the entity_id had changed so I was hoping if there was a way to avoid all those manual interventions when a light is added/removed/changed.

As for the other stuff such as variables for the action block, thank you! I didn’t know those existed so I tried to do it the template way. I’ll be sure to update my automation to make use of those features.

No. A State Trigger doesn’t support templating.

I agree it’s convenient but it triggers for every state-change that occurs in your system. You asked for something more efficient and a State Trigger is very efficient.

If you want efficiency, you will need to specify the light entities to be monitored. If you don’t want to do that then you don’t have much choice beyond using an Event Trigger.

1 Like

Here’s something you may wish to try. It combines the efficiency of a State Trigger with the convenience of a Group. It’s untested with lights so caveat emptor.

Create a State-based Template Sensor that reports the latest light that just turned on. Replace group.my_lights with whatever is the entity_id of your group of lights.

template:
  - sensor:
      - name: Latest Light On
        state: >
          {% set x = expand('group.my_lights') | selectattr('state', 'eq', 'on') | sort(attribute='last_changed', reverse=true) | list %}
          {{ (x[0].entity_id if now() - x[0].last_changed < timedelta(seconds=3) else '') if x | count > 0 else '' }}

Create an automation with a State Trigger that monitors the sensor.

alias: 'TEST: Tell which light bulbs turned on'
description: ''
trigger:
  - platform: state
    entity_id: sensor.latest_light_on
condition:
  - condition: template
    value_template: "{{ trigger.to_state.state != '' }}"
action:
  - variables:
      is_above: '{{ is_state("sun.sun", "above_horizon") }}'
  - service: light.turn_on
    target:
      entity_id: '{{ trigger.to_state.state }}'
    data:
      brightness_pct: 1
      color_temp: '{{ 300 if is_above else 425 }}'
  - delay: '00:00:01'
  - service: light.turn_on
    target:
      entity_id: '{{ trigger.to_state.state }}'
    data:
      transition: 10
      brightness_pct: '{{ 100 if is_above else 50 }}'
  - service: notify.notify
    data:
      message: 'This light was turned on: {{ trigger.to_state.state }}'
mode: parallel
max: 10

As already stated, this is untested with lights so let me know if it works (or not).

2 Likes

This actually works pretty great! I wondered if it worked with lights that turn on in pairs and it does too. By the way, I’ve combined this with an automation that starts this script at startup so the group is automatically created:

sequence:
  - service: group.set
    data_template:
      object_id: my_lights
      entities: |
        {{ states.light |  map(attribute='entity_id') | join(',') }}
mode: single
alias: Create 'my_lights' group for every lights
icon: mdi:lightbulb
1 Like

I went back to the state trigger since the other didn’t work reliably when 3 or more lights open at the same time. I also modified the actions slightly to allow for color-supported bulbs as well:

alias: Automatic transition + color temperature for all lights
description: ''
trigger:
  - platform: state
    entity_id:
      - light.bulb_1
      - light.bulb_2
      - light.bulb_3
     # all the other lights are listed too...
    from: 'off'
    to: 'on'
condition: []
action:
  - variables:
      is_daytime: '{{ is_state("sun.sun", "above_horizon") }}'
      warm_color_temp: 425
      cold_color_temp: 300
      day_max_pct_brightness: 80
      night_max_pct_brightness: 33
  - choose:
      - conditions:
          - condition: template
            value_template: >-
              {{ "hs" in state_attr(trigger.entity_id, 'supported_color_modes')
              }}
        sequence:
          - service: light.turn_on
            target:
              entity_id: '{{ trigger.entity_id }}'
            data:
              brightness_pct: 1
              hs_color:
                - '{{ trigger.to_state.attributes.hs_color[0] }}'
                - '{{ trigger.to_state.attributes.hs_color[1] }}'
    default:
      - service: light.turn_on
        data:
          brightness_pct: 1
          color_temp: '{{ cold_color_temp if is_daytime else warm_color_temp }}'
        target:
          entity_id: '{{ trigger.entity_id }}'
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - condition: template
    value_template: '{{ is_state(trigger.entity_id, "on") }}'
  - service: light.turn_on
    target:
      entity_id: '{{ trigger.entity_id }}'
    data:
      transition: 10
      brightness_pct: '{{ day_max_pct_brightness if is_daytime else night_max_pct_brightness }}'
mode: parallel
max: 10

It’s possible to adapt it to handle that situation but it’s simpler to use a State Trigger (like I had suggested in my first post and like you have already done).

Hi @synthe6, thanks so much for this.
After searching all night I think this is the basis of what I need.
Can you explain how you call this script from an automation?
Many thanks.
Michael

Hey, been wondering, is there any way this could be adapted to listen to any attribute changes, not just on/off? Say, I have group xyz, and light y changes its brightness from 50% to 80%, color, on/off state or whatever. Any way to get a trigger from that through a group (or list) or do I have to do it manually?

Have you checked if it already does that?

last_changed is updated when there’s a change in the value of an entity’s state or attributes.

Oh yeah, actually it does! Guess I got confused by the whole selecting of ‘on’ attribute :slight_smile:
With the help in another thread, I found out this sensor of yours can be shortened down a lot if you don’t care about the timedelta stuff I guess. My sensor now works fine with this:

template:
  - sensor:
      - name: Latest Light On
        state:{{ expand('group.all_living_room') | sort(attribute='last_updated', reverse=true) | map(attribute='last_updated')| first}}

And using the group creation script @synthe6 posted in here. However, one can of course also make it a bit simpler by just using expand(area_entities('Living Room') | select('match', 'light')) as an entity source instead of the groups :slight_smile:

Its purpose was to identify what changed mere seconds ago versus longer than that.

In the example you posted, the template is missing outer quotes.

I see!
I have learnt that very recently (very new to templates if you haven’t been able to tell yet), but why does it work regardless then?

Reference

Important template rules