How can i make automations with transition while the device doesnt support it?

It’s this part here:

(b | round(0, default=0) == start_pct + ((repeat.index - 1) * sign))

It’s checking if light’s current brightness value is equal to the previous value that it had set. If it isn’t then (someone/something external to the automation had changed it) the Template Condition reports false and the while stops looping.

1 Like

Cool, thanks! But that also implies I’ll need these two lines, where b gets defined, right?

{% set b = state_attr(light, 'brightness') %}
{% set b = (b/255*100)|round(0, default=0) if b != none else b %}

Yes; I was merely pointing out the part responsible for what I mentioned earlier:

Again, thanks for your input dude, appreciate you taking the time answering!

Simply adding in those bits doesn’t seem to work for me. Once i replace:

 - repeat:
     while:
       - condition: template
         value_template: >-
           {{  repeat.index <= n }}

with:

- repeat:
    while:
      - condition: template
        value_template: >-
          {% set b = state_attr(light, 'brightness') %}
          {% set b = (b/255*100)|round(0, default=0) if b != none else b %}
          {{  repeat.index <= n and
              ( (sign ==  1 and (b == none or b < end_pct)) or
              (sign == -1 and (b != none or b|int(0) > end_pct)) ) and 
              (b | round(0, default=0) == start_pct + ((repeat.index - 1) * sign)) }}

The light only turns on and it halts/stops. So far I can confirm these two lines by themselves don’t cause any issues:

{% set b = state_attr(light, 'brightness') %}
{% set b = (b/255*100)|round(0, default=0) if b != none else b %}

So I think it’s down to this bit:

{{  repeat.index <= n and
    ( (sign ==  1 and (b == none or b < end_pct)) or
      (sign == -1 and (b != none or b|int(0) > end_pct)) ) and 
    (b | round(0, default=0) == start_pct + ((repeat.index - 1) * sign)) }}

Could it be simply an issue with my indentation?

Looked some deeper into the traces of this script… and it this line specifically that makes it returns false after the first iteration:

    (b | round(0, default=0) == start_pct + ((repeat.index - 1) * sign)) }}

Ok I’ve managed to get it working by adding more tolerance with this adjustment:

(b | round(0, default=0) - (start_pct + ((repeat.index - 1) * sign))) | abs < 3 }}

This together with a slightly longer time-frames worked. I was testing it with 60 seconds, setting this to 180 seconds at least made everything work flawlessly. Works for me as I don’t intend to use this sort of a timeframe for transitions.

When manually switched off, the script will halt.

Final version:

fade_light_v2:
  description: "Fades lights to a desired level over a specified transition period."
  fields:
    light:
      name: Light
      description: Entity_id of light.
      selector:
        entity:
          domain: light
      example: light.kitchen
    end_pct:
      name: End brightness Level
      description: Integer value from 0 to 100 representing the desired final brightness level.
      selector:
        number:
          min: 0
          max: 100
          step: 1
          mode: slider
      default: 50
      example: "50"
    transition:
      name: Transition Time
      description: Transition time for fading in seconds.
      selector:
        number:
          min: 0
          max: 1800
          step: 1
          mode: slider
      default: 10
      example: "10"
  mode: parallel
  sequence:
    - variables:
        start_pct: "{{ ((state_attr(light, 'brightness') | int(0))/255*100) | round(0, default=0) }}"
        end_pct: "{{ end_pct | int(0) | round(0, default=0) }}"
        delay_msec: >-
          {{ ([100, (((transition / (end_pct - start_pct)) | abs) | round(3, default=0) * 1000) | int(0)]|sort)[1] }}
        sign: "{{ 1 if start_pct < end_pct else -1 }}"
        n: "{{ 1000 * transition / delay_msec | int(0) }}"
    - repeat:
        while:
          - condition: template
            value_template: >-
              {% set b = state_attr(light, 'brightness') %}
              {% set b = (b/255*100)|round(0, default=0) if b != none else b %}
              {{  repeat.index <= n and
              ( (sign ==  1 and (b == none or b < end_pct)) or 
              (sign == -1 and (b != none or b|int(0) > end_pct)) ) and 
              (b | round(0, default=0) - (start_pct + ((repeat.index - 1) * sign))) | abs < 3 }}
        sequence:
          - delay:
              milliseconds: "{{ delay_msec }}"
          - service: light.turn_on
            target:
              entity_id: "{{ light }}"
            data:
              brightness_pct: "{{ ([0, (start_pct + (repeat.index * sign)), 100]|sort)[1] }}"
