Ashley’s Light Fader 2.0✨: fade lights and/or color temperature with your choice of easing (curves), including ease-in, ease-out, and ease-in-out

What a fantastic script, thank you so much!!

It works brilliantly on my fancy lights with integrated leds.
However, with Philips Hue light bulbs I have noticed that they don’t fade in smoothly, whichever curve I apply. There’s a noticeable jump from 0 to 60% (estimate) brightness, and then an underwhelming fade in effect. I found some reports online saying that this is typical for led bulbs and, for Philips hue lights specifically, works better with the Hue Bridge (which I haven’t tested). Has this been your experience as well?

1 Like

@Ark88888 If I might ask, would you be open to trying a quick test automation?

If so, try creating an automation that has a “run in parallel” action, and then within that “run in parallel” action, try adding only four “light: turn on” actions—one for each lamp.

When you run that test automation, do those four lights turn on at the same time? Or no?

Hi, @acdown87!

I think there’s a good pretty chance that you might be experiencing the same issue that @Sim209 was running into.

In short, I think your lamp might be fibbing a bit:

If you might be interested in confirming that hunch, you can do so by enabling debug logging and then running your fade:

  1. First, if you haven’t yet installed the Home Assistant Log Viewer add-on , install that. (This should add a “Log Viewer” item to your sidebar within Home Assistant.)
  2. Then open the Log Viewer in one of your browser tabs. And then in a second browser tab, open the automation with your test fade.
  3. Then within the automation with the test fade, enable Debug Mode within the options for Ashley’s Light Fader.
  4. From there, run that fade, and while the fade is running, switch over to the browser tab where you’ve got the Log Viewer open.
  5. You should see some debugger output within the Log Viewer that looks something like this:

(I’ve sliiightly reformatted the below log bits just for clarity.)

2024-04-30 15:02:25.660 WARNING (MainThread) [homeassistant.components.system_log.external] 
easeInOutSine easing type with 686 ms delay. remainingTimeInMilliseconds = 44923, and absoluteBrightnessSpan = 50

2024-04-30 15:02:25.661 WARNING (MainThread) [homeassistant.components.system_log.external]
startBrightness = 25, endBrightness = 75, and processingDelayInMilliseconds = 62

2024-04-30 15:02:28.548 WARNING (MainThread) [homeassistant.components.system_log.external]
Set Living Room Lamps to 26 brightness. (Linear brightness would have been 28.) 
Delay is 686 ms. Elapsed time is 2.97 seconds. (endBrightness is 75.)

2024-04-30 15:02:30.750 WARNING (MainThread) [homeassistant.components.system_log.external] 
Set Living Room Lamps to 27 brightness. (Linear brightness would have been 31.) 
Delay is 686 ms. Elapsed time is 5.17 seconds. (endBrightness is 75.)

2024-04-30 15:02:32.237 WARNING (MainThread) [homeassistant.components.system_log.external]
Set Living Room Lamps to 28 brightness. (Linear brightness would have been 32.) 
Delay is 686 ms. Elapsed time is 6.66 seconds. (endBrightness is 75.)

And if you might like, feel free to share an excerpt from your debug logs, and I’ll be happy to give that a look.

@flimofly Many thanks for your kind words!

It so happens that I have some Philips Hue bulbs myself, and although I haven’t specifically come across the issues that you had mentioned, I’d be happy to try to chime with some thoughts.

I have a potential idea about what you might be running into here—and the gist of it is that nonsmooth fades are generally caused by the fader script having to take too large of a jump between its brightness, levels. For instance, if the fader were to have to apply brightness levels of 1%, 20%, 40%, 80%, and then 100%, that would almost definitely not be terribly smooth.

