RM Example: Circadian Color Temperature

see this post for the newest rules:

original post

I created a rule to slowly adjust the color temp of my lights from 6500K down to 2200-2700K (depending on the light) throughout the day. I'm not trying to recreate a circadian pattern so much as I am trying to actively hack it by suppressing melatonin the morning and then having nice warm light in the evening to encourage melatonin production. The rule sets the color temp to 6500K right before my 5am alarm and then starts a downward march at sunrise and lands on nice warm lighting by sunset. for my sengled color bulbs I take them all the way down to 2200 over the hour after sunset.

In addition to all that, there are also two global variables %colorTemp% and %colorTemp2700% that I then call from the specific lighting rules for each individual lamp (this has greatly simplified my lighting rules as I was previously changing the color temperature of lights based on modes).

my feature request is for @bravenel and is as follows:
It would be nice to able to call the system sunrise and sunset variables without having to recreate them as I do here in order to do math based on those times. The problem is that if my hub gets flaky at sunset the night before, my rule flies off the rails the next day. Between hub updates or hubconnect or some network issue, if I miss that 1 minute window at sunrise or sunset my lights get all weird and I have to use an online unix timestamp conversion tool to manually repair things. If I could use the system variables, then I think it would make things much more reliable.

Just and idea here: instead of doing everything in one rule, break it up.

Make one that tiggers at sunrise and sets a global variable “sunrise”
Make another one that triggers at sunset that sets a global variable “sunset”
Change the rule above to trigger when the global variables sunrise or sunset changed

This way you can discount the “flaky” situations as you don’t need that IF at the beginning

hmm, I don’t think that will fix my problem. The rule itself is quite stable - i’ve been using it for about 3 months now. The problem occurs when the entire hub gets bogged down such as during a hub update or if the network is down or if it just isn’t working well. After that all the math breaks down.

the rule really requires the reliability of hubitat (and the fact that this rule works as well as it does speaks to that reliability) as it is continuously calculating these values based on the ones that came before. in the past 3 months I’ve only had to manually correct it a handful of times. having access to system variables would mitigate that even more.

This is really the province of a small custom app, not Rule Machine. Time is messy. But even so, I don't follow how having access to those variables would help. You still would have the problem of knowing that those values need to be updated. If you have GVs for sunrise and sunset (in epoch time seconds), what more do you really need?

I would certainly agree with @dan.t that those should be separate little triggers, one for each, that just set those GVs. Then you'd always have them available.

Are you using Change Color Temperature Over Time? What update interval do you need? With a longer update interval, one that spans a hub update, you could set that once each morning and it would just keep on going. Even with a shorter interval it would keep on going. Perhaps you could have a special "fix-up" rule that makes it run from now until sunset in the event the hub went down, to get it back on track -- that you could manually fire when needed. I don't see why you need to trigger this every 10 minutes. Let Change Color Temperature do that work for you.

So, if you have those rules that grab sunrise and sunset times, this would do it:

Trigger Event:  Sunrise
   Set timespan to (sunset - sunrise)
   Set timespan to timespan + 3600
   Change CT Over Time: target 2200, time %timespan% seconds, interval 10 seconds

Use a separate rule for whatever you want at 4:52, could be Simple Lighting.


I guess I figured that the system had a way of setting sunrise and sunset that was not predicated on it being active at exactly the time corresponding to sunrise and sunset. Therefore the math of the rule would be updated as long as the system had a connection to the internet and the correct time and location. as it is now, it has to be working at exactly sunrise and sunset everyday to capture those times into a variable.

I am not using Change Color Temp Over Time as that was not an option when I wrote this rule. I’ve been thinking about that and how to possibly integrate it since you posted the update. My use case would involve having it change over the course of the entire day, which seems somewhat fragile. If the hub is rebooted or interrupted somehow it would kill this automation. I suppose that is why you mentioned a “fix-up” rule.

The reason it updates every 10 minutes is b/c that seemed like a small enough step to march down the color temp in an unnoticed way. The math of my rule divides the color temp range into an even number of steps to step down every 10 minutes. Then my lighting rules that take advantage of this variable re-evaluate when the variable changes. That way my great room lights (which are often on for much of the day) will slowly change with time.

I would worry about using Change CT Over Time causing my rules to fire continuously this setup, so I’ll have to rethink my triggers.

Doesn't need a connection to the internet for this. Sunrise and sunset are from built-in astronomical clock.

I have rules that run every day at sunrise and sunset, and have for years. They have never missed a day.

You choose the interval. It fires on that interval. It doesn't fire "continuously". Even if you fire it every 10 seconds it's not much load on the hub. You're firing every 600 seconds, a miniscule load.

this has been some interesting food for thought. as always, thanks for your input. My original rule was doing a lot of math that is now built in with CT Over Time. I’ve rewritten my rule as follows:

