ZHA - Cycle color for light entity

A script blueprint to change the color of a light entity, cycling through a configurable list of colors (up to 12). Calling the script will change the light entity to the next color in the list (can optionally go backwards as well).

Blueprint

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

# This script will step through (forwards or backwards) a list of assigned colors for an RGB light entity
# Credit: https://gist.github.com/mdolnik/7147b5df4b08f7979afad02a5dd137a2
# Credit: https://community.home-assistant.io/t/trying-to-cycle-through-colors-on-a-hue-bulb-each-time-a-button-is-pressed/493249/3

blueprint:
  name: Cycle color on a light
  description: >-
    A script that increments or decrements a color on a light.
  domain: script
  source_url: https://github.com/nwithan8/configs/blob/5fd9ea779c12444e69d11cf4bc8bf39a028f4506/home_assistant/blueprints/scripts/cycle_color_on_light.yaml
  input:
    light:
      name: Light
      description: "The Light entity or Light Group entity to loop through the colors chosen below."
      selector:
        entity:
          domain:
            - light
            - group
          multiple: false
    color_tracker:
      name: Color state helper
      description: An input number helper to store the current color in
      selector:
        entity:
          domain: input_number
    color_1:
      name: Color 1
      description: "Set to black to omit this color."
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_2:
      name: Color 2
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_3:
      name: Color 3
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_4:
      name: Color 4
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_5:
      name: Color 5
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_6:
      name: Color 6
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_7:
      name: Color 7
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_8:
      name: Color 8
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_9:
      name: Color 9
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_10:
      name: Color 10
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_11:
      name: Color 11
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}
    color_12:
      name: Color 12
      description: "Set to black to omit this color"
      default:
        - 0
        - 0
        - 0
      selector:
        color_rgb: {}

# Only single, otherwise could flood with attempts
mode: single

fields:
  transition:
    name: Transition Time
    description: "Choose the time it takes to move to the next color."
    selector:
      duration: {}
    default:
      hours: 0
      minutes: 0
      seconds: 1
  decrement:
    name: Decrement
    description: Go backwards instead of forward in the color list
    required: true
    selector:
      boolean:

variables:
  light: !input "light"
  color_tracker: !input "color_tracker"
  transition_seconds: "{{ ((transition.hours)*60*60) + ((transition.minutes)*60)
    + transition.seconds }}"
  color_rgbs:
    - !input "color_1"
    - !input "color_2"
    - !input "color_3"
    - !input "color_4"
    - !input "color_5"
    - !input "color_6"
    - !input "color_7"
    - !input "color_8"
    - !input "color_9"
    - !input "color_10"
    - !input "color_11"
    - !input "color_12"
  # Convert the array of RGB colors to a comma separated list of HSV values.
  # Exclude any colors set to black.
  # https://community.home-assistant.io/t/using-hsv-hsb-to-set-colored-lights/15472
  # https://github.com/home-assistant/core/issues/33678#issuecomment-609424851
  # https://stackoverflow.com/a/56141280/4147996
  color_hsv_list_csv: >-
    {%- set data = namespace(entries=[]) -%}
    {%- for color_rgb in color_rgbs -%}
      {%- if color_rgb != [0,0,0] -%}
        {%- set r = (color_rgb[0]/255) -%}
        {%- set g = (color_rgb[1]/255) -%}
        {%- set b = (color_rgb[2]/255) -%}
        {%- set maxRGB = max(r,g,b) -%}
        {%- set minRGB = min(r,g,b) -%}
        {%- set chroma = maxRGB - minRGB -%}
        {%- if chroma == 0 -%}
          {%- set h = 0 -%}
          {%- set s = 0 -%}
          {%- set v = maxRGB -%}
        {%- else -%}
          {%- if r == minRGB -%}
            {%- set h = 3-((g-b)/chroma) -%}
          {%- elif b == minRGB -%}
            {%- set h = 1-((r-g)/chroma) -%}
          {%- else -%}
            {%- set h = 5-((b-r)/chroma) -%}
          {%- endif -%}
          {%- set h = 60 * h -%}
          {%- set s = chroma / maxRGB -%}
          {%- set v = maxRGB -%}
        {%- endif -%}
        {%- set h = h|round(2)|string -%}
        {%- set s = s|round(2)|string -%}
        {%- set v = v|round(2)|string -%}
        {%- set comma_sep = h + "|" + s + "|" + v -%}
        {%- set data.entries = data.entries + [comma_sep] -%}
      {%- endif -%}
    {%- endfor -%}
    {{ data.entries | join(",") }}
  color_hsv_list: '{{ color_hsv_list_csv.split(",") }}'
  color_count: "{{ color_hsv_list | length | int - 1}}"

