Esempio n. 1
0
 def update_static_attributes(self):
     """Update static attributes of the luminary."""
     self._unique_id = self._get_unique_id()
     self._supported_features = self._get_supported_features()
     self._effect_list = self._get_effect_list()
     if self._supported_features & SUPPORT_COLOR_TEMP:
         self._min_mireds = color_util.color_temperature_kelvin_to_mired(
             self._luminary.max_temp() or DEFAULT_KELVIN
         )
         self._max_mireds = color_util.color_temperature_kelvin_to_mired(
             self._luminary.min_temp() or DEFAULT_KELVIN
         )
Esempio n. 2
0
    def _calculate_color_values(self):
        """Parse color rgb and color temperature data."""
        # Color Data String
        data = self.values.color.data[ATTR_VALUE]

        # RGB is always present in the OpenZWave color data string.
        rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
        self._hs = color_util.color_RGB_to_hs(*rgb)

        if self.values.color_channels is None:
            return

        # Color Channels
        self._color_channels = self.values.color_channels.data[ATTR_VALUE]

        # Parse remaining color channels. OpenZWave appends white channels
        # that are present.
        index = 7
        temp_warm = 0
        temp_cold = 0

        # Update color temp limits.
        if self.values.min_kelvin:
            self._max_mireds = color_util.color_temperature_kelvin_to_mired(
                self.values.min_kelvin.data[ATTR_VALUE])
        if self.values.max_kelvin:
            self._min_mireds = color_util.color_temperature_kelvin_to_mired(
                self.values.max_kelvin.data[ATTR_VALUE])

        # Warm white
        if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
            self._white = int(data[index:index + 2], 16)
            temp_warm = self._white

        index += 2

        # Cold white
        if self._color_channels & COLOR_CHANNEL_COLD_WHITE:
            self._white = int(data[index:index + 2], 16)
            temp_cold = self._white

        # Calculate color temps based on white LED status
        if temp_cold or temp_warm:
            self._ct = round(self._max_mireds -
                             ((temp_cold / 255) *
                              (self._max_mireds - self._min_mireds)))

        if not (self._color_channels & COLOR_CHANNEL_RED
                or self._color_channels & COLOR_CHANNEL_GREEN
                or self._color_channels & COLOR_CHANNEL_BLUE):
            self._hs = None
Esempio n. 3
0
def preprocess_turn_on_alternatives(params):
    """Process extra data for turn light on request."""
    profile = Profiles.get(params.pop(ATTR_PROFILE, None))
    if profile is not None:
        params.setdefault(ATTR_XY_COLOR, profile[:2])
        params.setdefault(ATTR_BRIGHTNESS, profile[2])

    color_name = params.pop(ATTR_COLOR_NAME, None)
    if color_name is not None:
        try:
            params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)
        except ValueError:
            _LOGGER.warning("Got unknown color %s, falling back to white",
                            color_name)
            params[ATTR_RGB_COLOR] = (255, 255, 255)

    kelvin = params.pop(ATTR_KELVIN, None)
    if kelvin is not None:
        mired = color_util.color_temperature_kelvin_to_mired(kelvin)
        params[ATTR_COLOR_TEMP] = int(mired)

    brightness_pct = params.pop(ATTR_BRIGHTNESS_PCT, None)
    if brightness_pct is not None:
        params[ATTR_BRIGHTNESS] = int(255 * brightness_pct / 100)

    xy_color = params.pop(ATTR_XY_COLOR, None)
    if xy_color is not None:
        params[ATTR_HS_COLOR] = color_util.color_xy_to_hs(*xy_color)

    rgb_color = params.pop(ATTR_RGB_COLOR, None)
    if rgb_color is not None:
        params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
Esempio n. 4
0
def preprocess_turn_on_alternatives(opp, params):
    """Process extra data for turn light on request.

    Async friendly.
    """
    # Bail out, we process this later.
    if ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params:
        return

    if ATTR_PROFILE in params:
        opp.data[DATA_PROFILES].apply_profile(params.pop(ATTR_PROFILE), params)

    color_name = params.pop(ATTR_COLOR_NAME, None)
    if color_name is not None:
        try:
            params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)
        except ValueError:
            _LOGGER.warning("Got unknown color %s, falling back to white",
                            color_name)
            params[ATTR_RGB_COLOR] = (255, 255, 255)

    kelvin = params.pop(ATTR_KELVIN, None)
    if kelvin is not None:
        mired = color_util.color_temperature_kelvin_to_mired(kelvin)
        params[ATTR_COLOR_TEMP] = int(mired)

    brightness_pct = params.pop(ATTR_BRIGHTNESS_PCT, None)
    if brightness_pct is not None:
        params[ATTR_BRIGHTNESS] = round(255 * brightness_pct / 100)
