Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    def _set_light_mode(self, light_mode):
        _LOGGER.info("ArloNightLight: {} light mode {}".format(self._name, light_mode))
        if light_mode is None:
            return

        # {'mode': 'rgb', 'rgb': {'red': 118, 'green': 255, 'blue': 91}}
        # {'mode': 'temperature', 'temperature': 2650}
        # {'mode': 'rainbow'}
        mode = light_mode.get("mode")
        if mode is None:
            return

        if mode == "rgb":
            rgb = light_mode.get("rgb")
            self._hs_color = color_util.color_RGB_to_hs(
                rgb.get("red"), rgb.get("green"), rgb.get("blue")
            )
            self._effect = LIGHT_EFFECT_NONE
        elif mode == "temperature":
            temperature = light_mode.get("temperature")
            self._color_temp = color_util.color_temperature_kelvin_to_mired(temperature)
            self._hs_color = color_util.color_temperature_to_hs(temperature)
            self._effect = LIGHT_EFFECT_NONE
        elif mode == LIGHT_EFFECT_RAINBOW:
            self._effect = LIGHT_EFFECT_RAINBOW
Ejemplo n.º 3
0
    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

        # 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)
Ejemplo n.º 4
0
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]
Ejemplo n.º 5
0
    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))
Ejemplo n.º 6
0
    def async_update_state(self, new_state):
        """Update light after state change."""
        # Handle State
        state = new_state.state
        if state == STATE_ON and self.char_on.value != 1:
            self.char_on.set_value(1)
        elif state == STATE_OFF and self.char_on.value != 0:
            self.char_on.set_value(0)

        # Handle Brightness
        if CHAR_BRIGHTNESS in self.chars:
            brightness = new_state.attributes.get(ATTR_BRIGHTNESS)
            if 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
                if self.char_brightness.value != brightness:
                    self.char_brightness.set_value(brightness)

        # Handle color temperature
        if CHAR_COLOR_TEMPERATURE in self.chars:
            color_temperature = new_state.attributes.get(ATTR_COLOR_TEMP)
            if isinstance(color_temperature, (int, float)):
                color_temperature = round(color_temperature, 0)
                if self.char_color_temperature.value != color_temperature:
                    self.char_color_temperature.set_value(color_temperature)

        # Handle Color
        if CHAR_SATURATION in self.chars and CHAR_HUE in self.chars:
            if ATTR_HS_COLOR in new_state.attributes:
                hue, saturation = new_state.attributes[ATTR_HS_COLOR]
            elif ATTR_COLOR_TEMP in new_state.attributes:
                hue, saturation = color_temperature_to_hs(
                    color_temperature_mired_to_kelvin(
                        new_state.attributes[ATTR_COLOR_TEMP]))
            else:
                hue, saturation = None, None
            if isinstance(hue,
                          (int, float)) and isinstance(saturation,
                                                       (int, float)):
                hue = round(hue, 0)
                saturation = round(saturation, 0)
                if hue != self.char_hue.value:
                    self.char_hue.set_value(hue)
                if saturation != self.char_saturation.value:
                    self.char_saturation.set_value(saturation)
