"""WiZ integration light platform.""" from __future__ import annotations import logging from typing import Any from pywizlight import PilotBuilder from pywizlight.bulblibrary import BulbClass, BulbType from pywizlight.rgbcw import convertHSfromRGBCW from pywizlight.scenes import get_id_from_scene_name from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_HS_COLOR, COLOR_MODE_BRIGHTNESS, COLOR_MODE_COLOR_TEMP, COLOR_MODE_HS, SUPPORT_EFFECT, LightEntity, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.color import ( color_temperature_kelvin_to_mired, color_temperature_mired_to_kelvin, ) from .const import DOMAIN, SOCKET_DEVICE_STR from .entity import WizToggleEntity from .models import WizData _LOGGER = logging.getLogger(__name__) DEFAULT_COLOR_MODES = {COLOR_MODE_HS, COLOR_MODE_COLOR_TEMP} DEFAULT_MIN_MIREDS = 153 DEFAULT_MAX_MIREDS = 454 def get_supported_color_modes(bulb_type: BulbType) -> set[str]: """Flag supported features.""" color_modes = set() features = bulb_type.features if features.color: color_modes.add(COLOR_MODE_HS) if features.color_tmp: color_modes.add(COLOR_MODE_COLOR_TEMP) if not color_modes and features.brightness: color_modes.add(COLOR_MODE_BRIGHTNESS) return color_modes def get_min_max_mireds(bulb_type: BulbType) -> tuple[int, int]: """Return the coldest and warmest color_temp that this light supports.""" # DW bulbs have no kelvin if bulb_type.bulb_type == BulbClass.DW: return 0, 0 # If bulbtype is TW or RGB then return the kelvin value return color_temperature_kelvin_to_mired( bulb_type.kelvin_range.max ), color_temperature_kelvin_to_mired(bulb_type.kelvin_range.min) async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the WiZ Platform from config_flow.""" wiz_data: WizData = hass.data[DOMAIN][entry.entry_id] if SOCKET_DEVICE_STR not in wiz_data.bulb.bulbtype.name: async_add_entities([WizBulbEntity(wiz_data, entry.title)]) class WizBulbEntity(WizToggleEntity, LightEntity): """Representation of WiZ Light bulb.""" def __init__(self, wiz_data: WizData, name: str) -> None: """Initialize an WiZLight.""" super().__init__(wiz_data, name) bulb_type: BulbType = self._device.bulbtype self._attr_effect_list = wiz_data.scenes self._attr_min_mireds, self._attr_max_mireds = get_min_max_mireds(bulb_type) self._attr_supported_color_modes = get_supported_color_modes(bulb_type) if bulb_type.features.effect: self._attr_supported_features = SUPPORT_EFFECT @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" state = self._device.state if (brightness := state.get_brightness()) is not None: self._attr_brightness = max(0, min(255, brightness)) color_modes = self.supported_color_modes assert color_modes is not None if COLOR_MODE_COLOR_TEMP in color_modes and state.get_colortemp() is not None: self._attr_color_mode = COLOR_MODE_COLOR_TEMP if color_temp := state.get_colortemp(): self._attr_color_temp = color_temperature_kelvin_to_mired(color_temp) elif ( COLOR_MODE_HS in color_modes and (rgb := state.get_rgb()) is not None and rgb[0] is not None ): if (warm_white := state.get_warm_white()) is not None: self._attr_hs_color = convertHSfromRGBCW(rgb, warm_white) self._attr_color_mode = COLOR_MODE_HS else: self._attr_color_mode = COLOR_MODE_BRIGHTNESS self._attr_effect = state.get_scene() super()._handle_coordinator_update() @callback def _async_pilot_builder(self, **kwargs: Any) -> PilotBuilder: """Create the PilotBuilder for turn on.""" brightness = kwargs.get(ATTR_BRIGHTNESS) if ATTR_HS_COLOR in kwargs: return PilotBuilder( hucolor=(kwargs[ATTR_HS_COLOR][0], kwargs[ATTR_HS_COLOR][1]), brightness=brightness, ) color_temp = None if ATTR_COLOR_TEMP in kwargs: color_temp = color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP]) scene_id = None if ATTR_EFFECT in kwargs: scene_id = get_id_from_scene_name(kwargs[ATTR_EFFECT]) if scene_id == 1000: # rhythm return PilotBuilder() _LOGGER.debug( "[wizlight %s] Pilot will be sent with brightness=%s, color_temp=%s, scene_id=%s", self._device.ip, brightness, color_temp, scene_id, ) return PilotBuilder(brightness=brightness, colortemp=color_temp, scene=scene_id) async def async_turn_on(self, **kwargs: Any) -> None: """Instruct the light to turn on.""" await self._device.turn_on(self._async_pilot_builder(**kwargs)) await self.coordinator.async_request_refresh()