Esempio n. 5
0
    def color_temp(self) -> int | None:
        """Return the CT color value in mireds."""
        if self.control_result:
            color_temp = self.control_result["temp"]
        else:
            color_temp = self.block.colorTemp

        color_temp = min(self._max_kelvin, max(self._min_kelvin, color_temp))

        return int(color_temperature_kelvin_to_mired(color_temp))
Esempio n. 6
0
    def update_dynamic_attributes(self):
        """Update dynamic attributes of the luminary."""
        self._is_on = self._luminary.on()
        self._available = self._luminary.reachable() and not self._luminary.deleted()
        if self._supported_features & SUPPORT_BRIGHTNESS:
            self._brightness = int(self._luminary.lum() * 2.55)

        if self._supported_features & SUPPORT_COLOR_TEMP:
            self._color_temp = color_util.color_temperature_kelvin_to_mired(
                self._luminary.temp() or DEFAULT_KELVIN
            )

        if self._supported_features & SUPPORT_COLOR:
            self._rgb_color = self._luminary.rgb()
Esempio n. 7
0
 async def async_update(self):
     """Update entity attributes when the device status has changed."""
     # Brightness and transition
     if self._supported_features & SUPPORT_BRIGHTNESS:
         self._brightness = int(
             convert_scale(self._device.status.level, 100, 255, 0))
     # Color Temperature
     if self._supported_features & SUPPORT_COLOR_TEMP:
         self._color_temp = color_util.color_temperature_kelvin_to_mired(
             self._device.status.color_temperature)
     # Color
     if self._supported_features & SUPPORT_COLOR:
         self._hs_color = (
             convert_scale(self._device.status.hue, 100, 360),
             self._device.status.saturation,
         )