Ejemplo n.º 7
0
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on the light."""
        data = {ATTR_ON: True, ATTR_SEGMENT_ID: self._segment}

        if ATTR_COLOR_TEMP in kwargs:
            mireds = color_util.color_temperature_kelvin_to_mired(
                kwargs[ATTR_COLOR_TEMP])
            data[ATTR_COLOR_PRIMARY] = tuple(
                map(int, color_util.color_temperature_to_rgb(mireds)))

        if ATTR_HS_COLOR in kwargs:
            hue, sat = kwargs[ATTR_HS_COLOR]
            data[ATTR_COLOR_PRIMARY] = color_util.color_hsv_to_RGB(
                hue, sat, 100)

        if ATTR_TRANSITION in kwargs:
            data[ATTR_TRANSITION] = kwargs[ATTR_TRANSITION]

        if ATTR_BRIGHTNESS in kwargs:
            data[ATTR_BRIGHTNESS] = kwargs[ATTR_BRIGHTNESS]

        if ATTR_EFFECT in kwargs:
            data[ATTR_EFFECT] = kwargs[ATTR_EFFECT]

        # Support for RGBW strips
        if self._rgbw and any(x in (ATTR_COLOR_TEMP, ATTR_HS_COLOR)
                              for x in kwargs):
            data[ATTR_COLOR_PRIMARY] = color_util.color_rgb_to_rgbw(
                *data[ATTR_COLOR_PRIMARY])

        try:
            await self.wled.light(**data)

            self._state = True

            if ATTR_BRIGHTNESS in kwargs:
                self._brightness = kwargs[ATTR_BRIGHTNESS]

            if ATTR_EFFECT in kwargs:
                self._effect = kwargs[ATTR_EFFECT]

            if ATTR_HS_COLOR in kwargs:
                self._color = kwargs[ATTR_HS_COLOR]

            if ATTR_COLOR_TEMP in kwargs:
                self._color = color_util.color_temperature_to_hs(mireds)

        except WLEDError:
            _LOGGER.error("An error occurred while turning on WLED light.")
            self._available = False
        self.async_schedule_update_ha_state()
Ejemplo n.º 8
0
    def async_update_state(self, new_state):
        """Update light after state change."""
        # Handle State
        state = new_state.state
        attributes = new_state.attributes
        self.char_on.set_value(int(state == STATE_ON))

        # Handle Brightness
        if self.brightness_supported:
            brightness = attributes.get(ATTR_BRIGHTNESS)
            if 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)

        # Handle Color - color must always be set before color temperature
        # or the iOS UI will not display it correctly.
        if self.color_supported:
            if ATTR_COLOR_TEMP in attributes:
                hue, saturation = color_temperature_to_hs(
                    color_temperature_mired_to_kelvin(
                        new_state.attributes[ATTR_COLOR_TEMP]))
            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))

        # Handle color temperature
        if self.color_temp_supported:
            color_temp = attributes.get(ATTR_COLOR_TEMP)
            if isinstance(color_temp, (int, float)):
                self.char_color_temp.set_value(round(color_temp, 0))
Ejemplo n.º 9
0
 def _light_internal_convert_color(self,
                                   color_mode: ColorMode | str) -> dict:
     data: dict[str, tuple] = {}
     if color_mode == ColorMode.HS and self.hs_color:
         hs_color = self.hs_color
         data[ATTR_HS_COLOR] = (round(hs_color[0],
                                      3), round(hs_color[1], 3))
         data[ATTR_RGB_COLOR] = color_util.color_hs_to_RGB(*hs_color)
         data[ATTR_XY_COLOR] = color_util.color_hs_to_xy(*hs_color)
     elif color_mode == ColorMode.XY and self.xy_color:
         xy_color = self.xy_color
         data[ATTR_HS_COLOR] = color_util.color_xy_to_hs(*xy_color)
         data[ATTR_RGB_COLOR] = color_util.color_xy_to_RGB(*xy_color)
         data[ATTR_XY_COLOR] = (round(xy_color[0],
                                      6), round(xy_color[1], 6))
     elif color_mode == ColorMode.RGB and self.rgb_color:
         rgb_color = self.rgb_color
         data[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
         data[ATTR_RGB_COLOR] = tuple(int(x) for x in rgb_color[0:3])
         data[ATTR_XY_COLOR] = color_util.color_RGB_to_xy(*rgb_color)
     elif color_mode == ColorMode.RGBW and self._light_internal_rgbw_color:
         rgbw_color = self._light_internal_rgbw_color
         rgb_color = color_util.color_rgbw_to_rgb(*rgbw_color)
         data[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
         data[ATTR_RGB_COLOR] = tuple(int(x) for x in rgb_color[0:3])
         data[ATTR_RGBW_COLOR] = tuple(int(x) for x in rgbw_color[0:4])
         data[ATTR_XY_COLOR] = color_util.color_RGB_to_xy(*rgb_color)
     elif color_mode == ColorMode.RGBWW and self.rgbww_color:
         rgbww_color = self.rgbww_color
         rgb_color = color_util.color_rgbww_to_rgb(*rgbww_color,
                                                   self.min_mireds,
                                                   self.max_mireds)
         data[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
         data[ATTR_RGB_COLOR] = tuple(int(x) for x in rgb_color[0:3])
         data[ATTR_RGBWW_COLOR] = tuple(int(x) for x in rgbww_color[0:5])
         data[ATTR_XY_COLOR] = color_util.color_RGB_to_xy(*rgb_color)
     elif color_mode == ColorMode.COLOR_TEMP and self.color_temp:
         hs_color = color_util.color_temperature_to_hs(
             color_util.color_temperature_mired_to_kelvin(self.color_temp))
         data[ATTR_HS_COLOR] = (round(hs_color[0],
                                      3), round(hs_color[1], 3))
         data[ATTR_RGB_COLOR] = color_util.color_hs_to_RGB(*hs_color)
         data[ATTR_XY_COLOR] = color_util.color_hs_to_xy(*hs_color)
     return data
Ejemplo n.º 10
0
    def _get_hs_from_properties(self):
        rgb = self._properties.get('rgb', None)
        color_mode = self._properties.get('color_mode', None)
        if not rgb or not color_mode:
            return None

        color_mode = int(color_mode)
        if color_mode == 2:  # color temperature
            temp_in_k = mired_to_kelvin(self._color_temp)
            return color_util.color_temperature_to_hs(temp_in_k)
        if color_mode == 3:  # hsv
            hue = int(self._properties.get('hue'))
            sat = int(self._properties.get('sat'))
            return (hue / 360 * 65536, sat / 100 * 255)

        rgb = int(rgb)
        blue = rgb & 0xff
        green = (rgb >> 8) & 0xff
        red = (rgb >> 16) & 0xff

        return color_util.color_RGB_to_hs(red, green, blue)
Ejemplo n.º 11
0
    def _get_hs_from_properties(self):
        rgb = self._properties.get('rgb', None)
        color_mode = self._properties.get('color_mode', None)
        if not rgb or not color_mode:
            return None

        color_mode = int(color_mode)
        if color_mode == 2:  # color temperature
            temp_in_k = mired_to_kelvin(self._color_temp)
            return color_util.color_temperature_to_hs(temp_in_k)
        if color_mode == 3:  # hsv
            hue = int(self._properties.get('hue'))
            sat = int(self._properties.get('sat'))
            return (hue / 360 * 65536, sat / 100 * 255)

        rgb = int(rgb)
        blue = rgb & 0xff
        green = (rgb >> 8) & 0xff
        red = (rgb >> 16) & 0xff

        return color_util.color_RGB_to_hs(red, green, blue)
Ejemplo n.º 12
0
    def _get_hs_from_properties(self):
        rgb = self._get_property("rgb")
        color_mode = self._get_property("color_mode")

        if not rgb or not color_mode:
            return None

        color_mode = int(color_mode)
        if color_mode == 2:  # color temperature
            temp_in_k = mired_to_kelvin(self.color_temp)
            return color_util.color_temperature_to_hs(temp_in_k)
        if color_mode == 3:  # hsv
            hue = int(self._get_property("hue"))
            sat = int(self._get_property("sat"))

            return (hue / 360 * 65536, sat / 100 * 255)

        rgb = int(rgb)
        blue = rgb & 0xFF
        green = (rgb >> 8) & 0xFF
        red = (rgb >> 16) & 0xFF

        return color_util.color_RGB_to_hs(red, green, blue)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on the light."""
        data = {ATTR_ON: True, ATTR_SEGMENT_ID: self._segment}

        if ATTR_COLOR_TEMP in kwargs:
            mireds = color_util.color_temperature_kelvin_to_mired(
                kwargs[ATTR_COLOR_TEMP]
            )
            data[ATTR_COLOR_PRIMARY] = tuple(
                map(int, color_util.color_temperature_to_rgb(mireds))
            )

        if ATTR_HS_COLOR in kwargs:
            hue, sat = kwargs[ATTR_HS_COLOR]
            data[ATTR_COLOR_PRIMARY] = color_util.color_hsv_to_RGB(hue, sat, 100)

        if ATTR_TRANSITION in kwargs:
            data[ATTR_TRANSITION] = kwargs[ATTR_TRANSITION]

        if ATTR_BRIGHTNESS in kwargs:
            data[ATTR_BRIGHTNESS] = kwargs[ATTR_BRIGHTNESS]

        if ATTR_EFFECT in kwargs:
            data[ATTR_EFFECT] = kwargs[ATTR_EFFECT]

        # Support for RGBW strips, adds white value
        if self._rgbw and any(
            x in (ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_WHITE_VALUE) for x in kwargs
        ):
            # WLED cannot just accept a white value, it needs the color.
            # We use the last know color in case just the white value changes.
            if not any(x in (ATTR_COLOR_TEMP, ATTR_HS_COLOR) for x in kwargs):
                hue, sat = self._color
                data[ATTR_COLOR_PRIMARY] = color_util.color_hsv_to_RGB(hue, sat, 100)

            # Add requested or last known white value
            if ATTR_WHITE_VALUE in kwargs:
                data[ATTR_COLOR_PRIMARY] += (kwargs[ATTR_WHITE_VALUE],)
            else:
                data[ATTR_COLOR_PRIMARY] += (self._white_value,)

        try:
            await self.wled.light(**data)

            self._state = True

            if ATTR_BRIGHTNESS in kwargs:
                self._brightness = kwargs[ATTR_BRIGHTNESS]

            if ATTR_EFFECT in kwargs:
                self._effect = kwargs[ATTR_EFFECT]

            if ATTR_HS_COLOR in kwargs:
                self._color = kwargs[ATTR_HS_COLOR]

            if ATTR_COLOR_TEMP in kwargs:
                self._color = color_util.color_temperature_to_hs(mireds)

            if ATTR_WHITE_VALUE in kwargs:
                self._white_value = kwargs[ATTR_WHITE_VALUE]

        except WLEDError:
            _LOGGER.error("An error occurred while turning on WLED light.")
            self._available = False
        self.async_schedule_update_ha_state()
Ejemplo n.º 15
0
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]
Ejemplo n.º 16
0
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()
Ejemplo n.º 17
0
    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,
            ),
        )
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
 def _hs_color_for_temperature(self,
                               temperature: int) -> Tuple[float, float]:
     temp_k = color_util.color_temperature_mired_to_kelvin(temperature)
     hs_color = color_util.color_temperature_to_hs(temp_k)
     return hs_color