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

Add tinymu smart toiletlid #544

Merged
merged 18 commits into from
Sep 11, 2019
1 change: 1 addition & 0 deletions miio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from miio.philips_moonlight import PhilipsMoonlight
from miio.powerstrip import PowerStrip
from miio.protocol import Message, Utils
from miio.toiletlid import Toiletlid
from miio.vacuum import Vacuum, VacuumException
from miio.vacuumcontainers import (VacuumStatus, ConsumableStatus, DNDStatus,
CleaningDetails, CleaningSummary, Timer, )
Expand Down
5 changes: 4 additions & 1 deletion miio/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from . import (Device, Vacuum, ChuangmiCamera, ChuangmiPlug, PowerStrip, AirPurifier, AirFresh,
Ceil, PhilipsBulb, PhilipsEyecare, PhilipsMoonlight, ChuangmiIr,
AirHumidifier, WaterPurifier, WifiSpeaker, WifiRepeater,
Yeelight, Fan, Cooker, AirConditioningCompanion, AirQualityMonitor, AqaraCamera)
Yeelight, Fan, Cooker, AirConditioningCompanion, AirQualityMonitor, AqaraCamera,
Toiletlid)

from .airconditioningcompanion import (MODEL_ACPARTNER_V1, MODEL_ACPARTNER_V2, MODEL_ACPARTNER_V3, )
from .airqualitymonitor import (MODEL_AIRQUALITYMONITOR_V1, MODEL_AIRQUALITYMONITOR_B1,
Expand All @@ -23,6 +24,7 @@
from .fan import (MODEL_FAN_V2, MODEL_FAN_V3, MODEL_FAN_SA1, MODEL_FAN_ZA1, MODEL_FAN_ZA3,
MODEL_FAN_ZA4, MODEL_FAN_P5, )
from .powerstrip import (MODEL_POWER_STRIP_V1, MODEL_POWER_STRIP_V2, )
from .toiletlid import (MODEL_TOILETLID_V1, )

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -89,6 +91,7 @@
"zhimi-fan-za3": partial(Fan, model=MODEL_FAN_ZA3),
"zhimi-fan-za4": partial(Fan, model=MODEL_FAN_ZA4),
"dmaker-fan-p5": partial(Fan, model=MODEL_FAN_P5),
"tinymu-toiletlid-v1": partial(Toiletlid, model=MODEL_TOILETLID_V1),
"zhimi-airfresh-va2": AirFresh,
"zhimi-airmonitor-v1": partial(AirQualityMonitor, model=MODEL_AIRQUALITYMONITOR_V1),
"cgllc-airmonitor-b1": partial(AirQualityMonitor, model=MODEL_AIRQUALITYMONITOR_B1),
Expand Down
148 changes: 148 additions & 0 deletions miio/toiletlid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import enum
import logging
from typing import Any, Dict

import click

from .click_common import command, format_output, EnumType
from .device import Device, DeviceException

_LOGGER = logging.getLogger(__name__)

MODEL_TOILETLID_V1 = "tinymu.toiletlid.v1"

AVAILABLE_PROPERTIES_COMMON = ["work_state", "filter_use_flux", "filter_use_time"]

AVAILABLE_PROPERTIES = {MODEL_TOILETLID_V1: AVAILABLE_PROPERTIES_COMMON}


class AmbientLightColor(enum.Enum):
White = "0"
Yellow = "1"
Powder = "2"
Green = "3"
Purple = "4"
Blue = "5"
Orange = "6"
Red = "7"


class AmbientLightException(DeviceException):
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
pass


class ToiletlidStatus:
def __init__(self, data: Dict[str, Any]) -> None:
self.data = data

@property
def work_state(self) -> int:
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
"""Device state code"""
return self.data["work_state"]

@property
def is_on(self) -> bool:
return self.work_state != 1

@property
def filter_use_percentage(self) -> str:
"""Filter percentage of remaining life"""
return "{}%".format(self.data["filter_use_flux"])

@property
def filter_remaining_time(self) -> int:
"""Filter remaining life days"""
return self.data["filter_use_time"]

@property
def ambient_light(self) -> str:
"""Ambient light color."""
return self.data["ambient_light"]

def __repr__(self) -> str:
return (
"<ToiletlidStatus work=%s, "
"state=%s, "
"ambient_light=%s, "
"filter_use_percentage=%s, "
"filter_remaining_time=%s>"
% (
self.is_on,
self.work_state,
self.ambient_light,
self.filter_use_percentage,
self.filter_remaining_time,
)
)


class Toiletlid(Device):
def __init__(
self,
ip: str = None,
token: str = None,
start_id: int = 0,
debug: int = 0,
lazy_discover: bool = True,
model: str = MODEL_TOILETLID_V1,
) -> None:
super().__init__(ip, token, start_id, debug, lazy_discover)

if model in AVAILABLE_PROPERTIES:
self.model = model
else:
self.model = MODEL_TOILETLID_V1
rytilahti marked this conversation as resolved.
Show resolved Hide resolved

@command(
default_output=format_output(
"",
"Work: {result.work}\n"
"State: {result.work_state}\n"
"Ambient Light: {result.ambient_light}\n"
"Filter remaining: {result.filter_use_percentage}\n"
"Filter remaining time: {result.filter_remaining_time}\n",
)
)
def status(self) -> ToiletlidStatus:
"""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.error(
"Count (%s) of requested properties does not match the "
"count (%s) of received values.",
properties_count,
values_count,
)
color = self.get_ambient_light()
return ToiletlidStatus(dict(zip(properties, values), ambient_light=color))

@command(default_output=format_output("Nozzle clean"))
def nozzle_clean(self):
"""Nozzle clean."""
return self.send("nozzle_clean", ["on"])
rytilahti marked this conversation as resolved.
Show resolved Hide resolved

@command(
click.argument("color", type=EnumType(AmbientLightColor, False)),
default_output=format_output(
"Set the ambient light to {color} color the next time you start it."
),
)
def set_ambient_light(self, color: AmbientLightColor):
"""Set Ambient light color."""
return self.send("set_aled_v_of_uid", ["", color.value])

@command(default_output=format_output("Get the Ambient light color."))
def get_ambient_light(self) -> str:
"""Get Ambient light color."""
color = self.send("get_aled_v_of_uid", [""])
try:
return AmbientLightColor(color[0]).name
except TypeError:
raise DeviceException(
"Get Ambient Light Operating Device Not Responding!"
) from None
except ValueError as e:
raise AmbientLightException(e) from None
rytilahti marked this conversation as resolved.
Show resolved Hide resolved