1 Like

What kind of lighting do you have that its brightness doesn’t match what it was set to?

My guess is whatever lighting integration you’re using experiences communication problems (‘flooding’) when the interval between successive commands is very short.

I’m trying to do the same thing as everyone else here but over long transition times (15m). I’m using the transition as a morning “sunrise” alarm. After running cleanly for 30 seconds or so, the script fails with:

Stopped because an error was encountered at 5 January 2023 at 07:00:37 (runtime: 36.88 seconds)
string indices must be integers

The script is called from an automation that is currently set to trigger at 7am weekdays. I’m passing in target brightness of 100% and a transition time of 900s, along with my light entity.

Anyone able to help me troubleshoot this?

The script I’m using is:

description: Fades lights to a desired level over a specified transition period.
fields:
  light:
    name: Light
    description: Entity_id of light.
    selector:
      entity:
        domain: light
    example: light.kitchen
  end_pct:
    name: End brightness Level
    description: >-
      Integer value from 0 to 100 representing the desired final brightness
      level.
    selector:
      number:
        min: 0
        max: 100
        step: 1
        mode: slider
    default: 50
    example: "50"
  transition:
    name: Transition Time
    description: Transition time for fading in seconds.
    selector:
      number:
        min: 0
        max: 1800
        step: 1
        mode: slider
    default: 10
    example: "10"
mode: parallel
sequence:
  - variables:
      start_pct: >-
        {{ ((state_attr(light, 'brightness') | int(0))/255*100) | round(0,
        default=0) }}
      end_pct: "{{ end_pct | int(0) | round(0, default=0) }}"
      delay_msec: >-
        {{ ([100, (((transition / (end_pct - start_pct)) | abs) | round(3,
        default=0) * 1000) | int(0)]|sort)[1] }}
      sign: "{{ 1 if start_pct < end_pct else -1 }}"
      "n": "{{ 1000 * transition / delay_msec | int(0) }}"
  - repeat:
      while:
        - condition: template
          value_template: "{{  repeat.index <= n }}"
      sequence:
        - delay:
            milliseconds: "{{ delay_msec }}"
        - service: light.turn_on
          target:
            entity_id: "{{ light }}"
          data:
            brightness_pct: "{{ ([0, (start_pct + (repeat.index * sign)), 100]|sort)[1] }}"
alias: ""
max: 10

Where do I put this code? In my script.yaml with your inintal code or do I add this somewhere else. It is just I do not know where to put the fade out light code. I do not see where you say to put it.

We don’t know how your config is structured and whether you do everything in YAML or also via the UI. If you look at the script documentation, it’s telling you it must go under a singular script: key in your configuration.yaml, but if your config is split it could be different (packages can repeat keys). Do you have a script.yaml? Then it would be a yes (most likely).

Hey all, I modified ReanuKeeves01 script to fade lights slightly differently.

I found the script ReanuKeeves01 posted worked great except it only ever faded the light in ticks of 1%. This meant to go from 100% to 10%, you needed 90 ticks. Ticks are limited to a minimum of 100ms. Assuming this limit is a common smart light hardware limitation; mine didn’t change faster when I went below 100ms.
This all meant to go from 100% to 10%, the minimum transition time you need to put is 9 seconds. The fastest rate is 10% every 1 second.

I’ve updated the script to now always fade in the time you set on the transition. It does this by calculating the perfect brightness % tick and delay MS.

For example if you want to go from 100% to 10% in 4 seconds, it calculates that it needs to tick 3% every 133ms, and it fades at that rate without issue.

tl;dr This script works very well when you want to fade large % amounts quickly.

The updated script:

alias: Light Fader
description: Fades lights to a desired level over a specified transition period.
fields:
  light:
    name: Light
    description: Entity_id of light.
    selector:
      entity:
        domain: light
    example: light.kitchen
  end_pct:
    name: End brightness Level
    description: >-
      Integer value from 0 to 100 representing the desired final brightness
      level.
    selector:
      number:
        min: 0
        max: 100
        step: 1
        mode: slider
    default: 50
    example: "50"
  transition:
    name: Transition Time
    description: >-
      Transition time for fading in seconds. Tick rate of brightness % is
      dependant on this and total brightness % traversed.
    selector:
      number:
        min: 0
        max: 1800
        step: 1
        mode: slider
    default: 10
    example: "10"
