Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Merge of the Chuangmi Plug V1, V2, V3 and M1 #270

Merged
merged 19 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions miio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
180 changes: 180 additions & 0 deletions miio/chuangmi_plug.py
Original file line number Diff line number Diff line change
@@ -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 = "<ChuangmiPlugStatus " \
"power=%s, " \
"usb_power=%s, " \
"temperature=%s" \
"load_power=%s, " \
"wifi_led=%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)
29 changes: 18 additions & 11 deletions miio/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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",
Expand Down
65 changes: 0 additions & 65 deletions miio/plug.py

This file was deleted.

Loading