From 8d0dbedf7fcba0aeabd42c973b646592c253581e Mon Sep 17 00:00:00 2001 From: Malte Deiseroth Date: Sat, 29 Apr 2017 08:44:59 +0200 Subject: [PATCH 1/6] Added osramlighrify groups. Allows you to make use of the build in osram lightify groups. Group states get handeled similar as in the case of phillips hue. A lightify group shows up as light in the homeassistant webinterface. If one light of the group is on, the complete group is considered to be on. To use this feature, first define some groups within your lighrify bridge, then set add `allow_lightify_groups=true` to you osramlightify config. It might look like: ````yaml - platform: osramlightify host: IP-ADDRES allow_lightify_groups: true ``` --- .../components/light/osramlightify.py | 146 ++++++++++++++---- requirements_all.txt | 2 +- 2 files changed, 118 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index 1ddfe1baa5388..d39f124718c57 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -4,6 +4,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.osramlightify/ """ +import sys import logging import socket import random @@ -15,26 +16,32 @@ from homeassistant.const import CONF_HOST from homeassistant.components.light import ( Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_RGB_COLOR, - ATTR_TRANSITION, EFFECT_RANDOM, SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, - SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, PLATFORM_SCHEMA) + ATTR_XY_COLOR, ATTR_TRANSITION, EFFECT_RANDOM, SUPPORT_BRIGHTNESS, + SUPPORT_EFFECT, SUPPORT_XY_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR, + SUPPORT_TRANSITION, PLATFORM_SCHEMA) from homeassistant.util.color import ( - color_temperature_mired_to_kelvin, color_temperature_kelvin_to_mired) + color_temperature_mired_to_kelvin, color_temperature_kelvin_to_mired, + color_xy_brightness_to_RGB) import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['https://github.com/tfriedel/python-lightify/archive/' - 'd6eadcf311e6e21746182d1480e97b350dda2b3e.zip#lightify==1.0.4'] + '1bb1db0e7bd5b14304d7bb267e2398cd5160df46.zip#lightify==1.0.5'] _LOGGER = logging.getLogger(__name__) MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) +CONF_ALLOW_LIGHTIFY_GROUPS = "allow_lightify_groups" +DEFAULT_ALLOW_LIGHTIFY_GROUPS = False SUPPORT_OSRAMLIGHTIFY = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT | SUPPORT_RGB_COLOR | - SUPPORT_TRANSITION) + SUPPORT_TRANSITION | SUPPORT_XY_COLOR) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_ALLOW_LIGHTIFY_GROUPS, + default=DEFAULT_ALLOW_LIGHTIFY_GROUPS): cv.boolean, }) @@ -42,6 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Osram Lightify lights.""" import lightify host = config.get(CONF_HOST) + add_groups = config.get(CONF_ALLOW_LIGHTIFY_GROUPS) if host: try: bridge = lightify.Lightify(host) @@ -50,20 +58,26 @@ def setup_platform(hass, config, add_devices, discovery_info=None): str(err)) _LOGGER.exception(msg) return False - setup_bridge(bridge, add_devices) + setup_bridge(bridge, add_devices, add_groups) else: _LOGGER.error('No host found in configuration') return False -def setup_bridge(bridge, add_devices_callback): +def setup_bridge(bridge, add_devices_callback, add_groups): """Setup the Lightify bridge.""" lights = {} @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update_lights(): """Update the lights objects with latest info from bridge.""" - bridge.update_all_light_status() + try: + bridge.update_all_light_status() + bridge.update_group_list() + except socket.error: + errno, errstr = sys.exc_info()[:2] + if errno == socket.timeout: + _LOGGER.error('Timeout during updating of lights.') new_lights = [] @@ -77,20 +91,29 @@ def update_lights(): else: lights[light_id].light = light + if add_groups: + for (group_name, group) in bridge.groups().items(): + if group_name not in lights: + osram_group = OsramLightifyGroup(group, bridge, + update_lights) + lights[group_name] = osram_group + new_lights.append(osram_group) + else: + lights[group_name].group = group + if new_lights: add_devices_callback(new_lights) update_lights() -class OsramLightifyLight(Light): - """Representation of an Osram Lightify Light.""" +class Luminary(): + """ABS for Lightify Lights and Groups.""" - def __init__(self, light_id, light, update_lights): - """Initialize the light.""" - self._light = light - self._light_id = light_id + def __init__(self, luminary, update_lights): + """Init Luminary object.""" self.update_lights = update_lights + self._luminary = luminary self._brightness = None self._rgb = None self._name = None @@ -134,13 +157,18 @@ def supported_features(self): """Flag supported features.""" return SUPPORT_OSRAMLIGHTIFY + @property + def effect_list(self): + """List of supported effects.""" + return [EFFECT_RANDOM] + def turn_on(self, **kwargs): """Turn the device on.""" _LOGGER.debug("turn_on Attempting to turn on light: %s ", self._name) - self._light.set_onoff(1) - self._state = self._light.on() + self._luminary.set_onoff(1) + self._state = True if ATTR_TRANSITION in kwargs: transition = int(kwargs[ATTR_TRANSITION] * 10) @@ -158,30 +186,41 @@ def turn_on(self, **kwargs): _LOGGER.debug("turn_on requested ATTR_RGB_COLOR for light:" " %s is: %s %s %s ", self._name, red, green, blue) - self._light.set_rgb(red, green, blue, transition) + self._luminary.set_rgb(red, green, blue, transition) + + if ATTR_XY_COLOR in kwargs: + x_mired, y_mired = kwargs[ATTR_XY_COLOR] + _LOGGER.debug("turn_on requested ATTR_XY_COLOR for light:" + " %s is: %s,%s", self._name, x_mired, y_mired) + red, green, blue = color_xy_brightness_to_RGB( + x_mired, y_mired, self._brightness + ) + self._luminary.set_rgb(red, green, blue, transition) if ATTR_COLOR_TEMP in kwargs: color_t = kwargs[ATTR_COLOR_TEMP] kelvin = int(color_temperature_mired_to_kelvin(color_t)) _LOGGER.debug("turn_on requested set_temperature for light:" " %s: %s ", self._name, kelvin) - self._light.set_temperature(kelvin, transition) + self._luminary.set_temperature(kelvin, transition) if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] _LOGGER.debug("turn_on requested brightness for light: %s is: %s ", self._name, self._brightness) - self._brightness = self._light.set_luminance( + self._brightness = self._luminary.set_luminance( int(self._brightness / 2.55), transition) if ATTR_EFFECT in kwargs: effect = kwargs.get(ATTR_EFFECT) if effect == EFFECT_RANDOM: - self._light.set_rgb(random.randrange(0, 255), - random.randrange(0, 255), - random.randrange(0, 255), - transition) + self._luminary.set_rgb( + random.randrange(0, 255), + random.randrange(0, 255), + random.randrange(0, 255), + transition + ) _LOGGER.debug("turn_on requested random effect for light:" " %s with transition %s ", self._name, transition) @@ -197,22 +236,71 @@ def turn_off(self, **kwargs): _LOGGER.debug("turn_off requested transition time for light:" " %s is: %s ", self._name, transition) - self._light.set_luminance(0, transition) + self._luminary.set_luminance(0, transition) else: transition = 0 _LOGGER.debug("turn_off requested transition time for light:" " %s is: %s ", self._name, transition) - self._light.set_onoff(0) - self._state = self._light.on() - + self._luminary.set_onoff(0) + self._state = False self.schedule_update_ha_state() def update(self): """Synchronize state with bridge.""" self.update_lights(no_throttle=True) - self._brightness = int(self._light.lum() * 2.55) - self._name = self._light.name() + self._name = self._luminary.name() + + +class OsramLightifyLight(Luminary, Light): + """Representation of an Osram Lightify Light.""" + + def __init__(self, light_id, light, update_lights): + """Initialize the light.""" + self._light_id = light_id + super().__init__(light, update_lights) + + def update(self): + """Update status of a Light.""" + super().update() + self._state = self._luminary.on() + self._rgb = self._luminary.rgb() + o_temp = self._luminary.temp() + if o_temp == 0: + self._temperature = None + else: + self._temperature = color_temperature_kelvin_to_mired( + self._luminary.temp() + ) + self._brightness = int(self._luminary.lum() * 2.55) + + +class OsramLightifyGroup(Luminary, Light): + """Representation of an Osram Lightify Group.""" + + def __init__(self, group, bridge, update_lights): + """Init light group.""" + self._bridge = bridge + self._light = None + self._light_ids = [] + super().__init__(group, update_lights) + + def _get_state(self): + """Get state of group. + + The group is on, if any of the lights in on. + """ + states = [] + for light_id in self._light_ids: + states.append(self._bridge.lights()[light_id].on()) + return any(states) + + def update(self): + """Update group status.""" + super().update() + self._light_ids = self._luminary.lights() + self._light = self._bridge.lights()[self._light_ids[0]] + self._brightness = int(self._light.lum() * 2.25) self._rgb = self._light.rgb() o_temp = self._light.temp() if o_temp == 0: diff --git a/requirements_all.txt b/requirements_all.txt index 67c67f53b57f3..25bb1ee49f61e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -298,7 +298,7 @@ https://github.com/sander76/powerviewApi/archive/246e782d60d5c0addcc98d7899a0186 https://github.com/soldag/pyflic/archive/0.4.zip#pyflic==0.4 # homeassistant.components.light.osramlightify -https://github.com/tfriedel/python-lightify/archive/d6eadcf311e6e21746182d1480e97b350dda2b3e.zip#lightify==1.0.4 +https://github.com/tfriedel/python-lightify/archive/1bb1db0e7bd5b14304d7bb267e2398cd5160df46.zip#lightify==1.0.5 # homeassistant.components.lutron https://github.com/thecynic/pylutron/archive/v0.1.0.zip#pylutron==0.1.0 From 52720b7ede42d7473099ea13b18ad60282491d40 Mon Sep 17 00:00:00 2001 From: Malte Deiseroth Date: Sun, 30 Apr 2017 21:13:19 +0200 Subject: [PATCH 2/6] Fixed Pylint errors. --- homeassistant/components/light/osramlightify.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index d39f124718c57..4ff299668f685 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -107,7 +107,7 @@ def update_lights(): update_lights() -class Luminary(): +class Luminary(Light): """ABS for Lightify Lights and Groups.""" def __init__(self, luminary, update_lights): @@ -115,7 +115,7 @@ def __init__(self, luminary, update_lights): self.update_lights = update_lights self._luminary = luminary self._brightness = None - self._rgb = None + self._rgb = [None] self._name = None self._temperature = None self._state = False @@ -252,7 +252,7 @@ def update(self): self._name = self._luminary.name() -class OsramLightifyLight(Luminary, Light): +class OsramLightifyLight(Luminary): """Representation of an Osram Lightify Light.""" def __init__(self, light_id, light, update_lights): @@ -275,7 +275,7 @@ def update(self): self._brightness = int(self._luminary.lum() * 2.55) -class OsramLightifyGroup(Luminary, Light): +class OsramLightifyGroup(Luminary): """Representation of an Osram Lightify Group.""" def __init__(self, group, bridge, update_lights): From 8236b3ec73ae4276b7075893352cfc1ea64f3cd2 Mon Sep 17 00:00:00 2001 From: Malte Date: Tue, 2 May 2017 20:15:03 +0200 Subject: [PATCH 3/6] Included requests. --- .../components/light/osramlightify.py | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index 4ff299668f685..51035305d1b0a 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -32,7 +32,7 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) CONF_ALLOW_LIGHTIFY_GROUPS = "allow_lightify_groups" -DEFAULT_ALLOW_LIGHTIFY_GROUPS = False +DEFAULT_ALLOW_LIGHTIFY_GROUPS = True SUPPORT_OSRAMLIGHTIFY = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT | SUPPORT_RGB_COLOR | @@ -74,10 +74,10 @@ def update_lights(): try: bridge.update_all_light_status() bridge.update_group_list() - except socket.error: - errno, errstr = sys.exc_info()[:2] - if errno == socket.timeout: - _LOGGER.error('Timeout during updating of lights.') + except TimeoutError: + _LOGGER.error('Timeout during updating of lights.') + except OSError: + _LOGGER.error('OSError during updating of lights.') new_lights = [] @@ -129,8 +129,6 @@ def name(self): @property def rgb_color(self): """Last RGB color value set.""" - _LOGGER.debug("rgb_color light state for light: %s is: %s %s %s ", - self._name, self._rgb[0], self._rgb[1], self._rgb[2]) return self._rgb @property @@ -141,15 +139,11 @@ def color_temp(self): @property def brightness(self): """Brightness of this light between 0..255.""" - _LOGGER.debug("brightness for light %s is: %s", - self._name, self._brightness) return self._brightness @property def is_on(self): """Update Status to True if device is on.""" - _LOGGER.debug("is_on light state for light: %s is: %s", - self._name, self._state) return self._state @property @@ -164,9 +158,6 @@ def effect_list(self): def turn_on(self, **kwargs): """Turn the device on.""" - _LOGGER.debug("turn_on Attempting to turn on light: %s ", - self._name) - self._luminary.set_onoff(1) self._state = True @@ -281,7 +272,6 @@ class OsramLightifyGroup(Luminary): def __init__(self, group, bridge, update_lights): """Init light group.""" self._bridge = bridge - self._light = None self._light_ids = [] super().__init__(group, update_lights) @@ -290,21 +280,19 @@ def _get_state(self): The group is on, if any of the lights in on. """ - states = [] - for light_id in self._light_ids: - states.append(self._bridge.lights()[light_id].on()) - return any(states) + lights = self._bridge.lights() + return any(lights[light_id].on() for light_id in self._light_ids) def update(self): """Update group status.""" super().update() self._light_ids = self._luminary.lights() - self._light = self._bridge.lights()[self._light_ids[0]] - self._brightness = int(self._light.lum() * 2.25) - self._rgb = self._light.rgb() - o_temp = self._light.temp() + light = self._bridge.lights()[self._light_ids[0]] + self._brightness = int(light.lum() * 2.55) + self._rgb = light.rgb() + o_temp = light.temp() if o_temp == 0: self._temperature = None else: self._temperature = color_temperature_kelvin_to_mired(o_temp) - self._state = self._light.on() + self._state = light.on() From 4dea47fb493cd3ca3e9e9a6f0a185c9b10acb9a5 Mon Sep 17 00:00:00 2001 From: Malte Date: Wed, 3 May 2017 07:33:06 +0200 Subject: [PATCH 4/6] Included more requests. --- homeassistant/components/light/osramlightify.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index 51035305d1b0a..3b87b9083b23f 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -4,7 +4,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.osramlightify/ """ -import sys import logging import socket import random @@ -159,7 +158,6 @@ def effect_list(self): def turn_on(self, **kwargs): """Turn the device on.""" self._luminary.set_onoff(1) - self._state = True if ATTR_TRANSITION in kwargs: transition = int(kwargs[ATTR_TRANSITION] * 10) @@ -234,7 +232,6 @@ def turn_off(self, **kwargs): " %s is: %s ", self._name, transition) self._luminary.set_onoff(0) - self._state = False self.schedule_update_ha_state() def update(self): From dc08bdc3520e9f0b42e964b43e22fa4a56223cde Mon Sep 17 00:00:00 2001 From: Malte Date: Wed, 3 May 2017 19:55:35 +0200 Subject: [PATCH 5/6] Fixed setup bridge and removed _light attribute. --- homeassistant/components/light/osramlightify.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index fba704ae89d95..1c9b35fcdc160 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -189,7 +189,7 @@ def turn_on(self, **kwargs): kelvin = int(color_temperature_mired_to_kelvin(color_t)) _LOGGER.debug("turn_on requested set_temperature for light: " "%s: %s", self._name, kelvin) - self._light.set_temperature(kelvin, transition) + self._luminary.set_temperature(kelvin, transition) if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] @@ -202,11 +202,10 @@ def turn_on(self, **kwargs): if ATTR_EFFECT in kwargs: effect = kwargs.get(ATTR_EFFECT) if effect == EFFECT_RANDOM: - - self._light.set_rgb(random.randrange(0, 255), - random.randrange(0, 255), - random.randrange(0, 255), - transition) + self._luminary.set_rgb(random.randrange(0, 255), + random.randrange(0, 255), + random.randrange(0, 255), + transition) _LOGGER.debug("turn_on requested random effect for light: " "%s with transition %s", self._name, transition) From f65f7ec19d07ee17123bd52f813041307c3f62d7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 3 May 2017 23:10:55 -0700 Subject: [PATCH 6/6] Update osramlightify.py --- homeassistant/components/light/osramlightify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index 1c9b35fcdc160..143dc52cbee93 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -64,7 +64,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): def setup_bridge(bridge, add_devices_callback, add_groups): - """Setup the Lightify bridge.""" + """Set up the Lightify bridge.""" lights = {} @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)