Light Fade In

GE Dimmer Switch Connected to SmartThings via MQTT
Created a quick (and dirty) Python script to turn it on slowly over a period of X minutes

entity_id  = data.get('entity_id')
sleep_delay = int(data.get('delay_in_sec'))
start_level_pct = int(data.get('start_level_pct'))
end_level_pct = int(data.get('end_level_pct'))
step_pct  = int(data.get('step_in_level_pct'))

start_level = int(255*start_level_pct/100)
end_level = int(255*end_level_pct/100)
step = int(255*step_pct/100)

new_level = start_level
while new_level < end_level :
	states = hass.states.get(entity_id)
	current_level = states.attributes.get('brightness') or 0
	if (current_level > new_level) :
		logger.info('Exiting Fade In')
		break;
	else :
		logger.info('Setting brightness of ' + str(entity_id) + ' from ' + str(current_level) + ' to ' + str(new_level))
		data = { "entity_id" : entity_id, "brightness" : new_level }
		hass.services.call('light', 'turn_on', data)
		new_level = new_level + step
		time.sleep(sleep_delay)

And an automation to call this at 6 in the morning: (This example gradually turns the brightness from 1 to 50 percent over a period of 30 minutes - 1 percent increase in every 36 seconds)

- id: fade_in__light
  alias: Bedroom Light Fade In
  trigger:
    - platform: time
      at: "06:00:00"
  action:
    - service: python_script.fade_in_light
      data:
        entity_id: light.bedroom_light
        delay_in_sec: 36
        start_level_pct: 1
        end_level_pct: 50
        step_in_level_pct: 1
19 Likes

Thanks for your script !
I am new to HASS, I tried to use it but I’ve the following error :

2017-12-13 23:02:00 ERROR (SyncWorker_4) [homeassistant.components.python_script] Error loading script light_fade_in.py: Line 15: SyntaxError: invalid syntax in on statement: while new_level < end_level

Does somebody know why ?
Tahnks

Yes, I had missed a colon at the end of the line
Change that line to

while new_level < end_level :

1 Like

Yes, I have just done that after reading a python loop tutorial.
Then I have replaced

    step_pct: 1 

by

    step_in_level_pct: 1

but still doesn’t work.
Really don’t know why…

I’ve just updated the scripts. Try wrapping the variables in the logger line to String typecasting

And replace data_template with data in the automation yaml

Thanks now everything works fine.
Is there a way to avoid this :

[homeassistant.components.python_script] Using time.sleep can reduce the performance of Home Assistant

Its just a warning… Since the script is running outside homeassistant, I do not expect much issues, though… However, I do think we may be able to avoid this warning by using threading.Timer and moving the while loop to a function…

Works like a charm with my telldus lights. Thanks a bunch for this script!

Using a input_datetime component in the UI to set the time I can finally wake up to a nice indoor sunrise

My automation:

- alias: wakeup_light
  trigger:
  - platform: template
    value_template: '{{ now().strftime("%H:%M:00") == (states.input_datetime.wakeup_time.state)}}'
  action:
  - service: python_script.fade_in_light
    data:
      delay_in_sec: 30
      end_level_pct: 100
      entity_id: light.bedroom_ceiling
      start_level_pct: 1
      step_in_level_pct: 5
2 Likes

This works great for my GE / Jasco ZW3101 zwave dimmer module! I know very little about python scripting and this was my first adventure into adding a python script to HA. I just wanted to expand on finnysamuel’s and add a few tips for new folks:

For starters I needed to enable python scripts, in configuration.yaml I added this line:

python_script:

I am running hassbian, so I created a scripts folder in the HA directory:

mkdir /home/homeassistant/.homeassistant/python_scripts

I created a fade_in and fade_out script, I am not sure if these needed to be executable or not, I made them just in case.

pi@hassbian:/home/homeassistant/.homeassistant/python_scripts $ ls -al
-rwxr-xr-x 1 homeassistant homeassistant  979 Apr 29 10:06 fade_in_light.py
-rwxr-xr-x 1 homeassistant homeassistant 1003 Apr 29 09:49 fade_out_light.py

Here is what my two scripts looks like:

Fade in:
Note: the only change I really made to finnysamuel’s work was at the end, I noticed I was unable to get to 100% brightness without it.

entity_id  = data.get('entity_id')
sleep_delay = int(data.get('delay_in_sec'))
start_level_pct = int(data.get('start_level_pct'))
end_level_pct = int(data.get('end_level_pct'))
step_pct  = int(data.get('step_in_level_pct'))

start_level = int(255*start_level_pct/100)
end_level = int(255*end_level_pct/100)
step = int(255*step_pct/100)

