Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Yeelight support (expose more properties, add support for secondary lights) #1035

Merged
merged 15 commits into from
May 16, 2021
Merged
15 changes: 15 additions & 0 deletions miio/tests/test_yeelight.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ def __init__(self, *args, **kwargs):
"name": "test name",
"lan_ctrl": "1",
"save_state": "1",
"delayoff": "60",
"music_on": "1",
"flowing": "0",
"flow_params": "",
"active_mode": "1",
"nl_br": "100",
"bg_power": "off",
"bg_bright": "100",
"bg_lmode": "2",
"bg_rgb": "16711680",
"bg_hue": "359",
"bg_sat": "100",
"bg_ct": "3584",
"bg_flowing": "0",
"bg_flow_params": "",
}

self.return_values = {
Expand Down
167 changes: 153 additions & 14 deletions miio/yeelight.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class YeelightMode(IntEnum):

class YeelightStatus(DeviceStatus):
def __init__(self, data):
# ['power', 'bright', 'ct', 'rgb', 'hue', 'sat', 'color_mode', 'name', 'lan_ctrl', 'save_state']
# ['on', '100', '3584', '16711680', '359', '100', '2', 'name', '1', '1']
# ['name', 'lan_ctrl', 'save_state', 'delayoff', 'music_on', 'power', 'bright', 'color_mode', 'rgb', 'hue', 'sat', 'ct', 'flowing', 'flow_params', 'active_mode', 'nl_br', 'bg_power', 'bg_bright', 'bg_lmode', 'bg_rgb', 'bg_hue', 'bg_sat', 'bg_ct', 'bg_flowing', 'bg_flow_params']
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
# ['name', '1', '1', '60', '1', 'on', '100', '2', '16711680', '359', '100', '3584', '1', '[0, 24, 0]', '1', '100', 'on', '100', '2', '16711680', '359', '100', '3584', '1', '[0, 24, 0]']
self.data = data

@property
Expand Down Expand Up @@ -68,7 +68,7 @@ def color_temp(self) -> Optional[int]:
return None

@property
def developer_mode(self) -> bool:
def developer_mode(self) -> Optional[bool]:
"""Return whether the developer mode is active."""
lan_ctrl = self.data["lan_ctrl"]
if lan_ctrl:
Expand All @@ -85,6 +85,109 @@ def name(self) -> str:
"""Return the internal name of the bulb."""
return self.data["name"]

@property
def color_flowing(self) -> bool:
"""Return whether the color flowing is active."""
return bool(int(self.data["flowing"]))

@property
def color_flow_params(self) -> Optional[str]:
"""Return color flowing params."""
if self.color_flowing:
return self.data["flow_params"]
return None

@property
def delay_off(self) -> int:
"""Return delay in minute before bulb is off."""
return self.data["delayoff"]
rytilahti marked this conversation as resolved.
Show resolved Hide resolved

@property
def music_mode(self) -> Optional[bool]:
"""Return whether the music mode is active."""
music_on = self.data["music_on"]
if music_on:
return bool(int(music_on))
return None

@property
def moonlight_mode(self) -> Optional[bool]:
"""Return whether the moonlight mode is active."""
active_mode = self.data["active_mode"]
if active_mode:
return bool(int(active_mode))
return None

@property
def moonlight_mode_brightness(self) -> Optional[int]:
"""Return current moonlight brightness."""
nl_br = self.data["nl_br"]
if nl_br:
return int(self.data["nl_br"])
return None

@property
def is_bg_on(self) -> Optional[bool]:
"""Return whether the background light is on or off."""
bg_power = self.data["bg_power"]
if bg_power:
return bg_power == "on"
return None
rytilahti marked this conversation as resolved.
Show resolved Hide resolved

@property
def bg_brightness(self) -> Optional[int]:
"""Return current background lights brightness."""
if self.is_bg_on is not None:
return int(self.data["bg_bright"])
return None

@property
def bg_rgb(self) -> Optional[Tuple[int, int, int]]:
"""Return background lights color in RGB if RGB mode is active."""
rgb = self.data["bg_rgb"]
if self.bg_color_mode == YeelightMode.RGB and rgb:
return int_to_rgb(int(rgb))
return None

@property
def bg_color_mode(self) -> Optional[YeelightMode]:
"""Return current background lights color mode."""
if self.is_bg_on is not None:
return YeelightMode(int(self.data["bg_lmode"]))
return None

@property
def bg_hsv(self) -> Optional[Tuple[int, int, int]]:
"""Return current background lights color in HSV if HSV mode is active."""
hue = self.data["bg_hue"]
sat = self.data["bg_sat"]
brightness = self.data["bg_bright"]
if self.bg_color_mode == YeelightMode.HSV and (hue or sat or brightness):
return hue, sat, brightness
return None

@property
def bg_color_temp(self) -> Optional[int]:
"""Return current background lights color temperature, if applicable."""
ct = self.data["bg_ct"]
if self.bg_color_mode == YeelightMode.ColorTemperature and ct:
return int(ct)
return None

@property
def bg_color_flowing(self) -> Optional[bool]:
"""Return whether the flowing mode is active for background lights."""
if self.is_bg_on is not None:
return bool(int(self.data["bg_flowing"]))
return None

@property
def bg_color_flow_params(self) -> Optional[str]:
"""Return color flowing params for background lights."""
if self.bg_color_flowing:
return self.data["bg_flow_params"]
return None


class Yeelight(Device):
"""A rudimentary support for Yeelight bulbs.
Expand All @@ -109,30 +212,66 @@ def __init__(self, *args, **kwargs):
default_output=format_output(
"",
"Name: {result.name}\n"
"Power: {result.is_on}\n"
"Brightness: {result.brightness}\n"
"Color mode: {result.color_mode}\n"
"RGB: {result.rgb}\n"
"HSV: {result.hsv}\n"
"Temperature: {result.color_temp}\n"
"Developer mode: {result.developer_mode}\n"
"Update default on change: {result.save_state_on_change}\n"
"Delay in minute before off: {result.delay_off}\n"
"Music mode: {result.music_mode}\n"
"Light\n"
" Power: {result.is_on}\n"
" Brightness: {result.brightness}\n"
" Color mode: {result.color_mode}\n"
" RGB: {result.rgb}\n"
" HSV: {result.hsv}\n"
" Temperature: {result.color_temp}\n"
" Color flowing mode: {result.color_flowing}\n"
" Color flowing parameters: {result.color_flow_params}\n"
"Moonlight\n"
" Is in mode: {result.moonlight_mode}\n"
" Moonlight mode brightness: {result.moonlight_mode_brightness}\n"
"Background light\n"
" Power: {result.is_bg_on}\n"
" Brightness: {result.bg_brightness}\n"
" Color mode: {result.bg_color_mode}\n"
" RGB: {result.bg_rgb}\n"
" HSV: {result.bg_hsv}\n"
" Temperature: {result.bg_color_temp}\n"
" Color flowing mode: {result.bg_color_flowing}\n"
" Color flowing parameters: {result.bg_color_flow_params}\n"
"\n",
)
)
def status(self) -> YeelightStatus:
"""Retrieve properties."""
properties = [
# general properties
"name",
"lan_ctrl",
"save_state",
"delayoff",
"music_on",
# light properties
"power",
"bright",
"ct",
"color_mode",
"rgb",
"hue",
"sat",
"color_mode",
"name",
"lan_ctrl",
"save_state",
"ct",
"flowing",
"flow_params",
# moonlight properties
"active_mode",
"nl_br",
# background light properties
"bg_power",
"bg_bright",
"bg_lmode",
"bg_rgb",
"bg_hue",
"bg_sat",
"bg_ct",
"bg_flowing",
"bg_flow_params",
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
]

values = self.get_properties(properties)
Expand Down