Here are the two main things that can cause fades to have large brightness jumps in their sequence:

  • It so happens that any given light takes a certain amount of time to process each set-brightness command. For instance, if a given light were to hypothetically take 500 ms to process a given light command, and if the fade were to be requested for 5 seconds, then that would only allow for about 10 set-brightness commands between the start of the fade (0 seconds) and the finish (5 seconds).
    • So if it might turn out that your light isn’t be able to process set-brightness commands very quickly, then that may be one factor.
  • A related factor is that even if a given light might be able to process set-brightness commands rather quickly, you still can’t exceed what the math might allow.
    • So for example, let’s suppose that a given lamp might be able to process set-brightness commands super quickly—perhaps it might be able to process 10 per second (which would work out to 100 ms per set-brightness command). In that scenario, if supposing that you were to try to fade that light from 0% to 100% over a span of 1 second, that probably still wouldn’t work go very smoothly since you could only fit in about 10 set-brightness commands within that 1 second.

Of those two factors, the first one—the inherent delay within the lamp—is outside of your control. While the second one—the fade’s duration or the fade’s brightness span—is something that you might have some control over.

Fortunately, you’ve already affirmed your good taste by buying Philips Hue bulbs. [Philips isn’t a sponsor or anything—I just like their stuff.] It so happens that Philips Hue bulbs natively support transitions, and when bulbs natively support transitions, those are almost always way smoother than what any script can possibly achieve.

So if you might need to fade your Philips Hue bulbs between two brightness levels super quickly, I would recommend using the bulbs’ built-in native transitions.

Or if you might be feeling daring, you could potentially instead try enabling this script’s “If available, use the lamp’s native transitions too?” option, which attempts to apply its own fade while mixing that with the bulb’s native transitions to help smooth out the overall effect. That being said, that feature is marked as “experimental” for a reason—it’s something that won’t always necessarily offer much (if any) improvement over the lamp’s built-in fade transition.

In short, I think that your best bet would be to lean on your bulb’s support for native transitions. (And if you might like, you could also potentially try out the “If available, use the lamp’s native transitions too?” option too—although if perhaps you might prefer to skip straight to using your bulb’s native transitions, that’s a reasonable approach too.)

Morning @handcoding, thank you for such a detailed response.

So I ran the steps as you mentioned, and found that indeed the log seems to think the fader automation stopped because the lamp was turned off. I increased the minimum delay to 500ms, but resulted in the same action.

Here is a sample from the logs:

2024-09-09 11:03:11.364 WARNING (MainThread) [homeassistant.components.system_log.external] easeInOutSine easing type with 500 ms delay. remainingTimeInMilliseconds = 59968, and absoluteBrightnessSpan = 255
2024-09-09 11:03:11.364 WARNING (MainThread) [homeassistant.components.system_log.external] startBrightness = 0, endBrightness = 255, and processingDelayInMilliseconds = 30
2024-09-09 11:03:11.491 WARNING (MainThread) [homeassistant.components.system_log.external] easeInOutSine easing type with 500 ms delay. remainingTimeInMilliseconds = 59847, and absoluteBrightnessSpan = 255
2024-09-09 11:03:11.492 WARNING (MainThread) [homeassistant.components.system_log.external] startBrightness = 0, endBrightness = 255, and processingDelayInMilliseconds = 151
2024-09-09 11:03:13.446 WARNING (MainThread) [homeassistant.components.system_log.external] Set Kelsey’s Lamp to 1 brightness. (Linear brightness would have been 9.) Delay is 500 ms. Elapsed time is 2.12 seconds. (endBrightness is 255.)
2024-09-09 11:03:13.556 WARNING (MainThread) [homeassistant.components.system_log.external] Set Alec’s Lamp to 1 brightness. (Linear brightness would have been 9.) Delay is 500 ms. Elapsed time is 2.22 seconds. (endBrightness is 255.)
2024-09-09 11:03:14.059 WARNING (MainThread) [homeassistant.components.system_log.external] Stopped Ashley’s Light Fader because Alec’s Lamp was turned off during the fade.
2024-09-09 11:03:14.504 WARNING (MainThread) [homeassistant.components.system_log.external] Set Kelsey’s Lamp to 2 brightness. (Linear brightness would have been 13.) Delay is 500 ms. Elapsed time is 3.17 seconds. (endBrightness is 255.)
2024-09-09 11:03:15.039 WARNING (MainThread) [homeassistant.components.system_log.external] Set Kelsey’s Lamp to 2 brightness. (Linear brightness would have been 16.) Delay is 500 ms. Elapsed time is 3.71 seconds. (endBrightness is 255.)