mode: parallel
sequence:
  - variables:
      start_pct: >-
        {{ ((state_attr(light, 'brightness') | int(0))/255*100) | round(0,
        default=0) }}
      end_pct: "{{ end_pct | int(0) | round(0, default=0) }}"
      delay_msec: >-
        {% set min = (((transition / (end_pct - start_pct)) | abs) |
        round(3,default=0) * 1000) %} {{ (min * ((100 / min) | round(0,
        "ceil"))) | int(0) }}
      tick_pct: >-
        {{ ([1, (((start_pct - end_pct)|abs) / (transition * (1000 /
        delay_msec)))|round]|sort)[1] }}
      sign: "{{ tick_pct if start_pct < end_pct else tick_pct * -1 }}"
      "n": "{{ transition * (1000 / delay_msec) | int(0) }}"
  - repeat:
      while:
        - condition: template
          value_template: >-
            {% set b = state_attr(light, 'brightness') %} {% set b =
            (b/255*100)|round(0, default=0) if b != none else b %} {{ 
            repeat.index <= n and ( (sign >= 1 and (b == none or b < end_pct))
            or  (sign <= -1 and (b != none or b|int(0) > end_pct)) ) and  (b |
            round(0, default=0) - (start_pct + ((repeat.index - 1) * sign))) |
            abs < 3 }}
      sequence:
        - delay:
            milliseconds: "{{ delay_msec }}"
        - service: light.turn_on
          target:
            entity_id: "{{ light }}"
          data:
            brightness_pct: "{{ ([0, (start_pct + (repeat.index * sign)), 100]|sort)[1] }}"
max: 10
1 Like

@TimeBomb First off, I just want to say that I so appreciate all the effort that you put into this script!

And while I don’t at all want to take away from that, I think that I may have come across a potential bug that—just based on my Spidey-sense alone—miiiight potentially stem from a rounding issue somewhere?

Known-good scenario:

If I have a light that starts at 0% (off), and I set it to fade to 20% over a span of 10 seconds, that works as expected.

service: script.light_fader
data:
  light: light.living_room_lamps
  end_pct: 20
  transition: 10

Weirdness scenario:

On the other hand, if I have a light that starts at 0% (off), and I set it to fade to 20% over a span of 11 seconds, then that doesn’t quite seem to work?

In this scenario, the lamp fades from 0% to 11%—and then it stops.

service: script.light_fader
data:
  light: light.living_room_lamps
  end_pct: 20
  transition: 11

Would you happen to have any ideas there?

Anyone having light fader script issues now?

I updated HA after going a couple months and now my used-to-work scripts are going nuts with this error:

Error executing script. Error rendering template for call_service at pos 1: ZeroDivisionError: division by zero

Testing the once working values in developer tools ends up giving me this:

fade_light_v2: Error executing script. Error rendering template for variables at pos 1: ZeroDivisionError: division by zero

I went back and took anything that was divisible by 10 and changed it to all odd numbers. Some values work, some do not.

One example that is failing now:

  - service: script.fade_light_v2
    data:
      light: light.hallway_main_lights
      end_pct: 9
      transition: 120

The script I’ve been running on is:

    - variables:
        start_pct: "{{ ((state_attr(light, 'brightness') | int(0))/255*100) | round(0, default=0) }}"
        end_pct: "{{ end_pct | int(0) | round(0, default=0) }}"
        delay_msec: >-
          {{ ([100, (((transition / (end_pct - start_pct)) | abs) | round(3, default=0) * 1000) | int(0)]|sort)[1] }}
        sign: "{{ 1 if start_pct < end_pct else -1 }}"
        n: "{{ 1000 * transition / delay_msec | int(0) }}"
    - repeat:
        while:
          - condition: template
            value_template: >-
              {% set b = state_attr(light, 'brightness') %}
              {% set b = (b/255*100)|round(0, default=0) if b != none else b %}
              {{  repeat.index <= n and
              ( (sign ==  1 and (b == none or b < end_pct)) or 
              (sign == -1 and (b != none or b|int(0) > end_pct)) ) and 
              (b | round(0, default=0) - (start_pct + ((repeat.index - 1) * sign))) | abs < 3 }}
        sequence:
          - delay:
              milliseconds: "{{ delay_msec }}"
          - service: light.turn_on
            target:
              entity_id: "{{ light }}"
            data:
              brightness_pct: "{{ ([0, (start_pct + (repeat.index * sign)), 100]|sort)[1] }}"    

