-
-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Added osramlightify groups. #7376
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
Changes from 3 commits
8d0dbed
52720b7
8236b3e
4dea47f
354a4f5
dc08bdc
f65f7ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,33 +16,40 @@ | |
| 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 = True | ||
|
|
||
| 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, | ||
| }) | ||
|
|
||
|
|
||
| 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.""" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this change.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I remove it, the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. never mind |
||
| 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 TimeoutError: | ||
| _LOGGER.error('Timeout during updating of lights.') | ||
| except OSError: | ||
| _LOGGER.error('OSError during updating of lights.') | ||
|
|
||
| new_lights = [] | ||
|
|
||
|
|
@@ -77,22 +91,31 @@ 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(Light): | ||
| """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._rgb = [None] | ||
| self._name = None | ||
| self._temperature = None | ||
| self._state = False | ||
|
|
@@ -106,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 | ||
|
|
@@ -118,29 +139,27 @@ 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 | ||
| 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 +177,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,26 +227,72 @@ 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() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you remove this line? it's not needed since should_poll is defaulting to True and so this is automatically called.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not something that we should fix in a platform but instead fix for everyone at once. We already wait 2 seconds for a status update: https://github.com/home-assistant/home-assistant-polymer/blob/master/src/components/entity/ha-entity-toggle.html#L135-L136 Please remove this line.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay, done |
||
|
|
||
| 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._rgb = self._light.rgb() | ||
| o_temp = self._light.temp() | ||
| self._name = self._luminary.name() | ||
|
|
||
|
|
||
| class OsramLightifyLight(Luminary): | ||
| """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): | ||
| """Representation of an Osram Lightify Group.""" | ||
|
|
||
| def __init__(self, group, bridge, update_lights): | ||
| """Init light group.""" | ||
| self._bridge = bridge | ||
| 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. | ||
| """ | ||
| 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() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is I think that things are getting very complicated because of the inheritance.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I first stared out without, but my code became 90% redundant and so I splittend i t up. The only difference between the two is the
Well its the main interface to the lightify API. Essentially all communication with the lights goes through the |
||
| 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() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'sys' imported but unused
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed