def limitlessled_temperature(self): """Convert Home Assistant color temperature units to percentage.""" max_kelvin = color_temperature_mired_to_kelvin(self.min_mireds) min_kelvin = color_temperature_mired_to_kelvin(self.max_mireds) width = max_kelvin - min_kelvin kelvin = color_temperature_mired_to_kelvin(self._temperature) temperature = (kelvin - min_kelvin) / width return max(0, min(1, temperature))
def sync_attributes(self): """Return color temperature attributes for a sync request.""" attrs = self.state.attributes return { 'temperatureMinK': color_util.color_temperature_mired_to_kelvin( attrs.get(light.ATTR_MIN_MIREDS)), 'temperatureMaxK': color_util.color_temperature_mired_to_kelvin( attrs.get(light.ATTR_MAX_MIREDS)), }
async def async_turn_on(self, **kwargs): """Turn the light on.""" brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness) hs_color = kwargs.get(ATTR_HS_COLOR, self.hs_color) mireds = kwargs.get(ATTR_COLOR_TEMP, self.color_temp) update_brightness = ATTR_BRIGHTNESS in kwargs update_color = ATTR_HS_COLOR in kwargs update_color_temp = ATTR_COLOR_TEMP in kwargs # always only go one path for turning on (avoid conflicting changes # and weird effects) if self.device.supports_brightness and \ (update_brightness and not update_color): # if we don't need to update the color, try updating brightness # directly if supported; don't do it if color also has to be # changed, as RGB color implicitly sets the brightness as well await self.device.set_brightness(brightness) elif self.device.supports_color and \ (update_brightness or update_color): # change RGB color (includes brightness) # if brightness or hs_color was not yet set use the default value # to calculate RGB from as a fallback if brightness is None: brightness = DEFAULT_BRIGHTNESS if hs_color is None: hs_color = DEFAULT_COLOR await self.device.set_color( color_util.color_hsv_to_RGB(*hs_color, brightness * 100 / 255)) elif self.device.supports_color_temperature and \ update_color_temp: # change color temperature without ON telegram kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds)) if kelvin > self._max_kelvin: kelvin = self._max_kelvin elif kelvin < self._min_kelvin: kelvin = self._min_kelvin await self.device.set_color_temperature(kelvin) elif self.device.supports_tunable_white and \ update_color_temp: # calculate relative_ct from Kelvin to fit typical KNX devices kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds)) relative_ct = int(255 * (kelvin - self._min_kelvin) / (self._max_kelvin - self._min_kelvin)) await self.device.set_tunable_white(relative_ct) else: # no color/brightness change requested, so just turn it on await self.device.set_on()
def query_attributes(self): """Return color temperature query attributes.""" features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) color = {} if features & light.SUPPORT_COLOR: color_hs = self.state.attributes.get(light.ATTR_HS_COLOR) brightness = self.state.attributes.get(light.ATTR_BRIGHTNESS, 1) if color_hs is not None: color['spectrumHsv'] = { 'hue': color_hs[0], 'saturation': color_hs[1]/100, 'value': brightness/255, } if features & light.SUPPORT_COLOR_TEMP: temp = self.state.attributes.get(light.ATTR_COLOR_TEMP) # Some faulty integrations might put 0 in here, raising exception. if temp == 0: _LOGGER.warning('Entity %s has incorrect color temperature %s', self.state.entity_id, temp) elif temp is not None: color['temperatureK'] = \ color_util.color_temperature_mired_to_kelvin(temp) response = {} if color: response['color'] = color return response
def async_turn_on(self, **kwargs): """ Instruct the light to turn on. After adding "self._light_data.hexcolor is not None" for ATTR_HS_COLOR, this also supports Philips Hue bulbs. """ if ATTR_HS_COLOR in kwargs and self._light_data.hex_color is not None: rgb = color_util.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) yield from self._api( self._light.light_control.set_rgb_color(*rgb)) elif ATTR_COLOR_TEMP in kwargs and \ self._light_data.hex_color is not None and \ self._temp_supported: kelvin = color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) yield from self._api( self._light_control.set_kelvin_color(kelvin)) keys = {} if ATTR_TRANSITION in kwargs: keys['transition_time'] = int(kwargs[ATTR_TRANSITION]) * 10 if ATTR_BRIGHTNESS in kwargs: if kwargs[ATTR_BRIGHTNESS] == 255: kwargs[ATTR_BRIGHTNESS] = 254 yield from self._api( self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS], **keys)) else: yield from self._api( self._light_control.set_state(True))
def find_hsbk(**kwargs): """Find the desired color from a number of possible inputs.""" hue, saturation, brightness, kelvin = [None]*4 preprocess_turn_on_alternatives(kwargs) if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ color_util.color_RGB_to_hsv(*kwargs[ATTR_RGB_COLOR]) saturation = convert_8_to_16(saturation) brightness = convert_8_to_16(brightness) kelvin = 3500 if ATTR_XY_COLOR in kwargs: hue, saturation = color_util.color_xy_to_hs(*kwargs[ATTR_XY_COLOR]) saturation = convert_8_to_16(saturation) kelvin = 3500 if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) saturation = 0 if ATTR_BRIGHTNESS in kwargs: brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS]) hsbk = [hue, saturation, brightness, kelvin] return None if hsbk == [None]*4 else hsbk
def turn_on(self, **kwargs): """Turn the device on.""" if ATTR_TRANSITION in kwargs: fade = kwargs[ATTR_TRANSITION] * 1000 else: fade = 0 if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR]) else: hue = self._hue saturation = self._sat brightness = self._bri if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1) else: brightness = self._bri if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) else: kelvin = self._kel _LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d", self._ip, self._power, hue, saturation, brightness, kelvin, fade) if self._power == 0: self._liffylights.set_power(self._ip, 65535, fade) self._liffylights.set_color(self._ip, hue, saturation, brightness, kelvin, fade)
def query_response_light( entity: Entity, config: Config, units: UnitSystem) -> dict: """Convert a light entity to a QUERY response.""" response = {} # type: Dict[str, Any] brightness = entity.attributes.get(light.ATTR_BRIGHTNESS) if brightness is not None: response['brightness'] = int(100 * (brightness / 255)) supported_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if supported_features & \ (light.SUPPORT_COLOR_TEMP | light.SUPPORT_RGB_COLOR): response['color'] = {} if entity.attributes.get(light.ATTR_COLOR_TEMP) is not None: response['color']['temperature'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_COLOR_TEMP)))) if entity.attributes.get(light.ATTR_COLOR_NAME) is not None: response['color']['name'] = \ entity.attributes.get(light.ATTR_COLOR_NAME) if entity.attributes.get(light.ATTR_RGB_COLOR) is not None: color_rgb = entity.attributes.get(light.ATTR_RGB_COLOR) if color_rgb is not None: response['color']['spectrumRGB'] = \ int(color.color_rgb_to_hex( color_rgb[0], color_rgb[1], color_rgb[2]), 16) return response
async def async_turn_on(self, **kwargs): """Instruct the light to turn on.""" params = {} transition_time = None if ATTR_TRANSITION in kwargs: transition_time = int(kwargs[ATTR_TRANSITION]) * 10 brightness = kwargs.get(ATTR_BRIGHTNESS) if brightness is not None: if brightness > 254: brightness = 254 elif brightness < 0: brightness = 0 if ATTR_HS_COLOR in kwargs and self._light_control.can_set_color: params[ATTR_BRIGHTNESS] = brightness hue = int(kwargs[ATTR_HS_COLOR][0] * (65535 / 360)) sat = int(kwargs[ATTR_HS_COLOR][1] * (65279 / 100)) if brightness is None: params[ATTR_TRANSITION_TIME] = transition_time await self._api( self._light_control.set_hsb(hue, sat, **params)) return if ATTR_COLOR_TEMP in kwargs and (self._light_control.can_set_temp or self._light_control.can_set_color): temp = kwargs[ATTR_COLOR_TEMP] if temp > self.max_mireds: temp = self.max_mireds elif temp < self.min_mireds: temp = self.min_mireds if brightness is None: params[ATTR_TRANSITION_TIME] = transition_time # White Spectrum bulb if (self._light_control.can_set_temp and not self._light_control.can_set_color): await self._api( self._light_control.set_color_temp(temp, **params)) # Color bulb (CWS) # color_temp needs to be set with hue/saturation if self._light_control.can_set_color: params[ATTR_BRIGHTNESS] = brightness temp_k = color_util.color_temperature_mired_to_kelvin(temp) hs_color = color_util.color_temperature_to_hs(temp_k) hue = int(hs_color[0] * (65535 / 360)) sat = int(hs_color[1] * (65279 / 100)) await self._api( self._light_control.set_hsb(hue, sat, **params)) if brightness is not None: params[ATTR_TRANSITION_TIME] = transition_time await self._api( self._light_control.set_dimmer(brightness, **params)) else: await self._api( self._light_control.set_state(True))
def turn_on(self, **kwargs): """Turn the device on.""" if ATTR_TRANSITION in kwargs: transition = int(kwargs[ATTR_TRANSITION] * 10) else: transition = 0 if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] self._luminary.set_luminance( int(self._brightness / 2.55), transition) else: self._luminary.set_onoff(1) if ATTR_HS_COLOR in kwargs: red, green, blue = \ color_util.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) 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)) self._luminary.set_temperature(kelvin, transition) if ATTR_EFFECT in kwargs: effect = kwargs.get(ATTR_EFFECT) if effect == EFFECT_RANDOM: self._luminary.set_rgb( random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255), transition) self.schedule_update_ha_state()
def turn_on(self, **kwargs): """Turn the device on.""" if ATTR_TRANSITION in kwargs: transition = int(kwargs[ATTR_TRANSITION] * 10) _LOGGER.debug("turn_on requested transition time for light: " "%s is: %s", self._name, transition) else: transition = 0 _LOGGER.debug("turn_on requested transition time for light: " "%s is: %s", self._name, 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._luminary.set_luminance( int(self._brightness / 2.55), transition) else: self._luminary.set_onoff(1) if ATTR_RGB_COLOR in kwargs: red, green, blue = kwargs[ATTR_RGB_COLOR] _LOGGER.debug("turn_on requested ATTR_RGB_COLOR for light:" " %s is: %s %s %s ", self._name, red, green, blue) 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._luminary.set_temperature(kelvin, transition) if ATTR_EFFECT in kwargs: effect = kwargs.get(ATTR_EFFECT) if effect == EFFECT_RANDOM: 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) self.schedule_update_ha_state()
def query_attributes(self): """Return color temperature query attributes.""" response = {} temp = self.state.attributes.get(light.ATTR_COLOR_TEMP) if temp is not None: response['color'] = { 'temperature': color_util.color_temperature_mired_to_kelvin(temp) } return response
def sync_attributes(self): """Return color temperature attributes for a sync request.""" attrs = self.state.attributes features = attrs.get(ATTR_SUPPORTED_FEATURES, 0) response = {} if features & light.SUPPORT_COLOR: response['colorModel'] = 'hsv' if features & light.SUPPORT_COLOR_TEMP: # Max Kelvin is Min Mireds K = 1000000 / mireds # Min Kevin is Max Mireds K = 1000000 / mireds response['colorTemperatureRange'] = { 'temperatureMaxK': color_util.color_temperature_mired_to_kelvin( attrs.get(light.ATTR_MIN_MIREDS)), 'temperatureMinK': color_util.color_temperature_mired_to_kelvin( attrs.get(light.ATTR_MAX_MIREDS)), } return response
def turn_on(self, **kwargs): """Turn on or control the light.""" if (ATTR_BRIGHTNESS not in kwargs and ATTR_HS_COLOR not in kwargs and ATTR_COLOR_TEMP not in kwargs): self.tuya.turn_on() if ATTR_BRIGHTNESS in kwargs: self.tuya.set_brightness(kwargs[ATTR_BRIGHTNESS]) if ATTR_HS_COLOR in kwargs: self.tuya.set_color(kwargs[ATTR_HS_COLOR]) if ATTR_COLOR_TEMP in kwargs: color_temp = colorutil.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) self.tuya.set_color_temp(color_temp)
def async_turn_on(self, **kwargs): """Turn the device on.""" if ATTR_TRANSITION in kwargs: fade = int(kwargs[ATTR_TRANSITION] * 1000) else: fade = 0 changed_color = False if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR]) changed_color = True else: hue = self._hue saturation = self._sat brightness = self._bri if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1) changed_color = True else: brightness = self._bri if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) changed_color = True else: kelvin = self._kel hsbk = [hue, saturation, brightness, kelvin] _LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d", self.ipaddr, self._power, fade, *hsbk) if self._power == 0: if changed_color: self.device.set_color(hsbk, None, 0) self.device.set_power(True, None, fade) else: self.device.set_power(True, None, 0) # racing for power status if changed_color: self.device.set_color(hsbk, None, fade) self.update_later(0) if fade < BULB_LATENCY: self.set_power(1) self.set_color(*hsbk)
def turn_on(self, **kwargs): """Turn on the light.""" if ATTR_COLOR_TEMP in kwargs and self._device.is_color_capable: self._device.set_color_temp( int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]))) if ATTR_HS_COLOR in kwargs and self._device.is_color_capable: self._device.set_color(kwargs[ATTR_HS_COLOR]) if ATTR_BRIGHTNESS in kwargs and self._device.is_dimmable: # Convert HASS brightness (0-255) to Abode brightness (0-99) # If 100 is sent to Abode, response is 99 causing an error self._device.set_level(ceil(kwargs[ATTR_BRIGHTNESS] * 99 / 255.0)) else: self._device.switch_on()
def query_attributes(self): """Return color temperature query attributes.""" response = {} temp = self.state.attributes.get(light.ATTR_COLOR_TEMP) # Some faulty integrations might put 0 in here, raising exception. if temp == 0: _LOGGER.warning('Entity %s has incorrect color temperature %s', self.state.entity_id, temp) elif temp is not None: response['color'] = { 'temperature': color_util.color_temperature_mired_to_kelvin(temp) } return response
def find_hsbk(self, **kwargs): """Find the desired color from a number of possible inputs.""" changed_color = False hsbk = kwargs.pop(ATTR_HSBK, None) if hsbk is not None: return [hsbk, True] preprocess_turn_on_alternatives(kwargs) if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ color_util.color_RGB_to_hsv(*kwargs[ATTR_RGB_COLOR]) saturation = convert_8_to_16(saturation) brightness = convert_8_to_16(brightness) changed_color = True else: hue = self._hue saturation = self._sat brightness = self._bri if ATTR_XY_COLOR in kwargs: hue, saturation = color_util.color_xy_to_hs(*kwargs[ATTR_XY_COLOR]) saturation = convert_8_to_16(saturation) changed_color = True # When color or temperature is set, use a default value for the other if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) if not changed_color: saturation = 0 changed_color = True else: if changed_color: kelvin = 3500 else: kelvin = self._kel if ATTR_BRIGHTNESS in kwargs: brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS]) changed_color = True else: brightness = self._bri return [[hue, saturation, brightness, kelvin], changed_color]
def find_hsbk(self, **kwargs): """Find the desired color from a number of possible inputs.""" changed_color = False hsbk = kwargs.pop(ATTR_HSBK, None) if hsbk is not None: return [hsbk, True] color_name = kwargs.pop(ATTR_COLOR_NAME, None) if color_name is not None: kwargs[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name) if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR]) changed_color = True else: hue = self._hue saturation = self._sat brightness = self._bri if ATTR_XY_COLOR in kwargs: hue, saturation = color_util.color_xy_to_hs(*kwargs[ATTR_XY_COLOR]) saturation = saturation * (BYTE_MAX + 1) changed_color = True # When color or temperature is set, use a default value for the other if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) if not changed_color: saturation = 0 changed_color = True else: if changed_color: kelvin = 3500 else: kelvin = self._kel if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1) changed_color = True else: brightness = self._bri return [[hue, saturation, brightness, kelvin], changed_color]
def turn_on(self, **kwargs): """Turn the light on.""" if not self._on: self._lamp.switch(True) if ATTR_BRIGHTNESS in kwargs: brightness = int((kwargs[ATTR_BRIGHTNESS] / 255.0) * 200.0) self._lamp.brightness(brightness) return if ATTR_RGB_COLOR in kwargs: rgb = kwargs[ATTR_RGB_COLOR] self._lamp.rgb(*rgb) return if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) self._lamp.white(kelvin) return
def find_hsbk(self, **kwargs): """Find the desired color from a number of possible inputs.""" changed_color = False hsbk = kwargs.pop(ATTR_HSBK, None) if hsbk is not None: return [hsbk, True] color_name = kwargs.pop(ATTR_COLOR_NAME, None) if color_name is not None: kwargs[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name) if ATTR_RGB_COLOR in kwargs: hue, saturation, brightness = \ convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR]) changed_color = True else: hue = self._hue saturation = self._sat brightness = self._bri if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1) changed_color = True else: brightness = self._bri if ATTR_XY_COLOR in kwargs: hue, saturation, _ = \ color_util.color_xy_brightness_to_hsv( *kwargs[ATTR_XY_COLOR], ibrightness=(brightness // (BYTE_MAX + 1))) saturation = saturation * (BYTE_MAX + 1) changed_color = True if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) changed_color = True else: kelvin = self._kel return [[hue, saturation, brightness, kelvin], changed_color]
def turn_on(self, **kwargs): """ Instruct the light to turn on. After adding "self._light_data.hexcolor is not None" for ATTR_RGB_COLOR, this also supports Philips Hue bulbs. """ if ATTR_BRIGHTNESS in kwargs: self._api(self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS])) else: self._api(self._light_control.set_state(True)) if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None: self._api(self._light.light_control.set_rgb_color( *kwargs[ATTR_RGB_COLOR])) elif ATTR_COLOR_TEMP in kwargs and \ self._light_data.hex_color is not None and self._ok_temps: kelvin = color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) self._api(self._light_control.set_kelvin_color(kelvin))
def turn_on(self, **kwargs): """Turn on or control the light.""" if ( ATTR_BRIGHTNESS not in kwargs and ATTR_HS_COLOR not in kwargs and ATTR_COLOR_TEMP not in kwargs ): self.tuya.turn_on() if ATTR_BRIGHTNESS in kwargs: brightness = self.map_brightness(kwargs[ATTR_BRIGHTNESS], 1, 255, 29, 255) self.tuya.set_brightness(brightness) if ATTR_HS_COLOR in kwargs: self.tuya.set_color(kwargs[ATTR_HS_COLOR]) if not "entity_data" in self.hass.data[DOMAIN]: self.hass.data[DOMAIN] = {"entity_data": {}} self.hass.data[DOMAIN]["entity_data"][self.tuya.object_id()] = {"color": kwargs[ATTR_HS_COLOR]} if ATTR_COLOR_TEMP in kwargs: color_temp = colorutil.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP] ) self.tuya.set_color_temp(color_temp)
async def async_turn_on(self, **kwargs: Any) -> None: """Instruct the light to turn on.""" brightness = round( kwargs.get(ATTR_BRIGHTNESS, self.brightness) / 255 * 100) if (self.supported_color_modes and ColorMode.COLOR_TEMP in self.supported_color_modes and ATTR_COLOR_TEMP in kwargs): color_temp = kwargs[ATTR_COLOR_TEMP] kelvin = max( 2700, min(6500, color_temperature_mired_to_kelvin(color_temp))) await self._device.set_color_temp(brightness, kelvin) return if ATTR_RGB_COLOR in kwargs: rgb = kwargs[ATTR_RGB_COLOR] await self._device.set_rgb(brightness, rgb[0], rgb[1], rgb[2]) return if ATTR_BRIGHTNESS in kwargs: await self._device.set_brightness(brightness) return await self._device.turn_on()
def turn_on(self, **kwargs): """Turn the entity on.""" _LOGGER.debug("turn_on: {} {} {}".format(self._name, self._state, kwargs)) self._light.nightlight_on() if ATTR_BRIGHTNESS in kwargs: self._light.set_nightlight_brightness(kwargs[ATTR_BRIGHTNESS]) if ATTR_HS_COLOR in kwargs: rgb = color_util.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) self._light.set_nightlight_rgb(red=rgb[0], green=rgb[1], blue=rgb[2]) if ATTR_COLOR_TEMP in kwargs: kelvin = color_util.color_temperature_mired_to_kelvin(kwargs.get(ATTR_COLOR_TEMP)) self._light.set_nightlight_color_temperature(kelvin) if ATTR_EFFECT in kwargs: effect = kwargs[ATTR_EFFECT] if effect == LIGHT_EFFECT_RAINBOW: self._light.set_nightlight_mode("rainbow") else: self._light.set_nightlight_mode("rgb")
def find_hsbk(**kwargs): """Find the desired color from a number of possible inputs.""" hue, saturation, brightness, kelvin = [None]*4 preprocess_turn_on_alternatives(kwargs) if ATTR_HS_COLOR in kwargs: hue, saturation = kwargs[ATTR_HS_COLOR] hue = int(hue / 360 * 65535) saturation = int(saturation / 100 * 65535) kelvin = 3500 if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) saturation = 0 if ATTR_BRIGHTNESS in kwargs: brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS]) hsbk = [hue, saturation, brightness, kelvin] return None if hsbk == [None]*4 else hsbk
async def async_turn_on(self, **kwargs) -> None: """Turn on light.""" if self.block.type == "relay": self.control_result = await self.block.set_state(turn="on") self.async_write_ha_state() return params = {"turn": "on"} if ATTR_BRIGHTNESS in kwargs: tmp_brightness = int(kwargs[ATTR_BRIGHTNESS] / 255 * 100) if hasattr(self.block, "gain"): params["gain"] = tmp_brightness if hasattr(self.block, "brightness"): params["brightness"] = tmp_brightness if ATTR_COLOR_TEMP in kwargs: color_temp = color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP]) color_temp = min( KELVIN_MAX_VALUE, max(min_kelvin(self.wrapper.model), color_temp) ) # Color temperature change - used only in white mode, switch device mode to white if self.mode == "color": self.mode_result = await self.wrapper.device.switch_light_mode("white") params["red"] = params["green"] = params["blue"] = 255 params["temp"] = int(color_temp) elif ATTR_HS_COLOR in kwargs: red, green, blue = color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) # Color channels change - used only in color mode, switch device mode to color if self.mode == "white": self.mode_result = await self.wrapper.device.switch_light_mode("color") params["red"] = red params["green"] = green params["blue"] = blue elif ATTR_WHITE_VALUE in kwargs: # White channel change - used only in color mode, switch device mode device to color if self.mode == "white": self.mode_result = await self.wrapper.device.switch_light_mode("color") params["white"] = int(kwargs[ATTR_WHITE_VALUE]) self.control_result = await self.block.set_state(**params) self.async_write_ha_state()
async def async_turn_on(self, **kwargs): """ Instruct the light to turn on. """ # TODO: change this to set state using a single UDP call # rgb = None if ATTR_RGB_COLOR in kwargs: rgb = kwargs[ATTR_RGB_COLOR] if ATTR_HS_COLOR in kwargs: rgb = color_utils.color_hs_to_RGB(kwargs[ATTR_HS_COLOR][0], kwargs[ATTR_HS_COLOR][1]) brightness = None if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] colortemp = None if ATTR_COLOR_TEMP in kwargs: kelvin = color_utils.color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP]) colortemp = kelvin sceneid = None if ATTR_EFFECT in kwargs: sceneid = self._light.get_id_from_scene_name(kwargs[ATTR_EFFECT]) if sceneid == 1000: #rhythm pilot = PilotBuilder() else: pilot = PilotBuilder( rgb = rgb, brightness = brightness, colortemp = colortemp, scene = sceneid ) await self._light.turn_on(pilot)
def _async_pilot_builder(**kwargs: Any) -> PilotBuilder: """Create the PilotBuilder for turn on.""" brightness = kwargs.get(ATTR_BRIGHTNESS) if ATTR_RGBWW_COLOR in kwargs: return PilotBuilder(brightness=brightness, rgbww=kwargs[ATTR_RGBWW_COLOR]) if ATTR_RGBW_COLOR in kwargs: return PilotBuilder(brightness=brightness, rgbw=kwargs[ATTR_RGBW_COLOR]) if ATTR_COLOR_TEMP in kwargs: return PilotBuilder( brightness=brightness, colortemp=color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP]), ) if ATTR_EFFECT in kwargs: scene_id = get_id_from_scene_name(kwargs[ATTR_EFFECT]) if scene_id == 1000: # rhythm return PilotBuilder() return PilotBuilder(brightness=brightness, scene=scene_id) return PilotBuilder(brightness=brightness)
def turn_on(self, **kwargs): """ Instruct the light to turn on. After adding "self._light_data.hexcolor is not None" for ATTR_RGB_COLOR, this also supports Philips Hue bulbs. """ if ATTR_BRIGHTNESS in kwargs: self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS]) else: self._light_control.set_state(True) if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None: self._light.light_control.set_hex_color( color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR])) elif ATTR_COLOR_TEMP in kwargs and \ self._light_data.hex_color is not None and self._ok_temps: kelvin = color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) # find closest allowed kelvin temp from user input kelvin = min(self._ok_temps.keys(), key=lambda x: abs(x - kelvin)) self._light_control.set_hex_color(self._ok_temps[kelvin])
def turn_on(self, **kwargs): """Turn the device on.""" if ATTR_TRANSITION in kwargs: fade = int(kwargs[ATTR_TRANSITION] * 1000) else: fade = 0 if ATTR_HS_COLOR in kwargs: hue, saturation = kwargs[ATTR_HS_COLOR] hue = hue / 360 * 65535 saturation = saturation / 100 * 65535 else: hue = self._hue saturation = self._sat if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1) else: brightness = self._bri if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) else: kelvin = self._kel _LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d", self._ip, self._power, hue, saturation, brightness, kelvin, fade) if self._power == 0: self._liffylights.set_color(self._ip, hue, saturation, brightness, kelvin, 0) self._liffylights.set_power(self._ip, 65535, fade) else: self._liffylights.set_color(self._ip, hue, saturation, brightness, kelvin, fade)
async def async_turn_on(self, **kwargs): """Instruct the light to turn on.""" rgb = None if ATTR_RGB_COLOR in kwargs: rgb = kwargs.get(ATTR_RGB_COLOR) if ATTR_HS_COLOR in kwargs: rgb = color_utils.color_hs_to_RGB( kwargs[ATTR_HS_COLOR][0], kwargs[ATTR_HS_COLOR][1] ) brightness = None if ATTR_BRIGHTNESS in kwargs: brightness = kwargs.get(ATTR_BRIGHTNESS) colortemp = None if ATTR_COLOR_TEMP in kwargs: kelvin = color_utils.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP] ) colortemp = kelvin _LOGGER.debug( "[wizlight %s] kelvin changed and send to bulb: %s", self._light.ip, colortemp, ) sceneid = None if ATTR_EFFECT in kwargs: sceneid = self._light.get_id_from_scene_name(kwargs[ATTR_EFFECT]) if sceneid == 1000: # rhythm pilot = PilotBuilder() else: pilot = PilotBuilder( rgb=rgb, brightness=brightness, colortemp=colortemp, scene=sceneid ) await self._light.turn_on(pilot)
def async_turn_on(self, **kwargs): """ Instruct the light to turn on. After adding "self._light_data.hexcolor is not None" for ATTR_RGB_COLOR, this also supports Philips Hue bulbs. """ if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None: self.hass.async_add_job( self._api( self._light.light_control.set_rgb_color( *kwargs[ATTR_RGB_COLOR]))) elif ATTR_COLOR_TEMP in kwargs and \ self._light_data.hex_color is not None and \ self._temp_supported: kelvin = color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) self.hass.async_add_job( self._api(self._light_control.set_kelvin_color(kelvin))) keys = {} if ATTR_TRANSITION in kwargs: keys['transition_time'] = int(kwargs[ATTR_TRANSITION]) * 10 if ATTR_BRIGHTNESS in kwargs: if kwargs[ATTR_BRIGHTNESS] == 255: kwargs[ATTR_BRIGHTNESS] = 254 self.hass.async_add_job( self._api( self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS], **keys))) else: self.hass.async_add_job( self._api(self._light_control.set_state(True)))
def turn_on(self, **kwargs): """Turn the device on.""" transition = int(kwargs.get(ATTR_TRANSITION, 0) * 10) if ATTR_EFFECT in kwargs: self.play_effect(kwargs[ATTR_EFFECT], transition) return if ATTR_HS_COLOR in kwargs: self._rgb_color = color_util.color_hs_to_RGB(*kwargs[ATTR_HS_COLOR]) self._luminary.set_rgb(*self._rgb_color, transition) if ATTR_COLOR_TEMP in kwargs: self._color_temp = kwargs[ATTR_COLOR_TEMP] self._luminary.set_temperature( int(color_util.color_temperature_mired_to_kelvin(self._color_temp)), transition, ) self._is_on = True if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] self._luminary.set_luminance(int(self._brightness / 2.55), transition) else: self._luminary.set_onoff(True)
def turn_on(self, **kwargs): """Turn the light on.""" if not self.is_on: self._lamp.switch(True) if ATTR_BRIGHTNESS in kwargs: brightness = int((kwargs[ATTR_BRIGHTNESS] / 255.0) * 200.0) self._lamp.brightness(brightness) return if ATTR_RGB_COLOR in kwargs: rgb = kwargs[ATTR_RGB_COLOR] self._lamp.rgb(*rgb) return if ATTR_COLOR_TEMP in kwargs: kelvin = int(color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP])) self._lamp.white(kelvin) return if ATTR_EFFECT in kwargs: effect = kwargs[ATTR_EFFECT] self._lamp.effect(effect) return
async def async_turn_on(self, **kwargs): """Instruct the light to turn on.""" transition_time = None if ATTR_TRANSITION in kwargs: transition_time = int(kwargs[ATTR_TRANSITION]) * 10 dimmer_command = None if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] if brightness > 254: brightness = 254 elif brightness < 0: brightness = 0 dimmer_data = {ATTR_DIMMER: brightness, ATTR_TRANSITION_TIME: transition_time} dimmer_command = self._light_control.set_dimmer(**dimmer_data) transition_time = None else: dimmer_command = self._light_control.set_state(True) color_command = None if ATTR_HS_COLOR in kwargs and self._light_control.can_set_color: hue = int(kwargs[ATTR_HS_COLOR][0] * (self._light_control.max_hue / 360)) sat = int(kwargs[ATTR_HS_COLOR][1] * (self._light_control.max_saturation / 100)) color_data = {ATTR_HUE: hue, ATTR_SAT: sat, ATTR_TRANSITION_TIME: transition_time} color_command = self._light_control.set_hsb(**color_data) transition_time = None temp_command = None if ATTR_COLOR_TEMP in kwargs and (self._light_control.can_set_temp or self._light_control.can_set_color): temp = kwargs[ATTR_COLOR_TEMP] # White Spectrum bulb if self._light_control.can_set_temp: if temp > self.max_mireds: temp = self.max_mireds elif temp < self.min_mireds: temp = self.min_mireds temp_data = {ATTR_COLOR_TEMP: temp, ATTR_TRANSITION_TIME: transition_time} temp_command = self._light_control.set_color_temp(**temp_data) transition_time = None # Color bulb (CWS) # color_temp needs to be set with hue/saturation elif self._light_control.can_set_color: temp_k = color_util.color_temperature_mired_to_kelvin(temp) hs_color = color_util.color_temperature_to_hs(temp_k) hue = int(hs_color[0] * (self._light_control.max_hue / 360)) sat = int(hs_color[1] * (self._light_control.max_saturation / 100)) color_data = {ATTR_HUE: hue, ATTR_SAT: sat, ATTR_TRANSITION_TIME: transition_time} color_command = self._light_control.set_hsb(**color_data) transition_time = None # HSB can always be set, but color temp + brightness is bulb dependant command = dimmer_command if command is not None: command += color_command else: command = color_command if self._light_control.can_combine_commands: await self._api(command + temp_command) else: if temp_command is not None: await self._api(temp_command) if command is not None: await self._api(command)
def ct_to_rgb(temp): """Convert color temperature (mireds) to RGB.""" colorlist = list( color_temperature_to_rgb(color_temperature_mired_to_kelvin(temp))) return [int(val) for val in colorlist]
def entity_to_device(entity: Entity, config: Config, units: UnitSystem): """Convert a hass entity into an google actions device.""" entity_config = config.entity_config.get(entity.entity_id, {}) google_domain = entity_config.get(CONF_TYPE) class_data = MAPPING_COMPONENT.get( google_domain or entity.domain) if class_data is None: return None device = { 'id': entity.entity_id, 'name': {}, 'attributes': {}, 'traits': [], 'willReportState': False, } device['type'] = class_data[0] device['traits'].append(class_data[1]) # handle custom names device['name']['name'] = entity_config.get(CONF_NAME) or entity.name # use aliases aliases = entity_config.get(CONF_ALIASES) if aliases: device['name']['nicknames'] = aliases # add trait if entity supports feature if class_data[2]: supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) for feature, trait in class_data[2].items(): if feature & supported > 0: device['traits'].append(trait) # Actions require this attributes for a device # supporting temperature # For IKEA trådfri, these attributes only seem to # be set only if the device is on? if trait == TRAIT_COLOR_TEMP: if entity.attributes.get( light.ATTR_MAX_MIREDS) is not None: device['attributes']['temperatureMinK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MAX_MIREDS)))) if entity.attributes.get( light.ATTR_MIN_MIREDS) is not None: device['attributes']['temperatureMaxK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MIN_MIREDS)))) if entity.domain == climate.DOMAIN: modes = [] for mode in entity.attributes.get(climate.ATTR_OPERATION_LIST, []): if mode in CLIMATE_SUPPORTED_MODES: modes.append(mode) elif mode == climate.STATE_AUTO: modes.append(CLIMATE_MODE_HEATCOOL) device['attributes'] = { 'availableThermostatModes': ','.join(modes), 'thermostatTemperatureUnit': 'F' if units.temperature_unit == TEMP_FAHRENHEIT else 'C', } _LOGGER.debug('Thermostat attributes %s', device['attributes']) if entity.domain == sensor.DOMAIN: if google_domain == climate.DOMAIN: unit_of_measurement = entity.attributes.get( ATTR_UNIT_OF_MEASUREMENT, units.temperature_unit ) device['attributes'] = { 'thermostatTemperatureUnit': 'F' if unit_of_measurement == TEMP_FAHRENHEIT else 'C', } _LOGGER.debug('Sensor attributes %s', device['attributes']) return device
def test_should_return_25000_kelvin_when_input_is_40_mired(self): """Function should return 25000K if given 40 mired.""" kelvin = color_util.color_temperature_mired_to_kelvin(40) self.assertEqual(25000, kelvin)
def query_device(entity: Entity, units: UnitSystem) -> dict: """Take an entity and return a properly formatted device object.""" def celsius(deg: Optional[float]) -> Optional[float]: """Convert a float to Celsius and rounds to one decimal place.""" if deg is None: return None return round(METRIC_SYSTEM.temperature(deg, units.temperature_unit), 1) if entity.domain == climate.DOMAIN: mode = entity.attributes.get(climate.ATTR_OPERATION_MODE).lower() if mode not in CLIMATE_SUPPORTED_MODES: mode = 'on' response = { 'thermostatMode': mode, 'thermostatTemperatureSetpoint': celsius(entity.attributes.get(climate.ATTR_TEMPERATURE)), 'thermostatTemperatureAmbient': celsius(entity.attributes.get(climate.ATTR_CURRENT_TEMPERATURE)), 'thermostatTemperatureSetpointHigh': celsius(entity.attributes.get(climate.ATTR_TARGET_TEMP_HIGH)), 'thermostatTemperatureSetpointLow': celsius(entity.attributes.get(climate.ATTR_TARGET_TEMP_LOW)), 'thermostatHumidityAmbient': entity.attributes.get(climate.ATTR_CURRENT_HUMIDITY), } return {k: v for k, v in response.items() if v is not None} final_state = entity.state != STATE_OFF final_brightness = entity.attributes.get(light.ATTR_BRIGHTNESS, 255 if final_state else 0) if entity.domain == media_player.DOMAIN: level = entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0) # Convert 0.0-1.0 to 0-255 final_brightness = round(min(1.0, level) * 255) if final_brightness is None: final_brightness = 255 if final_state else 0 final_brightness = 100 * (final_brightness / 255) query_response = { "on": final_state, "online": True, "brightness": int(final_brightness) } supported_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if supported_features & \ (light.SUPPORT_COLOR_TEMP | light.SUPPORT_RGB_COLOR): query_response["color"] = {} if entity.attributes.get(light.ATTR_COLOR_TEMP) is not None: query_response["color"]["temperature"] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_COLOR_TEMP)))) if entity.attributes.get(light.ATTR_COLOR_NAME) is not None: query_response["color"]["name"] = \ entity.attributes.get(light.ATTR_COLOR_NAME) if entity.attributes.get(light.ATTR_RGB_COLOR) is not None: color_rgb = entity.attributes.get(light.ATTR_RGB_COLOR) if color_rgb is not None: query_response["color"]["spectrumRGB"] = \ int(color.color_rgb_to_hex( color_rgb[0], color_rgb[1], color_rgb[2]), 16) return query_response
def entity_to_device(entity: Entity, units: UnitSystem): """Convert a hass entity into an google actions device.""" class_data = MAPPING_COMPONENT.get( entity.attributes.get(ATTR_GOOGLE_ASSISTANT_TYPE) or entity.domain) if class_data is None: return None device = { 'id': entity.entity_id, 'name': {}, 'attributes': {}, 'traits': [], 'willReportState': False, } device['type'] = class_data[0] device['traits'].append(class_data[1]) # handle custom names device['name']['name'] = \ entity.attributes.get(ATTR_GOOGLE_ASSISTANT_NAME) or \ entity.attributes.get(CONF_FRIENDLY_NAME) # use aliases aliases = entity.attributes.get(CONF_ALIASES) if aliases: if isinstance(aliases, list): device['name']['nicknames'] = aliases else: _LOGGER.warning("%s must be a list", CONF_ALIASES) # add trait if entity supports feature if class_data[2]: supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) for feature, trait in class_data[2].items(): if feature & supported > 0: device['traits'].append(trait) # Actions require this attributes for a device # supporting temperature # For IKEA trådfri, these attributes only seem to # be set only if the device is on? if trait == TRAIT_COLOR_TEMP: if entity.attributes.get( light.ATTR_MAX_MIREDS) is not None: device['attributes']['temperatureMinK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MAX_MIREDS)))) if entity.attributes.get( light.ATTR_MIN_MIREDS) is not None: device['attributes']['temperatureMaxK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MIN_MIREDS)))) if entity.domain == climate.DOMAIN: modes = ','.join( m.lower() for m in entity.attributes.get( climate.ATTR_OPERATION_LIST, []) if m.lower() in CLIMATE_SUPPORTED_MODES) device['attributes'] = { 'availableThermostatModes': modes, 'thermostatTemperatureUnit': 'F' if units.temperature_unit == TEMP_FAHRENHEIT else 'C', } _LOGGER.debug('Thermostat attributes %s', device['attributes']) return device
def query_device(entity: Entity, units: UnitSystem) -> dict: """Take an entity and return a properly formatted device object.""" def celsius(deg: Optional[float]) -> Optional[float]: """Convert a float to Celsius and rounds to one decimal place.""" if deg is None: return None return round(METRIC_SYSTEM.temperature(deg, units.temperature_unit), 1) if entity.domain == climate.DOMAIN: mode = entity.attributes.get(climate.ATTR_OPERATION_MODE).lower() if mode not in CLIMATE_SUPPORTED_MODES: mode = 'on' response = { 'thermostatMode': mode, 'thermostatTemperatureSetpoint': celsius(entity.attributes.get(climate.ATTR_TEMPERATURE)), 'thermostatTemperatureAmbient': celsius(entity.attributes.get(climate.ATTR_CURRENT_TEMPERATURE)), 'thermostatTemperatureSetpointHigh': celsius(entity.attributes.get(climate.ATTR_TARGET_TEMP_HIGH)), 'thermostatTemperatureSetpointLow': celsius(entity.attributes.get(climate.ATTR_TARGET_TEMP_LOW)), 'thermostatHumidityAmbient': entity.attributes.get(climate.ATTR_CURRENT_HUMIDITY), } return {k: v for k, v in response.items() if v is not None} final_state = entity.state != STATE_OFF final_brightness = entity.attributes.get(light.ATTR_BRIGHTNESS, 255 if final_state else 0) if entity.domain == media_player.DOMAIN: level = entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0) # Convert 0.0-1.0 to 0-255 final_brightness = round(min(1.0, level) * 255) if final_brightness is None: final_brightness = 255 if final_state else 0 final_brightness = 100 * (final_brightness / 255) query_response = { "on": final_state, "online": True, "brightness": int(final_brightness) } supported_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if supported_features & \ (light.SUPPORT_COLOR_TEMP | light.SUPPORT_RGB_COLOR): query_response["color"] = {} if entity.attributes.get(light.ATTR_COLOR_TEMP) is not None: query_response["color"]["temperature"] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_COLOR_TEMP)))) if entity.attributes.get(light.ATTR_COLOR_NAME) is not None: query_response["color"]["name"] = \ entity.attributes.get(light.ATTR_COLOR_NAME) if entity.attributes.get(light.ATTR_RGB_COLOR) is not None: color_rgb = entity.attributes.get(light.ATTR_RGB_COLOR) if color_rgb is not None: query_response["color"]["spectrumRGB"] = \ int(color.color_rgb_to_hex( color_rgb[0], color_rgb[1], color_rgb[2]), 16) return query_response
# # We previously had a problem with the brightness # sometimes reporting as 0 when an effect was in progress, # however this has since been resolved in the upstream library return max(MIN_RGB_BRIGHTNESS, brightness) async def _async_set_mode(self, **kwargs: Any) -> None: """Set an effect or color mode.""" brightness = self._async_brightness(**kwargs) # Handle switch to Effect Mode if effect := kwargs.get(ATTR_EFFECT): await self._async_set_effect(effect, brightness) return # Handle switch to CCT Color Mode if color_temp_mired := kwargs.get(ATTR_COLOR_TEMP): color_temp_kelvin = color_temperature_mired_to_kelvin( color_temp_mired) if (ATTR_BRIGHTNESS not in kwargs and self.color_mode in MULTI_BRIGHTNESS_COLOR_MODES): # When switching to color temp from RGBWW or RGB&W mode, # we do not want the overall brightness of the RGB channels brightness = max(MIN_CCT_BRIGHTNESS, *self._device.rgb) await self._device.async_set_white_temp(color_temp_kelvin, brightness) return # Handle switch to RGB Color Mode if rgb := kwargs.get(ATTR_RGB_COLOR): if not self._device.requires_turn_on: rgb = _min_rgb_brightness(rgb) red, green, blue = rgb await self._device.async_set_levels(red, green,
def test_color_temperature_mired_to_kelvin(): """Test color_temperature_mired_to_kelvin.""" assert color_util.color_temperature_mired_to_kelvin(40) == 25000 assert color_util.color_temperature_mired_to_kelvin(200) == 5000 with pytest.raises(ZeroDivisionError): assert color_util.color_temperature_mired_to_kelvin(0)
async def test_services(hass: HomeAssistant, caplog): """Test Yeelight services.""" mocked_bulb = _mocked_bulb() with patch(f"{MODULE}.Bulb", return_value=mocked_bulb): await async_setup_component(hass, DOMAIN, YAML_CONFIGURATION) await hass.async_block_till_done() async def _async_test_service(service, data, method, payload=None, domain=DOMAIN): err_count = len( [x for x in caplog.records if x.levelno == logging.ERROR]) # success mocked_method = MagicMock() setattr(type(mocked_bulb), method, mocked_method) await hass.services.async_call(domain, service, data, blocking=True) if payload is None: mocked_method.assert_called_once() elif type(payload) == list: mocked_method.assert_called_once_with(*payload) else: mocked_method.assert_called_once_with(**payload) assert (len([x for x in caplog.records if x.levelno == logging.ERROR]) == err_count) # failure mocked_method = MagicMock(side_effect=BulbException) setattr(type(mocked_bulb), method, mocked_method) await hass.services.async_call(domain, service, data, blocking=True) assert (len([x for x in caplog.records if x.levelno == logging.ERROR]) == err_count + 1) # turn_on brightness = 100 color_temp = 200 transition = 1 await hass.services.async_call( "light", SERVICE_TURN_ON, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_BRIGHTNESS: brightness, ATTR_COLOR_TEMP: color_temp, ATTR_FLASH: FLASH_LONG, ATTR_EFFECT: EFFECT_STOP, ATTR_TRANSITION: transition, }, blocking=True, ) mocked_bulb.turn_on.assert_called_once_with( duration=transition * 1000, light_type=LightType.Main, power_mode=PowerMode.NORMAL, ) mocked_bulb.turn_on.reset_mock() mocked_bulb.start_music.assert_called_once() mocked_bulb.set_brightness.assert_called_once_with( brightness / 255 * 100, duration=transition * 1000, light_type=LightType.Main) mocked_bulb.set_color_temp.assert_called_once_with( color_temperature_mired_to_kelvin(color_temp), duration=transition * 1000, light_type=LightType.Main, ) mocked_bulb.start_flow.assert_called_once() # flash mocked_bulb.stop_flow.assert_called_once_with(light_type=LightType.Main) # turn_on nightlight await _async_test_service( SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_NIGHTLIGHT}, "turn_on", payload={ "duration": DEFAULT_TRANSITION, "light_type": LightType.Main, "power_mode": PowerMode.MOONLIGHT, }, domain="light", ) # turn_off await _async_test_service( SERVICE_TURN_OFF, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITION: transition }, "turn_off", domain="light", payload={ "duration": transition * 1000, "light_type": LightType.Main }, ) # set_mode mode = "rgb" await _async_test_service( SERVICE_SET_MODE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_MODE: "rgb" }, "set_power_mode", [PowerMode[mode.upper()]], ) # start_flow await _async_test_service( SERVICE_START_FLOW, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITIONS: [{ YEELIGHT_TEMPERATURE_TRANSACTION: [1900, 2000, 60] }], }, "start_flow", ) # set_color_scene await _async_test_service( SERVICE_SET_COLOR_SCENE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_RGB_COLOR: [10, 20, 30], ATTR_BRIGHTNESS: 50, }, "set_scene", [SceneClass.COLOR, 10, 20, 30, 50], ) # set_hsv_scene await _async_test_service( SERVICE_SET_HSV_SCENE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_HS_COLOR: [180, 50], ATTR_BRIGHTNESS: 50 }, "set_scene", [SceneClass.HSV, 180, 50, 50], ) # set_color_temp_scene await _async_test_service( SERVICE_SET_COLOR_TEMP_SCENE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_KELVIN: 4000, ATTR_BRIGHTNESS: 50 }, "set_scene", [SceneClass.CT, 4000, 50], ) # set_color_flow_scene await _async_test_service( SERVICE_SET_COLOR_FLOW_SCENE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITIONS: [{ YEELIGHT_TEMPERATURE_TRANSACTION: [1900, 2000, 60] }], }, "set_scene", ) # set_auto_delay_off_scene await _async_test_service( SERVICE_SET_AUTO_DELAY_OFF_SCENE, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_MINUTES: 1, ATTR_BRIGHTNESS: 50 }, "set_scene", [SceneClass.AUTO_DELAY_OFF, 50, 1], ) # test _cmd wrapper error handler err_count = len([x for x in caplog.records if x.levelno == logging.ERROR]) type(mocked_bulb).turn_on = MagicMock() type(mocked_bulb).set_brightness = MagicMock(side_effect=BulbException) await hass.services.async_call( "light", SERVICE_TURN_ON, { ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_BRIGHTNESS: 50 }, blocking=True, ) assert (len([x for x in caplog.records if x.levelno == logging.ERROR]) == err_count + 1)
async def async_turn_on(self, **kwargs): """Forward the turn_on command to all lights in the light group.""" data = {ATTR_ENTITY_ID: self._entity_ids} emulate_color_temp_entity_ids = [] if ATTR_BRIGHTNESS in kwargs: data[ATTR_BRIGHTNESS] = kwargs[ATTR_BRIGHTNESS] if ATTR_HS_COLOR in kwargs: data[ATTR_HS_COLOR] = kwargs[ATTR_HS_COLOR] if ATTR_RGB_COLOR in kwargs: data[ATTR_RGB_COLOR] = kwargs[ATTR_RGB_COLOR] if ATTR_RGBW_COLOR in kwargs: data[ATTR_RGBW_COLOR] = kwargs[ATTR_RGBW_COLOR] if ATTR_RGBWW_COLOR in kwargs: data[ATTR_RGBWW_COLOR] = kwargs[ATTR_RGBWW_COLOR] if ATTR_XY_COLOR in kwargs: data[ATTR_XY_COLOR] = kwargs[ATTR_XY_COLOR] if ATTR_COLOR_TEMP in kwargs: data[ATTR_COLOR_TEMP] = kwargs[ATTR_COLOR_TEMP] # Create a new entity list to mutate updated_entities = list(self._entity_ids) # Walk through initial entity ids, split entity lists by support for entity_id in self._entity_ids: state = self.hass.states.get(entity_id) if not state: continue support = state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) # Only pass color temperature to supported entity_ids if color_supported( support) and not color_temp_supported(support): emulate_color_temp_entity_ids.append(entity_id) updated_entities.remove(entity_id) data[ATTR_ENTITY_ID] = updated_entities if ATTR_WHITE_VALUE in kwargs: data[ATTR_WHITE_VALUE] = kwargs[ATTR_WHITE_VALUE] if ATTR_EFFECT in kwargs: data[ATTR_EFFECT] = kwargs[ATTR_EFFECT] if ATTR_TRANSITION in kwargs: data[ATTR_TRANSITION] = kwargs[ATTR_TRANSITION] if ATTR_FLASH in kwargs: data[ATTR_FLASH] = kwargs[ATTR_FLASH] if not emulate_color_temp_entity_ids: await self.hass.services.async_call( light.DOMAIN, light.SERVICE_TURN_ON, data, blocking=True, context=self._context, ) return emulate_color_temp_data = data.copy() temp_k = color_util.color_temperature_mired_to_kelvin( emulate_color_temp_data[ATTR_COLOR_TEMP]) hs_color = color_util.color_temperature_to_hs(temp_k) emulate_color_temp_data[ATTR_HS_COLOR] = hs_color del emulate_color_temp_data[ATTR_COLOR_TEMP] emulate_color_temp_data[ATTR_ENTITY_ID] = emulate_color_temp_entity_ids await asyncio.gather( self.hass.services.async_call( light.DOMAIN, light.SERVICE_TURN_ON, data, blocking=True, context=self._context, ), self.hass.services.async_call( light.DOMAIN, light.SERVICE_TURN_ON, emulate_color_temp_data, blocking=True, context=self._context, ), )
def test_should_return_5000_kelvin_when_input_is_200_mired(self): """Function should return 5000K if given 200 mired.""" kelvin = color_util.color_temperature_mired_to_kelvin(200) assert 5000 == kelvin
def test_should_return_5000_kelvin_when_input_is_200_mired(self): """Function should return 5000K if given 200 mired.""" kelvin = color_util.color_temperature_mired_to_kelvin(200) self.assertEqual(5000, kelvin)
async def async_set_color_temp(self, value: float): """Set the color temperature of the device.""" kelvin = color_util.color_temperature_mired_to_kelvin(value) kelvin = max(min(kelvin, 30000.0), 1.0) await self._device.set_color_temperature(kelvin, set_status=True)
async def async_set_color_temp(self, value: float): """Set the color temperature of the device.""" kelvin = color_util.color_temperature_mired_to_kelvin(value) kelvin = max(min(kelvin, 30000.0), 1.0) await self._device.set_color_temperature( kelvin, set_status=True)
async def async_turn_on(self, **kwargs: Any) -> None: """Turn the light on.""" brightness = kwargs.get(ATTR_BRIGHTNESS) mireds = kwargs.get(ATTR_COLOR_TEMP) rgb = kwargs.get(ATTR_RGB_COLOR) rgbw = kwargs.get(ATTR_RGBW_COLOR) hs_color = kwargs.get(ATTR_HS_COLOR) xy_color = kwargs.get(ATTR_XY_COLOR) if (not self.is_on and brightness is None and mireds is None and rgb is None and rgbw is None and hs_color is None and xy_color is None): await self._device.set_on() return async def set_color(rgb: tuple[int, int, int], white: int | None, brightness: int | None) -> None: """Set color of light. Normalize colors for brightness when not writable.""" if self._device.brightness.writable: # let the KNX light controller handle brightness await self._device.set_color(rgb, white) if brightness: await self._device.set_brightness(brightness) return if brightness is None: # normalize for brightness if brightness is derived from color brightness = self.brightness or 255 rgb = cast( Tuple[int, int, int], tuple(color * brightness // 255 for color in rgb), ) white = white * brightness // 255 if white is not None else None await self._device.set_color(rgb, white) # return after RGB(W) color has changed as it implicitly sets the brightness if rgbw is not None: await set_color(rgbw[:3], rgbw[3], brightness) return if rgb is not None: await set_color(rgb, None, brightness) return if mireds is not None: kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds)) kelvin = min(self._max_kelvin, max(self._min_kelvin, kelvin)) if self._device.supports_color_temperature: await self._device.set_color_temperature(kelvin) elif self._device.supports_tunable_white: relative_ct = int(255 * (kelvin - self._min_kelvin) / (self._max_kelvin - self._min_kelvin)) await self._device.set_tunable_white(relative_ct) if xy_color is not None: await self._device.set_xyy_color( XYYColor(color=xy_color, brightness=brightness)) return if hs_color is not None: # round so only one telegram will be sent if the other matches state hue = round(hs_color[0]) sat = round(hs_color[1]) await self._device.set_hs_color((hue, sat)) if brightness is not None: # brightness: 1..255; 0 brightness will call async_turn_off() if self._device.brightness.writable: await self._device.set_brightness(brightness) return # brightness without color in kwargs; set via color if self.color_mode == COLOR_MODE_XY: await self._device.set_xyy_color( XYYColor(brightness=brightness)) return # default to white if color not known for RGB(W) if self.color_mode == COLOR_MODE_RGBW: _rgbw = self.rgbw_color if not _rgbw or not any(_rgbw): _rgbw = (0, 0, 0, 255) await set_color(_rgbw[:3], _rgbw[3], brightness) return if self.color_mode == COLOR_MODE_RGB: _rgb = self.rgb_color if not _rgb or not any(_rgb): _rgb = (255, 255, 255) await set_color(_rgb, None, brightness) return
def ct_to_hs(temp): """Convert color temperature (mireds) to hs.""" colorlist = list( color_util.color_temperature_to_hs( color_util.color_temperature_mired_to_kelvin(temp))) return [int(val) for val in colorlist]
async def async_turn_on(self, **kwargs): """Instruct the light to turn on.""" transition_time = None if ATTR_TRANSITION in kwargs: transition_time = int(kwargs[ATTR_TRANSITION]) * 10 dimmer_command = None if ATTR_BRIGHTNESS in kwargs: brightness = kwargs[ATTR_BRIGHTNESS] brightness = min(brightness, 254) dimmer_data = { ATTR_DIMMER: brightness, ATTR_TRANSITION_TIME: transition_time, } dimmer_command = self._device_control.set_dimmer(**dimmer_data) transition_time = None else: dimmer_command = self._device_control.set_state(True) color_command = None if ATTR_HS_COLOR in kwargs and self._device_control.can_set_color: hue = int(kwargs[ATTR_HS_COLOR][0] * (self._device_control.max_hue / 360)) sat = int(kwargs[ATTR_HS_COLOR][1] * (self._device_control.max_saturation / 100)) color_data = { ATTR_HUE: hue, ATTR_SAT: sat, ATTR_TRANSITION_TIME: transition_time, } color_command = self._device_control.set_hsb(**color_data) transition_time = None temp_command = None if ATTR_COLOR_TEMP in kwargs and (self._device_control.can_set_temp or self._device_control.can_set_color): temp = kwargs[ATTR_COLOR_TEMP] # White Spectrum bulb if self._device_control.can_set_temp: if temp > self.max_mireds: temp = self.max_mireds elif temp < self.min_mireds: temp = self.min_mireds temp_data = { ATTR_COLOR_TEMP: temp, ATTR_TRANSITION_TIME: transition_time, } temp_command = self._device_control.set_color_temp(**temp_data) transition_time = None # Color bulb (CWS) # color_temp needs to be set with hue/saturation elif self._device_control.can_set_color: temp_k = color_util.color_temperature_mired_to_kelvin(temp) hs_color = color_util.color_temperature_to_hs(temp_k) hue = int(hs_color[0] * (self._device_control.max_hue / 360)) sat = int(hs_color[1] * (self._device_control.max_saturation / 100)) color_data = { ATTR_HUE: hue, ATTR_SAT: sat, ATTR_TRANSITION_TIME: transition_time, } color_command = self._device_control.set_hsb(**color_data) transition_time = None # HSB can always be set, but color temp + brightness is bulb dependent command = dimmer_command if command is not None: command += color_command else: command = color_command if self._device_control.can_combine_commands: await self._api(command + temp_command) else: if temp_command is not None: await self._api(temp_command) if command is not None: await self._api(command)
async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the light.""" if (color_temp := kwargs.get(ATTR_COLOR_TEMP)) is not None: self._device.light_color_temperature = color_temperature_mired_to_kelvin( color_temp)
async def async_turn_on(self, **kwargs: Any) -> None: """Turn on light.""" if self.block.type == "relay": self.control_result = await self.set_state(turn="on") self.async_write_ha_state() return set_mode = None supported_color_modes = self._attr_supported_color_modes params: dict[str, Any] = {"turn": "on"} if ATTR_TRANSITION in kwargs: params["transition"] = min(int(kwargs[ATTR_TRANSITION] * 1000), MAX_TRANSITION_TIME) if ATTR_BRIGHTNESS in kwargs and brightness_supported( supported_color_modes): brightness_pct = int(100 * (kwargs[ATTR_BRIGHTNESS] + 1) / 255) if hasattr(self.block, "gain"): params["gain"] = brightness_pct if hasattr(self.block, "brightness"): params["brightness"] = brightness_pct if ATTR_COLOR_TEMP in kwargs and ColorMode.COLOR_TEMP in supported_color_modes: color_temp = color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) color_temp = min(self._max_kelvin, max(self._min_kelvin, color_temp)) # Color temperature change - used only in white mode, switch device mode to white set_mode = "white" params["temp"] = int(color_temp) if ATTR_RGB_COLOR in kwargs and ColorMode.RGB in supported_color_modes: # Color channels change - used only in color mode, switch device mode to color set_mode = "color" (params["red"], params["green"], params["blue"]) = kwargs[ATTR_RGB_COLOR] if ATTR_RGBW_COLOR in kwargs and ColorMode.RGBW in supported_color_modes: # Color channels change - used only in color mode, switch device mode to color set_mode = "color" (params["red"], params["green"], params["blue"], params["white"]) = kwargs[ATTR_RGBW_COLOR] if ATTR_EFFECT in kwargs and ATTR_COLOR_TEMP not in kwargs: # Color effect change - used only in color mode, switch device mode to color set_mode = "color" if self.wrapper.model == "SHBLB-1": effect_dict = SHBLB_1_RGB_EFFECTS else: effect_dict = STANDARD_RGB_EFFECTS if kwargs[ATTR_EFFECT] in effect_dict.values(): params["effect"] = [ k for k, v in effect_dict.items() if v == kwargs[ATTR_EFFECT] ][0] else: LOGGER.error( "Effect '%s' not supported by device %s", kwargs[ATTR_EFFECT], self.wrapper.model, ) if (set_mode and set_mode != self.mode and self.wrapper.model in DUAL_MODE_LIGHT_MODELS): params["mode"] = set_mode self.control_result = await self.set_state(**params) self.async_write_ha_state()
async def async_handle_light_on_service(light, call): """Handle turning a light on. If brightness is set to 0, this service will turn the light off. """ params = dict(call.data["params"]) # Only process params once we processed brightness step if params and (ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params): brightness = light.brightness if light.is_on else 0 if ATTR_BRIGHTNESS_STEP in params: brightness += params.pop(ATTR_BRIGHTNESS_STEP) else: brightness += round( params.pop(ATTR_BRIGHTNESS_STEP_PCT) / 100 * 255) params[ATTR_BRIGHTNESS] = max(0, min(255, brightness)) preprocess_turn_on_alternatives(hass, params) if (not params or not light.is_on) or (params and ATTR_TRANSITION not in params): profiles.apply_default(light.entity_id, light.is_on, params) legacy_supported_color_modes = ( light._light_internal_supported_color_modes # pylint: disable=protected-access ) supported_color_modes = light.supported_color_modes # Backwards compatibility: if an RGBWW color is specified, convert to RGB + W # for legacy lights if ATTR_RGBW_COLOR in params: if (ColorMode.RGBW in legacy_supported_color_modes and not supported_color_modes): rgbw_color = params.pop(ATTR_RGBW_COLOR) params[ATTR_RGB_COLOR] = rgbw_color[0:3] params[ATTR_WHITE_VALUE] = rgbw_color[3] # If a color temperature is specified, emulate it if not supported by the light if ATTR_COLOR_TEMP in params: if (supported_color_modes and ColorMode.COLOR_TEMP not in supported_color_modes and ColorMode.RGBWW in supported_color_modes): color_temp = params.pop(ATTR_COLOR_TEMP) brightness = params.get(ATTR_BRIGHTNESS, light.brightness) params[ ATTR_RGBWW_COLOR] = color_util.color_temperature_to_rgbww( color_temp, brightness, light.min_mireds, light.max_mireds) elif ColorMode.COLOR_TEMP not in legacy_supported_color_modes: color_temp = params.pop(ATTR_COLOR_TEMP) if color_supported(legacy_supported_color_modes): temp_k = color_util.color_temperature_mired_to_kelvin( color_temp) params[ATTR_HS_COLOR] = color_util.color_temperature_to_hs( temp_k) # If a color is specified, convert to the color space supported by the light # Backwards compatibility: Fall back to hs color if light.supported_color_modes # is not implemented if not supported_color_modes: if (rgb_color := params.pop(ATTR_RGB_COLOR, None)) is not None: params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color) elif (xy_color := params.pop(ATTR_XY_COLOR, None)) is not None: params[ATTR_HS_COLOR] = color_util.color_xy_to_hs(*xy_color)
def entity_to_device(entity: Entity, units: UnitSystem): """Convert a hass entity into an google actions device.""" class_data = MAPPING_COMPONENT.get( entity.attributes.get(ATTR_GOOGLE_ASSISTANT_TYPE) or entity.domain) if class_data is None: return None device = { 'id': entity.entity_id, 'name': {}, 'attributes': {}, 'traits': [], 'willReportState': False, } device['type'] = class_data[0] device['traits'].append(class_data[1]) # handle custom names device['name']['name'] = \ entity.attributes.get(ATTR_GOOGLE_ASSISTANT_NAME) or \ entity.attributes.get(CONF_FRIENDLY_NAME) # use aliases aliases = entity.attributes.get(CONF_ALIASES) if aliases: if isinstance(aliases, list): device['name']['nicknames'] = aliases else: _LOGGER.warning("%s must be a list", CONF_ALIASES) # add trait if entity supports feature if class_data[2]: supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) for feature, trait in class_data[2].items(): if feature & supported > 0: device['traits'].append(trait) # Actions require this attributes for a device # supporting temperature # For IKEA trådfri, these attributes only seem to # be set only if the device is on? if trait == TRAIT_COLOR_TEMP: if entity.attributes.get( light.ATTR_MAX_MIREDS) is not None: device['attributes']['temperatureMinK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MAX_MIREDS)))) if entity.attributes.get( light.ATTR_MIN_MIREDS) is not None: device['attributes']['temperatureMaxK'] = \ int(round(color.color_temperature_mired_to_kelvin( entity.attributes.get(light.ATTR_MIN_MIREDS)))) if entity.domain == climate.DOMAIN: modes = ','.join( m.lower() for m in entity.attributes.get(climate.ATTR_OPERATION_LIST, []) if m.lower() in CLIMATE_SUPPORTED_MODES) device['attributes'] = { 'availableThermostatModes': modes, 'thermostatTemperatureUnit': 'F' if units.temperature_unit == TEMP_FAHRENHEIT else 'C', } _LOGGER.debug('Thermostat attributes %s', device['attributes']) return device
class Light(HomeAccessory): """Generate a Light accessory for a light entity. Currently supports: state, brightness, color temperature, rgb_color. """ def __init__(self, *args): """Initialize a new Light accessory object.""" super().__init__(*args, category=CATEGORY_LIGHTBULB) self.chars = [] self._event_timer = None self._pending_events = {} state = self.hass.states.get(self.entity_id) attributes = state.attributes self.color_modes = color_modes = ( attributes.get(ATTR_SUPPORTED_COLOR_MODES) or []) self._previous_color_mode = attributes.get(ATTR_COLOR_MODE) self.color_supported = color_supported(color_modes) self.color_temp_supported = color_temp_supported(color_modes) self.rgbw_supported = COLOR_MODE_RGBW in color_modes self.rgbww_supported = COLOR_MODE_RGBWW in color_modes self.white_supported = COLOR_MODE_WHITE in color_modes self.brightness_supported = brightness_supported(color_modes) if self.brightness_supported: self.chars.append(CHAR_BRIGHTNESS) if self.color_supported: self.chars.extend([CHAR_HUE, CHAR_SATURATION]) if self.color_temp_supported or COLOR_MODES_WITH_WHITES.intersection( self.color_modes): self.chars.append(CHAR_COLOR_TEMPERATURE) serv_light = self.add_preload_service(SERV_LIGHTBULB, self.chars) self.char_on = serv_light.configure_char(CHAR_ON, value=0) if self.brightness_supported: # Initial value is set to 100 because 0 is a special value (off). 100 is # an arbitrary non-zero value. It is updated immediately by async_update_state # to set to the correct initial value. self.char_brightness = serv_light.configure_char(CHAR_BRIGHTNESS, value=100) if CHAR_COLOR_TEMPERATURE in self.chars: self.min_mireds = math.floor( attributes.get(ATTR_MIN_MIREDS, DEFAULT_MIN_MIREDS)) self.max_mireds = math.ceil( attributes.get(ATTR_MAX_MIREDS, DEFAULT_MAX_MIREDS)) if not self.color_temp_supported and not self.rgbww_supported: self.max_mireds = self.min_mireds self.char_color_temp = serv_light.configure_char( CHAR_COLOR_TEMPERATURE, value=self.min_mireds, properties={ PROP_MIN_VALUE: self.min_mireds, PROP_MAX_VALUE: self.max_mireds, }, ) if self.color_supported: self.char_hue = serv_light.configure_char(CHAR_HUE, value=0) self.char_saturation = serv_light.configure_char(CHAR_SATURATION, value=75) self.async_update_state(state) serv_light.setter_callback = self._set_chars def _set_chars(self, char_values): _LOGGER.debug("Light _set_chars: %s", char_values) # Newest change always wins if CHAR_COLOR_TEMPERATURE in self._pending_events and ( CHAR_SATURATION in char_values or CHAR_HUE in char_values): del self._pending_events[CHAR_COLOR_TEMPERATURE] for char in (CHAR_HUE, CHAR_SATURATION): if char in self._pending_events and CHAR_COLOR_TEMPERATURE in char_values: del self._pending_events[char] self._pending_events.update(char_values) if self._event_timer: self._event_timer() self._event_timer = async_call_later(self.hass, CHANGE_COALESCE_TIME_WINDOW, self._async_send_events) @callback def _async_send_events(self, *_): """Process all changes at once.""" _LOGGER.debug("Coalesced _set_chars: %s", self._pending_events) char_values = self._pending_events self._pending_events = {} events = [] service = SERVICE_TURN_ON params = {ATTR_ENTITY_ID: self.entity_id} if CHAR_ON in char_values: if not char_values[CHAR_ON]: service = SERVICE_TURN_OFF events.append(f"Set state to {char_values[CHAR_ON]}") brightness_pct = None if CHAR_BRIGHTNESS in char_values: if char_values[CHAR_BRIGHTNESS] == 0: events[-1] = "Set state to 0" service = SERVICE_TURN_OFF else: brightness_pct = char_values[CHAR_BRIGHTNESS] events.append(f"brightness at {char_values[CHAR_BRIGHTNESS]}%") if service == SERVICE_TURN_OFF: self.async_call_service(DOMAIN, service, {ATTR_ENTITY_ID: self.entity_id}, ", ".join(events)) return # Handle white channels if CHAR_COLOR_TEMPERATURE in char_values: temp = char_values[CHAR_COLOR_TEMPERATURE] events.append(f"color temperature at {temp}") bright_val = round( ((brightness_pct or self.char_brightness.value) * 255) / 100) if self.color_temp_supported: params[ATTR_COLOR_TEMP] = temp elif self.rgbww_supported: params[ATTR_RGBWW_COLOR] = color_temperature_to_rgbww( temp, bright_val, self.min_mireds, self.max_mireds) elif self.rgbw_supported: params[ATTR_RGBW_COLOR] = (*(0, ) * 3, bright_val) elif self.white_supported: params[ATTR_WHITE] = bright_val elif CHAR_HUE in char_values or CHAR_SATURATION in char_values: hue_sat = ( char_values.get(CHAR_HUE, self.char_hue.value), char_values.get(CHAR_SATURATION, self.char_saturation.value), ) _LOGGER.debug("%s: Set hs_color to %s", self.entity_id, hue_sat) events.append(f"set color at {hue_sat}") params[ATTR_HS_COLOR] = hue_sat if (brightness_pct and ATTR_RGBWW_COLOR not in params and ATTR_RGBW_COLOR not in params): params[ATTR_BRIGHTNESS_PCT] = brightness_pct _LOGGER.debug("Calling light service with params: %s -> %s", char_values, params) self.async_call_service(DOMAIN, service, params, ", ".join(events)) @callback def async_update_state(self, new_state): """Update light after state change.""" # Handle State state = new_state.state attributes = new_state.attributes color_mode = attributes.get(ATTR_COLOR_MODE) self.char_on.set_value(int(state == STATE_ON)) color_mode_changed = self._previous_color_mode != color_mode self._previous_color_mode = color_mode # Handle Brightness if (self.brightness_supported and (brightness := attributes.get(ATTR_BRIGHTNESS)) is not None and isinstance(brightness, (int, float))): brightness = round(brightness / 255 * 100, 0) # The homeassistant component might report its brightness as 0 but is # not off. But 0 is a special value in homekit. When you turn on a # homekit accessory it will try to restore the last brightness state # which will be the last value saved by char_brightness.set_value. # But if it is set to 0, HomeKit will update the brightness to 100 as # it thinks 0 is off. # # Therefore, if the the brightness is 0 and the device is still on, # the brightness is mapped to 1 otherwise the update is ignored in # order to avoid this incorrect behavior. if brightness == 0 and state == STATE_ON: brightness = 1 self.char_brightness.set_value(brightness) if color_mode_changed: self.char_brightness.notify() # Handle Color - color must always be set before color temperature # or the iOS UI will not display it correctly. if self.color_supported: if color_temp := attributes.get(ATTR_COLOR_TEMP): hue, saturation = color_temperature_to_hs( color_temperature_mired_to_kelvin(color_temp)) elif color_mode == COLOR_MODE_WHITE: hue, saturation = 0, 0 else: hue, saturation = attributes.get(ATTR_HS_COLOR, (None, None)) if isinstance(hue, (int, float)) and isinstance(saturation, (int, float)): self.char_hue.set_value(round(hue, 0)) self.char_saturation.set_value(round(saturation, 0)) if color_mode_changed: # If the color temp changed, be sure to force the color to update self.char_hue.notify() self.char_saturation.notify()