From 42e60354ad1abdaf85ea759d78dbc319a5ca24c3 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Mon, 26 Mar 2018 21:51:44 +0200 Subject: [PATCH] Merge of the Chuangmi Plug V1, V2, V3 and M1 (#270) * Chuangmi Plug V1 and V3 merged. * Chuangmi V1 and V3 merge completed. * Whitespace removed * DummyDevice used in both cases * Chuangmi Plug M1 merged. * Missing blank line added. Comma removed. * Model parameter moved to the sub class. * Missed line removed. * Default model added. * Deprecation warning added * Test the device class via the deprecation layer * Revert "Test the device class via the deprecation layer" This reverts commit 7eb1443a5aa5fbb39d43560ebc20c67d928b6cf6. * Provide a model per mDNS prefix * Refactoring * Missing parameter added * Default model added * More compact imports * Deprecated decorator used * Update chuangmi_plug.py remvoe unused warnings. --- miio/__init__.py | 4 +- miio/chuangmi_plug.py | 180 ++++++++++++++++++++++++ miio/discovery.py | 29 ++-- miio/plug.py | 65 --------- miio/plug_v1.py | 78 ----------- miio/plug_v3.py | 115 ---------------- miio/tests/test_chuangmi_plug.py | 230 +++++++++++++++++++++++++++++++ miio/tests/test_plug.py | 55 -------- miio/tests/test_plug_v1.py | 90 ------------ miio/tests/test_plug_v3.py | 99 ------------- 10 files changed, 429 insertions(+), 516 deletions(-) create mode 100644 miio/chuangmi_plug.py delete mode 100644 miio/plug.py delete mode 100644 miio/plug_v1.py delete mode 100644 miio/plug_v3.py create mode 100644 miio/tests/test_chuangmi_plug.py delete mode 100644 miio/tests/test_plug.py delete mode 100644 miio/tests/test_plug_v1.py delete mode 100644 miio/tests/test_plug_v3.py diff --git a/miio/__init__.py b/miio/__init__.py index 53e464879..6b8000d75 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -3,9 +3,7 @@ from miio.vacuumcontainers import (VacuumStatus, ConsumableStatus, DNDStatus, CleaningDetails, CleaningSummary, Timer) from miio.vacuum import Vacuum, VacuumException -from miio.plug import Plug -from miio.plug_v1 import PlugV1 -from miio.plug_v3 import PlugV3 +from miio.chuangmi_plug import (Plug, PlugV1, PlugV3, ChuangmiPlug) from miio.airpurifier import AirPurifier from miio.airhumidifier import AirHumidifier from miio.waterpurifier import WaterPurifier diff --git a/miio/chuangmi_plug.py b/miio/chuangmi_plug.py new file mode 100644 index 000000000..5da4a30a8 --- /dev/null +++ b/miio/chuangmi_plug.py @@ -0,0 +1,180 @@ +import logging +from typing import Dict, Any, Optional +from collections import defaultdict +from .device import Device +from .utils import deprecated + +_LOGGER = logging.getLogger(__name__) + +MODEL_CHUANGMI_PLUG_V3 = 'chuangmi.plug.v3' +MODEL_CHUANGMI_PLUG_V1 = 'chuangmi.plug.v1' +MODEL_CHUANGMI_PLUG_M1 = 'chuangmi.plug.m1' +MODEL_CHUANGMI_PLUG_V2 = 'chuangmi.plug.v2' + +AVAILABLE_PROPERTIES = { + MODEL_CHUANGMI_PLUG_V1: ['on', 'usb_on', 'temperature'], + MODEL_CHUANGMI_PLUG_V3: ['on', 'usb_on', 'temperature', 'wifi_led'], + MODEL_CHUANGMI_PLUG_M1: ['power', 'temperature'], + MODEL_CHUANGMI_PLUG_V2: ['power', 'temperature'], +} + + +class ChuangmiPlugStatus: + """Container for status reports from the plug.""" + + def __init__(self, data: Dict[str, Any]) -> None: + """ + Response of a Chuangmi Plug V1 (chuangmi.plug.v1) + { 'power': True, 'usb_on': True, 'temperature': 32 } + + Response of a Chuangmi Plug V3 (chuangmi.plug.v3): + { 'on': True, 'usb_on': True, 'temperature': 32, 'wifi_led': True } + """ + self.data = data + + @property + def power(self) -> bool: + """Current power state.""" + if "on" in self.data: + return self.data["on"] + if "power" in self.data: + return self.data["power"] == 'on' + + @property + def is_on(self) -> bool: + """True if device is on.""" + return self.power + + @property + def temperature(self) -> int: + return self.data["temperature"] + + @property + def usb_power(self) -> Optional[bool]: + """True if USB is on.""" + if "usb_on" in self.data and self.data["usb_on"] is not None: + return self.data["usb_on"] + return None + + @property + def load_power(self) -> Optional[int]: + """Current power load, if available.""" + if "load_power" in self.data and self.data["load_power"] is not None: + return self.data["load_power"] + return None + + @property + def wifi_led(self) -> Optional[bool]: + """True if the wifi led is turned on.""" + if "wifi_led" in self.data and self.data["wifi_led"] is not None: + return self.data["wifi_led"] == "on" + return None + + def __repr__(self) -> str: + s = "" % \ + (self.power, + self.usb_power, + self.temperature, + self.load_power, + self.wifi_led) + return s + + +class ChuangmiPlug(Device): + """Main class representing the Chuangmi Plug V1 and V3.""" + + def __init__(self, ip: str = None, token: str = None, start_id: int = 0, + debug: int = 0, lazy_discover: bool = True, + model: str = MODEL_CHUANGMI_PLUG_M1) -> None: + super().__init__(ip, token, start_id, debug, lazy_discover) + + if model in AVAILABLE_PROPERTIES: + self.model = model + else: + self.model = MODEL_CHUANGMI_PLUG_M1 + + def status(self) -> ChuangmiPlugStatus: + """Retrieve properties.""" + properties = AVAILABLE_PROPERTIES[self.model] + values = self.send( + "get_prop", + properties + ) + + properties_count = len(properties) + values_count = len(values) + if properties_count != values_count: + _LOGGER.debug( + "Count (%s) of requested properties does not match the " + "count (%s) of received values.", + properties_count, values_count) + + if self.model == MODEL_CHUANGMI_PLUG_V3: + load_power = self.send("get_power", []) # Response: [300] + if len(load_power) == 1: + properties.append('load_power') + values.append(load_power[0]) + + return ChuangmiPlugStatus( + defaultdict(lambda: None, zip(properties, values))) + + def on(self): + """Power on.""" + if self.model == MODEL_CHUANGMI_PLUG_V1: + return self.send("set_on", []) + + return self.send("set_power", ["on"]) + + def off(self): + """Power off.""" + if self.model == MODEL_CHUANGMI_PLUG_V1: + return self.send("set_off", []) + + return self.send("set_power", ["off"]) + + def usb_on(self): + """Power on.""" + return self.send("set_usb_on", []) + + def usb_off(self): + """Power off.""" + return self.send("set_usb_off", []) + + def set_wifi_led(self, led: bool): + """Set the wifi led on/off.""" + if led: + return self.send("set_wifi_led", ["on"]) + else: + return self.send("set_wifi_led", ["off"]) + + +@deprecated("This device class is deprecated. Please use the ChuangmiPlug " + "class in future and select a model by parameter 'model'.") +class Plug(ChuangmiPlug): + def __init__(self, ip: str = None, token: str = None, start_id: int = 0, + debug: int = 0, lazy_discover: bool = True) -> None: + super().__init__(ip, token, start_id, debug, lazy_discover, + model=MODEL_CHUANGMI_PLUG_M1) + + +@deprecated("This device class is deprecated. Please use the ChuangmiPlug " + "class in future and select a model by parameter 'model'.") +class PlugV1(ChuangmiPlug): + def __init__(self, ip: str = None, token: str = None, start_id: int = 0, + debug: int = 0, lazy_discover: bool = True) -> None: + super().__init__(ip, token, start_id, debug, lazy_discover, + model=MODEL_CHUANGMI_PLUG_V1) + + +@deprecated("This device class is deprecated. Please use the ChuangmiPlug " + "class in future and select a model by parameter 'model'.") +class PlugV3(ChuangmiPlug): + def __init__(self, ip: str = None, token: str = None, start_id: int = 0, + debug: int = 0, lazy_discover: bool = True) -> None: + super().__init__(ip, token, start_id, debug, lazy_discover, + model=MODEL_CHUANGMI_PLUG_V3) diff --git a/miio/discovery.py b/miio/discovery.py index 6dc8d64f1..2200e8cb3 100644 --- a/miio/discovery.py +++ b/miio/discovery.py @@ -3,9 +3,13 @@ import ipaddress import inspect import codecs -from . import (Device, Vacuum, Plug, PlugV1, PlugV3, PowerStrip, AirPurifier, Ceil, +from . import (Device, Vacuum, ChuangmiPlug, PowerStrip, AirPurifier, Ceil, PhilipsBulb, PhilipsEyecare, ChuangmiIr, AirHumidifier, WaterPurifier, WifiSpeaker, Yeelight) +from .chuangmi_plug import (MODEL_CHUANGMI_PLUG_V1, MODEL_CHUANGMI_PLUG_V3, + MODEL_CHUANGMI_PLUG_M1) + +from functools import partial from typing import Union, Callable, Dict, Optional # noqa: F401 @@ -15,11 +19,11 @@ DEVICE_MAP = { "rockrobo-vacuum-v1": Vacuum, "roborock-vacuum-s5": Vacuum, - "chuangmi-plug-m1": Plug, - "chuangmi-plug-v2": Plug, - "chuangmi-plug-v1": PlugV1, - "chuangmi-plug_": PlugV1, - "chuangmi-plug-v3": PlugV3, + "chuangmi-plug-m1": partial(ChuangmiPlug, model=MODEL_CHUANGMI_PLUG_M1), + "chuangmi-plug-v2": partial(ChuangmiPlug, model=MODEL_CHUANGMI_PLUG_M1), + "chuangmi-plug-v1": partial(ChuangmiPlug, model=MODEL_CHUANGMI_PLUG_V1), + "chuangmi-plug_": partial(ChuangmiPlug, model=MODEL_CHUANGMI_PLUG_V1), + "chuangmi-plug-v3": partial(ChuangmiPlug, model=MODEL_CHUANGMI_PLUG_V3), "qmi-powerstrip-v1": PowerStrip, "zimi-powerstrip-v2": PowerStrip, "zhimi-airpurifier-m1": AirPurifier, # mini model @@ -63,13 +67,16 @@ def other_package_info(info, desc): desc) -def create_device(addr, device_cls) -> Device: +def create_device(name: str, addr: str, device_cls: partial) -> Device: """Return a device object for a zeroconf entry.""" + _LOGGER.debug("Found a supported '%s', using '%s' class", + name, device_cls.func.__name__) + dev = device_cls(ip=addr) m = dev.do_discover() dev.token = m.checksum _LOGGER.info("Found a supported '%s' at %s - token: %s", - device_cls.__name__, + device_cls.func.__name__, addr, pretty_token(dev.token)) return dev @@ -87,9 +94,9 @@ def check_and_create_device(self, info, addr) -> Optional[Device]: for identifier, v in DEVICE_MAP.items(): if name.startswith(identifier): if inspect.isclass(v): - _LOGGER.debug("Found a supported '%s', using '%s' class", - name, v.__name__) - return create_device(addr, v) + return create_device(name, addr, partial(v)) + elif type(v) is partial and inspect.isclass(v.func): + return create_device(name, addr, v) elif callable(v): dev = Device(ip=addr) _LOGGER.info("%s: token: %s", diff --git a/miio/plug.py b/miio/plug.py deleted file mode 100644 index a76099d78..000000000 --- a/miio/plug.py +++ /dev/null @@ -1,65 +0,0 @@ -import logging -from typing import Dict, Any, Optional -from collections import defaultdict -from .device import Device - -_LOGGER = logging.getLogger(__name__) - - -class PlugStatus: - """Container for status reports from the plug.""" - - def __init__(self, data: Dict[str, Any]) -> None: - self.data = data - - @property - def power(self) -> str: - """Power state.""" - return self.data["power"] - - @property - def is_on(self) -> bool: - """Return True if the device is on.""" - return self.power == "on" - - @property - def temperature(self) -> float: - """Return temperature.""" - return self.data["temperature"] - - def __repr__(self) -> str: - s = "" % \ - (self.power, - self.temperature) - return s - - -class Plug(Device): - """Main class representing the smart wifi socket / plug.""" - - def status(self) -> PlugStatus: - """Retrieve properties.""" - properties = ['power', 'temperature'] - values = self.send( - "get_prop", - properties - ) - - properties_count = len(properties) - values_count = len(values) - if properties_count != values_count: - _LOGGER.debug( - "Count (%s) of requested properties does not match the " - "count (%s) of received values.", - properties_count, values_count) - - return PlugStatus( - defaultdict(lambda: None, zip(properties, values))) - - def on(self): - """Power on.""" - return self.send("set_power", ["on"]) - - def off(self): - """Power off.""" - return self.send("set_power", ["off"]) diff --git a/miio/plug_v1.py b/miio/plug_v1.py deleted file mode 100644 index 19b06546a..000000000 --- a/miio/plug_v1.py +++ /dev/null @@ -1,78 +0,0 @@ -import logging -from typing import Dict, Any -from collections import defaultdict -from .device import Device - -_LOGGER = logging.getLogger(__name__) - -class PlugV1Status: - """Container for status reports from the plug.""" - - def __init__(self, data: Dict[str, Any]) -> None: - # { 'power': True, 'usb_on': True, 'temperature': 32 } - self.data = data - - @property - def power(self) -> bool: - """Current power state.""" - return self.data["on"] - - @property - def is_on(self) -> bool: - """True if device is on.""" - return self.power - - @property - def usb_power(self) -> bool: - """True if USB is on.""" - return self.data["usb_on"] - - @property - def temperature(self) -> float: - return self.data["temperature"] - - def __repr__(self) -> str: - s = "" % \ - (self.power, - self.usb_power, - self.temperature) - return s - - -class PlugV1(Device): - """Main class representing the chuangmi plug v1.""" - - def status(self) -> PlugV1Status: - """Retrieve properties.""" - properties = ['on', 'usb_on', 'temperature'] - values = self.send( - "get_prop", - properties - ) - - properties_count = len(properties) - values_count = len(values) - if properties_count != values_count: - _LOGGER.debug( - "Count (%s) of requested properties does not match the " - "count (%s) of received values.", - properties_count, values_count) - - return PlugV1Status( - defaultdict(lambda: None, zip(properties, values))) - - def on(self): - """Power on.""" - return self.send("set_on", []) - - def off(self): - """Power off.""" - return self.send("set_off", []) - - def usb_on(self): - """Power on.""" - return self.send("set_usb_on", []) - - def usb_off(self): - """Power off.""" - return self.send("set_usb_off", []) diff --git a/miio/plug_v3.py b/miio/plug_v3.py deleted file mode 100644 index 247604cd5..000000000 --- a/miio/plug_v3.py +++ /dev/null @@ -1,115 +0,0 @@ -import logging -from typing import Dict, Any, Optional -from collections import defaultdict -from .device import Device - -_LOGGER = logging.getLogger(__name__) - - -class PlugV3Status: - """Container for status reports from the plug.""" - - def __init__(self, data: Dict[str, Any]) -> None: - """ - Supported device models: chuangmi.plug.v3 - - Response of a Chuang Mi V3 (chuangmi.plug.v3): - { 'on': True, 'usb_on': True, 'temperature': 32, 'wifi_led': True } - """ - self.data = data - - @property - def power(self) -> bool: - """Current power state.""" - return self.data["on"] - - @property - def is_on(self) -> bool: - """True if device is on.""" - return self.power - - @property - def usb_power(self) -> bool: - """True if USB is on.""" - return self.data["usb_on"] - - @property - def temperature(self) -> int: - return self.data["temperature"] - - @property - def load_power(self) -> Optional[int]: - """Current power load, if available.""" - if self.data["load_power"] is not None: - return self.data["load_power"] - return None - - @property - def wifi_led(self) -> bool: - """True if the wifi led is turned on.""" - return self.data["wifi_led"] == "on" - - def __repr__(self) -> str: - s = "" % \ - (self.power, - self.usb_power, - self.load_power, - self.temperature, - self.wifi_led) - return s - - -class PlugV3(Device): - """Main class representing the chuangmi plug v3.""" - - def status(self) -> PlugV3Status: - """Retrieve properties.""" - properties = ['on', 'usb_on', 'temperature', 'wifi_led'] - values = self.send( - "get_prop", - properties - ) - - properties_count = len(properties) - values_count = len(values) - if properties_count != values_count: - _LOGGER.debug( - "Count (%s) of requested properties does not match the " - "count (%s) of received values.", - properties_count, values_count) - - load_power = self.send("get_power", []) # Response: [300] - if len(load_power) == 1: - properties.append('load_power') - values.append(load_power[0]) - - return PlugV3Status( - defaultdict(lambda: None, zip(properties, values))) - - def on(self): - """Power on.""" - return self.send("set_power", ["on"]) - - def off(self): - """Power off.""" - return self.send("set_power", ["off"]) - - def usb_on(self): - """Power on.""" - return self.send("set_usb_on", []) - - def usb_off(self): - """Power off.""" - return self.send("set_usb_off", []) - - def set_wifi_led(self, led: bool): - """Set the wifi led on/off.""" - if led: - return self.send("set_wifi_led", ["on"]) - else: - return self.send("set_wifi_led", ["off"]) diff --git a/miio/tests/test_chuangmi_plug.py b/miio/tests/test_chuangmi_plug.py new file mode 100644 index 000000000..b042b457e --- /dev/null +++ b/miio/tests/test_chuangmi_plug.py @@ -0,0 +1,230 @@ +from unittest import TestCase +from miio import ChuangmiPlug +from miio.chuangmi_plug import (ChuangmiPlugStatus, MODEL_CHUANGMI_PLUG_V1, + MODEL_CHUANGMI_PLUG_V3, MODEL_CHUANGMI_PLUG_M1) +from .dummies import DummyDevice +import pytest + + +class DummyChuangmiPlugV1(DummyDevice, ChuangmiPlug): + def __init__(self, *args, **kwargs): + self.model = MODEL_CHUANGMI_PLUG_V1 + self.state = { + 'on': True, + 'usb_on': True, + 'temperature': 32, + } + self.return_values = { + 'get_prop': self._get_state, + 'set_on': lambda x: self._set_state_basic("on", True), + 'set_off': lambda x: self._set_state_basic("on", False), + 'set_usb_on': lambda x: self._set_state_basic("usb_on", True), + 'set_usb_off': lambda x: self._set_state_basic("usb_on", False), + } + self.start_state = self.state.copy() + + def _set_state_basic(self, var, value): + """Set a state of a variable""" + self.state[var] = value + + +@pytest.fixture(scope="class") +def chuangmiplugv1(request): + request.cls.device = DummyChuangmiPlugV1() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("chuangmiplugv1") +class TestChuangmiPlugV1(TestCase): + def is_on(self): + return self.device.status().is_on + + def state(self): + return self.device.status() + + def test_on(self): + self.device.off() # ensure off + assert self.is_on() is False + + self.device.on() + assert self.is_on() is True + + def test_off(self): + self.device.on() # ensure on + assert self.is_on() is True + + self.device.off() + assert self.is_on() is False + + def test_status(self): + self.device._reset_state() + + assert repr(self.state()) == repr( + ChuangmiPlugStatus(self.device.start_state)) + + assert self.is_on() is True + assert self.state().usb_power is True + assert self.state().temperature == self.device.start_state[ + "temperature"] + + def test_usb_on(self): + self.device.usb_off() # ensure off + assert self.device.status().usb_power is False + + self.device.usb_on() + assert self.device.status().usb_power is True + + def test_usb_off(self): + self.device.usb_on() # ensure on + assert self.device.status().usb_power is True + + self.device.usb_off() + assert self.device.status().usb_power is False + + +class DummyChuangmiPlugV3(DummyDevice, ChuangmiPlug): + def __init__(self, *args, **kwargs): + self.model = MODEL_CHUANGMI_PLUG_V3 + self.state = { + 'on': True, + 'usb_on': True, + 'temperature': 32, + 'wifi_led': 'off' + } + self.return_values = { + 'get_prop': self._get_state, + 'get_power': self._get_load_power, + 'set_power': lambda x: self._set_state_basic("on", x == ["on"]), + 'set_usb_on': lambda x: self._set_state_basic("usb_on", True), + 'set_usb_off': lambda x: self._set_state_basic("usb_on", False), + 'set_wifi_led': lambda x: self._set_state("wifi_led", x), + } + self.start_state = self.state.copy() + + def _set_state_basic(self, var, value): + """Set a state of a variable""" + self.state[var] = value + + def _get_load_power(self, props=None): + """Return load power""" + return [300] + + +@pytest.fixture(scope="class") +def chuangmiplugv3(request): + request.cls.device = DummyChuangmiPlugV3() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("chuangmiplugv3") +class TestChuangmiPlugV3(TestCase): + def is_on(self): + return self.device.status().is_on + + def state(self): + return self.device.status() + + def test_on(self): + self.device.off() # ensure off + assert self.is_on() is False + + self.device.on() + assert self.is_on() is True + + def test_off(self): + self.device.on() # ensure on + assert self.is_on() is True + + self.device.off() + assert self.is_on() is False + + def test_status(self): + self.device._reset_state() + + load_power = self.device._get_load_power().pop(0) + + start_state_extended = self.device.start_state.copy() + start_state_extended['load_power'] = load_power + assert repr(self.state()) == repr( + ChuangmiPlugStatus(start_state_extended)) + + assert self.is_on() is True + assert self.state().usb_power is True + assert self.state().temperature == self.device.start_state[ + "temperature"] + assert self.state().load_power == load_power + + def test_usb_on(self): + self.device.usb_off() # ensure off + assert self.device.status().usb_power is False + + self.device.usb_on() + assert self.device.status().usb_power is True + + def test_usb_off(self): + self.device.usb_on() # ensure on + assert self.device.status().usb_power is True + + self.device.usb_off() + assert self.device.status().usb_power is False + + def test_set_wifi_led(self): + def wifi_led(): + return self.device.status().wifi_led + + self.device.set_wifi_led(True) + assert wifi_led() is True + + self.device.set_wifi_led(False) + assert wifi_led() is False + + +class DummyChuangmiPlugM1(DummyDevice, ChuangmiPlug): + def __init__(self, *args, **kwargs): + self.model = MODEL_CHUANGMI_PLUG_M1 + self.state = { + 'power': 'on', + 'temperature': 32, + } + self.return_values = { + 'get_prop': self._get_state, + 'set_power': lambda x: self._set_state("power", x), + } + super().__init__(args, kwargs) + + +@pytest.fixture(scope="class") +def chuangmiplugm1(request): + request.cls.device = DummyChuangmiPlugM1() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("chuangmiplugm1") +class TestChuangmiPlugM1(TestCase): + def is_on(self): + return self.device.status().is_on + + def state(self): + return self.device.status() + + def test_on(self): + self.device.off() # ensure off + assert self.is_on() is False + + self.device.on() + assert self.is_on() is True + + def test_off(self): + self.device.on() # ensure on + assert self.is_on() is True + + self.device.off() + assert self.is_on() is False + + def test_status(self): + self.device._reset_state() + + assert repr(self.state()) == repr(ChuangmiPlugStatus(self.device.start_state)) + + assert self.is_on() is True + assert self.state().temperature == self.device.start_state["temperature"] diff --git a/miio/tests/test_plug.py b/miio/tests/test_plug.py deleted file mode 100644 index 0487e65a4..000000000 --- a/miio/tests/test_plug.py +++ /dev/null @@ -1,55 +0,0 @@ -from unittest import TestCase -from miio import Plug -from miio.plug import PlugStatus -from .dummies import DummyDevice -import pytest - - -class DummyPlug(DummyDevice, Plug): - def __init__(self, *args, **kwargs): - self.state = { - 'power': 'on', - 'temperature': 32, - } - self.return_values = { - 'get_prop': self._get_state, - 'set_power': lambda x: self._set_state("power", x), - } - super().__init__(args, kwargs) - - -@pytest.fixture(scope="class") -def plug(request): - request.cls.device = DummyPlug() - # TODO add ability to test on a real device - - -@pytest.mark.usefixtures("plug") -class TestPlug(TestCase): - def is_on(self): - return self.device.status().is_on - - def state(self): - return self.device.status() - - def test_on(self): - self.device.off() # ensure off - assert self.is_on() is False - - self.device.on() - assert self.is_on() is True - - def test_off(self): - self.device.on() # ensure on - assert self.is_on() is True - - self.device.off() - assert self.is_on() is False - - def test_status(self): - self.device._reset_state() - - assert repr(self.state()) == repr(PlugStatus(self.device.start_state)) - - assert self.is_on() is True - assert self.state().temperature == self.device.start_state["temperature"] diff --git a/miio/tests/test_plug_v1.py b/miio/tests/test_plug_v1.py deleted file mode 100644 index 4f162ffa9..000000000 --- a/miio/tests/test_plug_v1.py +++ /dev/null @@ -1,90 +0,0 @@ -from unittest import TestCase -from miio import PlugV1 -from miio.plug_v1 import PlugV1Status -import pytest - - -class DummyPlugV1(PlugV1): - def __init__(self, *args, **kwargs): - self.state = { - 'on': True, - 'usb_on': True, - 'temperature': 32, - } - self.return_values = { - 'get_prop': self._get_state, - 'set_on': lambda x: self._set_state("on", True), - 'set_off': lambda x: self._set_state("on", False), - 'set_usb_on': lambda x: self._set_state("usb_on", True), - 'set_usb_off': lambda x: self._set_state("usb_on", False), - } - self.start_state = self.state.copy() - - def send(self, command: str, parameters=None, retry_count=3): - """Overridden send() to return values from `self.return_values`.""" - return self.return_values[command](parameters) - - def _reset_state(self): - """Revert back to the original state.""" - self.state = self.start_state.copy() - - def _set_state(self, var, value): - """Set a state of a variable""" - self.state[var] = value - - def _get_state(self, props): - """Return wanted properties""" - return [self.state[x] for x in props if x in self.state] - - -@pytest.fixture(scope="class") -def plugv1(request): - request.cls.device = DummyPlugV1() - # TODO add ability to test on a real device - - -@pytest.mark.usefixtures("plugv1") -class TestPlugV1(TestCase): - def is_on(self): - return self.device.status().is_on - - def state(self): - return self.device.status() - - def test_on(self): - self.device.off() # ensure off - assert self.is_on() is False - - self.device.on() - assert self.is_on() is True - - def test_off(self): - self.device.on() # ensure on - assert self.is_on() is True - - self.device.off() - assert self.is_on() is False - - def test_status(self): - self.device._reset_state() - - assert repr(self.state()) == repr(PlugV1Status(self.device.start_state)) - - assert self.is_on() is True - assert self.state().usb_power is True - assert self.state().temperature == self.device.start_state[ - "temperature"] - - def test_usb_on(self): - self.device.usb_off() # ensure off - assert self.device.status().usb_power is False - - self.device.usb_on() - assert self.device.status().usb_power is True - - def test_usb_off(self): - self.device.usb_on() # ensure on - assert self.device.status().usb_power is True - - self.device.usb_off() - assert self.device.status().usb_power is False diff --git a/miio/tests/test_plug_v3.py b/miio/tests/test_plug_v3.py deleted file mode 100644 index 18913da79..000000000 --- a/miio/tests/test_plug_v3.py +++ /dev/null @@ -1,99 +0,0 @@ -from unittest import TestCase -from miio import PlugV3 -from miio.plug_v3 import PlugV3Status -from .dummies import DummyDevice -import pytest - - -class DummyPlugV3(DummyDevice, PlugV3): - def __init__(self, *args, **kwargs): - self.state = { - 'on': True, - 'usb_on': True, - 'temperature': 32, - 'wifi_led': 'off' - } - self.return_values = { - 'get_prop': self._get_state, - 'get_power': self._get_load_power, - 'set_power': lambda x: self._set_state_basic("on", x == ["on"]), - 'set_usb_on': lambda x: self._set_state_basic("usb_on", True), - 'set_usb_off': lambda x: self._set_state_basic("usb_on", False), - 'set_wifi_led': lambda x: self._set_state("wifi_led", x), - } - self.start_state = self.state.copy() - - def _set_state_basic(self, var, value): - """Set a state of a variable""" - self.state[var] = value - - def _get_load_power(self, props=None): - """Return load power""" - return [300] - - -@pytest.fixture(scope="class") -def plugv3(request): - request.cls.device = DummyPlugV3() - # TODO add ability to test on a real device - - -@pytest.mark.usefixtures("plugv3") -class TestPlugV3(TestCase): - def is_on(self): - return self.device.status().is_on - - def state(self): - return self.device.status() - - def test_on(self): - self.device.off() # ensure off - assert self.is_on() is False - - self.device.on() - assert self.is_on() is True - - def test_off(self): - self.device.on() # ensure on - assert self.is_on() is True - - self.device.off() - assert self.is_on() is False - - def test_status(self): - self.device._reset_state() - - load_power = self.device._get_load_power().pop(0) - - start_state_extended = self.device.start_state.copy() - start_state_extended['load_power'] = load_power - assert repr(self.state()) == repr(PlugV3Status(start_state_extended)) - - assert self.is_on() is True - assert self.state().usb_power is True - assert self.state().temperature == self.device.start_state["temperature"] - assert self.state().load_power == load_power - - def test_usb_on(self): - self.device.usb_off() # ensure off - assert self.device.status().usb_power is False - - self.device.usb_on() - assert self.device.status().usb_power is True - - def test_usb_off(self): - self.device.usb_on() # ensure on - assert self.device.status().usb_power is True - - self.device.usb_off() - assert self.device.status().usb_power is False - - def test_set_wifi_led(self): - def wifi_led(): - return self.device.status().wifi_led - - self.device.set_wifi_led(True) - assert wifi_led() is True - - self.device.set_wifi_led(False) - assert wifi_led() is False