This fall, right after the time change, I found myself often working intensely enough to suddenly notice "it was dark outside" in the late afternoon. Good for productivity, I suppose; not so much otherwise? ¯\_(ツ)_/¯
I'd automated a whole bunch of other light situations, mostly with some combination of brightness level (obtained from my Tempest weather station) and/or time-based. But all of those solutions were "binary" (on/off). My thought here was to slowly and incrementally bring up the overhead smart lights in my home office space.
Multiple Options Available
I did a little cursory The Googling on the process, and found some elegant and "complete" solutions for this sort of thing. Most involved installing a script or blueprint and configuring things to your liking. The more I looked, the more I found stuff that worked but seemed like overkill for what I wanted: just a stepped-up sequence over a time period (slow change). Besides, I'd like to understand what I'm doing, so just grabbing someone else's solution and making it work for me wasn't desirable, especially when working with the scripts node.
The First Attempt
I'd only created one other script in Home Assistant before, to handle the garage door opener business (converting my 23-year-old door opener to a "smart" opener). So I figured for a first or proof-of-concept attempt I'd use things I'm more familiar with, namely timers and scenes.
I created a 20-minute timer to handle the "interval" between steps up on the brightness. I then created a set of scenes for the brightness "steps" I wanted (10% to 50%, the first being the starting step and the last being the normal "on" brightness in the space).
Then comes the automation. Ultimately it's an automation with two triggers, a time-based condition (I only want this to run at a certain time period of the day), and a series of conditional actions based on the light state when the automation was triggered, like so (simplified for readability):
Triggers
trigger:
- platform: state
entity_id:
- timer.stepped_lights_timer
from: active
to: idle
- type: illuminance
platform: device
device_id: guid-of-illuminance_sensor
entity_id: sensor.illuminance_sensor
domain: sensor
below: 6000
This will call the automation whenever the timer ends or when the outside brightness drops below my setpoint (6,000 lux in the example).
Conditional
I only want this to run on weekdays (in the window of 3-6 p.m.) and when "I'm home" (my phone is on the network):
condition:
- condition: and
conditions:
- condition: time
weekday:
- mon
- tue
- thu
- wed
- fri
after: "15:00:00"
before: "18:00:00"
- condition: state
entity_id: device_tracker.unifi_mac_address_of_phone
state: home
Actions
There are a whole set of conditions in the actual automation (from "off" to the threshold for my lights when they're 40%), but for simplicity I've included three states: lights are off; lights at 20% (increment brightness to 30%); and lights at 40% (last increment):
action:
- if:
- condition: device
type: is_off
device_id: guid-of-office_fl1
entity_id: light.office_fl1
domain: light
then:
- service: timer.start
data: {}
target:
entity_id: timer.stepped_lights_timer
- service: scene.turn_on
target:
entity_id: scene.office_lights_10
metadata: {}
- if:
- condition: numeric_state
entity_id: light.office_fan_lights
attribute: brightness
above: 41
below: 61
then:
- service: timer.start
data: {}
target:
entity_id: timer.stepped_lights_timer
- service: scene.turn_on
target:
entity_id: scene.office_lights_30
metadata: {}
- if:
- condition: numeric_state
entity_id: light.office_fan_lights
attribute: brightness
above: 92
below: 112
then:
- service: scene.turn_on
target:
entity_id: scene.office_lights_50
metadata: {}
The Outcome?
Hey, it worked great! I had to do some tinkering to get the above
and below
values for the actions (via the states developer tool in Home Assistant), but it worked great. Every twenty minutes (once invoked) the light would increase in brightness by 10% until it hit 50% -- my setpoint for the normal on/off switch.
HOWEVER, I knew there was a better way to set this up without requiring all the different scenes and timer, along with all the moving parts (conditional actions) of the automation. After using this automation for a few days, I moved to...
The Second Attempt
Knowing my idea wasn't totally bonkers and actually provided the desired outcome, I wanted to button and clean it up. This meant using a script, but that was less gnarly because I knew the working parts in question by this point so it was more a matter of stitching things together. Bonus points since it only requires two things: the automation and a script (no timers or scenes).
The beautiful part of this is the automation itself is far simpler:
The Automation
trigger:
- type: illuminance
platform: device
device_id: guid-of-illuminance_sensor
entity_id: sensor.illuminance_sensor
domain: sensor
below: 6000
condition:
- condition: and
conditions:
- condition: time
after: "15:00:00"
before: "18:00:00"
weekday:
- mon
- tue
- wed
- thu
- fri
- condition: state
entity_id: device_tracker.unifi_mac_address_of_phone
state: home
action:
- service: script.office_light_stepped_fade_up
data: {}
This is way easier to read and understand than the first attempt (especially in UI mode), and ultimately it just calls the script where the real action takes place!
The Script
In ~30 lines, this script handles all the details we were doing before, but in one "thing:"
sequence:
- variables:
initial_brightness_pct: 10
step_brightness: 10
time_delay_mins: 18
target_brightness_pct: 50
iterations: "{{ (target_brightness_pct - initial_brightness_pct) / step_brightness }}"
- service: light.turn_on
data:
brightness_pct: "{{ initial_brightness_pct }}"
target:
entity_id: light.office_fan_lights
enabled: true
- delay:
hours: 0
minutes: "{{ time_delay_mins }}"
seconds: 0
milliseconds: 0
enabled: true
- repeat:
sequence:
- service: light.turn_on
data:
brightness_step_pct: "{{ step_brightness }}"
target:
entity_id: light.office_fan_lights
- delay:
hours: 0
minutes: "{{ time_delay_mins }}"
seconds: 0
milliseconds: 0
count: "{{ iterations }}"
enabled: true
A couple of things happen here when the script is invoked/called:
- I create a set of variables for the script such as initial step, step percentage, target brightness, and delay between steps (in minutes). Using basic math, I determine the number of
iterations
it would take to get from the initial step to the target when jumping by step_brightness
): (target_brightness_pct - initial_brightness_pct) / step_brightness
- The light group is turned on with a
brightness_pct
value of initial_brightness_pct
(in this example 10%) - Delay/Pause for
time_delay_mins
- Repeat the same business from steps 2 and 3
iterations
times (except increment by step_brightness
when repeating)
When this script completes, the lights will step up in brightness by 10% five times over the course of 72 minutes (three iterations (18 minutes) plus the initial 18-minute delay). Now, I could have combined the initial turn_on
with the repeat sequence...but I chose to keep them separate for flexibility. I could start the sequence at 5% and have 10% steps, or some other combination where having the initial step be "different" than the increment could be useful. That's why the first step is outside of the repeat/loop.
The Outcome?
I really like this scripted option. I can keep things "together" (the variables, settings, etc.) and the automation and flow is far easier to understand than my first go. This option could also be made more extensible/modular for other lights, etc. by changing variables and such. And it's clean compared to what I was seeing in Google results!
Best of All...
When I tweaked the various settings such as the brightness invocation point (lux) and delay, the office light comes on and increments almost perfectly to offset the setting sun. It's very subtle; many days I don't even notice the steps (or when the light initially turns on) until well into the cycle.
There are several ways to solve this particular problem, but this solution was relatively simple and easy for me to implement -- both ways! It was a fun automation to build out and think through. Full disclosure, though, I've since deleted the original automation and timer because they were no longer necessary!
Good luck!