Circadian Lighting [Custom Component]

Stay healthier and sleep better by syncing your lights with natural daylight to maintain your circadian rhythm!

Circadian Lighting slowly synchronizes your color changing lights with local perceived color temperature of the sky throughout the day. This gives your environment a more natural feel, with cooler whites during the midday and warmer tints near twilight and dawn.

In addition, Circadian Lighting can set your lights to a nice cool white at 1% in “Sleep” mode, which is far brighter than starlight but won’t reset your circadian rhythm or break down too much rhodopsin in your eyes.

Expand for articles explaining the benefits of maintaining a natural Circadian rhythm

How is Circadian Lighting different than the built-in Flux component, or the many other solutions posted on the forums?

Circadian Lighting has a number of unique features that differentiates it from other options available:

  • Circadian Lighting has two main components, a sensor and switch(es). The sensor maintains the calculated color temperature to keep all lights in sync, while the switch(es) allow for specific options to be set for specific groups of lights.
  • Circadian Lighting allows you to set an offset for sunrise/sunset. This allows your lights to stay in sync with the natural changes in day length, but maintains flexibility in timing. (Specifying fixed sunrise/sunset times is also an option)
  • Circadian Lighting allows you to set the latitude/longitude used for calculating sunrise/sunset times. This is useful if you want to simulate days at a different location (useful for traveling.)
  • Circadian Lighting lets you have set lights using color temperature, RGB, XY, or just brightness - all within the same switch. So you can have some lights that adjust color temperature and some that only adjust brightness in the same instance.
  • Brightness is adjusted based on the position of the sun above/below the horizon. This mimics outside light levels rather than just setting a brightness based on color temperature. (Brightness adjustment is optional)
  • Circadian Lighting has a “sleep” mode, which activates when a specified entity is in a specified state. In “sleep” mode a set color temperature and brightness are used - this makes a great nightlight.
  • Circadian Lighting can automatically disable when a specified entity is in a specified state. This allows you to disable Circadian Lighting without having to manually toggle it off or create an Automation to do so.
  • Circadian Lighting remembers its state after a reboot.
  • Circadian Lighting tracks the state of all configured lights, so it reacts instantly to a light being turned on. When lights are turned on it the transition to the proper color temperature is very quick, rather than using the configured transition.
  • Circadian Lighting creates a sensor, which makes the calculated color temperature available in the front-end and to all other components. This means that in automation you can program lights to turn on to exactly the right color temperature, eliminating the jump from the color the light was at when turned off to the proper color.

Future enhancement ideas


Code/Configuration:

Files - ALL THREE REQUIRED!

Component Configuration:

# Example configuration.yaml entry
circadian_lighting:

Advanced Configuration

Switch Configuration:

# Example configuration.yaml entry
switch:
  - platform: circadian_lighting
    lights_ct:
      - light.desk
      - light.lamp

Switch configuration variables:

  • name (Optional): The name to use when displaying this switch.
  • lights_ct (Optional): array: List of light entities which should be set in mireds.
  • lights_rgb (Optional): array: List of light entities which should be set in RGB.
  • lights_xy (Optional): array: List of light entities which should be set in XY.
  • lights_brightness (Optional): array: List of light entities which should only have brightness adjusted.

Advanced Configuration

46 Likes

Pretty Graphs!

These graphs were generated using the values calculated by the Circadian Lighting sensor/switch(es).

Sun Position:

Color Temperature:

Brightness:

2 Likes

awesome, thanks for sharing.

Wow this is great, I have struggled to get flux to work correctly with my lights. Will definitely give this a shot. Thank you

Looks awesome, going to try this out tonight!

@claytonjn: If you plan to enhance your component by Hue scenes that always contain the correct circadian colortemp / brightness, you could have a look here.
I have built something on my own by defining “Circadian” Hue scenes and using a REST service to the Hue API to update those scenes every 10 minutes.

One disadvantage of the component: if I manually set the light (e. g. a multicoloured Hue scene) in a room, it will be overwritten after a few minutes. In my own solution, I check every light whether its colortemp does not differ “too much” (= arbitrary value of 15 mired) from the circadian colortemp value. If the difference is greater, I assume that it was adjusted manually before and shall therefore not be updated automatically. This somehow works for me, but of course is kind of a hack… :laughing:
Perhaps you could figure out something like this in your custom component also?

Cheers,
Tim

I could add that as a configuration option, although I would expect that the fact that the Circadian Lighting “switch” can be turned off, and that you can specify an entity to disable Circadian Lighting, would cover that situation. For example, an automation should be able to easily switch off Circadian Lighting when any specified scene(s) are on, and enable it when they’re off.