new_level = start_level
while new_level < end_level :
        states = hass.states.get(entity_id)
        current_level = states.attributes.get('brightness') or 0
        if (current_level > new_level) :
                logger.info('Exiting fade in - light already on')
                break;
        else :
                logger.info('Setting brightness of ' + str(entity_id) + ' from ' + str(current_level) + ' to ' + str(new_level))
                data = { "entity_id" : entity_id, "brightness" : new_level }
                hass.services.call('light', 'turn_on', data)
                new_level = new_level + step
                time.sleep(sleep_delay)

data = { "entity_id" : entity_id, "brightness" : end_level }
hass.services.call('light', 'turn_on', data)

Fade Out:

entity_id  = data.get('entity_id')
sleep_delay = int(data.get('delay_in_sec'))
start_level_pct = int(data.get('start_level_pct'))
end_level_pct = int(data.get('end_level_pct'))
step_pct  = int(data.get('step_in_level_pct'))

start_level = int(255*start_level_pct/100)
end_level = int(255*end_level_pct/100)
step = int(255*step_pct/100)

new_level = start_level
while new_level >= end_level :
        states = hass.states.get(entity_id)
        current_level = states.attributes.get('brightness') or 0
        if (current_level < new_level) :
                logger.info('Exiting fade out - light already dimmed')
                break;
        else :
                logger.info('Setting brightness of ' + str(entity_id) + ' from ' + str(current_level) + ' to ' + str(new_level))
                data = { "entity_id" : entity_id, "brightness" : new_level }
                hass.services.call('light', 'turn_on', data)
                new_level = new_level - step
                time.sleep(sleep_delay)

data = { "entity_id" : entity_id, "brightness" : end_level }
hass.services.call('light', 'turn_on', data)

Here are my automatons:

- alias: Family Room Light 15min Fade to 100% starting an hour before sunset
  trigger:
    platform: sun
    event: sunset
    offset: "-01:00:00"
  action:
    - service: python_script.fade_in_light
      data:
        entity_id: light.level
        delay_in_sec: 9
        start_level_pct: 0
        end_level_pct: 100
        step_in_level_pct: 1

- alias: Family Room Light 15min Fade to 30%
  trigger:
    platform: time
    at: '22:00:00'
  action:
    - service: python_script.fade_out_light
      data:
        entity_id: light.level
        delay_in_sec: 12.85
        start_level_pct: 100
        end_level_pct: 30
        step_in_level_pct: 1

I hope this helps some folks

EDIT: Thanks jmart518 for the fix on the fade out.

5 Likes

Thanks for sharing!

I do have an issue with the fade_out script. No matter what value I put for end_level_pct, my light fades to the same point everytime. ~46% or Brightness: 118.

Any ideas on what would cause this?

EDIT: Fixed by adding this to the bottom of the fade out script

data = { "entity_id" : entity_id, "brightness" : end_level }
hass.services.call('light', 'turn_on', data)

I merged both fade_in and fade_out scripts into one and changed the parameters to more closely match the arguments in the light component.

This uses the current brightness of the light and will fade over the specified transition time (in seconds) to the brightness value specified.

The script calculates the delay time based on the number of steps between current and end brightness. This delay value cannot be lower than 3/4 second as the python script doesn’t seem to execute faster than that.

I need to figure out how to set the stepping of the brightness better since shorter transition times would require larger steps due to how slow the script runs. This probably needs to be logarithmic. Currently if the transition vs the brightness change causes the delay to go under 3/4 of a second, it sets the stepping to 5.

"""
https://community.home-assistant.io/t/light-fade-in/35509

automation:
- alias: Light 15min Fade to 100% starting an hour before sunset
    trigger:
    platform: sun
    event: sunset
    offset: "-01:00:00"
    action:
    - service: python_script.zwave_fade
        data:
          entity_id: light.level  # Entity ID to fade
          transition: 20  # Seconds to go from current to end brightness
          brightness_pct: 100  # Brightness to end at as a percentage
          brightness: 255  # Brightness to end at (overrides brightness_pct)
"""

entity_id = data.get('entity_id')
brightness = data.get('brightness', None)
brightness_pct = data.get('brightness_pct', None)

if entity_id is not None and (brightness is not None or brightness_pct is not None):
    light = hass.states.get(entity_id)

    start_level = light.attributes.get('brightness', 0)
    transition = data.get('transition', 0)

    """ Use brightness or convert brightness_pct """
    end_level = int(brightness) if brightness is not None else math.ceil(
        brightness_pct * 2.55)

    """ Calculate number of steps """
    steps = int(math.fabs((start_level - end_level)))
    fadeout = True if start_level > end_level else False

    """ Calculate the delay time """
    delay = round(transition / steps, 3)

    """ Disable delay anbd increase stepping if delay < 3/4 second """
    if (delay < .750):
        delay = 0
        steps = int(steps / 5)
        step_by = 5
    else:
        step_by = 1

    logger.info('Setting brightness of ' + str(entity_id) +
                ' from ' + str(start_level) + ' to ' + str(end_level) +
                ' steps ' + str(steps) + ' delay ' + str(delay))

    new_level = start_level
    for x in range(steps):
        current_level = light.attributes.get('brightness', 0)
        if (fadeout and current_level < new_level):
            break
        elif (not fadeout and current_level > new_level):
            break
        else:
            data = {"entity_id": entity_id, "brightness": new_level}
            hass.services.call('light', 'turn_on', data)
            if (fadeout):
                new_level = new_level - step_by
            else:
                new_level = new_level + step_by
            """ Do not sleep for 0 delay """
            if (delay > 0):
                time.sleep(delay)

