This is really just a play project (to see if I can make the lights look pretty - I don’t have a real practical need for it).
But I am trying to do “animated” effects where the lights in the room fade up in a pattern for example where the light starts one side of the room and moves across.
I can do this with a script and a bunch of light.turn_on and delay actions where I typically:
Turn the lights on very dimly (to set the start color).
Then do a transition (transition attribute of the turn_on) to the first set of colors.
Delay the script while the transitions are happening.
Do a transition to the next color.
… Repeat …
Finally activate the final scene that I want the room to end up in.
The approach works and looks nice - it’s just really cumbersome creating the script to do all the transitions.
Some caveats:
My lights are all Zigbee bulbs hence I don’t want to send too many commands (max 1 color change per second per light) - this is why I am using the transitions.
At the moment I have a mix of lights from different manufactures so the color spaces are not all identical.
Additionally some of them handle the transitions differently.
I have to be careful when I change colors as some of the bulbs have a tendency to go to white while transitions (doesn’t look good), hence I end up throwing in intermediate states to prevent that.
The net result is that I have to do a lot of intermediate steps and tweak individual bulbs.
I realize I could simplify the problem, if I buy a bunch of identical bulbs - but that’s not my current situation.
Anyway is there an alternative approach for tackling this - it doesn’t have to be a working code solution (happy to code it myself) just looking for a better way of tackling it.
Chated with Claude Code for a bit and came up with the following, its not great, but its a lot better than what I had:
alias: Play Light Animation
fields:
frames:
name: Frames
description: >-
Ordered list of steps. Each item - entity_id (single id or list), data
(light.turn_on service data, e.g.
brightness/rgb_color/color_temp_kelvin/transition), delay (seconds to wait
after this frame before the next one starts; omit or 0 for no wait).
required: true
selector:
object: {}
final_scenes:
name: Final Scenes
description: >-
Optional list of scenes to activate once all frames have played, each
routed through script.scene_selected. Each item - room, scene_name, and an
optional transition_time (seconds); if omitted, scene_selected uses its
normal automatic transition behavior.
required: false
selector:
object: {}
sequence:
- repeat:
for_each: "{{ frames }}"
sequence:
- action: light.turn_on
target:
entity_id: "{{ repeat.item.entity_id }}"
data: "{{ repeat.item.data | default({}) }}"
- delay: "{{ repeat.item.delay | default(0) }}"
- if:
- condition: template
value_template: "{{ final_scenes is defined and final_scenes | count > 0 }}"
then:
- repeat:
for_each: "{{ final_scenes }}"
sequence:
- action: script.turn_on
target:
entity_id: script.scene_selected
data:
variables:
room: "{{ repeat.item.room }}"
scene_name: "{{ repeat.item.scene_name }}"
transition_time: "{{ repeat.item.transition_time | default(none) }}"
As you can see it’s just a couple of loops, but that cleans up the invocation quite a bit.
I.e. here is a sample script that handles an “animation”: