From 645cd89406ad31a93d44f7a19ebbaf75229e8d9d Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 27 Sep 2015 15:35:47 -0500 Subject: [PATCH 1/5] limitlessled: fix docstring --- homeassistant/components/light/limitlessled.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 9096bb32a10..631fcbed64e 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -89,7 +89,7 @@ class LimitlessLED(Light): @property def should_poll(self): - """ No polling needed for a demo light. """ + """ No polling needed. """ return False @property From 34531895a014545bdd46a0a32f552718f4b0ad99 Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 27 Sep 2015 16:16:58 -0500 Subject: [PATCH 2/5] limitlessled: Use LedControllerPool This change is in preparation for adapting this component to support multiple LimitlessLED bridges. Ultimately LedControllerPool helps to maintain the mandatory 100ms pauses across multiple controllers so messages are reliably received. --- .../components/light/limitlessled.py | 22 +++++++++++-------- requirements_all.txt | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 631fcbed64e..082a36faa4f 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -33,32 +33,34 @@ from homeassistant.components.light import (Light, ATTR_BRIGHTNESS, from homeassistant.util.color import color_RGB_to_xy _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['ledcontroller==1.0.7'] +REQUIREMENTS = ['ledcontroller==1.1.0'] def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ import ledcontroller - led = ledcontroller.LedController(config['host']) + pool = ledcontroller.LedControllerPool([config['host']]) lights = [] for i in range(1, 5): if 'group_%d_name' % (i) in config: - lights.append(LimitlessLED(led, i, config['group_%d_name' % (i)])) + lights.append(LimitlessLED(pool, 0, i, config['group_%d_name' % (i)])) add_devices_callback(lights) +# pylint: disable=too-many-instance-attributes class LimitlessLED(Light): """ Represents a LimitlessLED light """ - def __init__(self, led, group, name): - self.led = led + def __init__(self, pool, controller_id, group, name): + self.pool = pool + self.controller_id = controller_id self.group = group # LimitlessLEDs don't report state, we have track it ourselves. - self.led.off(self.group) + self.pool.execute(self.controller_id, "off", self.group) self._name = name or DEVICE_DEFAULT_NAME self._state = False @@ -132,12 +134,14 @@ class LimitlessLED(Light): if ATTR_XY_COLOR in kwargs: self._xy_color = kwargs[ATTR_XY_COLOR] - self.led.set_color(self._xy_to_led_color(self._xy_color), self.group) - self.led.set_brightness(self._brightness / 255.0, self.group) + self.pool.execute(self.controller_id, "set_color", + self._xy_to_led_color(self._xy_color), self.group) + self.pool.execute(self.controller_id, "set_brightness", + self._brightness / 255.0, self.group) self.update_ha_state() def turn_off(self, **kwargs): """ Turn the device off. """ self._state = False - self.led.off(self.group) + self.pool.execute(self.controller_id, "off", self.group) self.update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 4610100b161..5ff29e9d8a5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -14,7 +14,7 @@ astral==0.8.1 phue==0.8 # Limitlessled/Easybulb/Milight library (lights.limitlessled) -ledcontroller==1.0.7 +ledcontroller==1.1.0 # Chromecast bindings (media_player.cast) pychromecast==0.6.12 From ab80af099c165af45d08b447074f89bcf2137a02 Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 27 Sep 2015 16:46:08 -0500 Subject: [PATCH 3/5] limitlessled: Add support for multiple bridges This adds support for a controlling multiple Limitless LED bridges. --- .../components/light/limitlessled.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 082a36faa4f..c77c1319724 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -19,11 +19,14 @@ configuration.yaml file. light: platform: limitlessled - host: 192.168.1.10 - group_1_name: Living Room - group_2_name: Bedroom - group_3_name: Office - group_4_name: Kitchen + bridges: + - host: 192.168.1.10 + group_1_name: Living Room + group_2_name: Bedroom + group_3_name: Office + group_4_name: Kitchen + - host: 192.168.1.11 + group_2_name: Basement """ import logging @@ -40,12 +43,16 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ import ledcontroller - pool = ledcontroller.LedControllerPool([config['host']]) + for bridge_id, bridge in enumerate(bridges): + bridge['id'] = bridge_id + + pool = ledcontroller.LedControllerPool([x['host'] for x in bridges]) lights = [] - for i in range(1, 5): - if 'group_%d_name' % (i) in config: - lights.append(LimitlessLED(pool, 0, i, config['group_%d_name' % (i)])) + for bridge in bridges: + for i in range(1, 5): + if 'group_%d_name' % (i) in bridge: + lights.append(LimitlessLED(pool, bridge['id'], i, bridge['group_%d_name' % (i)])) add_devices_callback(lights) From ea7ca48ba2700dd2c12e85715ce6f3f8a2364987 Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 27 Sep 2015 16:59:02 -0500 Subject: [PATCH 4/5] limitlessled: Add support for previous configuration format Quick hack that preserves functionality of existing configuration formats to ease upgrades. --- homeassistant/components/light/limitlessled.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index c77c1319724..e6045add119 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -43,6 +43,9 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ import ledcontroller + # Handle old configuration format: + bridges = config.get('bridges', [config]) + for bridge_id, bridge in enumerate(bridges): bridge['id'] = bridge_id From 52ebb2fb3bd22ff4b5c217b4ee9583a7a0461583 Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 27 Sep 2015 17:22:38 -0500 Subject: [PATCH 5/5] limitlessled: Add support for White Limitless LED bulbs LimitlessLED bulbs actually come in three flavors: RGB, RGBW, and White. The ledcontroller library used to control these bulbs only supports RGBW and White bulbs. This changelist adds support for the White bulb variant. The White bulbs are a bit annoying in that they don't support absolute brightness or color temperature adjustments; they only support a relative "increase" or "decrease" adjustment. This, along with the unreliable, one-way communication medium that requires repeats to be "sure" that the bulb received a command, makes implementing brightness control difficult. So, for now, these bulbs are more limited than the RGBW variants and only support On/Off control. --- .../components/light/limitlessled.py | 83 ++++++++++++++----- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index e6045add119..ba8b8235260 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -24,6 +24,7 @@ light: group_1_name: Living Room group_2_name: Bedroom group_3_name: Office + group_3_type: white group_4_name: Kitchen - host: 192.168.1.11 group_2_name: Basement @@ -54,26 +55,70 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): lights = [] for bridge in bridges: for i in range(1, 5): - if 'group_%d_name' % (i) in bridge: - lights.append(LimitlessLED(pool, bridge['id'], i, bridge['group_%d_name' % (i)])) + name_key = 'group_%d_name' % i + if name_key in bridge: + group_type = bridge.get('group_%d_type' % i, 'rgbw') + lights.append(LimitlessLED.factory(pool, bridge['id'], i, + bridge[name_key], + group_type)) add_devices_callback(lights) -# pylint: disable=too-many-instance-attributes class LimitlessLED(Light): """ Represents a LimitlessLED light """ - def __init__(self, pool, controller_id, group, name): + @staticmethod + def factory(pool, controller_id, group, name, group_type): + ''' Construct a Limitless LED of the appropriate type ''' + if group_type == 'white': + return WhiteLimitlessLED(pool, controller_id, group, name) + elif group_type == 'rgbw': + return RGBWLimitlessLED(pool, controller_id, group, name) + + # pylint: disable=too-many-arguments + def __init__(self, pool, controller_id, group, name, group_type): self.pool = pool self.controller_id = controller_id self.group = group + self.pool.execute(self.controller_id, "set_group_type", self.group, + group_type) + # LimitlessLEDs don't report state, we have track it ourselves. self.pool.execute(self.controller_id, "off", self.group) self._name = name or DEVICE_DEFAULT_NAME self._state = False + + @property + def should_poll(self): + """ No polling needed. """ + return False + + @property + def name(self): + """ Returns the name of the device if any. """ + return self._name + + @property + def is_on(self): + """ True if device is on. """ + return self._state + + def turn_off(self, **kwargs): + """ Turn the device off. """ + self._state = False + self.pool.execute(self.controller_id, "off", self.group) + self.update_ha_state() + + +class RGBWLimitlessLED(LimitlessLED): + """ Represents a RGBW LimitlessLED light """ + + def __init__(self, pool, controller_id, group, name): + super().__init__(pool, controller_id, group, name, 'rgbw') + self._brightness = 100 self._xy_color = color_RGB_to_xy(255, 255, 255) @@ -99,16 +144,6 @@ class LimitlessLED(Light): ((0xE6, 0xE6, 0xFA), 'lavendar'), ]] - @property - def should_poll(self): - """ No polling needed. """ - return False - - @property - def name(self): - """ Returns the name of the device if any. """ - return self._name - @property def brightness(self): return self._brightness @@ -129,11 +164,6 @@ class LimitlessLED(Light): # First candidate in the sorted list is closest to desired color: return sorted(candidates)[0][1] - @property - def is_on(self): - """ True if device is on. """ - return self._state - def turn_on(self, **kwargs): """ Turn the device on. """ self._state = True @@ -150,8 +180,15 @@ class LimitlessLED(Light): self._brightness / 255.0, self.group) self.update_ha_state() - def turn_off(self, **kwargs): - """ Turn the device off. """ - self._state = False - self.pool.execute(self.controller_id, "off", self.group) + +class WhiteLimitlessLED(LimitlessLED): + """ Represents a White LimitlessLED light """ + + def __init__(self, pool, controller_id, group, name): + super().__init__(pool, controller_id, group, name, 'white') + + def turn_on(self, **kwargs): + """ Turn the device on. """ + self._state = True + self.pool.execute(self.controller_id, "on", self.group) self.update_ha_state()