Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for min and max value templates #66

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion custom_components/circadian_lighting/services.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
values_update:
description: Updates values for Circadian Lighting.
fields:
#fields:
115 changes: 107 additions & 8 deletions custom_components/circadian_lighting/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
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

import math


_LOGGER = logging.getLogger(__name__)

Expand All @@ -36,8 +40,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'
Expand Down Expand Up @@ -66,7 +72,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):
Expand All @@ -81,6 +89,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)
Expand All @@ -89,6 +99,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])
Expand All @@ -106,6 +117,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."""
Expand All @@ -123,6 +135,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
Expand All @@ -132,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:
Expand All @@ -150,6 +165,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):
Expand Down Expand Up @@ -222,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())
Expand All @@ -238,10 +260,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:
Expand Down Expand Up @@ -292,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."""
Expand Down Expand Up @@ -334,6 +365,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:
Expand All @@ -349,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
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