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
147 changes: 147 additions & 0 deletions miio/toiletlid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import enum
import logging
from typing import Any, Dict

import click

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

_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 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

@property
def work(self) -> bool:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need for this property, considering there's already a more generic is_on?

"""True if device is use on."""
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.work,
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]
_props_per_request = 15

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local variable '_props_per_request' is assigned to but never used

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind fixing this?


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:
"""Set Ambient light color."""
color = self.send("get_aled_v_of_uid", [""])
if color:
return AmbientLightColor(color[0]).name
else:
return AmbientLightColor("0").name
rytilahti marked this conversation as resolved.
Show resolved Hide resolved