If I do add a “differential threshold” how would Circadian Lighting know that it should begin adjusting the lights again?

First feedback after playing around a little:

  • I had to manually install timezonefinder as dependency (via pip)
  • When I define a sleep_entity or a disable_entity, HA throws an error:
2018-07-26 20:05:56 ERROR (MainThread) [homeassistant.components.switch] Error while setting up platform circadian_lighting
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity_platform.py", line 129, in _async_setup_platform
    SLOW_SETUP_MAX_WAIT, loop=hass.loop)
  File "/usr/lib/python3.5/asyncio/tasks.py", line 400, in wait_for
    return fut.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/switch/circadian_lighting.py", line 89, in setup_platform
    disable_entity, disable_state)
  File "/home/homeassistant/.homeassistant/custom_components/switch/circadian_lighting.py", line 130, in __init__
    self._attributes['brightness'] = self.calc_brightness()
  File "/home/homeassistant/.homeassistant/custom_components/switch/circadian_lighting.py", line 219, in calc_brightness
    if self._attributes['sleep_entity'] is not None and self.hass.states.get(self._attributes['sleep_entity']) == self._attributes['sleep_state']:
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/core.py", line 697, in get
    return self._states.get(entity_id.lower())
AttributeError: 'list' object has no attribute 'lower'

Apart from that, the component seems to work fine.

OK, but how could I figure out from HA that a (Hue) scene was activated? The Hue app itself seems to only compare the actual bulb values with those stored in the scene and if they all match, the scene is marked as “active”. Even if I did that comparison or find another way to get that information from the Hue API, I would come too late since the switch immediately kicks in and changes the lights before I have the chance to disable it…

If a room / light group is switched off, the corresponding circadian switch can be enabled again via automation, that’s where I agree.

Valid point. I would say only after the lights have been switched entirely off. Since I work with Hue scenes containing the current circadian colortemp and brightness values, the difference is very small when the lights are switched on again and would fall into the “differential threshold”.

I’m not sure why that is, but I had troubles with it too. HA is supposed to install any requirements before loading the component - in my case it only did so after a couple reboots. I’ll reach out on discord and try to figure out what’s going on there.

Can you post your configuration.yaml?

Hmm, you’re right. Scenes used to be pulled in as switches, but aren’t anymore. When you update a Hue scene with the API, does it update all lights that are currently set to that scene, or does it only apply to lights that are turned on since the update?

circadian_lighting:
  max_colortemp: 5000 
  min_colortemp: 2857
  interval: 600
  transition: 3
  
switch:
  - platform: circadian_lighting
    name: "Wohnzimmer"
    lights_ct:
      - light.fado_homeserver
      - light.tripod
      - light.linea
    min_brightness: 18
    max_brightness: 100
    sleep_entity: input_boolean.b_circadian_sleepmode
    sleep_state: "on"
    sleep_colortemp: 5500
    sleep_brightness: 18
    disable_entity: sensor.wohnzimmer_tado_mode
    disable_state: AWAY

Tried with only sleep_* attributes or only with disable_* or both - no joy…

The latter. Modifying a scene does not impact lights, no matter if they are switched on or off in that moment. The changes apply only if I activate the scene again after the update.

Constantly updating a Hue scene makes sure that any lights that are switched on (via that scene) instantly have the correct colortemp/brightness values. It does not change active lights over time. This is done by another automation I have, very similar to your component.

I am not a developer myself but looking at your code it seems to me that you define sleep_entity and disable_entity as list/array just like lights_ct etc.:

vol.Optional(CONF_SLEEP_ENTITY): cv.entity_ids,
[...]
vol.Optional(CONF_DISABLE_ENTITY): cv.entity_ids

Yeah so I basically ran myself in a circle when coding that part. My original intent is that the user could specify any number of entities for sleep/disable, but then I wasn’t sure how to handle the case where the entities may need different states. So the actual code expects a single entity, but the configuration validation expects a list.

I’m open to suggestions for how to handle this…should I allow a list of entity_ids but they all would need a single state, should I just make one option that expects a list of comma separated entity_id and state, or does anyone have a better idea?

Okay, that’s what I thought (although I was hoping for the former). In that case you should be able to manually pull scenes in as a generic RESTful switch, but you’d have to create each one manually. If you have many scenes for many lights that could prove unmanageable. I’ll definitely add the threshold option to the to-do list as I do think that’s could be a good solution.

