How to save value between iterations of a sequence

I have been using HA for over a year and am just starting to get into (for me) some more complex scripts. I have run into an issue with variable scope in a script and cannot seem to find a way out. My guess is that I am missing a concept in HA that might be more appropriate for solving my problem.

My script’s goal: I have a set of 14 shelves each of which has an RGBW light. I normally set the shelves to a set of static colors (often white but say a mix of red and green at Christmas). To make things more dynamic, I am trying to set up a script that will randomly select a shelf and temporarily change its color and then return it to its original color before choosing another shelf to change. I like to use transitions for the lights so that one is fading out to its original color as the new one is fading into its temporary color.

The issue: You can see my initial script below. It attempts to change a random shelf to green and then restore its color to what it was at the beginning. It works… up until it selects the same shelf twice in a row. With the transition, when the “new” shelf is selected to be the same as the last iteration, the “old” shelf (itself) is still holding its temporary color so now the “new” shelf believes its current color is green. This means that over time, the whole set of shelves turns to green.

The solution I see is to prevent the same shelf being selected twice in a row… but here I run up against variable scope. I tried to create a variable to save the index of the last selected light and then at the beginning of a new iteration ensure that the newly selected light is not the same as the last iteration. Of course, with YAML’s scoping, I cannot get a variable to do this.

Do you see any other way to ensure that the same shelf is not selected on two back-to-back iterations of the sequence?

alias: Test
variables:
  shelves: |
    {{ [
      'light.sculptureshelf_shelf_01', 
      'light.sculptureshelf_shelf_02', 
      'light.sculptureshelf_shelf_03', 
      'light.sculptureshelf_shelf_04', 
      'light.sculptureshelf_shelf_05', 
      'light.sculptureshelf_shelf_06', 
      'light.sculptureshelf_shelf_07', 
      'light.sculptureshelf_shelf_08', 
      'light.sculptureshelf_shelf_09', 
      'light.sculptureshelf_shelf_10', 
      'light.sculptureshelf_shelf_11', 
      'light.sculptureshelf_shelf_12', 
      'light.sculptureshelf_shelf_13', 
      'light.sculptureshelf_shelf_14'
    ] }}
sequence:
  - repeat:
      sequence:
        - alias: Select Light
          variables:
            random_light: "{{ range(0, 13) | random }}"
        - alias: Get current color
          variables:
            current_color: "{{ state_attr(shelves[random_light], 'rgbw_color') }}"
        - alias: Turn on light
          action: light.turn_on
          data:
            rgbw_color:
              - 0
              - 255
              - 0
              - 0
            transition: 5
          target:
            entity_id: "{{ shelves[random_light] }}"
        - delay:
            hours: 0
            minutes: 0
            seconds: 20
            milliseconds: 0
        - alias: Turn off light
          action: light.turn_on
          data:
            transition: 5
            rgbw_color: "{{ current_color }}"
          target:
            entity_id: "{{ shelves[random_light] }}"
      while: []
description: ""

This should get you what you want, but it’s template heavy. Should be easier to manage though.

alias: Test
sequence:
  - repeat:
      sequence:
        - alias: Select Light
          variables:
            target_color:
              - 0
              - 255
              - 0
              - 0
            current: >
              {% set numbers = list(range(13)) %}
              {% set number = numbers | random %}
              {% set light_str = 'light.sculptureshelf_shelf_{0:02d}' %}
              {% if is_state_attr(light_str.format(number), target_color) %}
                {% set number = numbers | reject(number) | random %}
              {% endif %}
              {% set light = light_str.format(number) %}
              {{ dict(light=light, color=state_attr(light, 'rgbw_color')) }}
        - alias: Turn on light
          action: light.turn_on
          data:
            rgbw_color: "{{ target_color }}"
            transition: 5
          target:
            entity_id: "{{ current.light }}"
        - delay:
            hours: 0
            minutes: 0
            seconds: 20
            milliseconds: 0
        - alias: Turn off light
          action: light.turn_on
          data:
            transition: 5
            rgbw_color: "{{ current.color }}"
          target:
            entity_id: "{{ current.light }}"
      while: []
description: ""

It does not store a value. It simply checks to see if the random light is already the target color. If it is, it chooses a separate one. I believe the only reason this is happening to you is because you don’t have a delay after the turn off. If you waited 5 seconds (the duration of your transition) the light’s state wouldn’t be green.

Anyways, what I posted above will work without the delay.

If you want to store values without the heavy templating, you need to make a helper to store the last light you used and reject that value from the options.

@petro Thanks for the advice, I’ve gone with using a Helper - I hadn’t thought of that. Unfortunately, I am hoping later to have it change to a random color (not just green) so checking color wouldn’t work long term.

Hi sailorcampbell,

There are many way to pick random colors, but I have this custom template. You could use it as is (You can load it from GitHub thru HACS) to pull a random color for you in any format or you can look at the template and copy some code out of it to help you.

1 Like