Running the automation a few times, which lamp gets reported as “off” seems to be rather random—perhaps just in terms of which one gets reported back first to HomeAssistant.

Quick update… found that setting the minimum delay to 1000ms solves the problem!

1 Like

Hello. I have this issue where if I fade the lights down to off. The next time I turn on the light(ikea gu10) either from the gui or a physical button press (ikea controller), the physical light itself is not on. However, the gui button shows it is toggle to on. Looking at the gui slider, it shows 0%. If I press again, the toggle shows off state, but the physical light is now on. Basically, the state is now reverse. To fix this, I will need to use the light slider once then when I press the button, it will show the correct state.

Further investigating, I notice this behaviour.
With the slider at any brightness (1% is the lowest it will go), I can toggle (highlight in green) the lights on/off and it will turn on/off. With the script, when I use endBrightnessPercent: 0, the light will turn off when the duration is met. When I toggle it back on, the light slider shows 0% but the physical light is not on. Some how the script sets the light from the last state 0% and not 1%.

The slider at 1% does not turn off the light. I need to toggle( in green) it to turn off the light. Toggle again will show at 1% and the light is on.

I tried to explain the best I could. Basically, the light slider needs to be at 1% and not 0% before the light is turned off. Otherwise the light will not turn on next time.

Hooray—that’s great to hear!

Hi @duceduc!

It so happens that there isn’t a particularly easy means to have the script itself stop at 1% brightness and then turn off the light.

That being said, if that may be the behavior that you’re looking for, one way that you could achieve that would be to create an automation with these two actions:

  1. Ashley’s Light Fader: Fade to 1% brightness
  2. Light: Turn Off

ok. I will give this a try. Thx.

Maybe also check issues logged against the integration you’re using for that light, because 0% brightness is synonymous with off in HA (nowadays; this behaviour changed somewhere, maybe last year).

1 Like

Most of my lights are from ikea, but I do have 2 that are from Philips Hue. All my lights are connected to a zigbee coordinator via z2mqtt. I have tested the Philips Hue bulb with the script and it does not behave like the ikea does. The Philips Hue bulb does turn back on at 1%.

Wondering if I need to update the ikea bulb firmware?
Current ikea gu10:

Firmware build date: 20220928
Firmware version: 2.3.095

Hi Ashley,
I have started using your script after you kindly responded in another post about a problem I was having. Your script has worked brilliantly to solve the issue of my light overloading from a tight loop and refusing to finish a fade.

When I looked at your script I wondered if you have ever considered doing RGB fades in addition to the color temperature fades? I was thinking that you already have most of the logic and it would just be a matter of applying it in triplicate. I wrote a very crude proof of concept that you can try if you’d like. (Clearly this is missing all of the special sauce that makes your script so popular.)

alias: Lights Fader with RGB
sequence:
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ is_state(light_entity, 'off') }}"
        sequence:
          - data:
              entity_id: "{{ light_entity }}"
            action: light.turn_on
          - delay: "00:00:01"
  - variables:
      starting_rgb: >
        {{ starting_rgb if starting_rgb is defined else
        (state_attr(light_entity, 'rgb_color')[0], state_attr(light_entity,
        'rgb_color')[1], state_attr(light_entity, 'rgb_color')[2]) if
        state_attr(light_entity, 'rgb_color') is not none else (255, 255, 255)
        }}
      starting_brightness: >
        {{ starting_brightness if starting_brightness is defined else
        state_attr(light_entity, 'brightness') | int if state_attr(light_entity,
        'brightness') is not none else 255 }}
  - data:
      name: Lights Fader
      message: >-
        Captured or provided state: RGB: {{ starting_rgb }}, Brightness: {{
        starting_brightness }} for light: {{ light_entity }}
    action: logbook.log
  - repeat:
      count: "{{ steps | int }}"
      sequence:
        - data_template:
            entity_id: "{{ light_entity }}"
            rgb_color:
              - >-
                {{ (starting_rgb[0] + ((ending_rgb[0] - starting_rgb[0]) /
                steps) * repeat.index) | int }}
              - >-
                {{ (starting_rgb[1] + ((ending_rgb[1] - starting_rgb[1]) /
                steps) * repeat.index) | int }}
              - >-
                {{ (starting_rgb[2] + ((ending_rgb[2] - starting_rgb[2]) /
                steps) * repeat.index) | int }}
            brightness: >-
              {{ (starting_brightness + ((ending_brightness -
              starting_brightness) / steps) * repeat.index) | int }}
          action: light.turn_on
        - delay:
            milliseconds: "{{ (fade_duration / steps * 1000) | int }}"
