From 1b6f7e2e5211e296e95aabab8172e5757cc14579 Mon Sep 17 00:00:00 2001 From: stigvi Date: Sat, 1 Feb 2020 13:15:22 +0100 Subject: [PATCH 1/3] Added support for min and max value templates --- .../circadian_lighting/switch.py | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/custom_components/circadian_lighting/switch.py b/custom_components/circadian_lighting/switch.py index 6fef883..2645581 100644 --- a/custom_components/circadian_lighting/switch.py +++ b/custom_components/circadian_lighting/switch.py @@ -20,11 +20,13 @@ from homeassistant.components.switch import SwitchDevice from homeassistant.const import ( ATTR_ENTITY_ID, CONF_NAME, CONF_PLATFORM, STATE_ON, - SERVICE_TURN_ON) + CONF_VALUE_TEMPLATE, SERVICE_TURN_ON) from homeassistant.util import slugify from homeassistant.util.color import ( color_RGB_to_xy, color_temperature_kelvin_to_mired, color_temperature_to_rgb, color_xy_to_hs) +from homeassistant.exceptions import TemplateError + _LOGGER = logging.getLogger(__name__) @@ -36,8 +38,10 @@ CONF_LIGHTS_BRIGHT = 'lights_brightness' CONF_DISABLE_BRIGHTNESS_ADJUST = 'disable_brightness_adjust' CONF_MIN_BRIGHT = 'min_brightness' +CONF_MIN_BRIGHT_TEMPLATE = 'min_brightness_template' DEFAULT_MIN_BRIGHT = 1 CONF_MAX_BRIGHT = 'max_brightness' +CONF_MAX_BRIGHT_TEMPLATE = 'max_brightness_template' DEFAULT_MAX_BRIGHT = 100 CONF_SLEEP_ENTITY = 'sleep_entity' CONF_SLEEP_STATE = 'sleep_state' @@ -66,7 +70,9 @@ vol.Optional(CONF_SLEEP_BRIGHT): vol.All(vol.Coerce(int), vol.Range(min=1, max=100)), vol.Optional(CONF_DISABLE_ENTITY): cv.entity_id, - vol.Optional(CONF_DISABLE_STATE): cv.string + vol.Optional(CONF_DISABLE_STATE): cv.string, + vol.Optional(CONF_MIN_BRIGHT_TEMPLATE): cv.template, + vol.Optional(CONF_MAX_BRIGHT_TEMPLATE): cv.template }) def setup_platform(hass, config, add_devices, discovery_info=None): @@ -81,6 +87,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = config.get(CONF_NAME) min_brightness = config.get(CONF_MIN_BRIGHT) max_brightness = config.get(CONF_MAX_BRIGHT) + min_brightness_template = config.get(CONF_MIN_BRIGHT_TEMPLATE) + max_brightness_template = config.get(CONF_MAX_BRIGHT_TEMPLATE) sleep_entity = config.get(CONF_SLEEP_ENTITY) sleep_state = config.get(CONF_SLEEP_STATE) sleep_colortemp = config.get(CONF_SLEEP_CT) @@ -89,6 +97,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): disable_state = config.get(CONF_DISABLE_STATE) cs = CircadianSwitch(hass, cl, name, lights_ct, lights_rgb, lights_xy, lights_brightness, disable_brightness_adjust, min_brightness, max_brightness, + min_brightness_template, max_brightness_template, sleep_entity, sleep_state, sleep_colortemp, sleep_brightness, disable_entity, disable_state) add_devices([cs]) @@ -106,6 +115,7 @@ class CircadianSwitch(SwitchDevice, RestoreEntity): def __init__(self, hass, cl, name, lights_ct, lights_rgb, lights_xy, lights_brightness, disable_brightness_adjust, min_brightness, max_brightness, + min_brightness_template, max_brightness_template, sleep_entity, sleep_state, sleep_colortemp, sleep_brightness, disable_entity, disable_state): """Initialize the Circadian Lighting switch.""" @@ -123,6 +133,8 @@ def __init__(self, hass, cl, name, lights_ct, lights_rgb, lights_xy, lights_brig self._disable_brightness_adjust = disable_brightness_adjust self._min_brightness = min_brightness self._max_brightness = max_brightness + self._min_brightness_template = min_brightness_template + self._max_brightness_template = max_brightness_template self._sleep_entity = sleep_entity self._sleep_state = sleep_state self._sleep_colortemp = sleep_colortemp @@ -150,6 +162,12 @@ def __init__(self, hass, cl, name, lights_ct, lights_rgb, lights_xy, lights_brig track_state_change(hass, self._sleep_entity, self.sleep_state_changed) if self._disable_entity is not None: track_state_change(hass, self._disable_entity, self.disable_state_changed) + if self._min_brightness_template is not None: + self._min_brightness_template.hass = hass + track_state_change(hass, self._min_brightness_template.extract_entities(), self.template_state_changed) + if self._max_brightness_template is not None: + self._max_brightness_template.hass = hass + track_state_change(hass, self._max_brightness_template.extract_entities(), self.template_state_changed) @property def entity_id(self): @@ -238,10 +256,18 @@ def calc_brightness(self): _LOGGER.debug(self._name + " in Sleep mode") return self._sleep_brightness else: + if self._max_brightness_template is not None: + max_br = max(min(float(self._max_brightness_template.async_render()), 100), 0) + else: + max_br = self._max_brightness + if self._min_brightness_template is not None: + min_br = min(max(float(self._min_brightness_template.async_render()), 0), max_br) + else: + min_br = self._min_brightness if self._cl.data['percent'] > 0: - return self._max_brightness + return max_br else: - return ((self._max_brightness - self._min_brightness) * ((100+self._cl.data['percent']) / 100)) + self._min_brightness + return ((max_br - min_br) * ((100+self._cl.data['percent']) / 100)) + min_br def update_switch(self, transition=None): if self._cl.data is not None: @@ -334,6 +360,13 @@ def light_state_changed(self, entity_id, from_state, to_state): self.adjust_lights([entity_id], DEFAULT_INITIAL_TRANSITION) except: pass + + def template_state_changed(self, entity_id, from_state, to_state): + try: + _LOGGER.debug(entity_id + " change from " + str(from_state) + " to " + str(to_state)) + self.update_switch(DEFAULT_INITIAL_TRANSITION) + except: + pass def sleep_state_changed(self, entity_id, from_state, to_state): try: From 075299967e160cdfe0a9941ebb081d67dacfb6a9 Mon Sep 17 00:00:00 2001 From: stigvi Date: Tue, 28 Apr 2020 15:04:47 +0200 Subject: [PATCH 2/3] Bugfix --- custom_components/circadian_lighting/services.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/circadian_lighting/services.yaml b/custom_components/circadian_lighting/services.yaml index e4f0b86..f6deec7 100644 --- a/custom_components/circadian_lighting/services.yaml +++ b/custom_components/circadian_lighting/services.yaml @@ -1,3 +1,3 @@ values_update: description: Updates values for Circadian Lighting. - fields: + #fields: From f85b8e3b5abdef0c0af7fad946db447de8126a08 Mon Sep 17 00:00:00 2001 From: stigvi Date: Tue, 28 Apr 2020 15:07:01 +0200 Subject: [PATCH 3/3] Better support for IKEA bulbs --- .../circadian_lighting/switch.py | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/custom_components/circadian_lighting/switch.py b/custom_components/circadian_lighting/switch.py index 2645581..0a6dc14 100644 --- a/custom_components/circadian_lighting/switch.py +++ b/custom_components/circadian_lighting/switch.py @@ -27,6 +27,8 @@ color_temperature_to_rgb, color_xy_to_hs) from homeassistant.exceptions import TemplateError +import math + _LOGGER = logging.getLogger(__name__) @@ -144,6 +146,7 @@ def __init__(self, hass, cl, name, lights_ct, lights_rgb, lights_xy, lights_brig self._attributes = {} self._attributes['hs_color'] = self._hs_color self._attributes['brightness'] = None + self._adjust_color = True self._lights = [] if lights_ct != None: @@ -240,7 +243,8 @@ def calc_rgb(self): _LOGGER.debug(self._name + " in Sleep mode") return color_temperature_to_rgb(self._sleep_colortemp) else: - return color_temperature_to_rgb(self._cl.data['colortemp']) + #return color_temperature_to_rgb(self._cl.data['colortemp']) + return self.convert_K_to_RGB(self._cl.data['colortemp']) def calc_xy(self): return color_RGB_to_xy(*self.calc_rgb()) @@ -318,14 +322,15 @@ def adjust_lights(self, lights, transition=None): """Set color of array of rgb light if on.""" if self._lights_rgb is not None and light in self._lights_rgb and is_on(self.hass, light): service_data = {ATTR_ENTITY_ID: light} - if rgb is not None: + if self._adjust_color is True and rgb is not None: service_data[ATTR_RGB_COLOR] = rgb - if brightness is not None: + if self._adjust_color is False and brightness is not None: service_data[ATTR_BRIGHTNESS] = brightness if transition is not None: service_data[ATTR_TRANSITION] = transition self.hass.services.call( LIGHT_DOMAIN, SERVICE_TURN_ON, service_data) + self._adjust_color = not self._adjust_color _LOGGER.debug(light + " RGB Adjusted - rgb_color: " + str(rgb) + ", brightness: " + str(brightness) + ", transition: " + str(transition)) """Set color of array of xy light if on.""" @@ -382,4 +387,65 @@ def disable_state_changed(self, entity_id, from_state, to_state): if from_state.state == self._disable_state: self.update_switch(DEFAULT_INITIAL_TRANSITION) except: - pass \ No newline at end of file + pass + + def convert_K_to_RGB(self, colour_temperature): + """ + Converts from K to RGB, algorithm courtesy of + http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ + """ + #range check + if colour_temperature < 1000: + colour_temperature = 1000 + elif colour_temperature > 40000: + colour_temperature = 40000 + + tmp_internal = colour_temperature / 100.0 + + # red + if tmp_internal <= 66: + red = 190 + #red = 255 + else: + tmp_red = 329.698727446 * math.pow(tmp_internal - 60, -0.1332047592) + if tmp_red < 0: + red = 0 + elif tmp_red > 255: + red = 255 + else: + red = tmp_red + + # green + if tmp_internal <=66: + tmp_green = 99.4708025861 * math.log(tmp_internal) - 175 + #tmp_green = 99.4708025861 * math.log(tmp_internal) - 161.1195681661 + if tmp_green < 0: + green = 0 + elif tmp_green > 255: + green = 255 + else: + green = tmp_green + else: + tmp_green = 288.1221695283 * math.pow(tmp_internal - 60, -0.0755148492) + if tmp_green < 0: + green = 0 + elif tmp_green > 255: + green = 255 + else: + green = tmp_green + + # blue + if tmp_internal >=66: + blue = 255 + elif tmp_internal <= 19: + blue = 0 + else: + tmp_blue = 138.5177312231 * math.log(tmp_internal - 10) - 305.0447927307 + if tmp_blue < 0: + blue = 0 + elif tmp_blue > 255: + blue = 255 + else: + blue = tmp_blue + + return red, green, blue