""" Ensure light ends at the final state """
if (end_level > 0):
    data = {"entity_id": entity_id, "brightness": end_level}
    hass.services.call('light', 'turn_on', data)
else:
    data = {"entity_id": entity_id}
    hass.services.call('light', 'turn_off', data)
5 Likes

Oh awesome. I’ve been procrastinating writing something like this for a long time!

Great job! Love this so far… i’m planning on using this to set a wake up light, so transition is set too 900.

Now, how do i stop this python script when it’s running? If i let this script run from a script in ha and would like to stop it when i am awake.

How smooth is this fade out? I have Fade Out scripts that I use which recursively call themselves, but in some cases the dimming is a little clunky and jarring

I’m not sure how to stop a currently running script. If there isn’t something built in to hass you could probably create an input boolean, add a check to this script for the value, and end it when that value equals something.

1 Like

It’s not smooth at all as it increments/decrements the brightness value directly. Since zwave lights only have 255 levels of brightness, it’s noticeable if the transition time is short. However, if you run this over a longer period like a minute or more, then the stepping isn’t as noticeable. I also mainly use this to fade out my living lights over an hour after 10pm and I don’t really notice it fading out.

I mainly rewrote this to see if I could simplify the usage of the script. I wanted it to use the current brightness, not have to pass a delay parameter, to more closely match the arguments in the light component, and combine it into one script.

1 Like

Ok thanks! Sounds like it produces similar results. Good work!

[homeassistant.components.python_script.fade_light.py] Error executing script: can't multiply 
sequence by non-int of type 'float'
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.6/site- 
packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "fade_light.py", line 30, in <module>
TypeError: can't multiply sequence by non-int of type 'float'

I think it’s this line you are having issues with

end_level = int(brightness) if brightness is not None else math.ceil(brightness_pct * 2.55)

It seems that if you pass any of the values in as a string then you get errors like this

Here is updated code that should account for strings

"""
https://community.home-assistant.io/t/light-fade-in/35509

automation:
- alias: Light 15min Fade to 100% starting an hour before sunset
    trigger:
    platform: sun
    event: sunset
    offset: "-01:00:00"
    action:
    - service: python_script.zwave_fade
        data:
          entity_id: light.level  # Entity ID to fade
          transition: 20  # Seconds to go from current to end brightness
          brightness: 255  # Brightness to end at
          brightness_pct: 100  # Brightness to end at as a percentage
"""

entity_id = data.get('entity_id')
brightness = data.get('brightness', None)
brightness_pct = data.get('brightness_pct', None)

if entity_id is not None and (brightness is not None or brightness_pct is not None):
    light = hass.states.get(entity_id)

    start_level = light.attributes.get('brightness', 0)
    transition = int(data.get('transition', 0))

    """ Use brightness or convert brightness_pct """
    end_level = int(brightness) if brightness is not None else math.ceil(
        float(brightness_pct) * 2.55)

    """ Calculate number of steps """
    steps = int(math.fabs((start_level - end_level)))
    fadeout = True if start_level > end_level else False

    """ Calculate the delay time """
    delay = round(transition / steps, 3)

    """ Disable delay anbd increase stepping if delay < 3/4 second """
    if (delay < .750):
        delay = 0
        steps = int(steps / 5)
        step_by = 5
    else:
        step_by = 1

    logger.info('Setting brightness of ' + str(entity_id) +
                ' from ' + str(start_level) + ' to ' + str(end_level) +
                ' steps ' + str(steps) + ' delay ' + str(delay))

    new_level = start_level
    for x in range(steps):
        current_level = light.attributes.get('brightness', 0)
        if (fadeout and current_level < new_level):
            break
        elif (not fadeout and current_level > new_level):
            break
        else:
            data = {"entity_id": entity_id, "brightness": new_level}
            hass.services.call('light', 'turn_on', data)
            if (fadeout):
                new_level = new_level - step_by
            else:
                new_level = new_level + step_by
            """ Do not sleep for 0 delay """
            if (delay > 0):
                time.sleep(delay)

""" Ensure light ends at the final state """
if (end_level > 0):
    data = {"entity_id": entity_id, "brightness": end_level}
    hass.services.call('light', 'turn_on', data)
else:
    data = {"entity_id": entity_id}
    hass.services.call('light', 'turn_off', data)
1 Like