""" homeassistant.components.light.limitlessled ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for LimitlessLED bulbs. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.limitlessled/ """ import logging from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_RGB_COLOR, ATTR_TRANSITION, EFFECT_COLORLOOP, EFFECT_WHITE, FLASH_LONG, Light) _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['limitlessled==1.0.0'] RGB_BOUNDARY = 40 DEFAULT_TRANSITION = 0 DEFAULT_PORT = 8899 DEFAULT_VERSION = 5 DEFAULT_LED_TYPE = 'rgbw' WHITE = [255, 255, 255] def rewrite_legacy(config): """ Rewrite legacy configuration to new format. """ bridges = config.get('bridges', [config]) new_bridges = [] for bridge_conf in bridges: groups = [] if 'groups' in bridge_conf: groups = bridge_conf['groups'] else: _LOGGER.warning("Legacy configuration format detected") for i in range(1, 5): name_key = 'group_%d_name' % i if name_key in bridge_conf: groups.append({ 'number': i, 'type': bridge_conf.get('group_%d_type' % i, DEFAULT_LED_TYPE), 'name': bridge_conf.get(name_key) }) new_bridges.append({ 'host': bridge_conf.get('host'), 'groups': groups }) return {'bridges': new_bridges} def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ from limitlessled.bridge import Bridge # Two legacy configuration formats are supported to # maintain backwards compatibility. config = rewrite_legacy(config) # Use the expanded configuration format. lights = [] for bridge_conf in config.get('bridges'): bridge = Bridge(bridge_conf.get('host'), port=bridge_conf.get('port', DEFAULT_PORT), version=bridge_conf.get('version', DEFAULT_VERSION)) for group_conf in bridge_conf.get('groups'): group = bridge.add_group(group_conf.get('number'), group_conf.get('name'), group_conf.get('type', DEFAULT_LED_TYPE)) lights.append(LimitlessLEDGroup.factory(group)) add_devices_callback(lights) def state(new_state): """ State decorator. Specify True (turn on) or False (turn off). """ def decorator(function): """ Decorator function. """ # pylint: disable=no-member,protected-access def wrapper(self, **kwargs): """ Wrap a group state change. """ from limitlessled.pipeline import Pipeline pipeline = Pipeline() transition_time = DEFAULT_TRANSITION # Stop any repeating pipeline. if self.repeating: self.repeating = False self.group.stop() # Not on and should be? Turn on. if not self.is_on and new_state is True: pipeline.on() # Set transition time. if ATTR_TRANSITION in kwargs: transition_time = kwargs[ATTR_TRANSITION] # Do group type-specific work. function(self, transition_time, pipeline, **kwargs) # Update state. self._is_on = new_state self.group.enqueue(pipeline) self.update_ha_state() return wrapper return decorator class LimitlessLEDGroup(Light): """ LimitessLED group. """ def __init__(self, group): """ Initialize a group. """ self.group = group self.repeating = False self._is_on = False self._brightness = None @staticmethod def factory(group): """ Produce LimitlessLEDGroup objects. """ from limitlessled.group.rgbw import RgbwGroup from limitlessled.group.white import WhiteGroup if isinstance(group, WhiteGroup): return LimitlessLEDWhiteGroup(group) elif isinstance(group, RgbwGroup): return LimitlessLEDRGBWGroup(group) @property def should_poll(self): """ No polling needed. LimitlessLED state cannot be fetched. """ return False @property def name(self): """ Returns the name of the group. """ return self.group.name @property def is_on(self): """ True if device is on. """ return self._is_on @property def brightness(self): """ Brightness property. """ return self._brightness @state(False) def turn_off(self, transition_time, pipeline, **kwargs): """ Turn off a group. """ if self.is_on: pipeline.transition(transition_time, brightness=0.0).off() class LimitlessLEDWhiteGroup(LimitlessLEDGroup): """ LimitlessLED White group. """ def __init__(self, group): """ Initialize White group. """ super().__init__(group) # Initialize group with known values. self.group.on = True self.group.temperature = 1.0 self.group.brightness = 0.0 self._brightness = _to_hass_brightness(1.0) self._temperature = _to_hass_temperature(self.group.temperature) self.group.on = False @property def color_temp(self): """ Temperature property. """ return self._temperature @state(True) def turn_on(self, transition_time, pipeline, **kwargs): """ Turn on (or adjust property of) a group. """ # Check arguments. if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] if ATTR_COLOR_TEMP in kwargs: self._temperature = kwargs[ATTR_COLOR_TEMP] # Set up transition. pipeline.transition(transition_time, brightness=_from_hass_brightness( self._brightness), temperature=_from_hass_temperature( self._temperature)) class LimitlessLEDRGBWGroup(LimitlessLEDGroup): """ LimitlessLED RGBW group. """ def __init__(self, group): """ Initialize RGBW group. """ super().__init__(group) # Initialize group with known values. self.group.on = True self.group.white() self._color = WHITE self.group.brightness = 0.0 self._brightness = _to_hass_brightness(1.0) self.group.on = False @property def rgb_color(self): """ Color property. """ return self._color @state(True) def turn_on(self, transition_time, pipeline, **kwargs): """ Turn on (or adjust property of) a group. """ from limitlessled.presets import COLORLOOP # Check arguments. if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] if ATTR_RGB_COLOR in kwargs: self._color = kwargs[ATTR_RGB_COLOR] # White is a special case. if min(self._color) > 256 - RGB_BOUNDARY: pipeline.white() self._color = WHITE # Set up transition. pipeline.transition(transition_time, brightness=_from_hass_brightness( self._brightness), color=_from_hass_color(self._color)) # Flash. if ATTR_FLASH in kwargs: duration = 0 if kwargs[ATTR_FLASH] == FLASH_LONG: duration = 1 pipeline.flash(duration=duration) # Add effects. if ATTR_EFFECT in kwargs: if kwargs[ATTR_EFFECT] == EFFECT_COLORLOOP: self.repeating = True pipeline.append(COLORLOOP) if kwargs[ATTR_EFFECT] == EFFECT_WHITE: pipeline.white() self._color = WHITE def _from_hass_temperature(temperature): """ Convert Home Assistant color temperature units to percentage. """ return (temperature - 154) / 346 def _to_hass_temperature(temperature): """ Convert percentage to Home Assistant color temperature units. """ return int(temperature * 346) + 154 def _from_hass_brightness(brightness): """ Convert Home Assistant brightness units to percentage. """ return brightness / 255 def _to_hass_brightness(brightness): """ Convert percentage to Home Assistant brightness units. """ return int(brightness * 255) def _from_hass_color(color): """ Convert Home Assistant RGB list to Color tuple. """ from limitlessled import Color return Color(*tuple(color)) def _to_hass_color(color): """ Convert from Color tuple to Home Assistant RGB list. """ return list([int(c) for c in color])