This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A Home Assistant (home-assistant.io) service to component lights that accept RGB, XY or MIREDS color commands. | |
Original Copyright (c) 2017 Alexandre Conde <xlcnd@outlook.com> | |
https://gist.github.com/xlcnd/01b2d8a28d9d77af901840072360a434 | |
Edited by Martin van Es, October 2018 | |
Licensed under MIT | |
INSTALL: | |
1. Create the file <config dir>/custom_components/circadian_lights.py and copy the code below to there. | |
2. In your <config dir>/configuration.yaml enter (adapt to your case): | |
circadian_lights: | |
min_kelvin: 2750 | |
max_kelvin: 3500 | |
lights: | |
- light.rgb_led_kitchen | |
- light.rgb_led_tv | |
- light.rgb_led_living_room | |
- light.xy_led_toillet | |
- light.temp_led_room1 | |
- light.temp_led_room2 | |
3. and add to the automation section: | |
- alias: 'Circadian Lights' | |
trigger: | |
platform: time | |
minutes: '/5' | |
seconds: 0 | |
action: | |
service: circadian_lights.change_color | |
and voilá! Restart HA and you will have the sun in your house and night lights 'friendly' of your circadian cycle. | |
NOTE: The effect will only apply to lights that are on! | |
""" | |
import datetime | |
import logging | |
import voluptuous as vol | |
import homeassistant.helpers.config_validation as cv | |
from homeassistant.components.light import ( | |
ATTR_PROFILE, ATTR_TRANSITION, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, | |
ATTR_RGB_COLOR, ATTR_XY_COLOR, | |
DOMAIN as DOMAIN_LIGHT) | |
from homeassistant.const import ( | |
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON) | |
from homeassistant.core import callback | |
from homeassistant.components import light, sun | |
from homeassistant.helpers.sun import get_astral_event_next | |
from homeassistant.const import MATCH_ALL | |
from homeassistant.util.dt import as_utc, parse_time | |
from homeassistant.util.color import (color_temperature_to_rgb, color_RGB_to_xy, | |
color_temperature_kelvin_to_mired) | |
_LOGGER = logging.getLogger(__name__) | |
DOMAIN = 'circadian_lights' | |
DEPENDENCIES = ['light', 'sun'] | |
SERVICE_CHANGE_COLOR = 'change_color' | |
CONF_MINK = 'min_kelvin' | |
CONF_MAXK = 'max_kelvin' | |
CONF_LIGHTS = 'lights' | |
#Warm point sunrise/sunset | |
KELVIN_MIN = 2750 | |
#Cold point midday | |
KELVIN_MAX = 3500 | |
CONFIG_SCHEMA = vol.Schema({ | |
DOMAIN: vol.Schema({ | |
vol.Optional(CONF_MINK, default=KELVIN_MIN): cv.positive_int, | |
vol.Optional(CONF_MAXK, default=KELVIN_MAX): cv.positive_int, | |
vol.Required(CONF_LIGHTS): cv.ensure_list, | |
}) | |
}, extra=vol.ALLOW_EXTRA) | |
class Color(object): | |
"""Attributes for several color models.""" | |
def __init__(self, value, kmin, kmax): | |
self.value = value | |
self.kelvins = kmin + (value * (kmax - kmin)) | |
self.mireds = color_temperature_kelvin_to_mired(self.kelvins) | |
self.r, self.g, self.b = (min(int(c), 255) for c in color_temperature_to_rgb(self.kelvins)) | |
self.x, self.y = color_RGB_to_xy(self.r, self.g, self.b) | |
def setup(hass, config): | |
"""Setup component circadian_lights.""" | |
# Read config | |
kelvin_min = config[DOMAIN].get(CONF_MINK, KELVIN_MIN) | |
kelvin_max = config[DOMAIN].get(CONF_MAXK, KELVIN_MAX) | |
lights = config[DOMAIN].get(CONF_LIGHTS, MATCH_ALL) or [] | |
_LOGGER.error('Circadian Min Kelvin: %s, Max Kelvin %s', kelvin_min, kelvin_max) | |
if not lights: | |
_LOGGER.error('Add light_ids to configuration under circadian_lights: %s', CONF_LIGHTS) | |
return False | |
def get_color(): | |
"""Sunlight colors while day, Red for night.""" | |
# See https://en.wikipedia.org/wiki/Color_temperature | |
# Get parameters | |
sunrise = as_utc(get_astral_event_next(hass, 'sunrise')) | |
sunset = as_utc(get_astral_event_next(hass, 'sunset')) | |
today = datetime.date.today() | |
now = as_utc(datetime.datetime.today()) | |
# While is night | |
value = 0 # in Kelvins (rgb=RED) | |
if sunrise > sunset: # While is day | |
sunrise = sunrise - datetime.timedelta(days=1) # aprox for sunrise today | |
midday = sunrise + datetime.timedelta(seconds=(sunset - sunrise).total_seconds() / 2) | |
value = (now - sunrise) / (midday - sunrise) | |
if value > 1: | |
value = 2 - value | |
return Color(value, kelvin_min, kelvin_max) | |
def get_active_lights(lights): | |
"""Get the ids of active lights.""" | |
ids = [] | |
for light_id in lights: | |
if hass.states.get(light_id) is None: | |
_LOGGER.error('Light id %s could not be found in state machine', light_id) | |
continue | |
if light.is_on(hass, light_id): | |
ids.append(light_id) | |
return ids | |
def change_color(event): | |
"""Change color for each light (service).""" | |
color = get_color() | |
_LOGGER.info('value: %.2f, mireds: %s, Kelvin: %d', | |
color.value, color.mireds, color.kelvins) | |
light_ids = get_active_lights(lights) | |
if not light_ids: | |
return | |
for light_id in light_ids: | |
if light.is_on(hass, light_id): | |
_LOGGER.info('Changing color of %s', light_id) | |
hass.async_create_task( | |
hass.services.async_call( | |
DOMAIN_LIGHT, SERVICE_TURN_ON, | |
{ | |
ATTR_ENTITY_ID: light_id, | |
ATTR_COLOR_TEMP: color.mireds, | |
#ATTR_RGB_COLOR: [color.r, color.g, color.b], | |
#ATTR_XY_COLOR: [color.x, color.y] | |
} | |
) | |
) | |
# Register service | |
hass.services.register(DOMAIN, SERVICE_CHANGE_COLOR, change_color) | |
return True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment