import time from homeassistant.components.light import ( ColorMode, LightEntity, LightEntityFeature, ) from homeassistant.util import color from .core.const import DOMAIN from .core.entity import XEntity from .core.ewelink import SIGNAL_ADD_ENTITIES, XRegistry PARALLEL_UPDATES = 0 # fix entity_platform parallel_updates Semaphore async def async_setup_entry(hass, config_entry, add_entities): ewelink: XRegistry = hass.data[DOMAIN][config_entry.entry_id] ewelink.dispatcher_connect( SIGNAL_ADD_ENTITIES, lambda x: add_entities([e for e in x if isinstance(e, LightEntity)]), ) def conv(value: int, a1: int, a2: int, b1: int, b2: int) -> int: value = round((value - a1) / (a2 - a1) * (b2 - b1) + b1) if value < min(b1, b2): value = min(b1, b2) if value > max(b1, b2): value = max(b1, b2) return value ############################################################################### # Category 1. XLight base (brightness) ############################################################################### # https://developers.home-assistant.io/docs/core/entity/light/ # noinspection PyAbstractClass class XLight(XEntity, LightEntity): uid = "" # prevent add param to entity_id # support on/off and brightness _attr_color_mode = ColorMode.BRIGHTNESS _attr_supported_color_modes = {ColorMode.BRIGHTNESS} _attr_supported_features = LightEntityFeature.TRANSITION def set_state(self, params: dict): if self.param in params: self._attr_is_on = params[self.param] == "on" def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: pass async def async_turn_on( self, brightness: int = None, color_temp: int = None, rgb_color=None, xy_color=None, hs_color=None, effect: str = None, transition: float = None, **kwargs, ) -> None: if xy_color: rgb_color = color.color_xy_to_RGB(*xy_color) elif hs_color: rgb_color = color.color_hs_to_RGB(*hs_color) if transition: await self.transiton(brightness, color_temp, rgb_color, transition) return if brightness == 0: await self.async_turn_off() return if brightness or color_temp or rgb_color or effect: params = self.get_params(brightness, color_temp, rgb_color, effect) else: params = None if params: # some lights can only be turned on when the lights are off if not self.is_on: await self.ewelink.send( self.device, {self.param: "on"}, query_cloud=False ) await self.ewelink.send( self.device, params, {"cmd": "dimmable", **params}, cmd_lan="dimmable", query_cloud=kwargs.get("query_cloud", True), ) else: await self.ewelink.send(self.device, {self.param: "on"}) async def async_turn_off(self, **kwargs) -> None: await self.ewelink.send(self.device, {self.param: "off"}) async def transiton( self, brightness: int, color_temp: int, rgb_color, transition: float, ): br0 = self.brightness or 0 br1 = brightness ct0 = self.color_temp or self.min_mireds ct1 = color_temp rgb0 = self.rgb_color or [0, 0, 0] rgb1 = rgb_color t0 = time.time() while (k := (time.time() - t0) / transition) < 1: if br1 is not None: brightness = br0 + round((br1 - br0) * k) if ct1 is not None: color_temp = ct0 + round((ct1 - ct0) * k) if rgb1 is not None: rgb_color = [rgb0[i] + round((rgb1[i] - rgb0[i]) * k) for i in range(3)] await self.async_turn_on( brightness, color_temp, rgb_color, query_cloud=False ) await self.async_turn_on(br1, ct1, rgb1) # noinspection PyAbstractClass, UIID36 class XDimmer(XLight): params = {"switch", "bright"} param = "switch" def set_state(self, params: dict): XLight.set_state(self, params) if "bright" in params: self._attr_brightness = conv(params["bright"], 10, 100, 1, 255) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if brightness: return {"bright": conv(brightness, 1, 255, 10, 100)} # noinspection PyAbstractClass, UIID57 class XLight57(XLight): params = {"state", "channel0"} param = "state" def set_state(self, params: dict): XLight.set_state(self, params) if "channel0" in params: self._attr_brightness = conv(params["channel0"], 25, 255, 1, 255) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if brightness: return {"channel0": str(conv(brightness, 1, 255, 25, 255))} # noinspection PyAbstractClass, UIID44 class XLightD1(XLight): params = {"switch", "brightness"} param = "switch" def set_state(self, params: dict): XLight.set_state(self, params) if "brightness" in params: self._attr_brightness = conv(params["brightness"], 0, 100, 1, 255) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if brightness: # brightness can be only with switch=on in one message (error 400) # the purpose of the mode is unclear # max brightness=100 (error 400) return { "brightness": conv(brightness, 1, 255, 0, 100), "mode": 0, "switch": "on", } ############################################################################### # Category 2. XLight base (color) ############################################################################### UIID22_MODES = { "Good Night": { "channel0": "0", "channel1": "0", "channel2": "189", "channel3": "118", "channel4": "0", "zyx_mode": 3, "type": "middle", }, "Reading": { "channel0": "0", "channel1": "0", "channel2": "255", "channel3": "255", "channel4": "255", "zyx_mode": 4, "type": "middle", }, "Party": { "channel0": "0", "channel1": "0", "channel2": "207", "channel3": "56", "channel4": "3", "zyx_mode": 5, "type": "middle", }, "Leisure": { "channel0": "0", "channel1": "0", "channel2": "56", "channel3": "85", "channel4": "179", "zyx_mode": 6, "type": "middle", }, } # noinspection PyAbstractClass, UIID22 class XLightB1(XLight): params = {"state", "zyx_mode", "channel0", "channel2"} param = "state" _attr_min_mireds = 1 # cold _attr_max_mireds = 3 # warm _attr_effect_list = list(UIID22_MODES.keys()) # support on/off, brightness, color_temp and RGB _attr_supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.RGB} _attr_supported_features = LightEntityFeature.EFFECT | LightEntityFeature.TRANSITION def set_state(self, params: dict): XLight.set_state(self, params) if "zyx_mode" in params: mode = params["zyx_mode"] # 1-6 if mode == 1: self._attr_color_mode = ColorMode.COLOR_TEMP else: self._attr_color_mode = ColorMode.RGB if mode >= 3: self._attr_effect = self.effect_list[mode - 3] else: self._attr_effect = None if self.color_mode == ColorMode.COLOR_TEMP: # from 25 to 255 cold = int(params["channel0"]) warm = int(params["channel1"]) if warm == 0: self._attr_color_temp = 1 elif cold == warm: self._attr_color_temp = 2 elif cold == 0: self._attr_color_temp = 3 self._attr_brightness = conv(max(cold, warm), 25, 255, 1, 255) else: self._attr_rgb_color = ( int(params["channel2"]), int(params["channel3"]), int(params["channel4"]), ) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if brightness or color_temp: ch = str(conv(brightness or self.brightness, 1, 255, 25, 255)) if not color_temp: color_temp = self.color_temp if color_temp == 1: params = {"channel0": ch, "channel1": "0"} elif color_temp == 2: params = {"channel0": ch, "channel1": ch} elif color_temp == 3: params = {"channel0": ch, "channel1": ch} else: raise NotImplementedError return { **params, "channel2": "0", "channel3": "0", "channel4": "0", "zyx_mode": 1, } if rgb_color: return { "channel0": "0", "channel1": "0", "channel2": str(rgb_color[0]), "channel3": str(rgb_color[1]), "channel4": str(rgb_color[2]), "zyx_mode": 2, } if effect: return UIID22_MODES[effect] # noinspection PyAbstractClass, UIID59 class XLightL1(XLight): params = {"switch", "bright", "colorR", "mode"} param = "switch" modes = { "Colorful": {"mode": 1, "switch": "on"}, "Colorful Gradient": {"mode": 2, "switch": "on"}, "Colorful Breath": {"mode": 3, "switch": "on"}, "DIY Gradient": {"mode": 4, "switch": "on"}, "DIY Pulse": {"mode": 5, "switch": "on"}, "DIY Breath": {"mode": 6, "switch": "on"}, "DIY Strobe": {"mode": 7, "switch": "on"}, "RGB Gradient": {"mode": 8, "switch": "on"}, "RGB Pulse": {"mode": 9, "switch": "on"}, "RGB Breath": {"mode": 10, "switch": "on"}, "RGB Strobe": {"mode": 11, "switch": "on"}, "Music": {"mode": 12, "switch": "on"}, } _attr_color_mode = ColorMode.RGB _attr_effect_list = list(modes.keys()) # support on/off, brightness, RGB _attr_supported_color_modes = {ColorMode.RGB} _attr_supported_features = LightEntityFeature.EFFECT | LightEntityFeature.TRANSITION def set_state(self, params: dict): XLight.set_state(self, params) if "bright" in params: self._attr_brightness = conv(params["bright"], 1, 100, 1, 255) if "colorR" in params and "colorG" in params and "colorB": self._attr_rgb_color = ( params["colorR"], params["colorG"], params["colorB"], ) if "mode" in params: self._attr_effect = next( (k for k, v in self.modes.items() if v["mode"] == params["mode"]), None ) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: params = {} if effect: params.update(self.modes[effect]) if brightness: params.setdefault("mode", 1) params["bright"] = conv(brightness, 1, 255, 1, 100) if rgb_color: params.setdefault("mode", 1) params.update( { "colorR": rgb_color[0], "colorG": rgb_color[1], "colorB": rgb_color[2], "light_type": 1, } ) return params # noinspection PyAbstractClass class XLightL3(XLightL1): modes = { "Warm White": { "switch": "on", "mode": 2, "speed07": 50, "bright07": 100, "light_type": 1, }, "Magic Forward": { "switch": "on", "mode": 7, "speed07": 50, "bright07": 100, "light_type": 1, }, "Magic Back": { "switch": "on", "mode": 8, "speed08": 50, "bright08": 100, "light_type": 1, }, "7 Color Wave": { "switch": "on", "mode": 35, "speed35": 50, "bright35": 100, "light_type": 1, }, "7 Color Wave Back": { "switch": "on", "mode": 36, "speed36": 50, "bright36": 100, "light_type": 1, }, "RGB Wave": { "switch": "on", "mode": 37, "speed37": 50, "bright37": 100, "light_type": 1, }, "RGB Wave Back": { "switch": "on", "mode": 38, "speed38": 50, "bright38": 100, "light_type": 1, }, "YCP Wave": { "switch": "on", "mode": 39, "speed39": 50, "bright39": 100, "light_type": 1, }, "YCP Wave Back": { "switch": "on", "mode": 40, "speed40": 50, "bright40": 100, "light_type": 1, }, "7 Color Race": { "switch": "on", "mode": 29, "speed29": 50, "bright29": 100, "light_type": 1, }, "7 Color Race Back": { "switch": "on", "mode": 30, "speed30": 50, "bright30": 100, "light_type": 1, }, "RGB Race": { "switch": "on", "mode": 31, "speed31": 50, "bright31": 100, "light_type": 1, }, "RGB Race Back": { "switch": "on", "mode": 32, "speed32": 50, "bright32": 100, "light_type": 1, }, "YCP Race": { "switch": "on", "mode": 33, "speed33": 50, "bright33": 100, "light_type": 1, }, "YCP Race Back": { "switch": "on", "mode": 34, "speed34": 50, "bright34": 100, "light_type": 1, }, "7 Color Flush": { "switch": "on", "mode": 41, "speed41": 50, "bright41": 100, "light_type": 1, }, "7 Color Flush Back": { "switch": "on", "mode": 42, "speed42": 50, "bright42": 100, "light_type": 1, }, "RGB Flush": { "switch": "on", "mode": 43, "speed43": 50, "bright43": 100, "light_type": 1, }, "RGB Flush Back": { "switch": "on", "mode": 44, "speed44": 50, "bright44": 100, "light_type": 1, }, "YCP Flush": { "switch": "on", "mode": 45, "speed45": 50, "bright45": 100, "light_type": 1, }, "YCP Flush Back": { "switch": "on", "mode": 46, "speed46": 50, "bright46": 100, "light_type": 1, }, "7 Color Flush Close": { "switch": "on", "mode": 47, "speed47": 50, "bright47": 100, "light_type": 1, }, "7 Color Flush Open": { "switch": "on", "mode": 48, "speed48": 50, "bright48": 100, "light_type": 1, }, "RGB Flush Close": { "switch": "on", "mode": 49, "speed49": 50, "bright49": 100, "light_type": 1, }, "RGB Flush Open": { "switch": "on", "mode": 50, "speed50": 50, "bright50": 100, "light_type": 1, }, "YCP Flush Close": { "switch": "on", "mode": 51, "speed51": 50, "bright51": 100, "light_type": 1, }, "YCP Flush Open": { "switch": "on", "mode": 52, "speed52": 50, "bright52": 100, "light_type": 1, }, "Red Marquee": { "switch": "on", "mode": 22, "speed22": 50, "bright22": 100, "light_type": 1, }, "Green Marquee": { "switch": "on", "mode": 23, "speed23": 50, "bright23": 100, "light_type": 1, }, "Blue Marquee": { "switch": "on", "mode": 24, "speed24": 50, "bright24": 100, "light_type": 1, }, "Yellow Marquee": { "switch": "on", "mode": 25, "speed25": 50, "bright25": 100, "light_type": 1, }, "Cyan Marquee": { "switch": "on", "mode": 26, "speed26": 50, "bright26": 100, "light_type": 1, }, "Purple Marquee": { "switch": "on", "mode": 27, "speed27": 50, "bright27": 100, "light_type": 1, }, "White Marquee": { "switch": "on", "mode": 28, "speed28": 50, "bright28": 100, "light_type": 1, }, "7 Color Jump": { "switch": "on", "mode": 10, "speed10": 50, "bright10": 100, "light_type": 1, }, "RGB Jump": { "switch": "on", "mode": 11, "speed11": 50, "bright11": 100, "light_type": 1, }, "YCP Jump": { "switch": "on", "mode": 12, "speed12": 50, "bright12": 100, "light_type": 1, }, "7 Color Gradual": { "switch": "on", "mode": 16, "speed16": 50, "bright16": 100, "light_type": 1, }, "RY Gradual": { "switch": "on", "mode": 17, "speed17": 50, "bright17": 100, "light_type": 1, }, "RP Gradual": { "switch": "on", "mode": 18, "speed18": 50, "bright18": 100, "light_type": 1, }, "GC Gradual": { "switch": "on", "mode": 19, "speed19": 50, "bright19": 100, "light_type": 1, }, "GY Gradual": { "switch": "on", "mode": 20, "speed20": 50, "bright20": 100, "light_type": 1, }, "BP Gradual": { "switch": "on", "mode": 21, "speed21": 50, "bright21": 100, "light_type": 1, }, "7 Color Strobe": { "switch": "on", "mode": 13, "speed13": 50, "bright13": 100, "light_type": 1, }, "RGB Strobe": { "switch": "on", "mode": 14, "speed14": 50, "bright14": 100, "light_type": 1, }, "YCP Strobe": { "switch": "on", "mode": 15, "speed15": 50, "bright15": 100, "light_type": 1, }, "Classic Music": { "switch": "on", "mode": 4, "rhythmMode": 0, "rhythmSensitive": 100, "bright": 100, "light_type": 1, }, "Soft Music": { "switch": "on", "mode": 4, "rhythmMode": 1, "rhythmSensitive": 100, "bright": 100, "light_type": 1, }, "Dynamic Music": { "switch": "on", "mode": 4, "rhythmMode": 2, "rhythmSensitive": 100, "bright": 100, "light_type": 1, }, "Disco Music": { "switch": "on", "mode": 4, "rhythmMode": 3, "rhythmSensitive": 100, "bright": 100, "light_type": 1, }, } _attr_effect_list = list(modes.keys()) def set_state(self, params: dict): XLightL1.set_state(self, params) if "rhythmMode" in params: self._attr_effect = next( ( k for k, v in self.modes.items() if v.get("rhythmMode") == params["rhythmMode"] ), None, ) B02_MODE_PAYLOADS = { "nightLight": {"br": 5, "ct": 0}, "read": {"br": 50, "ct": 0}, "computer": {"br": 20, "ct": 255}, "bright": {"br": 100, "ct": 255}, } # noinspection PyAbstractClass, UIID103 class XLightB02(XLight): params = {"switch", "ltype"} param = "switch" # FS-1, B02-F-A60 and other _attr_max_mireds: int = int(1000000 / 2200) # 454 _attr_min_mireds: int = int(1000000 / 6500) # 153 _attr_color_mode = ColorMode.COLOR_TEMP _attr_effect_list = list(B02_MODE_PAYLOADS.keys()) # support on/off, brightness and color_temp _attr_supported_color_modes = {ColorMode.COLOR_TEMP} _attr_supported_features = LightEntityFeature.EFFECT | LightEntityFeature.TRANSITION # ewelink specs min_br = 1 max_br = 100 min_ct = 0 max_ct = 255 def __init__(self, ewelink: XRegistry, device: dict): XEntity.__init__(self, ewelink, device) model = device.get("productModel") if model == "B02-F-ST64": self._attr_max_mireds = int(1000000 / 1800) # 555 self._attr_min_mireds = int(1000000 / 5000) # 200 elif model == "QMS-2C-CW": self._attr_max_mireds = int(1000000 / 2700) # 370 self._attr_min_mireds = int(1000000 / 6500) # 153 def set_state(self, params: dict): XLight.set_state(self, params) if "ltype" not in params: return self._attr_effect = params["ltype"] state = params[self.effect] if "br" in state: self._attr_brightness = conv(state["br"], self.min_br, self.max_br, 1, 255) if "ct" in state: self._attr_color_temp = conv( state["ct"], self.min_ct, self.max_ct, self.max_mireds, self.min_mireds ) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if brightness or color_temp: return { "ltype": "white", "white": { "br": conv( brightness or self.brightness, 1, 255, self.min_br, self.max_br ), "ct": conv( color_temp or self.color_temp, self.max_mireds, self.min_mireds, self.min_ct, self.max_ct, ), }, } if effect: return {"ltype": effect, effect: B02_MODE_PAYLOADS[effect]} # Taken straight from the debug mode and the eWeLink app B05_MODE_PAYLOADS = { "bright": {"r": 255, "g": 255, "b": 255, "br": 100}, "goodNight": {"r": 254, "g": 254, "b": 126, "br": 25}, "read": {"r": 255, "g": 255, "b": 255, "br": 60}, "nightLight": {"r": 255, "g": 242, "b": 226, "br": 5}, "party": {"r": 254, "g": 132, "b": 0, "br": 45, "tf": 1, "sp": 1}, "leisure": {"r": 0, "g": 40, "b": 254, "br": 55, "tf": 1, "sp": 1}, "soft": {"r": 38, "g": 254, "b": 0, "br": 20, "tf": 1, "sp": 1}, "colorful": {"r": 255, "g": 0, "b": 0, "br": 100, "tf": 1, "sp": 1}, } # noinspection PyAbstractClass, UIID 104 class XLightB05B(XLightB02): _attr_effect_list = list(B05_MODE_PAYLOADS.keys()) # support on/off, brightness, color_temp and RGB _attr_supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.RGB} _attr_max_mireds = 500 _attr_min_mireds = 153 def set_state(self, params: dict): XLight.set_state(self, params) if "ltype" not in params: return effect = params["ltype"] if effect == "white": self._attr_color_mode = ColorMode.COLOR_TEMP else: self._attr_color_mode = ColorMode.RGB if effect in self.effect_list: self._attr_effect = effect # fix https://github.com/AlexxIT/SonoffLAN/issues/1093 state = params.get(effect) or B05_MODE_PAYLOADS.get(effect) or {} if "br" in state: self._attr_brightness = conv(state["br"], self.min_br, self.max_br, 1, 255) if "ct" in state: self._attr_color_temp = conv( state["ct"], self.min_ct, self.max_ct, self.max_mireds, self.min_mireds ) if "r" in state or "g" in state or "b" in state: self._attr_rgb_color = ( state.get("r", 0), state.get("g", 0), state.get("b", 0), ) def get_params(self, brightness, color_temp, rgb_color, effect) -> dict: if color_temp: return { "ltype": "white", "white": { "br": conv( brightness or self.brightness, 1, 255, self.min_br, self.max_br ), "ct": conv( color_temp, self.max_mireds, self.min_mireds, self.min_ct, self.max_ct, ), }, } if rgb_color: return { "ltype": "color", "color": { "br": conv( brightness or self.brightness, 1, 255, self.min_br, self.max_br ), "r": rgb_color[0], "g": rgb_color[1], "b": rgb_color[2], }, } if brightness: if self.color_mode == ColorMode.COLOR_TEMP: return self.get_params(brightness, self.color_temp, None, None) else: return self.get_params(brightness, None, self.rgb_color, None) if effect is not None: return {"ltype": effect, effect: B05_MODE_PAYLOADS[effect]} ############################################################################### # Category 3. Other ############################################################################### # noinspection PyAbstractClass class XLightGroup(XEntity, LightEntity): """Differs from the usual switch by brightness adjustment. Is logical use only for two or more channels. Able to remember brightness on moment off. The sequence of channels is important. The first channels will be turned on at low brightness. """ params = {"switches"} channels: list = None _attr_brightness = 0 # support on/off and brightness _attr_color_mode = ColorMode.BRIGHTNESS _attr_supported_color_modes = {ColorMode.BRIGHTNESS} def set_state(self, params: dict): cnt = sum( 1 for i in params["switches"] if i["outlet"] in self.channels and i["switch"] == "on" ) if cnt: # if at least something is on - remember the new brightness self._attr_brightness = round(cnt / len(self.channels) * 255) self._attr_is_on = True else: self._attr_is_on = False async def async_turn_on(self, brightness: int = None, **kwargs): if brightness is not None: self._attr_brightness = brightness elif self._attr_brightness == 0: self._attr_brightness = 255 # how much light should turn on at such brightness cnt = round(self._attr_brightness / 255 * len(self.channels)) # the first part of the lights - turn on, the second - turn off switches = [ {"outlet": channel, "switch": "on" if i < cnt else "off"} for i, channel in enumerate(self.channels) ] await self.ewelink.send_bulk(self.device, {"switches": switches}) async def async_turn_off(self, **kwargs) -> None: switches = [{"outlet": ch, "switch": "off"} for ch in self.channels] await self.ewelink.send_bulk(self.device, {"switches": switches}) # noinspection PyAbstractClass, UIID22 class XFanLight(XEntity, LightEntity): params = {"switches", "light"} uid = "1" # backward compatibility def set_state(self, params: dict): if "switches" in params: params = next(i for i in params["switches"] if i["outlet"] == 0) self._attr_is_on = params["switch"] == "on" else: self._attr_is_on = params["light"] == "on" async def async_turn_on(self, **kwargs): params = {"switches": [{"outlet": 0, "switch": "on"}]} if self.device.get("localtype") == "fan_light": params_lan = {"light": "on"} else: params_lan = None await self.ewelink.send(self.device, params, params_lan) async def async_turn_off(self): params = {"switches": [{"outlet": 0, "switch": "off"}]} if self.device.get("localtype") == "fan_light": params_lan = {"light": "off"} else: params_lan = None await self.ewelink.send(self.device, params, params_lan) # noinspection PyAbstractClass, UIID25 class XDiffuserLight(XEntity, LightEntity): params = {"lightswitch", "lightbright", "lightmode", "lightRcolor"} _attr_effect_list = ["Color Light", "RGB Color", "Night Light"] _attr_supported_features = LightEntityFeature.EFFECT def set_state(self, params: dict): if "lightswitch" in params: self._attr_is_on = params["lightswitch"] == 1 if "lightbright" in params: self._attr_brightness = conv(params["lightbright"], 0, 100, 1, 255) if "lightmode" in params: mode = params["lightmode"] if mode == 1: # support on/off self._attr_color_mode = ColorMode.ONOFF self._attr_supported_color_modes = {ColorMode.ONOFF} elif mode == 2: self._attr_color_mode = ColorMode.RGB # support on/off, brightness and RGB self._attr_supported_color_modes = {ColorMode.RGB} elif mode == 3: # support on/off and brightness self._attr_color_mode = ColorMode.BRIGHTNESS self._attr_supported_color_modes = {ColorMode.BRIGHTNESS} if "lightRcolor" in params: self._attr_rgb_color = ( params["lightRcolor"], params["lightGcolor"], params["lightBcolor"], ) async def async_turn_on( self, brightness: int = None, rgb_color=None, effect: str = None, **kwargs ) -> None: params = {} if effect is not None: params["lightmode"] = mode = self.effect.index(effect) + 1 if mode == 2 and rgb_color is None: rgb_color = self._attr_rgb_color if brightness is not None: params["lightbright"] = conv(brightness, 1, 255, 0, 100) if rgb_color is not None: params.update( { "lightmode": 2, "lightRcolor": rgb_color[0], "lightGcolor": rgb_color[1], "lightBcolor": rgb_color[2], } ) if not params: params["lightswitch"] = 1 await self.ewelink.send(self.device, params) async def async_turn_off(self, **kwargs) -> None: await self.ewelink.send(self.device, {"lightswitch": 0}) class XT5Light(XEntity, LightEntity): params = {"lightSwitch", "lightMode"} _attr_effect_list = ["0", "1", "2", "3", "4", "5", "6", "7"] _attr_supported_features = LightEntityFeature.EFFECT def set_state(self, params: dict): if "lightSwitch" in params: self._attr_is_on = params["lightSwitch"] == "on" if "lightMode" in params: self._attr_effect = str(params["lightMode"]) async def async_turn_on( self, brightness: int = None, effect: str = None, **kwargs ) -> None: params = {} if effect and effect != "0": params["lightMode"] = int(effect) if not params: params["lightSwitch"] = "on" await self.ewelink.send(self.device, params) async def async_turn_off(self, **kwargs) -> None: await self.ewelink.send(self.device, {"lightSwitch": "off"})