sequence:
  - variables:
      # Next color index to change to.
      i_next: >
        {% set idx = 0 %}
        {% if decrement %}
          {% set idx = states(color_tracker) | int - 1 %}
          {% if idx < 0 %}
            {% set idx = color_count %}
          {% endif %}
        {% else %}
          {% set idx = states(color_tracker) | int + 1 %}
          {% if idx > color_count %}
            {% set idx = 0 %}
          {% endif %}
        {% endif %}
        {{ idx }}
      # Get the H/S of next colors.
      hsv_next_csv: "{{ color_hsv_list[i_next] }}"
      hue_next: '{{ hsv_next_csv.split("|")[0] }}'
      sat_next: '{{ (hsv_next_csv.split("|")[1])|float * 100 }}'
      # Light to interact with
      lights_to_change: "{{
        expand(light)
        | selectattr('domain', 'eq', 'light')
        | map(attribute='entity_id')
        | list
        }}"

  - service: light.turn_on
    target:
      entity_id: "{{ lights_to_change }}"
    data:
      hs_color: "{{ [hue_next, sat_next] }}"
      transition: "{{ transition_seconds }}"

  - service: input_number.set_value
    entity_id: !input "color_tracker"
    data:
      value: "{{ i_next | int }}"

Install:

  1. Click the “Import Blueprint” button above and follow the instructions to import the blueprint into your Home Assistant.
  2. Create a “Number” helper, minimum 0 and maximum 13. This will store the number of the currently-active color. DO NOT MANUALLY ALTER THIS NUMBER.

  1. Click “Create Script” from the Blueprint. Select the target light to change the color of, and the helper you just created. Select the colors you want to include. Any color left as the default black will not be included in the rotation. Colors will be cycled in the order they are listed.

Usage

  1. Call the script via a service call in an automation, in Developer Tools, or in another script.
  • Override the default 1-second transition time between colors
  • Optionally indicate to go backwards rather than forwards (decrement) in the list of colors.

I am getting an error when I try to run this script.

If I run it directly from the Settings/Automation & Scenes/Scripts page I get an error that transition is undefined.

If I add a card with a run button on the dashboard I get nothing (no error and now changes to the light)

But if I run it from the Services tab in Developer Tools it runs (although it only changes the colour once, I have to press it again to make it change it again).

So I am not sure what I am doing wrong - how can I create an automation that will run this? I followed the instructions on the Blueprint page for this blueprint so not sure what else to do (I am new to Home Assistant).

It’s failing with the run button because it requires parameters to be passed in, which you are doing when calling it via Developer Tools.

In an automation, if you add a “call service” action and select script.the_name_of_your_script_here, it should prompt you to configure the script parameters and call the script as part of the automation.

Calling the script once switches the color once, so if you want to cycle through multiple colors, you will need to call the script multiple times.

Hey,

Yes I managed to figure this out with an automation but it is still not working as expected. I have set the transition time to 5 seconds to try to give a smoother transition but it doesn’t work - the transition is always immediate so rather than smoothly moving from one color to the next it is an abrupt change (say from red to purple) which is not the effect I was hoping for. In fact changing the transition time doesn’t seem to do anything noticeable.

Also when using the repeat until condition, it seems to wait a long time between each iteration (about a minute) which is also not ideal (I am trying to create a party light effect).

Here is my automation code:

alias: Cycle Light Colour
description: ""
trigger:
  - platform: state
    entity_id:
      - light.smart_rgb_bulb_2103255492189890847348e1e967074a
    from: "off"
    to: "on"
condition: []
action:
  - repeat:
      until:
        - condition: state
          entity_id: light.smart_rgb_bulb_2103255492189890847348e1e967074a
          state: "off"
      sequence:
        - service: script.1691923417388
          data:
            transition:
              hours: 0
              minutes: 0
              seconds: 5
            decrement: false
mode: single

Perhaps it would make more sense to do the repeat until the number helper reaches 13 and then run another condition to call the same service again but this time with decrement: true and repeat until the number helper hits 0 again - then wrap both actions in another repeat until which continues until the state is off?

Can you share the logs of the scripts runs (the traces)?