If I were in your shoes, I would leave it at one single entity. If you allow more entities, someone will come up with “I want sleep state if two or more of my X entities are in state Y or Z” and things like that. People who need complex logic should define a (single) template sensor for that and then tie the circadian switch to it.

This way I could activate scenes only in HA. If I did it in the Hue app, it will be overwritten again because HA does not recognize the scene being activated…

Also, my son likes to play around with colours, i. e. he changes the colour of single bulbs, but does not use scenes. I bet he would be disappointed if every change he makes instantly is “corrected” by the circadian switch :rofl:

Thanks a lot! I’ll have to think this through a little more myself - if I have any ideas, I’ll let you know!

Good point, templates/automations should be able to handle more complex situations. In that case, could you try changing your configuration to this and let me now how it goes?

switch:
  - platform: circadian_lighting
    name: "Wohnzimmer"
    lights_ct:
      - light.fado_homeserver
      - light.tripod
      - light.linea
    min_brightness: 18
    max_brightness: 100
    sleep_entity:
      - input_boolean.b_circadian_sleepmode
    sleep_state: "on"
    sleep_colortemp: 5500
    sleep_brightness: 18
    disable_entity:
      - sensor.wohnzimmer_tado_mode
    disable_state: AWAY

Actually that’s not the case, RESTful switches allow you to specify a URL for turning on/off as well as one for checking state. I have a handful of scenes pulled in this way for a whole ambiance setup I have in the master bathroom and Home Assistant does know when they’re activated from Hue. That is a moot point though because as you said it wouldn’t handle the case of someone just manually setting colors in the app.

Nope, same error. This time the error even makes sense because sleep_entity and disable_entity actually ARE lists now…

Would you mind sharing your switch config? I am especially interested in your is_on_template definition… I use ordinary template switches for my lights, but their status of course is just derived from the lights’ state, not from a scene being active:

switch:
  - platform: template
    switches:
    
      lights_wohnzimmer:
        friendly_name: "Wohnzimmer"
        value_template: "{{ is_state('light.wohnzimmer', 'on') }}"
        turn_on:
          service: hue.hue_activate_scene
          data:
            group_name: "Wohnzimmer"
            scene_name: "WoZi Circadian"
        turn_off:
          service: light.turn_off
          data:
            entity_id: light.wohnzimmer

I tried something out and changed the switch code to

vol.Optional(CONF_SLEEP_ENTITY): cv.entity_id,
[...]
vol.Optional(CONF_DISABLE_ENTITY): cv.entity_id

and the config back to

sleep_entity: input_boolean.b_circadian_sleepmode
[...]
disable_entity: sensor.wohnzimmer_tado_mode

and the error is gone. Unfortunately none of the attributes work, i. e. I cannot switch to sleep mode or disable the switch… There are no subsequent errors, it just does not work.

Here’s an example. I misspoke, I have them configured as command line not REST. Anyways:

- platform: command_line
  switches:
    front_porch_candlelight:
      command_off: >
  curl -H "Content-Type: application/json" -X PUT -d '{"state":{"status":0}}' http://<IP>/api/<TOKEN>/sensors/43 &&
  curl -H "Content-Type: application/json" -X PUT -d '{"state":{"status":2}}' http://<IP>/api/<TOKEN>/sensors/43
      command_on: >
  curl -H "Content-Type: application/json" -X PUT -d '{"state":{"status":0}}' http://<IP>/api/<TOKEN>/sensors/43 &&
  curl -H "Content-Type: application/json" -X PUT -d '{"state":{"status":2}}' http://<IP>/api/<TOKEN>/sensors/43
      command_state: >
  curl -H "Content-Type: application/json" -X GET http://<IP>/api/<TOKEN>/sensors/44
      friendly_name: "Front Porch - Candlelight"
      value_template: '{{ value_json.state.status == 0 }}'

Now, this is for Hue Labs Living Colors scenes but the basic concept should apply for any scene. I had to do some playing around in a web debugger to figure out the sensors because they’re Labs buttons but it shouldn’t be that hard for the in-app scenes.

Strange, that was the change I just pushed. I tested it and it was working for me. Could you try adding this to your configuration.yaml and confirm if it’s working?

logger:
  logs:
    custom_components.circadian_lighting: debug
    custom_components.sensor.circadian_lighting: debug
    custom_components.switch.circadian_lighting: debug

It would be nice if there are LED bulbs out there that come really close to incandescent/halogen light bulbs in terms of dimmability as I switched from LIFX to halogen with Insteon Hub 2242-222 and never looked back.