ignore my variable values - those are just placeholders as I’m writing this before dawn.

I think this rule will handle self correction if it has to be rerun at a time other than sunrise. It just subtracts the the number of seconds of daylight that have passed from the timespan it is going to run over.

also, Change CT Over Time requires minutes, so I had to divide everything by 60. It also asks for the interval in seconds and gives a “1...60” example. It accepted 300, so I assume that is ok?

I put a conditional in there just keep me from borking all the numbers by running it at the wrong time, but that shouldn’t really be necessary.

I also created two other rules - one to set sunrise/sunset global variables and one to set the color temp to 6500 at 4:52 AM (i had to use RM for this as simple lighting doesn’t seem to allow for setting color temperature).

I’ll test this for a while before I change my lighting rules to use it.

final plea: my sunset value is really the night before, so I have to subtract the difference from 24 hours in order to get daylight hours. It would be nice to be able to access the upcoming sunset value and not just the one from the night before. It would be more accurate and I would not have to make sure to not do a hub update around sunset (which seems to be a common time for me to mess with hubitat).

I don't know if this will help, but I created a similar circadian rule in a much messier fashion that goes up and down, in contrast to your unidirectional rule. It has 3 opportunities to correct itself and get back on the rails, with a little buffer on either end. It's not exact and it's not a fine gradient, but it works. For your situation maybe you can set a few checkpoints along the way.

My original rule worked similarly and had programmed check points at 4:52 am, sunset and sunset + 60 min to set the colortemp to a constant. Different than yours my original rule took sunrise and sunset into account for the transitions. I now just set a constant at 4:52, the rest of it is calculated.

the new CT Over Time option has simplified things and honestly this new rule I posted above seems to working pretty well as long as I leave it alone. If things get off for some external reason hitting update rule and run actions will re-initiate it at the correct point in the transition.

I see two weak points - one is stacking pending events. I just hit run action several times while testing the rule and I had a bunch of pending events, which really shouldn’t have too much of an impact on the actual CT values, it should just cause it to be calculated more often that every 5 min. as long as I leave it alone, it seems to run fine.

the other is the aforementioned requirement of catching the sunrise and sunset times. the rule has to be running for at least one sunset and then one subsequent sunrise to have the correct numbers, otherwise those variables have to be manually adjusted to the correct epoch times. It works, but I’d love to just have access to what hubitat already knows without having to recapture it. then the rule would be essentially bulletproof.

1 Like

sort of as a proof of concept I rewrote the rule for those that like the CT to rise from warm light in the morning to cool light by noon. its not perfect as it is expecting noon to be exactly halfway between sunrise and sunset, which it obviously isn’t. it raises the color temp until noon, then after noon it starts lowering it. at noon it may be off the target by a few hundred CT.

if this were to run on its own it would take the lights from ~6500 at noon, down to 2200 or 2700 (both variables are included) at sunset, then starting at sunrise the next day it would start raising them to a goal of 6500 by noon again.

I haven’t fully tested this, but it makes sense in my head! :stuck_out_tongue_winking_eye:

The advantage to this over a dedicated app is just that it is lightweight and runs on the built in tools available, so it should hopefully be both reliable and low impact.

edit: If you wanted you could try to capture noon from the day before into a global variable and then just add 86400 to it (24 hours) to get an approximation of noon the following day. then do the math based on that.

edit2: here you go. two rules:
capture the times into global variables:

then calculate:

edit3: you have to add a second trigger to the calculation rule at 1200 in order for it to restart the fade.

@bravenel is the man!

with the new time variables and with the "change color temp over time" RM action, setting color temperature has never been easier. here are my new example rules:

Global variables:
noon_variable -- time variable
sunset_variable -- time variable
colorTemp -- number variable -- also has a color bulb connector

Rule #1
this rule sets these variables every day 1 minute after midnight (I also have a sunrise_variable, although it is not required for these rules):

Rule #2
this rule changes the color temperature of the variable %colorTemp% up to 5000K by noon, and then back down to 2200K by sunset.

it requires two local variables:
start_time -- time variable
timespan -- number variable

The nice thing about this rule is that it will calculate the time between the time the rule is run and either noon or sunset, and adjust the rate of color temperature change accordingly. That way if the you have to change the rule or the hub is reset you can just hit "run actions" to restart the countdown.

Then all you have to do is use the variable %colorTemp% in your automations and it change the color temperature according to your circadian rhythm.

I'll present an example of my great room lighting automation. It is fairly complex b/c the lights are often on in this room when we are home. With these rules they adjust so slowly that it isn't noticeable even if we are sitting in the room reading a book. it requires 3 rules:
on/off and set color temp:

adjust color temp even if the lights are on:

adjust level to start dimming at sunset:

Of course it could be much simpler, especially in a high traffic area where the light turns on and off often. In that case a single rule that just adjusts color temperature to the variable will likely suffice.