homeassistant/custom_components/sonoff/light.py
2025-01-10 21:08:35 -08:00

1099 lines
33 KiB
Python

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"})