There hasn’t been any improvements to LED bulbs that dim really low to the point that the LED light is barely on. That way it would be cool to use a circadian component. The reason why I switched to halogen light bulbs is because I care less about the energy savings that LED bulbs offer.

Well if you have the Insteon Hub paired with Home Assistant you should be able to use Circadian Lighting to at least control the brightness, if that helps.

1 Like

OK, thanks! I get the idea - unfortunately, this only works for scenes that were activated by pressing the dimmer switch, but not for those activated in the Hue app. Hue dimmer switches have a sensor they use as “memory” to store the current position in the scene cycle, but this is not updated when a scene is chosen in the App…

My log looks like this (lines from other components removed):

2018-07-27 08:29:38 WARNING (MainThread) [homeassistant.loader] You are using a custom component for circadian_lighting which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
2018-07-27 08:29:59 DEBUG (Thread-10) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:29:59 DEBUG (Thread-21) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:29:59 DEBUG (Thread-9) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:29:59 DEBUG (Thread-10) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:29:59 DEBUG (Thread-10) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:29:59 DEBUG (Thread-10) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:30:32 DEBUG (Thread-8) [custom_components.circadian_lighting] Circadian Lighting Component Updated
2018-07-27 08:30:32 DEBUG (Thread-12) [custom_components.switch.circadian_lighting] Wohnzimmer Switch Updated
2018-07-27 08:30:32 DEBUG (Thread-17) [custom_components.sensor.circadian_lighting] Circadian Lighting Sensor Updated
2018-07-27 08:30:32 DEBUG (Thread-12) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 10.0
2018-07-27 08:30:32 DEBUG (Thread-12) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 10.0
2018-07-27 08:30:32 DEBUG (Thread-12) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 10.0
2018-07-27 08:32:32 DEBUG (Thread-17) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:32:32 DEBUG (Thread-18) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:32:32 DEBUG (Thread-9) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:32:32 DEBUG (Thread-14) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:32:32 DEBUG (Thread-15) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:32:32 DEBUG (Thread-20) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:56 DEBUG (Thread-3) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:56 DEBUG (Thread-21) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:56 DEBUG (Thread-11) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:57 DEBUG (Thread-15) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:57 DEBUG (Thread-9) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:34:57 DEBUG (Thread-15) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 241, brightness: 255.0, transition: 1
2018-07-27 08:40:52 DEBUG (Thread-7) [custom_components.circadian_lighting] Circadian Lighting Component Updated
2018-07-27 08:40:52 DEBUG (Thread-20) [custom_components.switch.circadian_lighting] Wohnzimmer Switch Updated
2018-07-27 08:40:52 DEBUG (Thread-10) [custom_components.sensor.circadian_lighting] Circadian Lighting Sensor Updated
2018-07-27 08:40:52 DEBUG (Thread-20) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 238, brightness: 255.0, transition: 10.0
2018-07-27 08:40:52 DEBUG (Thread-20) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 238, brightness: 255.0, transition: 10.0
2018-07-27 08:40:52 DEBUG (Thread-20) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 238, brightness: 255.0, transition: 10.0
2018-07-27 08:40:52 DEBUG (Thread-6) [custom_components.switch.circadian_lighting] light.fado_homeserver CT Adjusted - color_temp: 238, brightness: 255.0, transition: 1
2018-07-27 08:40:52 DEBUG (Thread-4) [custom_components.switch.circadian_lighting] light.tripod CT Adjusted - color_temp: 238, brightness: 255.0, transition: 1
2018-07-27 08:40:52 DEBUG (Thread-8) [custom_components.switch.circadian_lighting] light.linea CT Adjusted - color_temp: 238, brightness: 255.0, transition: 1

I switched the sleep_entity and disable_entity on and off, but this does not reflect at all in the log.
Could you please share your config? What type of entity do you use for sleep/disable?

Interesting, I would expect that the app would still have to know when a scene has been activated.

I just pushed some changes to the switch component that adds additional logging and should fix the sleep_entity and disable_entity. I also added a state listener to the sleep_entity so that lights will be adjusted immediately when the entity is the the proper state.

I personally don’t use the disable_entity, I just have automations flip the switch off, but here’s an example of one of my configs with sleep_entity:

- platform: circadian_lighting
  lights_ct:
    - light.claytons_nightstand_lamp
    - light.corys_nightstand_lamp
  lights_brightness:
    - light.master_bedroom_light
  name: Master Bedroom Circadian Lighting
  sleep_entity: 'input_select.security_state'
  sleep_state: 'Stay'
  sleep_colortemp: 2000
  sleep_brightness: 1