variables:
  light_entity: "{{ light_entity }}"
  ending_rgb: "{{ ending_rgb | default([255,255,255]) }}"
  ending_brightness: "{{ ending_brightness | default(100) }}"
  fade_duration: "{{ fade_duration | default(20) }}"
  steps: "{{ steps | default(100) }}"
mode: single
description: >
  Fade between two RGB colors or fade from the current state of the light to a
  target RGB color
icon: mdi:color-helper

Then I just did a few very basic actions in an automation.

With Starting RGB and Brightness provided:

action: script.lights_fader_with_rgb
data:
  light_entity: light.master_led_strip
  starting_rgb: [170,13,5]
  starting_brightness: 1
  ending_rgb: [40,40,200]
  ending_brightness: 200
  fade_duration: 20
  steps: 30

Starting from the current state of the light:

action: script.lights_fader_with_rgb
data:
  light_entity: light.master_led_strip
  ending_rgb: [40,40,200]
  ending_brightness: 200
  fade_duration: 20
  steps: 30
1 Like

Hi, @RN-Say—and thanks so much for your kind words!

And thanks also for your detailed message, including even your proof-of-concept code (!). And as RGB fades go, while I can certainly understand the appeal there, it so happens that there are a couple of hitches that can make RGB fades potentially tricky—

  • It so happens that fading between two RGB colors by way a direct straight line can sometimes result in some odd midpoints. For instance, consider this color palette, which I just stumbled upon at color.adobe.com:

Let’s hypothetically suppose that someone had wanted to fade from the third color in that set (4, 191, 157) [light teal] to the fourth color in the set (242, 129, 87) [orange].

If one were to calculate a direct-line fade between those two RGB colors, the mathematical midpoint would be (123, 160, 122), which happens to be sort of a muddy green that doesn’t necessarily come across as being the intuitive midpoint of those two colors?


(screenshot via: rgbcolorpicker.com)

  • And the other sticky part about RGB fades—and this is actually even thornier than the previous quirk—is that there’s no clear means for handling things if someone were to try to fade from an RGB color to a Kelvin color temperature (or the other way: from a Kelvin color temperature to an RGB color). And that’s because—as @parautenbach aptly conveys in this earlier comment—there aren’t any consistent formulas available for converting from RGB to Kelvin (and from Kelvin to RGB):

All in all, I very much appreciate your idea, and if there were a way to make it work, I’d be rather tempted to give it a go! Unfortunately, though, I think that RGB fades might not quite be in the cards for this script.

Wow, just wow. When I first started in Home Assistant I wanted to do something like this but did not have the time to build it. Thank you!

1 Like

There’s a nice illustration in the first answer here: Using HSV might be a better option if you only have a start and end value. I’ve used RGB interpolation in some places, but I have multiple colour stops, so the linear/shortest path issue is less noticable.

1 Like

For colour fading I use this blueprint…

1 Like

Thanks bunches, @Noblewolf—that really means a lot! :rainbow:

2 Likes

Thanks for passing along that resource, @parautenbach!

And with that in hand, I could see that approach potentially helping quite substantially if someone had wanted to put together some code for RGB-to-RGB fades.

(Naturally, when it comes to Ashley’s Light Fader in particular, there would still be the sticky problem of what to do if someone were to attempt to fade from a Kelvin color temperature to an RGB value—or the other way around—but that’s not at all to take away from the value of what’s covered in that Stack Exchange thread that you had linked to about the HSV color space.)

2 Likes

Yeah, it’s different things, so I’d keep them apart. Colour temperature is only valid for black body radiation.

1 Like