Perplexed. Happy to send beer or two to someone who solves.

@TimeBomb continuing my post above about these scripts not working any longer in the latest HA, I switched to your script on HA 2023.6.2 and it also has all these errors which used to not occur in prior HA releases. Curious if you have any insight.

Example error:

Logger: homeassistant.components.automation.kitchen_lights_on_with_no_cloud_cover_already_on_adjustment
Source: components/automation/init.py:580
Integration: Automation (documentation, issues)
First occurred: 9:06:54 AM (1 occurrences)
Last logged: 9:06:54 AM
Error while executing automation automation.kitchen_lights_on_with_no_cloud_cover_already_on_adjustment: ZeroDivisionError: division by zero

Example’s automation action:

  action:
  - parallel:
    - service: script.fade_light_v3
      data:
        light: light.kitchen_main_lights
        end_pct: 0
        transition: 200
    - service: script.fade_light_v3
      data:
        light: light.kitchen_under_cabinet
        end_pct: 30
        transition: 180
    - service: light.turn_off
      target:
        entity_id: light.kitchen_sink_light

The problem is the script defaults to 0 for various things and if for some reason it needs to default then it would divide by 0.

First question, does your light have an attribute brightness?

Morning. On the road but didn’t want to not reply. My setup worked fine previously, but apparently something over updates stopped working. I use a new script recommended by @123 and it has been flawlessly and is more versatile than these previous ones.

The longest response ever but… I was using the UI… I did give up but here I am again more mature lol… Trying again.

This is my code. PLEASE if you see anything in my hotmess that can be improved upon (ANYONE) please tell me…

alias: Stremo Stops
description: Living Room Area
trigger:
  - platform: template
    value_template: >-
      {{ state_attr('media_player.android_tv_192_168_42_236', 'app_name') in
      ['stremio','Netflix', 'Hulu'] }}
    enabled: true
  - platform: device
    device_id: 39454180ddc15f07ef9c4cc1e6a4483d
    domain: media_player
    entity_id: 4d36e671555e1840ec54f1e3d844fc71
    type: paused
condition: []
action:
  - type: turn_on
    device_id: 265083593c6d894e16bfffce5bc68473
    entity_id: light.movie_5_end_movie
    domain: light
    enabled: true
  - service: scene.turn_on
    target:
      entity_id: scene.movie_5_end_movie_end_movie
    metadata: {}
  - service: google_assistant_sdk.send_text_command
    data:
      command: turn on fan
  - delay:
      hours: 0
      minutes: 0
      seconds: 10
      milliseconds: 0
  - service: scene.turn_on
    target:
      entity_id: scene.kitchen_edison
    metadata: {}
  - service: scene.turn_on
    target:
      entity_id: scene.living_room_edison
    metadata: {}
  - service: scene.turn_on
    target:
      entity_id: scene.hallway_edison
    metadata: {}
  - service: scene.turn_on
    target:
      entity_id: scene.balcony_raptors
    metadata: {}
  - service: scene.turn_on
    target:
      entity_id: scene.dining_room_dimmed
    metadata: {}
mode: single

Hello @123, first off thank you very much for all your work on this, and of course, thank you to mrsnyds for starting all this. I really hope I can start fading in and out some of the lights in my house.

I’m slowly figuring out how to implement this script into my HASS. I got as far as adding the script you provided to my scripts.yaml. I see it under services, but for some reason, the transition time differs from your screenshot and shows actual 24 hours time with AM/PM rather than a range of determined time.

I don’t know enough about scripts in HASS to make any changes without potentially breaking it, but is there a way to fix this?

edit 1: this is how it looks in YAML mode

You’re welcome!

I suggest you consider using something created more recently, for example this script has more functionality and currently gets updates from its author (handcoding) and technical support:

2 Likes

@123 thank you very much for the suggestion. Wish me luck! :smiley:

1 Like