text: """Light platform support for yeelight."""
  from __future__ import annotations
  
  import logging
  
  import voluptuous as vol
  import yeelight
  from yeelight import Bulb, BulbException, Flow, RGBTransition, SleepTransition, flows
  from yeelight.enums import BulbType, LightType, PowerMode, SceneClass
  
  from homeassistant.components.light import (
      ATTR_BRIGHTNESS,
      ATTR_COLOR_TEMP,
      ATTR_EFFECT,
      ATTR_FLASH,
      ATTR_HS_COLOR,
      ATTR_KELVIN,
      ATTR_RGB_COLOR,
      ATTR_TRANSITION,
      COLOR_MODE_BRIGHTNESS,
      COLOR_MODE_COLOR_TEMP,
      COLOR_MODE_HS,
      COLOR_MODE_ONOFF,
      COLOR_MODE_RGB,
      COLOR_MODE_UNKNOWN,
      FLASH_LONG,
      FLASH_SHORT,
      SUPPORT_EFFECT,
      SUPPORT_FLASH,
      SUPPORT_TRANSITION,
      LightEntity,
  )
  from homeassistant.config_entries import ConfigEntry
  from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE, CONF_NAME
  from homeassistant.core import HomeAssistant, callback
  from homeassistant.helpers import entity_platform
  import homeassistant.helpers.config_validation as cv
  from homeassistant.helpers.dispatcher import async_dispatcher_connect
  import homeassistant.util.color as color_util
  from homeassistant.util.color import (
      color_temperature_kelvin_to_mired as kelvin_to_mired,
      color_temperature_mired_to_kelvin as mired_to_kelvin,
  )
  
  from . import (
      ACTION_RECOVER,
      ATTR_ACTION,
      ATTR_COUNT,
      ATTR_MODE_MUSIC,
      ATTR_TRANSITIONS,
      CONF_FLOW_PARAMS,
      CONF_MODE_MUSIC,
      CONF_NIGHTLIGHT_SWITCH,
      CONF_SAVE_ON_CHANGE,
      CONF_TRANSITION,
      DATA_CONFIG_ENTRIES,
      DATA_CUSTOM_EFFECTS,
      DATA_DEVICE,
      DATA_UPDATED,
      DOMAIN,
      YEELIGHT_FLOW_TRANSITION_SCHEMA,
      YeelightEntity,
  )
  
  _LOGGER = logging.getLogger(__name__)
  
  SUPPORT_YEELIGHT = SUPPORT_TRANSITION | SUPPORT_FLASH | SUPPORT_EFFECT
  
  ATTR_MINUTES = "minutes"
  
  SERVICE_SET_MODE = "set_mode"
  SERVICE_SET_MUSIC_MODE = "set_music_mode"
  SERVICE_START_FLOW = "start_flow"
  SERVICE_SET_COLOR_SCENE = "set_color_scene"
  SERVICE_SET_HSV_SCENE = "set_hsv_scene"
  SERVICE_SET_COLOR_TEMP_SCENE = "set_color_temp_scene"
  SERVICE_SET_COLOR_FLOW_SCENE = "set_color_flow_scene"
  SERVICE_SET_AUTO_DELAY_OFF_SCENE = "set_auto_delay_off_scene"
  
  EFFECT_DISCO = "Disco"
  EFFECT_TEMP = "Slow Temp"
  EFFECT_STROBE = "Strobe epilepsy!"
  EFFECT_STROBE_COLOR = "Strobe color"
  EFFECT_ALARM = "Alarm"
  EFFECT_POLICE = "Police"
  EFFECT_POLICE2 = "Police2"
  EFFECT_CHRISTMAS = "Christmas"
  EFFECT_RGB = "RGB"
  EFFECT_RANDOM_LOOP = "Random Loop"
  EFFECT_FAST_RANDOM_LOOP = "Fast Random Loop"
  EFFECT_LSD = "LSD"
  EFFECT_SLOWDOWN = "Slowdown"
  EFFECT_WHATSAPP = "WhatsApp"
  EFFECT_FACEBOOK = "Facebook"
  EFFECT_TWITTER = "Twitter"
  EFFECT_STOP = "Stop"
  EFFECT_HOME = "Home"
  EFFECT_NIGHT_MODE = "Night Mode"
  EFFECT_DATE_NIGHT = "Date Night"
  EFFECT_MOVIE = "Movie"
  EFFECT_SUNRISE = "Sunrise"
  EFFECT_SUNSET = "Sunset"
  EFFECT_ROMANCE = "Romance"
  EFFECT_HAPPY_BIRTHDAY = "Happy Birthday"
  EFFECT_CANDLE_FLICKER = "Candle Flicker"
  
  YEELIGHT_TEMP_ONLY_EFFECT_LIST = [EFFECT_TEMP, EFFECT_STOP]
  
  YEELIGHT_MONO_EFFECT_LIST = [
      EFFECT_DISCO,
      EFFECT_STROBE,
      EFFECT_ALARM,
      EFFECT_POLICE2,
      EFFECT_WHATSAPP,
      EFFECT_FACEBOOK,
      EFFECT_TWITTER,
      EFFECT_HOME,
      EFFECT_CANDLE_FLICKER,
      *YEELIGHT_TEMP_ONLY_EFFECT_LIST,
  ]
  
  YEELIGHT_COLOR_EFFECT_LIST = [
      EFFECT_STROBE_COLOR,
      EFFECT_POLICE,
      EFFECT_CHRISTMAS,
      EFFECT_RGB,
      EFFECT_RANDOM_LOOP,
      EFFECT_FAST_RANDOM_LOOP,
      EFFECT_LSD,
      EFFECT_SLOWDOWN,
      EFFECT_NIGHT_MODE,
      EFFECT_DATE_NIGHT,
      EFFECT_MOVIE,
      EFFECT_SUNRISE,
      EFFECT_SUNSET,
      EFFECT_ROMANCE,
      EFFECT_HAPPY_BIRTHDAY,
      *YEELIGHT_MONO_EFFECT_LIST,
  ]
  
  EFFECTS_MAP = {
      EFFECT_DISCO: flows.disco,
      EFFECT_TEMP: flows.temp,
      EFFECT_STROBE: flows.strobe,
      EFFECT_STROBE_COLOR: flows.strobe_color,
      EFFECT_ALARM: flows.alarm,
      EFFECT_POLICE: flows.police,
      EFFECT_POLICE2: flows.police2,
      EFFECT_CHRISTMAS: flows.christmas,
      EFFECT_RGB: flows.rgb,
      EFFECT_RANDOM_LOOP: flows.random_loop,
      EFFECT_LSD: flows.lsd,
      EFFECT_SLOWDOWN: flows.slowdown,
      EFFECT_HOME: flows.home,
      EFFECT_NIGHT_MODE: flows.night_mode,
      EFFECT_DATE_NIGHT: flows.date_night,
      EFFECT_MOVIE: flows.movie,
      EFFECT_SUNRISE: flows.sunrise,
      EFFECT_SUNSET: flows.sunset,
      EFFECT_ROMANCE: flows.romance,
      EFFECT_HAPPY_BIRTHDAY: flows.happy_birthday,
      EFFECT_CANDLE_FLICKER: flows.candle_flicker,
  }
  
  VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Range(min=1, max=100))
  
  SERVICE_SCHEMA_SET_MODE = {
      vol.Required(ATTR_MODE): vol.In([mode.name.lower() for mode in PowerMode])
  }
  
  SERVICE_SCHEMA_SET_MUSIC_MODE = {vol.Required(ATTR_MODE_MUSIC): cv.boolean}
  
  SERVICE_SCHEMA_START_FLOW = YEELIGHT_FLOW_TRANSITION_SCHEMA
  
  SERVICE_SCHEMA_SET_COLOR_SCENE = {
      vol.Required(ATTR_RGB_COLOR): vol.All(
          vol.ExactSequence((cv.byte, cv.byte, cv.byte)), vol.Coerce(tuple)
      ),
      vol.Required(ATTR_BRIGHTNESS): VALID_BRIGHTNESS,
  }
  
  SERVICE_SCHEMA_SET_HSV_SCENE = {
      vol.Required(ATTR_HS_COLOR): vol.All(
          vol.ExactSequence(
              (
                  vol.All(vol.Coerce(float), vol.Range(min=0, max=359)),
                  vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
              )
          ),
          vol.Coerce(tuple),
      ),
      vol.Required(ATTR_BRIGHTNESS): VALID_BRIGHTNESS,
  }
  
  SERVICE_SCHEMA_SET_COLOR_TEMP_SCENE = {
      vol.Required(ATTR_KELVIN): vol.All(vol.Coerce(int), vol.Range(min=1700, max=6500)),
      vol.Required(ATTR_BRIGHTNESS): VALID_BRIGHTNESS,
  }
  
  SERVICE_SCHEMA_SET_COLOR_FLOW_SCENE = YEELIGHT_FLOW_TRANSITION_SCHEMA
  
  SERVICE_SCHEMA_SET_AUTO_DELAY_OFF_SCENE = {
      vol.Required(ATTR_MINUTES): vol.All(vol.Coerce(int), vol.Range(min=1, max=60)),
      vol.Required(ATTR_BRIGHTNESS): VALID_BRIGHTNESS,
  }
  
  
  @callback
  def _transitions_config_parser(transitions):
      """Parse transitions config into initialized objects."""
      transition_objects = []
      for transition_config in transitions:
          transition, params = list(transition_config.items())[0]
          transition_objects.append(getattr(yeelight, transition)(*params))
  
      return transition_objects
  
  
  @callback
  def _parse_custom_effects(effects_config):
      effects = {}
      for config in effects_config:
          params = config[CONF_FLOW_PARAMS]
          action = Flow.actions[params[ATTR_ACTION]]
          transitions = _transitions_config_parser(params[ATTR_TRANSITIONS])
  
          effects[config[CONF_NAME]] = {
              ATTR_COUNT: params[ATTR_COUNT],
              ATTR_ACTION: action,
              ATTR_TRANSITIONS: transitions,
          }
  
      return effects
  
  
  def _async_cmd(func):
      """Define a wrapper to catch exceptions from the bulb."""
  
      async def _async_wrap(self, *args, **kwargs):
          try:
              _LOGGER.debug("Calling %s with %s %s", func, args, kwargs)
              return await func(self, *args, **kwargs)
          except BulbException as ex:
              _LOGGER.error("Error when calling %s: %s", func, ex)
  
      return _async_wrap
  
  
  async def async_setup_entry(
      hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
  ) -> None:
      """Set up Yeelight from a config entry."""
      custom_effects = _parse_custom_effects(hass.data[DOMAIN][DATA_CUSTOM_EFFECTS])
  
      device = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][config_entry.entry_id][DATA_DEVICE]
      _LOGGER.debug("Adding %s", device.name)
  
      nl_switch_light = device.config.get(CONF_NIGHTLIGHT_SWITCH)
  
      lights = []
  
      device_type = device.type
  
      def _lights_setup_helper(klass):
          lights.append(klass(device, config_entry, custom_effects=custom_effects))
  
      if device_type == BulbType.White:
          _lights_setup_helper(YeelightGenericLight)
      elif device_type == BulbType.Color:
          if nl_switch_light and device.is_nightlight_supported:
              _lights_setup_helper(YeelightColorLightWithNightlightSwitch)
              _lights_setup_helper(YeelightNightLightModeWithoutBrightnessControl)
          else:
              _lights_setup_helper(YeelightColorLightWithoutNightlightSwitch)
      elif device_type == BulbType.WhiteTemp:
          if nl_switch_light and device.is_nightlight_supported:
              _lights_setup_helper(YeelightWithNightLight)
              _lights_setup_helper(YeelightNightLightMode)
          else:
              _lights_setup_helper(YeelightWhiteTempWithoutNightlightSwitch)
      elif device_type == BulbType.WhiteTempMood:
          if nl_switch_light and device.is_nightlight_supported:
              _lights_setup_helper(YeelightNightLightModeWithAmbientSupport)
              _lights_setup_helper(YeelightWithAmbientAndNightlight)
          else:
              _lights_setup_helper(YeelightWithAmbientWithoutNightlight)
          _lights_setup_helper(YeelightAmbientLight)
      else:
          _lights_setup_helper(YeelightGenericLight)
          _LOGGER.warning(
              "Cannot determine device type for %s, %s. Falling back to white only",
              device.host,
              device.name,
          )
  
      async_add_entities(lights, True)
      _async_setup_services(hass)
  
  
  @callback
  def _async_setup_services(hass: HomeAssistant):
      """Set up custom services."""
  
      async def _async_start_flow(entity, service_call):
          params = {**service_call.data}
          params.pop(ATTR_ENTITY_ID)
          params[ATTR_TRANSITIONS] = _transitions_config_parser(params[ATTR_TRANSITIONS])
          await entity.async_start_flow(**params)
  
      async def _async_set_color_scene(entity, service_call):
          await entity.async_set_scene(
              SceneClass.COLOR,
              *service_call.data[ATTR_RGB_COLOR],
              service_call.data[ATTR_BRIGHTNESS],
          )
  
      async def _async_set_hsv_scene(entity, service_call):
          await entity.async_set_scene(
              SceneClass.HSV,
              *service_call.data[ATTR_HS_COLOR],
              service_call.data[ATTR_BRIGHTNESS],
          )
  
      async def _async_set_color_temp_scene(entity, service_call):
          await entity.async_set_scene(
              SceneClass.CT,
              service_call.data[ATTR_KELVIN],
              service_call.data[ATTR_BRIGHTNESS],
          )
  
      async def _async_set_color_flow_scene(entity, service_call):
          flow = Flow(
              count=service_call.data[ATTR_COUNT],
              action=Flow.actions[service_call.data[ATTR_ACTION]],
              transitions=_transitions_config_parser(service_call.data[ATTR_TRANSITIONS]),
          )
          await entity.async_set_scene(SceneClass.CF, flow)
  
      async def _async_set_auto_delay_off_scene(entity, service_call):
          await entity.async_set_scene(
              SceneClass.AUTO_DELAY_OFF,
              service_call.data[ATTR_BRIGHTNESS],
              service_call.data[ATTR_MINUTES],
          )
  
      platform = entity_platform.async_get_current_platform()
  
      platform.async_register_entity_service(
          SERVICE_SET_MODE, SERVICE_SCHEMA_SET_MODE, "async_set_mode"
      )
      platform.async_register_entity_service(
          SERVICE_START_FLOW, SERVICE_SCHEMA_START_FLOW, _async_start_flow
      )
      platform.async_register_entity_service(
          SERVICE_SET_COLOR_SCENE, SERVICE_SCHEMA_SET_COLOR_SCENE, _async_set_color_scene
      )
      platform.async_register_entity_service(
          SERVICE_SET_HSV_SCENE, SERVICE_SCHEMA_SET_HSV_SCENE, _async_set_hsv_scene
      )
      platform.async_register_entity_service(
          SERVICE_SET_COLOR_TEMP_SCENE,
          SERVICE_SCHEMA_SET_COLOR_TEMP_SCENE,
          _async_set_color_temp_scene,
      )
      platform.async_register_entity_service(
          SERVICE_SET_COLOR_FLOW_SCENE,
          SERVICE_SCHEMA_SET_COLOR_FLOW_SCENE,
          _async_set_color_flow_scene,
      )
      platform.async_register_entity_service(
          SERVICE_SET_AUTO_DELAY_OFF_SCENE,
          SERVICE_SCHEMA_SET_AUTO_DELAY_OFF_SCENE,
          _async_set_auto_delay_off_scene,
      )
      platform.async_register_entity_service(
          SERVICE_SET_MUSIC_MODE, SERVICE_SCHEMA_SET_MUSIC_MODE, "set_music_mode"
      )
  
  
  class YeelightGenericLight(YeelightEntity, LightEntity):
      """Representation of a Yeelight generic light."""
  
      _attr_color_mode = COLOR_MODE_BRIGHTNESS
      _attr_supported_color_modes = {COLOR_MODE_BRIGHTNESS}
  
      def __init__(self, device, entry, custom_effects=None):
          """Initialize the Yeelight light."""
          super().__init__(device, entry)
  
          self.config = device.config
  
          self._color_temp = None
          self._effect = None
  
          model_specs = self._bulb.get_model_specs()
          self._min_mireds = kelvin_to_mired(model_specs["color_temp"]["max"])
          self._max_mireds = kelvin_to_mired(model_specs["color_temp"]["min"])
  
          self._light_type = LightType.Main
  
          if custom_effects:
              self._custom_effects = custom_effects
          else:
              self._custom_effects = {}
  
      async def async_added_to_hass(self):
          """Handle entity which will be added."""
          self.async_on_remove(
              async_dispatcher_connect(
                  self.hass,
                  DATA_UPDATED.format(self._device.host),
                  self.async_write_ha_state,
              )
          )
          await super().async_added_to_hass()
  
      @property
      def supported_features(self) -> int:
          """Flag supported features."""
          return SUPPORT_YEELIGHT
  
      @property
      def effect_list(self):
          """Return the list of supported effects."""
          return self._predefined_effects + self.custom_effects_names
  
      @property
      def color_temp(self) -> int:
          """Return the color temperature."""
          temp_in_k = self._get_property("ct")
          if temp_in_k:
              self._color_temp = kelvin_to_mired(int(temp_in_k))
          return self._color_temp
  
      @property
      def name(self) -> str:
          """Return the name of the device if any."""
          return self.device.name
  
      @property
      def is_on(self) -> bool:
          """Return true if device is on."""
          return self._get_property(self._power_property) == "on"
  
      @property
      def brightness(self) -> int:
          """Return the brightness of this light between 1..255."""
          # Always use "bright" as property name in music mode
          # Since music mode states are only caches in upstream library
          # and the cache key is always "bright" for brightness
          brightness_property = (
              "bright" if self._bulb.music_mode else self._brightness_property
          )
          brightness = self._get_property(brightness_property)
          return round(255 * (int(brightness) / 100))
  
      @property
      def min_mireds(self):
          """Return minimum supported color temperature."""
          return self._min_mireds
  
      @property
      def max_mireds(self):
          """Return maximum supported color temperature."""
          return self._max_mireds
  
      @property
      def custom_effects(self):
          """Return dict with custom effects."""
          return self._custom_effects
  
      @property
      def custom_effects_names(self):
          """Return list with custom effects names."""
          return list(self.custom_effects)
  
      @property
      def light_type(self):
          """Return light type."""
          return self._light_type
  
      @property
      def hs_color(self) -> tuple:
          """Return the color property."""
          hue = self._get_property("hue")
          sat = self._get_property("sat")
          if hue is None or sat is None:
              return None
  
          return (int(hue), int(sat))
  
      @property
      def rgb_color(self) -> tuple:
          """Return the color property."""
          rgb = self._get_property("rgb")
  
          if rgb is None:
              return None
  
          rgb = int(rgb)
          blue = rgb & 0xFF
          green = (rgb >> 8) & 0xFF
          red = (rgb >> 16) & 0xFF
  
          return (red, green, blue)
  
      @property
      def effect(self):
          """Return the current effect."""
          if not self.device.is_color_flow_enabled:
              return None
          return self._effect
  
      @property
      def _bulb(self) -> Bulb:
          return self.device.bulb
  
      @property
      def _properties(self) -> dict:
          if self._bulb is None:
              return {}
          return self._bulb.last_properties
  
      def _get_property(self, prop, default=None):
          return self._properties.get(prop, default)
  
      @property
      def _brightness_property(self):
          return "bright"
  
      @property
      def _power_property(self):
          return "power"
  
      @property
      def _turn_on_power_mode(self):
          return PowerMode.LAST
  
      @property
      def _predefined_effects(self):
          return YEELIGHT_MONO_EFFECT_LIST
  
      @property
      def extra_state_attributes(self):
          """Return the device specific state attributes."""
          attributes = {
              "flowing": self.device.is_color_flow_enabled,
              "music_mode": self._bulb.music_mode,
          }
  
          if self.device.is_nightlight_supported:
              attributes["night_light"] = self.device.is_nightlight_enabled
  
          return attributes
  
      @property
      def device(self):
          """Return yeelight device."""
          return self._device
  
      async def async_update(self):
          """Update light properties."""
          await self.device.async_update()
  
      def set_music_mode(self, music_mode) -> None:
          """Set the music mode on or off."""
          if music_mode:
              try:
                  self._bulb.start_music()
              except AssertionError as ex:
                  _LOGGER.error(ex)
          else:
              self._bulb.stop_music()
  
      @_async_cmd
      async def async_set_brightness(self, brightness, duration) -> None:
          """Set bulb brightness."""
          if brightness:
              _LOGGER.debug("Setting brightness: %s", brightness)
              await self._bulb.async_set_brightness(
                  brightness / 255 * 100, duration=duration, light_type=self.light_type
              )
  
      @_async_cmd
      async def async_set_hs(self, hs_color, duration) -> None:
          """Set bulb's color."""
          if hs_color and COLOR_MODE_HS in self.supported_color_modes:
              _LOGGER.debug("Setting HS: %s", hs_color)
              await self._bulb.async_set_hsv(
                  hs_color[0], hs_color[1], duration=duration, light_type=self.light_type
              )
  
      @_async_cmd
      async def async_set_rgb(self, rgb, duration) -> None:
          """Set bulb's color."""
          if rgb and COLOR_MODE_RGB in self.supported_color_modes:
              _LOGGER.debug("Setting RGB: %s", rgb)
              await self._bulb.async_set_rgb(
                  rgb[0], rgb[1], rgb[2], duration=duration, light_type=self.light_type
              )
  
      @_async_cmd
      async def async_set_colortemp(self, colortemp, duration) -> None:
          """Set bulb's color temperature."""
          if colortemp and COLOR_MODE_COLOR_TEMP in self.supported_color_modes:
              temp_in_k = mired_to_kelvin(colortemp)
              _LOGGER.debug("Setting color temp: %s K", temp_in_k)
  
              await self._bulb.async_set_color_temp(
                  temp_in_k, duration=duration, light_type=self.light_type
              )
  
      @_async_cmd
      async def async_set_default(self) -> None:
          """Set current options as default."""
          await self._bulb.async_set_default()
  
      @_async_cmd
      async def async_set_flash(self, flash) -> None:
          """Activate flash."""
          if flash:
              if int(self._bulb.last_properties["color_mode"]) != 1:
                  _LOGGER.error("Flash supported currently only in RGB mode")
                  return
  
              transition = int(self.config[CONF_TRANSITION])
              if flash == FLASH_LONG:
                  count = 1
                  duration = transition * 5
              if flash == FLASH_SHORT:
                  count = 1
                  duration = transition * 2
  
              red, green, blue = color_util.color_hs_to_RGB(*self.hs_color)
  
              transitions = []
              transitions.append(
                  RGBTransition(255, 0, 0, brightness=10, duration=duration)
              )
              transitions.append(SleepTransition(duration=transition))
              transitions.append(
                  RGBTransition(
                      red, green, blue, brightness=self.brightness, duration=duration
                  )
              )
  
              flow = Flow(count=count, transitions=transitions)
              try:
                  await self._bulb.async_start_flow(flow, light_type=self.light_type)
              except BulbException as ex:
                  _LOGGER.error("Unable to set flash: %s", ex)
  
      @_async_cmd
      async def async_set_effect(self, effect) -> None:
          """Activate effect."""
          if not effect:
              return
  
          if effect == EFFECT_STOP:
              await self._bulb.async_stop_flow(light_type=self.light_type)
              return
  
          if effect in self.custom_effects_names:
              flow = Flow(**self.custom_effects[effect])
          elif effect in EFFECTS_MAP:
              flow = EFFECTS_MAP[effect]()
          elif effect == EFFECT_FAST_RANDOM_LOOP:
              flow = flows.random_loop(duration=250)
          elif effect == EFFECT_WHATSAPP:
              flow = flows.pulse(37, 211, 102, count=2)
          elif effect == EFFECT_FACEBOOK:
              flow = flows.pulse(59, 89, 152, count=2)
          elif effect == EFFECT_TWITTER:
              flow = flows.pulse(0, 172, 237, count=2)
          else:
              return
  
          try:
              await self._bulb.async_start_flow(flow, light_type=self.light_type)
              self._effect = effect
          except BulbException as ex:
              _LOGGER.error("Unable to set effect: %s", ex)
  
      async def async_turn_on(self, **kwargs) -> None:
          """Turn the bulb on."""
          brightness = kwargs.get(ATTR_BRIGHTNESS)
          colortemp = kwargs.get(ATTR_COLOR_TEMP)
          hs_color = kwargs.get(ATTR_HS_COLOR)
          rgb = kwargs.get(ATTR_RGB_COLOR)
          flash = kwargs.get(ATTR_FLASH)
          effect = kwargs.get(ATTR_EFFECT)
  
          duration = int(self.config[CONF_TRANSITION])  # in ms
          if ATTR_TRANSITION in kwargs:  # passed kwarg overrides config
              duration = int(kwargs.get(ATTR_TRANSITION) * 1000)  # kwarg in s
  
          if not self.is_on:
              await self.device.async_turn_on(
                  duration=duration,
                  light_type=self.light_type,
                  power_mode=self._turn_on_power_mode,
              )
  
          if self.config[CONF_MODE_MUSIC] and not self._bulb.music_mode:
              try:
                  await self.hass.async_add_executor_job(
                      self.set_music_mode, self.config[CONF_MODE_MUSIC]
                  )
              except BulbException as ex:
                  _LOGGER.error(
                      "Unable to turn on music mode, consider disabling it: %s", ex
                  )
  
          try:
              # values checked for none in methods
              await self.async_set_hs(hs_color, duration)
              await self.async_set_rgb(rgb, duration)
              await self.async_set_colortemp(colortemp, duration)
              await self.async_set_brightness(brightness, duration)
              await self.async_set_flash(flash)
              await self.async_set_effect(effect)
          except BulbException as ex:
              _LOGGER.error("Unable to set bulb properties: %s", ex)
              return
  
          # save the current state if we had a manual change.
          if self.config[CONF_SAVE_ON_CHANGE] and (brightness or colortemp or rgb):
              try:
                  await self.async_set_default()
              except BulbException as ex:
                  _LOGGER.error("Unable to set the defaults: %s", ex)
                  return
  
      async def async_turn_off(self, **kwargs) -> None:
          """Turn off."""
          if not self.is_on:
              return
  
          duration = int(self.config[CONF_TRANSITION])  # in ms
          if ATTR_TRANSITION in kwargs:  # passed kwarg overrides config
              duration = int(kwargs.get(ATTR_TRANSITION) * 1000)  # kwarg in s
  
          await self.device.async_turn_off(duration=duration, light_type=self.light_type)
  
      async def async_set_mode(self, mode: str):
          """Set a power mode."""
          try:
              await self._bulb.async_set_power_mode(PowerMode[mode.upper()])
          except BulbException as ex:
              _LOGGER.error("Unable to set the power mode: %s", ex)
  
      async def async_start_flow(self, transitions, count=0, action=ACTION_RECOVER):
          """Start flow."""
          try:
              flow = Flow(
                  count=count, action=Flow.actions[action], transitions=transitions
              )
  
              await self._bulb.async_start_flow(flow, light_type=self.light_type)
          except BulbException as ex:
              _LOGGER.error("Unable to set effect: %s", ex)
  
      async def async_set_scene(self, scene_class, *args):
          """
          Set the light directly to the specified state.
  
          If the light is off, it will first be turned on.
          """
          try:
              await self._bulb.async_set_scene(scene_class, *args)
          except BulbException as ex:
              _LOGGER.error("Unable to set scene: %s", ex)
  
  
  class YeelightColorLightSupport(YeelightGenericLight):
      """Representation of a Color Yeelight light support."""
  
      _attr_supported_color_modes = {COLOR_MODE_COLOR_TEMP, COLOR_MODE_HS, COLOR_MODE_RGB}
  
      @property
      def color_mode(self):
          """Return the color mode."""
          color_mode = int(self._get_property("color_mode"))
          if color_mode == 1:  # RGB
              return COLOR_MODE_RGB
          if color_mode == 2:  # color temperature
              return COLOR_MODE_COLOR_TEMP
          if color_mode == 3:  # hsv
              return COLOR_MODE_HS
          _LOGGER.debug("Light reported unknown color mode: %s", color_mode)
          return COLOR_MODE_UNKNOWN
  
      @property
      def _predefined_effects(self):
          return YEELIGHT_COLOR_EFFECT_LIST
  
  
  class YeelightWhiteTempLightSupport:
      """Representation of a White temp Yeelight light."""
  
      _attr_color_mode = COLOR_MODE_COLOR_TEMP
      _attr_supported_color_modes = {COLOR_MODE_COLOR_TEMP}
  
      @property
      def _predefined_effects(self):
          return YEELIGHT_TEMP_ONLY_EFFECT_LIST
  
  
  class YeelightNightLightSupport:
      """Representation of a Yeelight nightlight support."""
  
      @property
      def _turn_on_power_mode(self):
          return PowerMode.NORMAL
  
  
  class YeelightColorLightWithoutNightlightSwitch(
      YeelightColorLightSupport, YeelightGenericLight
  ):
      """Representation of a Color Yeelight light."""
  
      @property
      def _brightness_property(self):
          return "current_brightness"
  
  
  class YeelightColorLightWithNightlightSwitch(
      YeelightNightLightSupport, YeelightColorLightSupport, YeelightGenericLight
  ):
      """Representation of a Yeelight with rgb support and nightlight.
  
      It represents case when nightlight switch is set to light.
      """
  
      @property
      def is_on(self) -> bool:
          """Return true if device is on."""
          return super().is_on and not self.device.is_nightlight_enabled
  
  
  class YeelightWhiteTempWithoutNightlightSwitch(
      YeelightWhiteTempLightSupport, YeelightGenericLight
  ):
      """White temp light, when nightlight switch is not set to light."""
  
      @property
      def _brightness_property(self):
          return "current_brightness"
  
  
  class YeelightWithNightLight(
      YeelightNightLightSupport, YeelightWhiteTempLightSupport, YeelightGenericLight
  ):
      """Representation of a Yeelight with temp only support and nightlight.
  
      It represents case when nightlight switch is set to light.
      """
  
      @property
      def is_on(self) -> bool:
          """Return true if device is on."""
          return super().is_on and not self.device.is_nightlight_enabled
  
  
  class YeelightNightLightMode(YeelightGenericLight):
      """Representation of a Yeelight when in nightlight mode."""
  
      @property
      def unique_id(self) -> str:
          """Return a unique ID."""
          unique = super().unique_id
          return f"{unique}-nightlight"
  
      @property
      def name(self) -> str:
          """Return the name of the device if any."""
          return f"{self.device.name} nightlight"
  
      @property
      def icon(self):
          """Return the icon to use in the frontend, if any."""
          return "mdi:weather-night"
  
      @property
      def is_on(self) -> bool:
          """Return true if device is on."""
          return super().is_on and self.device.is_nightlight_enabled
  
      @property
      def _brightness_property(self):
          return "nl_br"
  
      @property
      def _turn_on_power_mode(self):
          return PowerMode.MOONLIGHT
  
      @property
      def _predefined_effects(self):
          return YEELIGHT_TEMP_ONLY_EFFECT_LIST
  
  
  class YeelightNightLightModeWithAmbientSupport(YeelightNightLightMode):
      """Representation of a Yeelight, with ambient support, when in nightlight mode."""
  
      @property
      def _power_property(self):
          return "main_power"
  
  
  class YeelightNightLightModeWithoutBrightnessControl(YeelightNightLightMode):
      """Representation of a Yeelight, when in nightlight mode.
  
      It represents case when nightlight mode brightness control is not supported.
      """
  
      _attr_color_mode = COLOR_MODE_ONOFF
      _attr_supported_color_modes = {COLOR_MODE_ONOFF}
  
      @property
      def supported_features(self):
          """Flag no supported features."""
          return 0
  
  
  class YeelightWithAmbientWithoutNightlight(YeelightWhiteTempWithoutNightlightSwitch):
      """Representation of a Yeelight which has ambilight support.
  
      And nightlight switch type is none.
      """
  
      @property
      def _power_property(self):
          return "main_power"
  
  
  class YeelightWithAmbientAndNightlight(YeelightWithNightLight):
      """Representation of a Yeelight which has ambilight support.
  
      And nightlight switch type is set to light.
      """
  
      @property
      def _power_property(self):
          return "main_power"
  
  
  class YeelightAmbientLight(YeelightColorLightWithoutNightlightSwitch):
      """Representation of a Yeelight ambient light."""
  
      PROPERTIES_MAPPING = {"color_mode": "bg_lmode"}
  
      def __init__(self, *args, **kwargs):
          """Initialize the Yeelight Ambient light."""
          super().__init__(*args, **kwargs)
          self._min_mireds = kelvin_to_mired(6500)
          self._max_mireds = kelvin_to_mired(1700)
  
          self._light_type = LightType.Ambient
  
      @property
      def unique_id(self) -> str:
          """Return a unique ID."""
          unique = super().unique_id
          return f"{unique}-ambilight"
  
      @property
      def name(self) -> str:
          """Return the name of the device if any."""
          return f"{self.device.name} ambilight"
  
      @property
      def _brightness_property(self):
          return "bright"
  
      def _get_property(self, prop, default=None):
          bg_prop = self.PROPERTIES_MAPPING.get(prop)
  
          if not bg_prop:
              bg_prop = f"bg_{prop}"
  
          return super()._get_property(bg_prop, default)
  