From 7f604c166b146ca4be16d5b6743a390673de3576 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Thu, 6 May 2021 19:42:52 +0300 Subject: [PATCH 01/13] Add all yeelight properties from documentation --- miio/yeelight.py | 167 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 14 deletions(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index 4841ab0b0..093dd91a2 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -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'] + # ['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 @@ -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: @@ -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"] + + @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 + + @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. @@ -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", ] values = self.get_properties(properties) From a16d12fdc940ba395995678208112507ed5de605 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Thu, 6 May 2021 21:08:19 +0300 Subject: [PATCH 02/13] Add new property to DummyLight init --- miio/tests/test_yeelight.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/miio/tests/test_yeelight.py b/miio/tests/test_yeelight.py index c4d628438..f943d50a5 100644 --- a/miio/tests/test_yeelight.py +++ b/miio/tests/test_yeelight.py @@ -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 = { From e06a58073a097d5f8b032b6109e8a3aa196908c9 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Fri, 7 May 2021 09:47:12 +0300 Subject: [PATCH 03/13] Cast delay_off to int --- miio/yeelight.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index 093dd91a2..f09a2fb9d 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -100,7 +100,7 @@ def color_flow_params(self) -> Optional[str]: @property def delay_off(self) -> int: """Return delay in minute before bulb is off.""" - return self.data["delayoff"] + return int(self.data["delayoff"]) @property def music_mode(self) -> Optional[bool]: From 5d6132b473f77c4956703b8fbaa24ff35f85f2a0 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 11:16:26 +0300 Subject: [PATCH 04/13] Replase data with a dictionary --- miio/yeelight.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index f09a2fb9d..7cc7028ec 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -22,8 +22,14 @@ class YeelightMode(IntEnum): class YeelightStatus(DeviceStatus): def __init__(self, data): - # ['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'] - # ['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]'] + # yeelink.light.ceiling4, yeelink.light.ceiling20 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '1', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4115', 'flowing': '0', 'flow_params': '0,0,2000,3,0,33,2000,3,0,100', 'active_mode': '1', 'nl_br': '1', 'bg_power': 'off', 'bg_bright': '100', 'bg_lmode': '1', 'bg_rgb': '15531811', 'bg_hue': '65', 'bg_sat': '86', 'bg_ct': '4000', 'bg_flowing': '0', 'bg_flow_params': '0,0,3000,4,16711680,100,3000,4,65280,100,3000,4,255,100'} + # yeelink.light.ceiling1 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '100', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '5200', 'flowing': '0', 'flow_params': '', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} + # yeelink.light.ceiling22 - like yeelink.light.ceiling1 but without "lan_ctrl" + # {'name': '', 'lan_ctrl': '', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '84', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4000', 'flowing': '0', 'flow_params': '0,0,800,2,2700,50,800,2,2700,30,1200,2,2700,80,800,2,2700,60,1200,2,2700,90,2400,2,2700,50,1200,2,2700,80,800,2,2700,60,400,2,2700,70', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} + # yeelink.light.color3, yeelink.light.color4, yeelink.light.color5, yeelink.light.strip2 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '0', 'power': 'off', 'bright': '100', 'color_mode': '1', 'rgb': '2353663', 'hue': '186', 'sat': '86', 'ct': '6500', 'flowing': '0', 'flow_params': '0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100', 'active_mode': '', 'nl_br': '', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} self.data = data @property From f43c6529ae0da845c5b2cbbe3b3afc160794b146 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 16:54:51 +0300 Subject: [PATCH 05/13] add YeelightSubLight class --- miio/yeelight.py | 196 +++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 108 deletions(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index 7cc7028ec..81932f084 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -1,6 +1,6 @@ import warnings from enum import IntEnum -from typing import Optional, Tuple +from typing import List, Optional, Tuple import click @@ -14,38 +14,53 @@ class YeelightException(DeviceException): pass +class YeelightSubLightType(IntEnum): + Main = 1 + Background = 2 + + +SUBLIGHT_PROP_PREFIX = { + YeelightSubLightType.Main: "", + YeelightSubLightType.Background: "bg_", +} + +SUBLIGHT_COLOR_MODE_PROP = { + YeelightSubLightType.Main: "color_mode", + YeelightSubLightType.Background: "bg_lmode", +} + + class YeelightMode(IntEnum): RGB = 1 ColorTemperature = 2 HSV = 3 -class YeelightStatus(DeviceStatus): - def __init__(self, data): - # yeelink.light.ceiling4, yeelink.light.ceiling20 - # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '1', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4115', 'flowing': '0', 'flow_params': '0,0,2000,3,0,33,2000,3,0,100', 'active_mode': '1', 'nl_br': '1', 'bg_power': 'off', 'bg_bright': '100', 'bg_lmode': '1', 'bg_rgb': '15531811', 'bg_hue': '65', 'bg_sat': '86', 'bg_ct': '4000', 'bg_flowing': '0', 'bg_flow_params': '0,0,3000,4,16711680,100,3000,4,65280,100,3000,4,255,100'} - # yeelink.light.ceiling1 - # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '100', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '5200', 'flowing': '0', 'flow_params': '', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} - # yeelink.light.ceiling22 - like yeelink.light.ceiling1 but without "lan_ctrl" - # {'name': '', 'lan_ctrl': '', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '84', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4000', 'flowing': '0', 'flow_params': '0,0,800,2,2700,50,800,2,2700,30,1200,2,2700,80,800,2,2700,60,1200,2,2700,90,2400,2,2700,50,1200,2,2700,80,800,2,2700,60,400,2,2700,70', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} - # yeelink.light.color3, yeelink.light.color4, yeelink.light.color5, yeelink.light.strip2 - # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '0', 'power': 'off', 'bright': '100', 'color_mode': '1', 'rgb': '2353663', 'hue': '186', 'sat': '86', 'ct': '6500', 'flowing': '0', 'flow_params': '0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100', 'active_mode': '', 'nl_br': '', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} +class YeelightSubLight: + def __init__(self, data, type): self.data = data + self.type = type + + def get_prop_name(self, prop) -> str: + if prop == "color_mode": + return SUBLIGHT_COLOR_MODE_PROP[self.type] + else: + return SUBLIGHT_PROP_PREFIX[self.type] + prop @property def is_on(self) -> bool: - """Return whether the bulb is on or off.""" - return self.data["power"] == "on" + """Return whether the light is on or off.""" + return self.data[self.get_prop_name("power")] == "on" @property def brightness(self) -> int: """Return current brightness.""" - return int(self.data["bright"]) + return int(self.data[self.get_prop_name("bright")]) @property def rgb(self) -> Optional[Tuple[int, int, int]]: """Return color in RGB if RGB mode is active.""" - rgb = self.data["rgb"] + rgb = self.data[self.get_prop_name("rgb")] if self.color_mode == YeelightMode.RGB and rgb: return int_to_rgb(int(rgb)) return None @@ -53,14 +68,14 @@ def rgb(self) -> Optional[Tuple[int, int, int]]: @property def color_mode(self) -> YeelightMode: """Return current color mode.""" - return YeelightMode(int(self.data["color_mode"])) + return YeelightMode(int(self.data[self.get_prop_name("color_mode")])) @property def hsv(self) -> Optional[Tuple[int, int, int]]: """Return current color in HSV if HSV mode is active.""" - hue = self.data["hue"] - sat = self.data["sat"] - brightness = self.data["bright"] + hue = self.data[self.get_prop_name("hue")] + sat = self.data[self.get_prop_name("sat")] + brightness = self.data[self.get_prop_name("bright")] if self.color_mode == YeelightMode.HSV and (hue or sat or brightness): return hue, sat, brightness return None @@ -68,11 +83,36 @@ def hsv(self) -> Optional[Tuple[int, int, int]]: @property def color_temp(self) -> Optional[int]: """Return current color temperature, if applicable.""" - ct = self.data["ct"] + ct = self.data[self.get_prop_name("ct")] if self.color_mode == YeelightMode.ColorTemperature and ct: return int(ct) return None + @property + def color_flowing(self) -> bool: + """Return whether the color flowing is active.""" + return bool(int(self.data[self.get_prop_name("flowing")])) + + @property + def color_flow_params(self) -> Optional[str]: + """Return color flowing params.""" + if self.color_flowing: + return self.data[self.get_prop_name("flow_params")] + return None + + +class YeelightStatus(DeviceStatus): + def __init__(self, data): + # yeelink.light.ceiling4, yeelink.light.ceiling20 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '1', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4115', 'flowing': '0', 'flow_params': '0,0,2000,3,0,33,2000,3,0,100', 'active_mode': '1', 'nl_br': '1', 'bg_power': 'off', 'bg_bright': '100', 'bg_lmode': '1', 'bg_rgb': '15531811', 'bg_hue': '65', 'bg_sat': '86', 'bg_ct': '4000', 'bg_flowing': '0', 'bg_flow_params': '0,0,3000,4,16711680,100,3000,4,65280,100,3000,4,255,100'} + # yeelink.light.ceiling1 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '100', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '5200', 'flowing': '0', 'flow_params': '', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} + # yeelink.light.ceiling22 - like yeelink.light.ceiling1 but without "lan_ctrl" + # {'name': '', 'lan_ctrl': '', 'save_state': '1', 'delayoff': '0', 'music_on': '', 'power': 'off', 'bright': '84', 'color_mode': '2', 'rgb': '', 'hue': '', 'sat': '', 'ct': '4000', 'flowing': '0', 'flow_params': '0,0,800,2,2700,50,800,2,2700,30,1200,2,2700,80,800,2,2700,60,1200,2,2700,90,2400,2,2700,50,1200,2,2700,80,800,2,2700,60,400,2,2700,70', 'active_mode': '0', 'nl_br': '0', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} + # yeelink.light.color3, yeelink.light.color4, yeelink.light.color5, yeelink.light.strip2 + # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '0', 'power': 'off', 'bright': '100', 'color_mode': '1', 'rgb': '2353663', 'hue': '186', 'sat': '86', 'ct': '6500', 'flowing': '0', 'flow_params': '0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100', 'active_mode': '', 'nl_br': '', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} + self.data = data + @property def developer_mode(self) -> Optional[bool]: """Return whether the developer mode is active.""" @@ -91,18 +131,6 @@ 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.""" @@ -133,66 +161,17 @@ def moonlight_mode_brightness(self) -> Optional[int]: 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"] + def lights(self) -> List[YeelightSubLight]: + """Return list of sub lights.""" + sub_lights = list({YeelightSubLight(self.data, YeelightSubLightType.Main)}) + bg_power = self.data[ + "bg_power" + ] # to do: change this to model spec in the future. if bg_power: - return bg_power == "on" - return None - - @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 + sub_lights.append( + YeelightSubLight(self.data, YeelightSubLightType.Background) + ) + return sub_lights class Yeelight(Device): @@ -223,26 +202,27 @@ def __init__(self, *args, **kwargs): "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" + " Power: {result.lights[0].is_on}\n" + " Brightness: {result.lights[0].brightness}\n" + " Color mode: {result.lights[0].color_mode}\n" + " RGB: {result.lights[0].rgb}\n" + " HSV: {result.lights[0].hsv}\n" + " Temperature: {result.lights[0].color_temp}\n" + " Color flowing mode: {result.lights[0].color_flowing}\n" + " Color flowing parameters: {result.lights[0].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" + # Have no any idea how it must be + # "Background light\n" + # " Power: {result.lights[1].is_on}\n" + # " Brightness: {result.lights[1].brightness}\n" + # " Color mode: {result.lights[1].color_mode}\n" + # " RGB: {result.lights[1].rgb}\n" + # " HSV: {result.lights[1].hsv}\n" + # " Temperature: {result.lights[1].color_temp}\n" + # " Color flowing mode: {result.lights[1].color_flowing}\n" + # " Color flowing parameters: {result.lights[1].color_flow_params}\n" "\n", ) ) From 612ec6fd57d423f058757b0150d8146cbf6fea68 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 17:40:01 +0300 Subject: [PATCH 06/13] Using __repr__ to fix cl output, fix tests. --- miio/tests/test_yeelight.py | 28 ++++++++++++++-------------- miio/yeelight.py | 33 ++++++++++++++------------------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/miio/tests/test_yeelight.py b/miio/tests/test_yeelight.py index f943d50a5..ae9e1914c 100644 --- a/miio/tests/test_yeelight.py +++ b/miio/tests/test_yeelight.py @@ -81,11 +81,11 @@ def test_status(self): assert repr(status) == repr(YeelightStatus(self.device.start_state)) assert status.name == self.device.start_state["name"] - assert status.is_on is False - assert status.brightness == 100 - assert status.color_temp == 3584 - assert status.color_mode == YeelightMode.ColorTemperature - assert status.rgb is None + assert status.lights[0].is_on is False + assert status.lights[0].brightness == 100 + assert status.lights[0].color_temp == 3584 + assert status.lights[0].color_mode == YeelightMode.ColorTemperature + assert status.lights[0].rgb is None assert status.developer_mode is True assert status.save_state_on_change is True @@ -95,21 +95,21 @@ def test_status(self): def test_on(self): self.device.off() # make sure we are off - assert self.device.status().is_on is False + assert self.device.status().lights[0].is_on is False self.device.on() - assert self.device.status().is_on is True + assert self.device.status().lights[0].is_on is True def test_off(self): self.device.on() # make sure we are on - assert self.device.status().is_on is True + assert self.device.status().lights[0].is_on is True self.device.off() - assert self.device.status().is_on is False + assert self.device.status().lights[0].is_on is False def test_set_brightness(self): def brightness(): - return self.device.status().brightness + return self.device.status().lights[0].brightness self.device.set_brightness(50) assert brightness() == 50 @@ -125,7 +125,7 @@ def brightness(): def test_set_color_temp(self): def color_temp(): - return self.device.status().color_temp + return self.device.status().lights[0].color_temp self.device.set_color_temp(2000) assert color_temp() == 2000 @@ -140,7 +140,7 @@ def color_temp(): def test_set_rgb(self): def rgb(): - return self.device.status().rgb + return self.device.status().lights[0].rgb self.device._reset_state() self.device._set_state("color_mode", [1]) @@ -175,7 +175,7 @@ def rgb(): @pytest.mark.skip("hsv is not properly implemented") def test_set_hsv(self): self.reset_state() - hue, sat, val = self.device.status().hsv + hue, sat, val = self.device.status().lights[0].hsv assert hue == 359 assert sat == 100 assert val == 100 @@ -215,7 +215,7 @@ def name(): def test_toggle(self): def is_on(): - return self.device.status().is_on + return self.device.status().lights[0].is_on orig_state = is_on() self.device.toggle() diff --git a/miio/yeelight.py b/miio/yeelight.py index 81932f084..5787952c6 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -41,6 +41,19 @@ def __init__(self, data, type): self.data = data self.type = type + def __repr__(self): + s = "\n" + s += f" Sub Light - {self.type.name} \n" + s += f" Power: {self.is_on}\n" + s += f" Brightness: {self.brightness}\n" + s += f" Color mode: {self.color_mode}\n" + s += f" RGB: {self.rgb}\n" + s += f" HSV: {self.hsv}\n" + s += f" Temperature: {self.color_temp}\n" + s += f" Color flowing mode: {self.color_flowing}\n" + s += f" Color flowing parameters: {self.color_flow_params}\n" + return s + def get_prop_name(self, prop) -> str: if prop == "color_mode": return SUBLIGHT_COLOR_MODE_PROP[self.type] @@ -201,28 +214,10 @@ def __init__(self, *args, **kwargs): "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.lights[0].is_on}\n" - " Brightness: {result.lights[0].brightness}\n" - " Color mode: {result.lights[0].color_mode}\n" - " RGB: {result.lights[0].rgb}\n" - " HSV: {result.lights[0].hsv}\n" - " Temperature: {result.lights[0].color_temp}\n" - " Color flowing mode: {result.lights[0].color_flowing}\n" - " Color flowing parameters: {result.lights[0].color_flow_params}\n" + "Lights: \n{result.lights}\n" "Moonlight\n" " Is in mode: {result.moonlight_mode}\n" " Moonlight mode brightness: {result.moonlight_mode_brightness}\n" - # Have no any idea how it must be - # "Background light\n" - # " Power: {result.lights[1].is_on}\n" - # " Brightness: {result.lights[1].brightness}\n" - # " Color mode: {result.lights[1].color_mode}\n" - # " RGB: {result.lights[1].rgb}\n" - # " HSV: {result.lights[1].hsv}\n" - # " Temperature: {result.lights[1].color_temp}\n" - # " Color flowing mode: {result.lights[1].color_flowing}\n" - # " Color flowing parameters: {result.lights[1].color_flow_params}\n" "\n", ) ) From 525561127a0fc25754f9b3b72edccf9f1e9c2d63 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 20:27:22 +0300 Subject: [PATCH 07/13] return params for base lamp to YeelightStatus --- miio/tests/test_yeelight.py | 28 +++++++++++++------------- miio/yeelight.py | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/miio/tests/test_yeelight.py b/miio/tests/test_yeelight.py index ae9e1914c..f943d50a5 100644 --- a/miio/tests/test_yeelight.py +++ b/miio/tests/test_yeelight.py @@ -81,11 +81,11 @@ def test_status(self): assert repr(status) == repr(YeelightStatus(self.device.start_state)) assert status.name == self.device.start_state["name"] - assert status.lights[0].is_on is False - assert status.lights[0].brightness == 100 - assert status.lights[0].color_temp == 3584 - assert status.lights[0].color_mode == YeelightMode.ColorTemperature - assert status.lights[0].rgb is None + assert status.is_on is False + assert status.brightness == 100 + assert status.color_temp == 3584 + assert status.color_mode == YeelightMode.ColorTemperature + assert status.rgb is None assert status.developer_mode is True assert status.save_state_on_change is True @@ -95,21 +95,21 @@ def test_status(self): def test_on(self): self.device.off() # make sure we are off - assert self.device.status().lights[0].is_on is False + assert self.device.status().is_on is False self.device.on() - assert self.device.status().lights[0].is_on is True + assert self.device.status().is_on is True def test_off(self): self.device.on() # make sure we are on - assert self.device.status().lights[0].is_on is True + assert self.device.status().is_on is True self.device.off() - assert self.device.status().lights[0].is_on is False + assert self.device.status().is_on is False def test_set_brightness(self): def brightness(): - return self.device.status().lights[0].brightness + return self.device.status().brightness self.device.set_brightness(50) assert brightness() == 50 @@ -125,7 +125,7 @@ def brightness(): def test_set_color_temp(self): def color_temp(): - return self.device.status().lights[0].color_temp + return self.device.status().color_temp self.device.set_color_temp(2000) assert color_temp() == 2000 @@ -140,7 +140,7 @@ def color_temp(): def test_set_rgb(self): def rgb(): - return self.device.status().lights[0].rgb + return self.device.status().rgb self.device._reset_state() self.device._set_state("color_mode", [1]) @@ -175,7 +175,7 @@ def rgb(): @pytest.mark.skip("hsv is not properly implemented") def test_set_hsv(self): self.reset_state() - hue, sat, val = self.device.status().lights[0].hsv + hue, sat, val = self.device.status().hsv assert hue == 359 assert sat == 100 assert val == 100 @@ -215,7 +215,7 @@ def name(): def test_toggle(self): def is_on(): - return self.device.status().lights[0].is_on + return self.device.status().is_on orig_state = is_on() self.device.toggle() diff --git a/miio/yeelight.py b/miio/yeelight.py index 5787952c6..cf453cc12 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -126,6 +126,46 @@ def __init__(self, data): # {'name': '', 'lan_ctrl': '1', 'save_state': '1', 'delayoff': '0', 'music_on': '0', 'power': 'off', 'bright': '100', 'color_mode': '1', 'rgb': '2353663', 'hue': '186', 'sat': '86', 'ct': '6500', 'flowing': '0', 'flow_params': '0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100', 'active_mode': '', 'nl_br': '', 'bg_power': '', 'bg_bright': '', 'bg_lmode': '', 'bg_rgb': '', 'bg_hue': '', 'bg_sat': '', 'bg_ct': '', 'bg_flowing': '', 'bg_flow_params': ''} self.data = data + @property + def is_on(self) -> bool: + """Return whether the light is on or off.""" + return self.lights[0].is_on + + @property + def brightness(self) -> int: + """Return current brightness.""" + return self.lights[0].brightness + + @property + def rgb(self) -> Optional[Tuple[int, int, int]]: + """Return color in RGB if RGB mode is active.""" + return self.lights[0].rgb + + @property + def color_mode(self) -> YeelightMode: + """Return current color mode.""" + return self.lights[0].color_mode + + @property + def hsv(self) -> Optional[Tuple[int, int, int]]: + """Return current color in HSV if HSV mode is active.""" + return self.lights[0].hsv + + @property + def color_temp(self) -> Optional[int]: + """Return current color temperature, if applicable.""" + return self.lights[0].color_temp + + @property + def color_flowing(self) -> bool: + """Return whether the color flowing is active.""" + return self.lights[0].color_flowing + + @property + def color_flow_params(self) -> Optional[str]: + """Return color flowing params.""" + return self.lights[0].color_flow_params + @property def developer_mode(self) -> Optional[bool]: """Return whether the developer mode is active.""" From 6d2ce92b2018f372fac5f551c309755f11f23cca Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 20:42:22 +0300 Subject: [PATCH 08/13] Improve comand line output - YeelightSubLight was inherited from the DeviceStatus - added cli_format_lights property --- miio/yeelight.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index cf453cc12..33e5be8d4 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -36,24 +36,11 @@ class YeelightMode(IntEnum): HSV = 3 -class YeelightSubLight: +class YeelightSubLight(DeviceStatus): def __init__(self, data, type): self.data = data self.type = type - def __repr__(self): - s = "\n" - s += f" Sub Light - {self.type.name} \n" - s += f" Power: {self.is_on}\n" - s += f" Brightness: {self.brightness}\n" - s += f" Color mode: {self.color_mode}\n" - s += f" RGB: {self.rgb}\n" - s += f" HSV: {self.hsv}\n" - s += f" Temperature: {self.color_temp}\n" - s += f" Color flowing mode: {self.color_flowing}\n" - s += f" Color flowing parameters: {self.color_flow_params}\n" - return s - def get_prop_name(self, prop) -> str: if prop == "color_mode": return SUBLIGHT_COLOR_MODE_PROP[self.type] @@ -226,6 +213,22 @@ def lights(self) -> List[YeelightSubLight]: ) return sub_lights + @property + def cli_format_lights(self) -> str: + """Return human readable sub lights string.""" + s = "" + for light in self.lights: + s += f"{light.type.name} light\n" + s += f" Power: {light.is_on}\n" + s += f" Brightness: {light.brightness}\n" + s += f" Color mode: {light.color_mode}\n" + s += f" RGB: {light.rgb}\n" + s += f" HSV: {light.hsv}\n" + s += f" Temperature: {light.color_temp}\n" + s += f" Color flowing mode: {light.color_flowing}\n" + s += f" Color flowing parameters: {light.color_flow_params}\n" + return s + class Yeelight(Device): """A rudimentary support for Yeelight bulbs. @@ -254,7 +257,7 @@ def __init__(self, *args, **kwargs): "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" - "Lights: \n{result.lights}\n" + "{result.cli_format_lights}" "Moonlight\n" " Is in mode: {result.moonlight_mode}\n" " Moonlight mode brightness: {result.moonlight_mode_brightness}\n" From 43ca9b34a3ac6759c826e62c641b059fb20507b1 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 21:11:55 +0300 Subject: [PATCH 09/13] use cli_format function for output --- miio/yeelight.py | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index 33e5be8d4..5a79f07be 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -214,19 +214,34 @@ def lights(self) -> List[YeelightSubLight]: return sub_lights @property - def cli_format_lights(self) -> str: + def cli_format(self) -> str: """Return human readable sub lights string.""" - s = "" + s = f"Name: {self.name}\n" + s += f"Update default on change: {self.save_state_on_change}\n" + s += f"Delay in minute before off: {self.delay_off}\n" + if self.music_mode is not None: + s += f"Music mode: {self.music_mode}\n" + if self.developer_mode is not None: + s += f"Developer mode: {self.developer_mode}\n" for light in self.lights: s += f"{light.type.name} light\n" s += f" Power: {light.is_on}\n" s += f" Brightness: {light.brightness}\n" s += f" Color mode: {light.color_mode}\n" - s += f" RGB: {light.rgb}\n" - s += f" HSV: {light.hsv}\n" - s += f" Temperature: {light.color_temp}\n" + if light.color_mode == YeelightMode.RGB: + s += f" RGB: {light.rgb}\n" + elif light.color_mode == YeelightMode.HSV: + s += f" HSV: {light.hsv}\n" + else: + s += f" Temperature: {light.color_temp}\n" s += f" Color flowing mode: {light.color_flowing}\n" - s += f" Color flowing parameters: {light.color_flow_params}\n" + if light.color_flowing: + s += f" Color flowing parameters: {light.color_flow_params}\n" + if self.moonlight_mode is not None: + s += "Moonlight\n" + s += f" Is in mode: {self.moonlight_mode}\n" + s += f" Moonlight mode brightness: {self.moonlight_mode_brightness}\n" + s += "\n" return s @@ -249,21 +264,7 @@ def __init__(self, *args, **kwargs): ) super().__init__(*args, **kwargs) - @command( - default_output=format_output( - "", - "Name: {result.name}\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" - "{result.cli_format_lights}" - "Moonlight\n" - " Is in mode: {result.moonlight_mode}\n" - " Moonlight mode brightness: {result.moonlight_mode_brightness}\n" - "\n", - ) - ) + @command(default_output=format_output("", "{result.cli_format}")) def status(self) -> YeelightStatus: """Retrieve properties.""" properties = [ From 621d19fbfbee0eb7e6e03fa675e529d560c2978b Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 8 May 2021 21:16:09 +0300 Subject: [PATCH 10/13] Show color mode name --- miio/yeelight.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miio/yeelight.py b/miio/yeelight.py index 5a79f07be..0e1e30b82 100644 --- a/miio/yeelight.py +++ b/miio/yeelight.py @@ -227,7 +227,7 @@ def cli_format(self) -> str: s += f"{light.type.name} light\n" s += f" Power: {light.is_on}\n" s += f" Brightness: {light.brightness}\n" - s += f" Color mode: {light.color_mode}\n" + s += f" Color mode: {light.color_mode.name}\n" if light.color_mode == YeelightMode.RGB: s += f" RGB: {light.rgb}\n" elif light.color_mode == YeelightMode.HSV: From 2d88e54a3de36cf2dbc4e796517a91335d990abb Mon Sep 17 00:00:00 2001 From: Kirmas Date: Mon, 10 May 2021 23:14:40 +0300 Subject: [PATCH 11/13] Added more devices and properties to test --- miio/tests/test_yeelight.py | 461 +++++++++++++++++++++++++++++++++--- 1 file changed, 423 insertions(+), 38 deletions(-) diff --git a/miio/tests/test_yeelight.py b/miio/tests/test_yeelight.py index f943d50a5..fbcbed544 100644 --- a/miio/tests/test_yeelight.py +++ b/miio/tests/test_yeelight.py @@ -10,34 +10,6 @@ class DummyLight(DummyDevice, Yeelight): def __init__(self, *args, **kwargs): - self.state = { - "power": "off", - "bright": "100", - "ct": "3584", - "rgb": "16711680", - "hue": "359", - "sat": "100", - "color_mode": "2", - "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 = { "get_prop": self._get_state, "set_power": lambda x: self._set_state("power", x), @@ -66,14 +38,46 @@ def toggle_power(self, _): self.state["power"] = "on" +class DummyLightСolor(DummyLight): + def __init__(self, *args, **kwargs): + self.state = { + "name": "test name", + "lan_ctrl": "1", + "save_state": "1", + "delayoff": "0", + "music_on": "1", + "power": "off", + "bright": "100", + "color_mode": "2", + "rgb": "16711680", + "hue": "359", + "sat": "100", + "ct": "3584", + "flowing": "0", + "flow_params": "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100", + "active_mode": "", + "nl_br": "", + "bg_power": "", + "bg_bright": "", + "bg_lmode": "", + "bg_rgb": "", + "bg_hue": "", + "bg_sat": "", + "bg_ct": "", + "bg_flowing": "", + "bg_flow_params": "", + } + super().__init__(*args, **kwargs) + + @pytest.fixture(scope="class") -def dummylight(request): - request.cls.device = DummyLight() +def dummylightcolor(request): + request.cls.device = DummyLightСolor() # TODO add ability to test on a real device -@pytest.mark.usefixtures("dummylight") -class TestYeelight(TestCase): +@pytest.mark.usefixtures("dummylightcolor") +class TestYeelightLightColor(TestCase): def test_status(self): self.device._reset_state() status = self.device.status() # type: YeelightStatus @@ -81,17 +85,41 @@ def test_status(self): assert repr(status) == repr(YeelightStatus(self.device.start_state)) assert status.name == self.device.start_state["name"] - assert status.is_on is False - assert status.brightness == 100 - assert status.color_temp == 3584 - assert status.color_mode == YeelightMode.ColorTemperature - assert status.rgb is None assert status.developer_mode is True assert status.save_state_on_change is True - + assert status.delay_off == 0 + assert status.music_mode is True + assert len(status.lights) == 1 + assert status.is_on is False and status.is_on == status.lights[0].is_on + assert ( + status.brightness == 100 + and status.brightness == status.lights[0].brightness + ) + assert ( + status.color_mode == YeelightMode.ColorTemperature + and status.color_mode == status.lights[0].color_mode + ) + assert ( + status.color_temp == 3584 + and status.color_temp == status.lights[0].color_temp + ) + assert status.rgb is None and status.rgb == status.lights[0].rgb + assert status.hsv is None and status.hsv == status.lights[0].hsv # following are tested in set mode tests # assert status.rgb == 16711680 # assert status.hsv == (359, 100, 100) + assert ( + status.color_flowing is False + and status.color_flowing == status.lights[0].color_flowing + ) + assert ( + status.color_flow_params is None + and status.color_flow_params == status.lights[0].color_flow_params + ) + # color_flow_params will be tested after future implementation + # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params + assert status.moonlight_mode is None + assert status.moonlight_mode_brightness is None def test_on(self): self.device.off() # make sure we are off @@ -233,3 +261,360 @@ def test_set_default(self): @pytest.mark.skip("set_scene is not implemented") def test_set_scene(self): self.fail() + + +class DummyLightCeilingV1(DummyLight): # without background light + def __init__(self, *args, **kwargs): + self.state = { + "name": "test name", + "lan_ctrl": "1", + "save_state": "1", + "delayoff": "0", + "music_on": "", + "power": "off", + "bright": "100", + "color_mode": "2", + "rgb": "", + "hue": "", + "sat": "", + "ct": "3584", + "flowing": "0", + "flow_params": "0,0,2000,3,0,33,2000,3,0,100", + "active_mode": "1", + "nl_br": "100", + "bg_power": "", + "bg_bright": "", + "bg_lmode": "", + "bg_rgb": "", + "bg_hue": "", + "bg_sat": "", + "bg_ct": "", + "bg_flowing": "", + "bg_flow_params": "", + } + super().__init__(*args, **kwargs) + + +@pytest.fixture(scope="class") +def dummylightceilingv1(request): + request.cls.device = DummyLightCeilingV1() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("dummylightceilingv1") +class TestYeelightLightCeilingV1(TestCase): + def test_status(self): + self.device._reset_state() + status = self.device.status() # type: YeelightStatus + + assert repr(status) == repr(YeelightStatus(self.device.start_state)) + + assert status.name == self.device.start_state["name"] + assert status.developer_mode is True + assert status.save_state_on_change is True + assert status.delay_off == 0 + assert status.music_mode is None + assert len(status.lights) == 1 + assert status.is_on is False and status.is_on == status.lights[0].is_on + assert ( + status.brightness == 100 + and status.brightness == status.lights[0].brightness + ) + assert ( + status.color_mode == YeelightMode.ColorTemperature + and status.color_mode == status.lights[0].color_mode + ) + assert ( + status.color_temp == 3584 + and status.color_temp == status.lights[0].color_temp + ) + assert status.rgb is None and status.rgb == status.lights[0].rgb + assert status.hsv is None and status.hsv == status.lights[0].hsv + # following are tested in set mode tests + # assert status.rgb == 16711680 + # assert status.hsv == (359, 100, 100) + assert ( + status.color_flowing is False + and status.color_flowing == status.lights[0].color_flowing + ) + assert ( + status.color_flow_params is None + and status.color_flow_params == status.lights[0].color_flow_params + ) + # color_flow_params will be tested after future implementation + # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params + assert status.moonlight_mode is True + assert status.moonlight_mode_brightness == 100 + + def test_on(self): + self.device.off() # make sure we are off + assert self.device.status().is_on is False + + self.device.on() + assert self.device.status().is_on is True + + def test_off(self): + self.device.on() # make sure we are on + assert self.device.status().is_on is True + + self.device.off() + assert self.device.status().is_on is False + + def test_set_brightness(self): + def brightness(): + return self.device.status().brightness + + self.device.set_brightness(50) + assert brightness() == 50 + self.device.set_brightness(0) + assert brightness() == 0 + self.device.set_brightness(100) + + with pytest.raises(YeelightException): + self.device.set_brightness(-100) + + with pytest.raises(YeelightException): + self.device.set_brightness(200) + + def test_set_color_temp(self): + def color_temp(): + return self.device.status().color_temp + + self.device.set_color_temp(2000) + assert color_temp() == 2000 + self.device.set_color_temp(6500) + assert color_temp() == 6500 + + with pytest.raises(YeelightException): + self.device.set_color_temp(1000) + + with pytest.raises(YeelightException): + self.device.set_color_temp(7000) + + def test_set_developer_mode(self): + def dev_mode(): + return self.device.status().developer_mode + + orig_mode = dev_mode() + self.device.set_developer_mode(not orig_mode) + new_mode = dev_mode() + assert new_mode is not orig_mode + self.device.set_developer_mode(not new_mode) + assert new_mode is not dev_mode() + + def test_set_save_state_on_change(self): + def save_state(): + return self.device.status().save_state_on_change + + orig_state = save_state() + self.device.set_save_state_on_change(not orig_state) + new_state = save_state() + assert new_state is not orig_state + self.device.set_save_state_on_change(not new_state) + new_state = save_state() + assert new_state is orig_state + + def test_set_name(self): + def name(): + return self.device.status().name + + assert name() == "test name" + self.device.set_name("new test name") + assert name() == "new test name" + + def test_toggle(self): + def is_on(): + return self.device.status().is_on + + orig_state = is_on() + self.device.toggle() + new_state = is_on() + assert orig_state != new_state + + self.device.toggle() + new_state = is_on() + assert new_state == orig_state + + +class DummyLightCeilingV2(DummyLight): # without background light + def __init__(self, *args, **kwargs): + self.state = { + "name": "test name", + "lan_ctrl": "1", + "save_state": "1", + "delayoff": "0", + "music_on": "", + "power": "off", + "bright": "100", + "color_mode": "2", + "rgb": "", + "hue": "", + "sat": "", + "ct": "3584", + "flowing": "0", + "flow_params": "0,0,2000,3,0,33,2000,3,0,100", + "active_mode": "1", + "nl_br": "100", + "bg_power": "off", + "bg_bright": "100", + "bg_lmode": "2", + "bg_rgb": "15531811", + "bg_hue": "65", + "bg_sat": "86", + "bg_ct": "4000", + "bg_flowing": "0", + "bg_flow_params": "0,0,3000,4,16711680,100,3000,4,65280,100,3000,4,255,100", + } + super().__init__(*args, **kwargs) + + +@pytest.fixture(scope="class") +def dummylightceilingv2(request): + request.cls.device = DummyLightCeilingV2() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("dummylightceilingv2") +class TestYeelightLightCeilingV2(TestCase): + def test_status(self): + self.device._reset_state() + status = self.device.status() # type: YeelightStatus + + assert repr(status) == repr(YeelightStatus(self.device.start_state)) + + assert status.name == self.device.start_state["name"] + assert status.developer_mode is True + assert status.save_state_on_change is True + assert status.delay_off == 0 + assert status.music_mode is None + assert len(status.lights) == 2 + assert status.is_on is False and status.is_on == status.lights[0].is_on + assert ( + status.brightness == 100 + and status.brightness == status.lights[0].brightness + ) + assert ( + status.color_mode == YeelightMode.ColorTemperature + and status.color_mode == status.lights[0].color_mode + ) + assert ( + status.color_temp == 3584 + and status.color_temp == status.lights[0].color_temp + ) + assert status.rgb is None and status.rgb == status.lights[0].rgb + assert status.hsv is None and status.hsv == status.lights[0].hsv + # following are tested in set mode tests + # assert status.rgb == 16711680 + # assert status.hsv == (359, 100, 100) + assert ( + status.color_flowing is False + and status.color_flowing == status.lights[0].color_flowing + ) + assert ( + status.color_flow_params is None + and status.color_flow_params == status.lights[0].color_flow_params + ) + # color_flow_params will be tested after future implementation + # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params + assert status.lights[1].is_on is False + assert status.lights[1].brightness == 100 + assert status.lights[1].color_mode == YeelightMode.ColorTemperature + assert status.lights[1].color_temp == 4000 + assert status.lights[1].rgb is None + assert status.lights[1].hsv is None + # following are tested in set mode tests + # assert status.rgb == 15531811 + # assert status.hsv == (65, 86, 100) + assert status.lights[1].color_flowing is False + assert status.lights[1].color_flow_params is None + assert status.moonlight_mode is True + assert status.moonlight_mode_brightness == 100 + + def test_on(self): + self.device.off() # make sure we are off + assert self.device.status().is_on is False + + self.device.on() + assert self.device.status().is_on is True + + def test_off(self): + self.device.on() # make sure we are on + assert self.device.status().is_on is True + + self.device.off() + assert self.device.status().is_on is False + + def test_set_brightness(self): + def brightness(): + return self.device.status().brightness + + self.device.set_brightness(50) + assert brightness() == 50 + self.device.set_brightness(0) + assert brightness() == 0 + self.device.set_brightness(100) + + with pytest.raises(YeelightException): + self.device.set_brightness(-100) + + with pytest.raises(YeelightException): + self.device.set_brightness(200) + + def test_set_color_temp(self): + def color_temp(): + return self.device.status().color_temp + + self.device.set_color_temp(2000) + assert color_temp() == 2000 + self.device.set_color_temp(6500) + assert color_temp() == 6500 + + with pytest.raises(YeelightException): + self.device.set_color_temp(1000) + + with pytest.raises(YeelightException): + self.device.set_color_temp(7000) + + def test_set_developer_mode(self): + def dev_mode(): + return self.device.status().developer_mode + + orig_mode = dev_mode() + self.device.set_developer_mode(not orig_mode) + new_mode = dev_mode() + assert new_mode is not orig_mode + self.device.set_developer_mode(not new_mode) + assert new_mode is not dev_mode() + + def test_set_save_state_on_change(self): + def save_state(): + return self.device.status().save_state_on_change + + orig_state = save_state() + self.device.set_save_state_on_change(not orig_state) + new_state = save_state() + assert new_state is not orig_state + self.device.set_save_state_on_change(not new_state) + new_state = save_state() + assert new_state is orig_state + + def test_set_name(self): + def name(): + return self.device.status().name + + assert name() == "test name" + self.device.set_name("new test name") + assert name() == "new test name" + + def test_toggle(self): + def is_on(): + return self.device.status().is_on + + orig_state = is_on() + self.device.toggle() + new_state = is_on() + assert orig_state != new_state + + self.device.toggle() + new_state = is_on() + assert new_state == orig_state From 3184be5d97cfe87213727931b79914dd72e95b73 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sat, 15 May 2021 21:49:24 +0300 Subject: [PATCH 12/13] Add common tests --- miio/tests/test_yeelight.py | 397 ++++++++++++------------------------ 1 file changed, 130 insertions(+), 267 deletions(-) diff --git a/miio/tests/test_yeelight.py b/miio/tests/test_yeelight.py index fbcbed544..b578e11ea 100644 --- a/miio/tests/test_yeelight.py +++ b/miio/tests/test_yeelight.py @@ -38,7 +38,7 @@ def toggle_power(self, _): self.state["power"] = "on" -class DummyLightСolor(DummyLight): +class DummyCommonBulb(DummyLight): def __init__(self, *args, **kwargs): self.state = { "name": "test name", @@ -49,12 +49,12 @@ def __init__(self, *args, **kwargs): "power": "off", "bright": "100", "color_mode": "2", - "rgb": "16711680", - "hue": "359", - "sat": "100", + "rgb": "", + "hue": "", + "sat": "", "ct": "3584", - "flowing": "0", - "flow_params": "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100", + "flowing": "", + "flow_params": "", "active_mode": "", "nl_br": "", "bg_power": "", @@ -71,56 +71,13 @@ def __init__(self, *args, **kwargs): @pytest.fixture(scope="class") -def dummylightcolor(request): - request.cls.device = DummyLightСolor() +def dummycommonbulb(request): + request.cls.device = DummyCommonBulb() # TODO add ability to test on a real device -@pytest.mark.usefixtures("dummylightcolor") -class TestYeelightLightColor(TestCase): - def test_status(self): - self.device._reset_state() - status = self.device.status() # type: YeelightStatus - - assert repr(status) == repr(YeelightStatus(self.device.start_state)) - - assert status.name == self.device.start_state["name"] - assert status.developer_mode is True - assert status.save_state_on_change is True - assert status.delay_off == 0 - assert status.music_mode is True - assert len(status.lights) == 1 - assert status.is_on is False and status.is_on == status.lights[0].is_on - assert ( - status.brightness == 100 - and status.brightness == status.lights[0].brightness - ) - assert ( - status.color_mode == YeelightMode.ColorTemperature - and status.color_mode == status.lights[0].color_mode - ) - assert ( - status.color_temp == 3584 - and status.color_temp == status.lights[0].color_temp - ) - assert status.rgb is None and status.rgb == status.lights[0].rgb - assert status.hsv is None and status.hsv == status.lights[0].hsv - # following are tested in set mode tests - # assert status.rgb == 16711680 - # assert status.hsv == (359, 100, 100) - assert ( - status.color_flowing is False - and status.color_flowing == status.lights[0].color_flowing - ) - assert ( - status.color_flow_params is None - and status.color_flow_params == status.lights[0].color_flow_params - ) - # color_flow_params will be tested after future implementation - # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params - assert status.moonlight_mode is None - assert status.moonlight_mode_brightness is None - +@pytest.mark.usefixtures("dummycommonbulb") +class TestYeelightCommon(TestCase): def test_on(self): self.device.off() # make sure we are off assert self.device.status().is_on is False @@ -166,50 +123,6 @@ def color_temp(): with pytest.raises(YeelightException): self.device.set_color_temp(7000) - def test_set_rgb(self): - def rgb(): - return self.device.status().rgb - - self.device._reset_state() - self.device._set_state("color_mode", [1]) - - assert rgb() == (255, 0, 0) - - self.device.set_rgb((0, 0, 1)) - assert rgb() == (0, 0, 1) - self.device.set_rgb((255, 255, 0)) - assert rgb() == (255, 255, 0) - self.device.set_rgb((255, 255, 255)) - assert rgb() == (255, 255, 255) - - with pytest.raises(YeelightException): - self.device.set_rgb((-1, 0, 0)) - - with pytest.raises(YeelightException): - self.device.set_rgb((256, 0, 0)) - - with pytest.raises(YeelightException): - self.device.set_rgb((0, -1, 0)) - - with pytest.raises(YeelightException): - self.device.set_rgb((0, 256, 0)) - - with pytest.raises(YeelightException): - self.device.set_rgb((0, 0, -1)) - - with pytest.raises(YeelightException): - self.device.set_rgb((0, 0, 256)) - - @pytest.mark.skip("hsv is not properly implemented") - def test_set_hsv(self): - self.reset_state() - hue, sat, val = self.device.status().hsv - assert hue == 359 - assert sat == 100 - assert val == 100 - - self.device.set_hsv() - def test_set_developer_mode(self): def dev_mode(): return self.device.status().developer_mode @@ -263,25 +176,25 @@ def test_set_scene(self): self.fail() -class DummyLightCeilingV1(DummyLight): # without background light +class DummyLightСolor(DummyLight): def __init__(self, *args, **kwargs): self.state = { "name": "test name", "lan_ctrl": "1", "save_state": "1", "delayoff": "0", - "music_on": "", + "music_on": "1", "power": "off", "bright": "100", "color_mode": "2", - "rgb": "", - "hue": "", - "sat": "", + "rgb": "16711680", + "hue": "359", + "sat": "100", "ct": "3584", "flowing": "0", - "flow_params": "0,0,2000,3,0,33,2000,3,0,100", - "active_mode": "1", - "nl_br": "100", + "flow_params": "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100", + "active_mode": "", + "nl_br": "", "bg_power": "", "bg_bright": "", "bg_lmode": "", @@ -296,13 +209,13 @@ def __init__(self, *args, **kwargs): @pytest.fixture(scope="class") -def dummylightceilingv1(request): - request.cls.device = DummyLightCeilingV1() +def dummylightcolor(request): + request.cls.device = DummyLightСolor() # TODO add ability to test on a real device -@pytest.mark.usefixtures("dummylightceilingv1") -class TestYeelightLightCeilingV1(TestCase): +@pytest.mark.usefixtures("dummylightcolor") +class TestYeelightLightColor(TestCase): def test_status(self): self.device._reset_state() status = self.device.status() # type: YeelightStatus @@ -313,7 +226,7 @@ def test_status(self): assert status.developer_mode is True assert status.save_state_on_change is True assert status.delay_off == 0 - assert status.music_mode is None + assert status.music_mode is True assert len(status.lights) == 1 assert status.is_on is False and status.is_on == status.lights[0].is_on assert ( @@ -343,97 +256,136 @@ def test_status(self): ) # color_flow_params will be tested after future implementation # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params - assert status.moonlight_mode is True - assert status.moonlight_mode_brightness == 100 - - def test_on(self): - self.device.off() # make sure we are off - assert self.device.status().is_on is False - - self.device.on() - assert self.device.status().is_on is True + assert status.moonlight_mode is None + assert status.moonlight_mode_brightness is None - def test_off(self): - self.device.on() # make sure we are on - assert self.device.status().is_on is True + def test_set_rgb(self): + def rgb(): + return self.device.status().rgb - self.device.off() - assert self.device.status().is_on is False + self.device._reset_state() + self.device._set_state("color_mode", [1]) - def test_set_brightness(self): - def brightness(): - return self.device.status().brightness + assert rgb() == (255, 0, 0) - self.device.set_brightness(50) - assert brightness() == 50 - self.device.set_brightness(0) - assert brightness() == 0 - self.device.set_brightness(100) + self.device.set_rgb((0, 0, 1)) + assert rgb() == (0, 0, 1) + self.device.set_rgb((255, 255, 0)) + assert rgb() == (255, 255, 0) + self.device.set_rgb((255, 255, 255)) + assert rgb() == (255, 255, 255) with pytest.raises(YeelightException): - self.device.set_brightness(-100) + self.device.set_rgb((-1, 0, 0)) with pytest.raises(YeelightException): - self.device.set_brightness(200) + self.device.set_rgb((256, 0, 0)) - def test_set_color_temp(self): - def color_temp(): - return self.device.status().color_temp + with pytest.raises(YeelightException): + self.device.set_rgb((0, -1, 0)) - self.device.set_color_temp(2000) - assert color_temp() == 2000 - self.device.set_color_temp(6500) - assert color_temp() == 6500 + with pytest.raises(YeelightException): + self.device.set_rgb((0, 256, 0)) with pytest.raises(YeelightException): - self.device.set_color_temp(1000) + self.device.set_rgb((0, 0, -1)) with pytest.raises(YeelightException): - self.device.set_color_temp(7000) + self.device.set_rgb((0, 0, 256)) - def test_set_developer_mode(self): - def dev_mode(): - return self.device.status().developer_mode + @pytest.mark.skip("hsv is not properly implemented") + def test_set_hsv(self): + self.reset_state() + hue, sat, val = self.device.status().hsv + assert hue == 359 + assert sat == 100 + assert val == 100 - orig_mode = dev_mode() - self.device.set_developer_mode(not orig_mode) - new_mode = dev_mode() - assert new_mode is not orig_mode - self.device.set_developer_mode(not new_mode) - assert new_mode is not dev_mode() + self.device.set_hsv() - def test_set_save_state_on_change(self): - def save_state(): - return self.device.status().save_state_on_change - orig_state = save_state() - self.device.set_save_state_on_change(not orig_state) - new_state = save_state() - assert new_state is not orig_state - self.device.set_save_state_on_change(not new_state) - new_state = save_state() - assert new_state is orig_state +class DummyLightCeilingV1(DummyLight): # without background light + def __init__(self, *args, **kwargs): + self.state = { + "name": "test name", + "lan_ctrl": "1", + "save_state": "1", + "delayoff": "0", + "music_on": "", + "power": "off", + "bright": "100", + "color_mode": "2", + "rgb": "", + "hue": "", + "sat": "", + "ct": "3584", + "flowing": "0", + "flow_params": "0,0,2000,3,0,33,2000,3,0,100", + "active_mode": "1", + "nl_br": "100", + "bg_power": "", + "bg_bright": "", + "bg_lmode": "", + "bg_rgb": "", + "bg_hue": "", + "bg_sat": "", + "bg_ct": "", + "bg_flowing": "", + "bg_flow_params": "", + } + super().__init__(*args, **kwargs) - def test_set_name(self): - def name(): - return self.device.status().name - assert name() == "test name" - self.device.set_name("new test name") - assert name() == "new test name" +@pytest.fixture(scope="class") +def dummylightceilingv1(request): + request.cls.device = DummyLightCeilingV1() + # TODO add ability to test on a real device - def test_toggle(self): - def is_on(): - return self.device.status().is_on - orig_state = is_on() - self.device.toggle() - new_state = is_on() - assert orig_state != new_state +@pytest.mark.usefixtures("dummylightceilingv1") +class TestYeelightLightCeilingV1(TestCase): + def test_status(self): + self.device._reset_state() + status = self.device.status() # type: YeelightStatus - self.device.toggle() - new_state = is_on() - assert new_state == orig_state + assert repr(status) == repr(YeelightStatus(self.device.start_state)) + + assert status.name == self.device.start_state["name"] + assert status.developer_mode is True + assert status.save_state_on_change is True + assert status.delay_off == 0 + assert status.music_mode is None + assert len(status.lights) == 1 + assert status.is_on is False and status.is_on == status.lights[0].is_on + assert ( + status.brightness == 100 + and status.brightness == status.lights[0].brightness + ) + assert ( + status.color_mode == YeelightMode.ColorTemperature + and status.color_mode == status.lights[0].color_mode + ) + assert ( + status.color_temp == 3584 + and status.color_temp == status.lights[0].color_temp + ) + assert status.rgb is None and status.rgb == status.lights[0].rgb + assert status.hsv is None and status.hsv == status.lights[0].hsv + # following are tested in set mode tests + # assert status.rgb == 16711680 + # assert status.hsv == (359, 100, 100) + assert ( + status.color_flowing is False + and status.color_flowing == status.lights[0].color_flowing + ) + assert ( + status.color_flow_params is None + and status.color_flow_params == status.lights[0].color_flow_params + ) + # color_flow_params will be tested after future implementation + # assert status.color_flow_params == "0,0,1000,1,16711680,100,1000,1,65280,100,1000,1,255,100" and status.color_flow_params == status.lights[0].color_flow_params + assert status.moonlight_mode is True + assert status.moonlight_mode_brightness == 100 class DummyLightCeilingV2(DummyLight): # without background light @@ -529,92 +481,3 @@ def test_status(self): assert status.lights[1].color_flow_params is None assert status.moonlight_mode is True assert status.moonlight_mode_brightness == 100 - - def test_on(self): - self.device.off() # make sure we are off - assert self.device.status().is_on is False - - self.device.on() - assert self.device.status().is_on is True - - def test_off(self): - self.device.on() # make sure we are on - assert self.device.status().is_on is True - - self.device.off() - assert self.device.status().is_on is False - - def test_set_brightness(self): - def brightness(): - return self.device.status().brightness - - self.device.set_brightness(50) - assert brightness() == 50 - self.device.set_brightness(0) - assert brightness() == 0 - self.device.set_brightness(100) - - with pytest.raises(YeelightException): - self.device.set_brightness(-100) - - with pytest.raises(YeelightException): - self.device.set_brightness(200) - - def test_set_color_temp(self): - def color_temp(): - return self.device.status().color_temp - - self.device.set_color_temp(2000) - assert color_temp() == 2000 - self.device.set_color_temp(6500) - assert color_temp() == 6500 - - with pytest.raises(YeelightException): - self.device.set_color_temp(1000) - - with pytest.raises(YeelightException): - self.device.set_color_temp(7000) - - def test_set_developer_mode(self): - def dev_mode(): - return self.device.status().developer_mode - - orig_mode = dev_mode() - self.device.set_developer_mode(not orig_mode) - new_mode = dev_mode() - assert new_mode is not orig_mode - self.device.set_developer_mode(not new_mode) - assert new_mode is not dev_mode() - - def test_set_save_state_on_change(self): - def save_state(): - return self.device.status().save_state_on_change - - orig_state = save_state() - self.device.set_save_state_on_change(not orig_state) - new_state = save_state() - assert new_state is not orig_state - self.device.set_save_state_on_change(not new_state) - new_state = save_state() - assert new_state is orig_state - - def test_set_name(self): - def name(): - return self.device.status().name - - assert name() == "test name" - self.device.set_name("new test name") - assert name() == "new test name" - - def test_toggle(self): - def is_on(): - return self.device.status().is_on - - orig_state = is_on() - self.device.toggle() - new_state = is_on() - assert orig_state != new_state - - self.device.toggle() - new_state = is_on() - assert new_state == orig_state From ac1cf967566be54b60549ba06cdf6b8db2cf95d2 Mon Sep 17 00:00:00 2001 From: Kirmas Date: Sun, 16 May 2021 09:42:23 +0300 Subject: [PATCH 13/13] SIM119 was added to flake8 Ignore --- .flake8 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index d300f5384..6f01e6582 100644 --- a/.flake8 +++ b/.flake8 @@ -7,4 +7,5 @@ max-line-length = 88 select = C,E,F,W,B,SIM,T # the line lengths are enforced by black and docformatter # therefore we ignore E501 and B950 here -ignore = E501,B950,W503,E203 +# SIM119 - are irrelevant as we still support python 3.6 series +ignore = E501,B950,W503,E203,SIM119