Esempio n. 8
0
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on the light."""
        data: dict[str, Any] = {
            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:
            # WLED uses 100ms per unit, so 10 = 1 second.
            data[ATTR_TRANSITION] = round(kwargs[ATTR_TRANSITION] * 10)

        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 all(x not in (ATTR_COLOR_TEMP, ATTR_HS_COLOR) for x in kwargs):
                hue, sat = self.hs_color
                data[ATTR_COLOR_PRIMARY] = color_util.color_hsv_to_RGB(
                    hue, sat, 100)

            # On a RGBW strip, when the color is pure white, disable the RGB LEDs in
            # WLED by setting RGB to 0,0,0
            if data[ATTR_COLOR_PRIMARY] == (255, 255, 255):
                data[ATTR_COLOR_PRIMARY] = (0, 0, 0)

            # 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, )

        # When only 1 segment is present, switch along the master, and use
        # the master for power/brightness control.
        if len(self.coordinator.data.state.segments) == 1:
            master_data = {ATTR_ON: True}
            if ATTR_BRIGHTNESS in data:
                master_data[ATTR_BRIGHTNESS] = data[ATTR_BRIGHTNESS]
                data[ATTR_BRIGHTNESS] = 255

            if ATTR_TRANSITION in data:
                master_data[ATTR_TRANSITION] = data[ATTR_TRANSITION]
                del data[ATTR_TRANSITION]

            await self.coordinator.wled.segment(**data)
            await self.coordinator.wled.master(**master_data)
            return

        await self.coordinator.wled.segment(**data)
Esempio n. 9
0
    async def async_flux_update(self, utcnow=None):
        """Update all the lights using flux."""
        if utcnow is None:
            utcnow = dt_utcnow()

        now = as_local(utcnow)

        sunset = get_astral_event_date(self.opp, SUN_EVENT_SUNSET, now.date())
        start_time = self.find_start_time(now)
        stop_time = self.find_stop_time(now)

        if stop_time <= start_time:
            # stop_time does not happen in the same day as start_time
            if start_time < now:
                # stop time is tomorrow
                stop_time += datetime.timedelta(days=1)
        elif now < start_time:
            # stop_time was yesterday since the new start_time is not reached
            stop_time -= datetime.timedelta(days=1)

        if start_time < now < sunset:
            # Daytime
            time_state = "day"
            temp_range = abs(self._start_colortemp - self._sunset_colortemp)
            day_length = int(sunset.timestamp() - start_time.timestamp())
            seconds_from_start = int(now.timestamp() - start_time.timestamp())
            percentage_complete = seconds_from_start / day_length
            temp_offset = temp_range * percentage_complete
            if self._start_colortemp > self._sunset_colortemp:
                temp = self._start_colortemp - temp_offset
            else:
                temp = self._start_colortemp + temp_offset
        else:
            # Night time
            time_state = "night"

            if now < stop_time:
                if stop_time < start_time and stop_time.day == sunset.day:
                    # we need to use yesterday's sunset time
                    sunset_time = sunset - datetime.timedelta(days=1)
                else:
                    sunset_time = sunset

                night_length = int(stop_time.timestamp() - sunset_time.timestamp())
                seconds_from_sunset = int(now.timestamp() - sunset_time.timestamp())
                percentage_complete = seconds_from_sunset / night_length
            else:
                percentage_complete = 1

            temp_range = abs(self._sunset_colortemp - self._stop_colortemp)
            temp_offset = temp_range * percentage_complete
            if self._sunset_colortemp > self._stop_colortemp:
                temp = self._sunset_colortemp - temp_offset
            else:
                temp = self._sunset_colortemp + temp_offset
        rgb = color_temperature_to_rgb(temp)
        x_val, y_val, b_val = color_RGB_to_xy_brightness(*rgb)
        brightness = self._brightness if self._brightness else b_val
        if self._disable_brightness_adjust:
            brightness = None
        if self._mode == MODE_XY:
            await async_set_lights_xy(
                self.opp, self._lights, x_val, y_val, brightness, self._transition
            )
            _LOGGER.debug(
                "Lights updated to x:%s y:%s brightness:%s, %s%% "
                "of %s cycle complete at %s",
                x_val,
                y_val,
                brightness,
                round(percentage_complete * 100),
                time_state,
                now,
            )
        elif self._mode == MODE_RGB:
            await async_set_lights_rgb(self.opp, self._lights, rgb, self._transition)
            _LOGGER.debug(
                "Lights updated to rgb:%s, %s%% of %s cycle complete at %s",
                rgb,
                round(percentage_complete * 100),
                time_state,
                now,
            )
        else:
            # Convert to mired and clamp to allowed values
            mired = color_temperature_kelvin_to_mired(temp)
            await async_set_lights_temp(
                self.opp, self._lights, mired, brightness, self._transition
            )
            _LOGGER.debug(
                "Lights updated to mired:%s brightness:%s, %s%% "
                "of %s cycle complete at %s",
                mired,
                brightness,
                round(percentage_complete * 100),
                time_state,
                now,
            )
Esempio n. 10
0
 def max_mireds(self) -> int:
     """Return the warmest color_temp that this light supports."""
     return int(color_temperature_kelvin_to_mired(self._min_kelvin))
Esempio n. 11
0
 def color_temp(self):
     """Return the color temperature."""
     _, sat, _, kelvin = self.bulb.color
     if sat:
         return None
     return color_util.color_temperature_kelvin_to_mired(kelvin)
Esempio n. 12
0
 def color_temp(self):
     """Define current bulb color in degrees Kelvin."""
     if not self.wink.supports_temperature():
         return None
     return color_util.color_temperature_kelvin_to_mired(
         self.wink.color_temperature_kelvin())
Esempio n. 13
0
 def max_mireds(self):
     """Return color temperature max mireds."""
     return colorutil.color_temperature_kelvin_to_mired(self._min_kelvin)
Esempio n. 14
0
 def max_mireds(self):
     """Return the warmest color_temp that this light supports."""
     kelvin = lifx_features(self.bulb)["min_kelvin"]
     return math.ceil(color_util.color_temperature_kelvin_to_mired(kelvin))
Esempio n. 15
0
async def test_device_types(opp: OpenPeerPower):
    """Test different device types."""
    mocked_bulb = _mocked_bulb()
    properties = {**PROPERTIES}
    properties.pop("active_mode")
    properties["color_mode"] = "3"
    mocked_bulb.last_properties = properties

    async def _async_setup(config_entry):
        with patch(f"{MODULE}.Bulb", return_value=mocked_bulb):
            await opp.config_entries.async_setup(config_entry.entry_id)
            await opp.async_block_till_done()

    async def _async_test(
        bulb_type,
        model,
        target_properties,
        nightlight_properties=None,
        name=UNIQUE_NAME,
        entity_id=ENTITY_LIGHT,
    ):
        config_entry = MockConfigEntry(
            domain=DOMAIN,
            data={
                **CONFIG_ENTRY_DATA,
                CONF_NIGHTLIGHT_SWITCH: False,
            },
        )
        config_entry.add_to_opp(opp)

        mocked_bulb.bulb_type = bulb_type
        model_specs = _MODEL_SPECS.get(model)
        type(mocked_bulb).get_model_specs = MagicMock(return_value=model_specs)
        await _async_setup(config_entry)

        state = opp.states.get(entity_id)
        assert state.state == "on"
        target_properties["friendly_name"] = name
        target_properties["flowing"] = False
        target_properties["night_light"] = True
        target_properties["music_mode"] = False
        assert dict(state.attributes) == target_properties

        await opp.config_entries.async_unload(config_entry.entry_id)
        await config_entry.async_remove(opp)
        registry = er.async_get(opp)
        registry.async_clear_config_entry(config_entry.entry_id)

        # nightlight
        if nightlight_properties is None:
            return
        config_entry = MockConfigEntry(
            domain=DOMAIN,
            data={
                **CONFIG_ENTRY_DATA,
                CONF_NIGHTLIGHT_SWITCH: True,
            },
        )
        config_entry.add_to_opp(opp)
        await _async_setup(config_entry)

        assert opp.states.get(entity_id).state == "off"
        state = opp.states.get(f"{entity_id}_nightlight")
        assert state.state == "on"
        nightlight_properties["friendly_name"] = f"{name} nightlight"
        nightlight_properties["icon"] = "mdi:weather-night"
        nightlight_properties["flowing"] = False
        nightlight_properties["night_light"] = True
        nightlight_properties["music_mode"] = False
        assert dict(state.attributes) == nightlight_properties

        await opp.config_entries.async_unload(config_entry.entry_id)
        await config_entry.async_remove(opp)
        registry.async_clear_config_entry(config_entry.entry_id)

    bright = round(255 * int(PROPERTIES["bright"]) / 100)
    current_brightness = round(255 * int(PROPERTIES["current_brightness"]) /
                               100)
    ct = color_temperature_kelvin_to_mired(int(PROPERTIES["ct"]))
    hue = int(PROPERTIES["hue"])
    sat = int(PROPERTIES["sat"])
    hs_color = (round(hue / 360 * 65536, 3), round(sat / 100 * 255, 3))
    rgb_color = color_hs_to_RGB(*hs_color)
    xy_color = color_hs_to_xy(*hs_color)
    bg_bright = round(255 * int(PROPERTIES["bg_bright"]) / 100)
    bg_ct = color_temperature_kelvin_to_mired(int(PROPERTIES["bg_ct"]))
    bg_rgb = int(PROPERTIES["bg_rgb"])
    bg_rgb_color = ((bg_rgb >> 16) & 0xFF, (bg_rgb >> 8) & 0xFF, bg_rgb & 0xFF)
    bg_hs_color = color_RGB_to_hs(*bg_rgb_color)
    bg_xy_color = color_RGB_to_xy(*bg_rgb_color)
    nl_br = round(255 * int(PROPERTIES["nl_br"]) / 100)

    # Default
    await _async_test(
        None,
        "mono",
        {
            "effect_list": YEELIGHT_MONO_EFFECT_LIST,
            "supported_features": SUPPORT_YEELIGHT,
            "brightness": bright,
            "color_mode": "brightness",
            "supported_color_modes": ["brightness"],
        },
    )

    # White
    await _async_test(
        BulbType.White,
        "mono",
        {
            "effect_list": YEELIGHT_MONO_EFFECT_LIST,
            "supported_features": SUPPORT_YEELIGHT,
            "brightness": bright,
            "color_mode": "brightness",
            "supported_color_modes": ["brightness"],
        },
    )

    # Color
    model_specs = _MODEL_SPECS["color"]
    await _async_test(
        BulbType.Color,
        "color",
        {
            "effect_list":
            YEELIGHT_COLOR_EFFECT_LIST,
            "supported_features":
            SUPPORT_YEELIGHT_RGB,
            "min_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["max"]),
            "max_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["min"]),
            "brightness":
            current_brightness,
            "color_temp":
            ct,
            "hs_color":
            hs_color,
            "rgb_color":
            rgb_color,
            "xy_color":
            xy_color,
            "color_mode":
            "hs",
            "supported_color_modes": ["color_temp", "hs"],
        },
        {
            "supported_features": 0,
            "color_mode": "onoff",
            "supported_color_modes": ["onoff"],
        },
    )

    # WhiteTemp
    model_specs = _MODEL_SPECS["ceiling1"]
    await _async_test(
        BulbType.WhiteTemp,
        "ceiling1",
        {
            "effect_list":
            YEELIGHT_TEMP_ONLY_EFFECT_LIST,
            "supported_features":
            SUPPORT_YEELIGHT_WHITE_TEMP,
            "min_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["max"]),
            "max_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["min"]),
            "brightness":
            current_brightness,
            "color_temp":
            ct,
            "color_mode":
            "color_temp",
            "supported_color_modes": ["color_temp"],
        },
        {
            "effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
            "supported_features": SUPPORT_YEELIGHT,
            "brightness": nl_br,
            "color_mode": "brightness",
            "supported_color_modes": ["brightness"],
        },
    )

    # WhiteTempMood
    properties.pop("power")
    properties["main_power"] = "on"
    model_specs = _MODEL_SPECS["ceiling4"]
    await _async_test(
        BulbType.WhiteTempMood,
        "ceiling4",
        {
            "friendly_name":
            NAME,
            "effect_list":
            YEELIGHT_TEMP_ONLY_EFFECT_LIST,
            "flowing":
            False,
            "night_light":
            True,
            "supported_features":
            SUPPORT_YEELIGHT_WHITE_TEMP,
            "min_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["max"]),
            "max_mireds":
            color_temperature_kelvin_to_mired(
                model_specs["color_temp"]["min"]),
            "brightness":
            current_brightness,
            "color_temp":
            ct,
            "color_mode":
            "color_temp",
            "supported_color_modes": ["color_temp"],
        },
        {
            "effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
            "supported_features": SUPPORT_YEELIGHT,
            "brightness": nl_br,
            "color_mode": "brightness",
            "supported_color_modes": ["brightness"],
        },
    )
    await _async_test(
        BulbType.WhiteTempMood,
        "ceiling4",
        {
            "effect_list": YEELIGHT_COLOR_EFFECT_LIST,
            "supported_features": SUPPORT_YEELIGHT_RGB,
            "min_mireds": color_temperature_kelvin_to_mired(6500),
            "max_mireds": color_temperature_kelvin_to_mired(1700),
            "brightness": bg_bright,
            "color_temp": bg_ct,
            "hs_color": bg_hs_color,
            "rgb_color": bg_rgb_color,
            "xy_color": bg_xy_color,
            "color_mode": "hs",
            "supported_color_modes": ["color_temp", "hs"],
        },
        name=f"{UNIQUE_NAME} ambilight",
        entity_id=f"{ENTITY_LIGHT}_ambilight",
    )
Esempio n. 16
0
 def color_temp(self):
     """Return the color temp of the light."""
     if self._device.has_color:
         return color_temperature_kelvin_to_mired(self._device.color_temp)
Esempio n. 17
0
def test_color_temperature_kelvin_to_mired():
    """Test color_temperature_kelvin_to_mired."""
    assert color_util.color_temperature_kelvin_to_mired(25000) == 40
    assert color_util.color_temperature_kelvin_to_mired(5000) == 200
    with pytest.raises(ZeroDivisionError):
        assert color_util.color_temperature_kelvin_to_mired(0)
Esempio n. 18
0
 def max_mireds(self):
     """Return the warmest color_temp that this light supports."""
     return math.ceil(
         color_util.color_temperature_kelvin_to_mired(
             self._lamp.min_kelvin))
Esempio n. 19
0
 def color_temp(self):
     """Return the color temperature."""
     return color_util.color_temperature_kelvin_to_mired(
         self._lamp.state()["white"])
Esempio n. 20
0
 def color_temp(self):
     """Return the current color temperature."""
     if self._color_temp is not None:
         return color_util.color_temperature_kelvin_to_mired(
             self._color_temp)
     return None
Esempio n. 21
0
 def color_temp(self):
     """Return the color_temp of the light."""
     color_temp = int(self._tuya.color_temp())
     if color_temp is None:
         return None
     return colorutil.color_temperature_kelvin_to_mired(color_temp)