From 8bbad1adf3ace1b69765c1aca32619254054eb6c Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Mon, 23 Nov 2020 08:04:46 +0100 Subject: [PATCH 01/30] Create g1vacuum.py --- miio/g1vacuum.py | 314 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 miio/g1vacuum.py diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py new file mode 100644 index 000000000..ba05ddf3d --- /dev/null +++ b/miio/g1vacuum.py @@ -0,0 +1,314 @@ +import logging +from dataclasses import dataclass, field +from typing import Any, Dict +from enum import Enum +import click +from .click_common import EnumType, command, format_output +from .miot_device import MiotDevice + +_LOGGER = logging.getLogger(__name__) + +_MAPPING = { + #Source https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 + "battery": {"siid": 3, "piid": 1}, + "charge_state": {"siid": 3, "piid": 2}, + "error": {"siid": 2, "piid": 2}, + "state": {"siid": 2, "piid": 1}, + "fan_speed": {"siid": 2, "piid": 6}, + "operating_mode": {"siid": 2, "piid": 4}, + "mop_state": {"siid": 16, "piid": 1}, + "water_level": {"siid": 2, "piid": 5}, + "brush_life_level": {"siid": 14, "piid": 1}, +# # "brush_life_time": {"siid": 14, "piid": 2}, + "brush_life_level2": {"siid": 15, "piid": 1}, +# # "brush_life_time2": {"siid": 15, "piid": 2}, + "filter_life_level": {"siid": 11, "piid": 1}, +# # "filter_life_time": {"siid": 11, "piid": 2}, + "clean_area": {"siid": 9, "piid": 1}, + "clean_time": {"siid": 18, "piid": 5}, + "total_clean_count": {"siid": 9, "piid": 5}, +# "total_clean_area": {"siid": 9, "piid": 3}, +# # "dnd_enabled": {"siid": 12, "piid": 2}, +# # "audio_volume": {"siid": 4, "piid": 2}, +# # "direction_key": {"siid": 8, "piid": 1} +} + +class G1ChargeState(Enum): + Not_charging = 0 + Charging = 1 + Charging_competely = 2 + +class G1Error(Enum): + Left_wheel_error = 1 + Right_wheel_error = 2 + Cliff_error = 3 + Low_battery_error = 4 + Bump_error = 5 + Main_brush_error = 6 + Side_brush_error = 7 + Fan_motor_error = 8 + Dustbin_error = 9 + Charging_error = 10 + No_water_error = 11 + Everything_is_ok = 0 + Pick_up_error = 12 + +class G1State(Enum): + """Vacuum Status""" + Idle = 1 + Sweeping = 2 + Paused = 3 + Error = 4 + Charging = 5 + Go_Charging = 6 + +class G1Mode(Enum): + """Vacuum Mode""" + Global_clean = 1 + Spot_clean = 2 + Wiping = 3 + +class G1WaterLevel(Enum): + """Water Flow Level""" + Level1 = 1 + Level2 = 2 + Level3 = 3 + +class G1FanSpeed(Enum): + """Fan speeds, same as for ViomiVacuum.""" + Mute = 0 + Standard = 1 + Medium = 2 + High = 3 + +class G1Languages(Enum): + Chinese = 0 + English = 1 + +class G1MopState(Enum): + Off = 0 + On = 1 + +class G1MovementDirection(Enum): + Left = 0 + Right = 1 + Forward = 2 + Backward = 3 + Stop = 4 + +class G1Status: + """Container for status reports from the Mijia Vacuum G1.""" + + def __init__(self, data: Dict[str, Any]) -> None: + self.data = data + + @property + def battery(self) -> int: + """Battery Level.""" + return self.data["battery"] + + @property + def charge_state(self) -> G1ChargeState: + """Charging State.""" + return G1ChargeState[G1ChargeState(self.data["charge_state"]).name] + + @property + def error(self) -> G1Error: + """Error Message.""" + return G1Error[G1Error(self.data["error"]).name] + + @property + def state(self) -> G1State: + """Vacuum Status.""" + return G1State[G1State(self.data["state"]).name] + + @property + def fan_speed(self) -> G1FanSpeed: + """Fan Speed.""" + return G1FanSpeed[G1FanSpeed(self.data["fan_speed"]).name] + + @property + def operating_mode(self) -> G1Mode: + """Operating Mode.""" + return G1Mode[G1Mode(self.data["operating_mode"]).name] + + @property + def mop_state(self) -> G1MopState: + """Mop State.""" + return G1MopState[G1MopState(self.data["mop_state"]).name] + + @property + def water_level(self) -> G1MopState: + """Mop State.""" + return G1WaterLevel[G1WaterLevel(self.data["water_level"]).name] + + @property + def brush_life_level(self) -> int: + """Brush Life Level.""" + return self.data["brush_life_level"] + + @property + def brush_life_level2(self) -> int: + """Side Brush Life Level.""" + return self.data["brush_life_level2"] + + @property + def filter_life_level(self) -> int: + """Filter Life Level.""" + return self.data["filter_life_level"] + + @property + def clean_area(self) -> int: + """Clean Area.""" + return self.data["clean_area"] + + @property + def clean_time(self) -> int: + """Clean Time.""" + return self.data["clean_time"] + + @property + def total_clean_count(self) -> int: + """Total Clean Count.""" + return self.data["total_clean_count"] + + # @property + # def total_clean_area(self) -> int: + # """Total Clean Area.""" + # return self.data["total_clean_area"] + + def __repr__(self) -> str: + s = ( + "" + % ( + self.battery, + self.state, + self.error, + self.charge_state, + self.fan_speed, + self.operating_mode, + self.mop_state, + self.water_level, + self.brush_life_level, + self.brush_life_level2, + self.filter_life_level, + self.clean_area, + self.clean_time, + self.total_clean_count, +# self.total_clean_area, + ) + ) + return s + +class G1Vacuum(MiotDevice): + """Support for G1 vacuum (G1, mijia.vacuum.v2).""" + + def __init__( + self, + ip: str = None, + token: str = None, + start_id: int = 0, + debug: int = 0, + lazy_discover: bool = True, + ) -> None: + super().__init__(_MAPPING, ip, token, start_id, debug, lazy_discover) + + @command( + default_output=format_output( + "", + "State: {result.state}\n" + "Error: {result.error}\n" + "Battery: {result.battery}%\n" + "Mode: {result.operating_mode}\n" + "Mop State: {result.mop_state}\n" + "Charge Status: {result.charge_state}\n" + "Fan speed: {result.fan_speed}\n" + "Water level: {result.water_level}\n" + "Filter Life Level: {result.filter_life_level}%\n" + "Brush Life Level: {result.brush_life_level}%\n" + "Side Brush Life Level: {result.brush_life_level2}%\n" + "Clean Area: {result.clean_area}\n" + "Clean Time: {result.clean_time}\n" +# "Total Clean Area: {result.total_clean_area}\n" + "Total Clean Count: {result.total_clean_count}\n", + ) + ) + + def status(self) -> G1Status: + """Retrieve properties.""" + + return G1Status( + { + prop["did"]: prop["value"] if prop["code"] == 0 else None + for prop in self.get_properties_for_mapping() + } + ) + + def call_action(self, siid, aiid, params=None): + # {"did":"","siid":18,"aiid":1,"in":[{"piid":1,"value":2}] + if params is None: + params = [] + payload = { + "did": f"call-{siid}-{aiid}", + "siid": siid, + "aiid": aiid, + "in": params, + } + return self.send("action", payload) + + @command() + def return_home(self) -> None: + """Return Home.""" + return self.call_action(2, 3) + + @command() + def start(self) -> None: + """Start Cleaning""" + return self.call_action(2, 1) + + @command() + def stop(self) -> None: + """Stop Cleaning""" + return self.call_action(2, 2) + + @command() + def find(self) -> None: + """Find the robot.""" + return self.call_action(6, 1) + + @command() + def reset_brush_life(self) -> None: + """Reset Brush Life.""" + return self.call_action(14, 1) + + @command() + def reset_filter_life(self) -> None: + """Reset Filter Life.""" + return self.call_action(11, 1) + + @command() + def reset_brush_life2(self) -> None: + """Reset Brush Life""" + return self.call_action(15, 1) + + # @command( + # click.argument("level", type=EnumType(G1FanLevel, casesensitive=False))) + # def fanlevel(self, level): + # """aiid 1 Set Fan Level: in: [] -> out: []""" + # return self.set_properties_for_dataclass(battery=0,fan_level=level.value) + + From 4048b56f7fb90c173d4e6359e9ed22b63635d3a7 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 24 Nov 2020 08:00:18 +0100 Subject: [PATCH 02/30] Update g1vacuum.py --- miio/g1vacuum.py | 60 +++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index ba05ddf3d..5d972e718 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -33,12 +33,12 @@ # # "direction_key": {"siid": 8, "piid": 1} } -class G1ChargeState(Enum): +class ChargeState(Enum): Not_charging = 0 Charging = 1 Charging_competely = 2 -class G1Error(Enum): +class Error(Enum): Left_wheel_error = 1 Right_wheel_error = 2 Cliff_error = 3 @@ -53,7 +53,7 @@ class G1Error(Enum): Everything_is_ok = 0 Pick_up_error = 12 -class G1State(Enum): +class State(Enum): """Vacuum Status""" Idle = 1 Sweeping = 2 @@ -62,34 +62,34 @@ class G1State(Enum): Charging = 5 Go_Charging = 6 -class G1Mode(Enum): +class VacuumMode(Enum): """Vacuum Mode""" Global_clean = 1 Spot_clean = 2 Wiping = 3 -class G1WaterLevel(Enum): +class WaterLevel(Enum): """Water Flow Level""" Level1 = 1 Level2 = 2 Level3 = 3 -class G1FanSpeed(Enum): +class FanSpeed(Enum): """Fan speeds, same as for ViomiVacuum.""" Mute = 0 Standard = 1 Medium = 2 High = 3 -class G1Languages(Enum): +class Languages(Enum): Chinese = 0 English = 1 -class G1MopState(Enum): +class MopState(Enum): Off = 0 On = 1 -class G1MovementDirection(Enum): +class MovementDirection(Enum): Left = 0 Right = 1 Forward = 2 @@ -108,39 +108,39 @@ def battery(self) -> int: return self.data["battery"] @property - def charge_state(self) -> G1ChargeState: + def charge_state(self) -> ChargeState: """Charging State.""" - return G1ChargeState[G1ChargeState(self.data["charge_state"]).name] + return ChargeState[ChargeState(self.data["charge_state"]).name] @property - def error(self) -> G1Error: + def error(self) -> Error: """Error Message.""" - return G1Error[G1Error(self.data["error"]).name] + return Error[Error(self.data["error"]).name] @property - def state(self) -> G1State: + def state(self) -> State: """Vacuum Status.""" - return G1State[G1State(self.data["state"]).name] + return State[State(self.data["state"]).name] @property - def fan_speed(self) -> G1FanSpeed: + def fan_speed(self) -> FanSpeed: """Fan Speed.""" - return G1FanSpeed[G1FanSpeed(self.data["fan_speed"]).name] + return FanSpeed[FanSpeed(self.data["fan_speed"]).name] @property - def operating_mode(self) -> G1Mode: + def operating_mode(self) -> VacuumMode: """Operating Mode.""" - return G1Mode[G1Mode(self.data["operating_mode"]).name] + return VacuumMode[VacuumMode(self.data["operating_mode"]).name] @property - def mop_state(self) -> G1MopState: + def mop_state(self) -> MopState: """Mop State.""" - return G1MopState[G1MopState(self.data["mop_state"]).name] + return MopState[MopState(self.data["mop_state"]).name] @property - def water_level(self) -> G1MopState: + def water_level(self) -> WaterLevel: """Mop State.""" - return G1WaterLevel[G1WaterLevel(self.data["water_level"]).name] + return WaterLevel[WaterLevel(self.data["water_level"]).name] @property def brush_life_level(self) -> int: @@ -305,10 +305,12 @@ def reset_brush_life2(self) -> None: """Reset Brush Life""" return self.call_action(15, 1) - # @command( - # click.argument("level", type=EnumType(G1FanLevel, casesensitive=False))) - # def fanlevel(self, level): - # """aiid 1 Set Fan Level: in: [] -> out: []""" - # return self.set_properties_for_dataclass(battery=0,fan_level=level.value) - + @command( + click.argument("fan_speed", type=EnumType(FanSpeed)), + default_output=format_output("Setting fan speed to {fan_speed}"), + ) + def set_fan_speed(self, fan_speed: FanSpeed): + """Set fan speed.""" + return self.set_property("fan_speed", fan_speed.value) + From 098ca3d36705fc3f7afaa228b7bccdd3997788e7 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 26 Nov 2020 09:25:49 +0100 Subject: [PATCH 03/30] __init__py forgot to commit that too --- miio/__init__.py | 1 + miio/g1vacuum.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/miio/__init__.py b/miio/__init__.py index 9350ef6be..bf52319c3 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -33,6 +33,7 @@ from miio.exceptions import DeviceError, DeviceException from miio.fan import Fan, FanP5, FanSA1, FanV2, FanZA1, FanZA4 from miio.fan_miot import FanMiot, FanP9, FanP10, FanP11 +from miio.g1vacuum import G1Vacuum from miio.gateway import Gateway from miio.heater import Heater from miio.philips_bulb import PhilipsBulb, PhilipsWhiteBulb diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 5d972e718..c2e1cf840 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -91,7 +91,7 @@ class MopState(Enum): class MovementDirection(Enum): Left = 0 - Right = 1 + Right = 1 Forward = 2 Backward = 3 Stop = 4 From f1cf345f2813c09fa895dd0037e996b727addd58 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 26 Nov 2020 10:06:51 +0100 Subject: [PATCH 04/30] Update g1vacuum.py --- miio/g1vacuum.py | 92 +++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index c2e1cf840..2327f3778 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -1,5 +1,4 @@ import logging -from dataclasses import dataclass, field from typing import Any, Dict from enum import Enum import click @@ -9,7 +8,7 @@ _LOGGER = logging.getLogger(__name__) _MAPPING = { - #Source https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 + # https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 "battery": {"siid": 3, "piid": 1}, "charge_state": {"siid": 3, "piid": 2}, "error": {"siid": 2, "piid": 2}, @@ -19,18 +18,18 @@ "mop_state": {"siid": 16, "piid": 1}, "water_level": {"siid": 2, "piid": 5}, "brush_life_level": {"siid": 14, "piid": 1}, -# # "brush_life_time": {"siid": 14, "piid": 2}, + # "brush_life_time": {"siid": 14, "piid": 2}, "brush_life_level2": {"siid": 15, "piid": 1}, -# # "brush_life_time2": {"siid": 15, "piid": 2}, + # "brush_life_time2": {"siid": 15, "piid": 2}, "filter_life_level": {"siid": 11, "piid": 1}, -# # "filter_life_time": {"siid": 11, "piid": 2}, + # "filter_life_time": {"siid": 11, "piid": 2}, "clean_area": {"siid": 9, "piid": 1}, "clean_time": {"siid": 18, "piid": 5}, "total_clean_count": {"siid": 9, "piid": 5}, -# "total_clean_area": {"siid": 9, "piid": 3}, -# # "dnd_enabled": {"siid": 12, "piid": 2}, -# # "audio_volume": {"siid": 4, "piid": 2}, -# # "direction_key": {"siid": 8, "piid": 1} + # "total_clean_area": {"siid": 9, "piid": 3}, + # "dnd_enabled": {"siid": 12, "piid": 2}, + # "audio_volume": {"siid": 4, "piid": 2}, + # "direction_key": {"siid": 8, "piid": 1} } class ChargeState(Enum): @@ -54,7 +53,7 @@ class Error(Enum): Pick_up_error = 12 class State(Enum): - """Vacuum Status""" + """Vacuum Status""" Idle = 1 Sweeping = 2 Paused = 3 @@ -63,85 +62,85 @@ class State(Enum): Go_Charging = 6 class VacuumMode(Enum): - """Vacuum Mode""" + """Vacuum Mode""" Global_clean = 1 Spot_clean = 2 Wiping = 3 class WaterLevel(Enum): - """Water Flow Level""" + """Water Flow Level""" Level1 = 1 Level2 = 2 Level3 = 3 class FanSpeed(Enum): - """Fan speeds, same as for ViomiVacuum.""" + """Fan speeds, same as for ViomiVacuum.""" Mute = 0 Standard = 1 Medium = 2 High = 3 - + class Languages(Enum): Chinese = 0 English = 1 class MopState(Enum): - Off = 0 - On = 1 - + Off = 0 + On = 1 + class MovementDirection(Enum): Left = 0 - Right = 1 + Right = 1 Forward = 2 Backward = 3 Stop = 4 - + class G1Status: """Container for status reports from the Mijia Vacuum G1.""" def __init__(self, data: Dict[str, Any]) -> None: self.data = data - + @property def battery(self) -> int: """Battery Level.""" return self.data["battery"] - + @property def charge_state(self) -> ChargeState: """Charging State.""" - return ChargeState[ChargeState(self.data["charge_state"]).name] + return ChargeState[ChargeState(self.data["charge_state"]).name] @property def error(self) -> Error: """Error Message.""" - return Error[Error(self.data["error"]).name] + return Error[Error(self.data["error"]).name] @property def state(self) -> State: """Vacuum Status.""" - return State[State(self.data["state"]).name] + return State[State(self.data["state"]).name] @property def fan_speed(self) -> FanSpeed: """Fan Speed.""" - return FanSpeed[FanSpeed(self.data["fan_speed"]).name] + return FanSpeed[FanSpeed(self.data["fan_speed"]).name] @property def operating_mode(self) -> VacuumMode: """Operating Mode.""" - return VacuumMode[VacuumMode(self.data["operating_mode"]).name] - + return VacuumMode[VacuumMode(self.data["operating_mode"]).name] + @property def mop_state(self) -> MopState: """Mop State.""" - return MopState[MopState(self.data["mop_state"]).name] - + return MopState[MopState(self.data["mop_state"]).name] + @property def water_level(self) -> WaterLevel: """Mop State.""" - return WaterLevel[WaterLevel(self.data["water_level"]).name] - + return WaterLevel[WaterLevel(self.data["water_level"]).name] + @property def brush_life_level(self) -> int: """Brush Life Level.""" @@ -161,7 +160,7 @@ def filter_life_level(self) -> int: def clean_area(self) -> int: """Clean Area.""" return self.data["clean_area"] - + @property def clean_time(self) -> int: """Clean Time.""" @@ -178,7 +177,7 @@ def total_clean_count(self) -> int: # return self.data["total_clean_area"] def __repr__(self) -> str: - s = ( + ret = ( " str: "mode=%s, " "mopstate=%s, " "waterlevel=%s, " - "brushlife=%s, " - "sidebrushlife=%s, " + "brushlevel=%s, " + "sidebrushlevel=%s, " "filterlife=%s, " "cleanarea=%s, " "cleantime=%s, " "totalcleancount=%s, " -# "totalcleanarea=%s>" % ( self.battery, self.state, @@ -209,21 +207,20 @@ def __repr__(self) -> str: self.clean_area, self.clean_time, self.total_clean_count, -# self.total_clean_area, ) ) - return s + return ret class G1Vacuum(MiotDevice): """Support for G1 vacuum (G1, mijia.vacuum.v2).""" def __init__( - self, - ip: str = None, - token: str = None, - start_id: int = 0, - debug: int = 0, - lazy_discover: bool = True, + self, + ip: str = None, + token: str = None, + start_id: int = 0, + debug: int = 0, + lazy_discover: bool = True, ) -> None: super().__init__(_MAPPING, ip, token, start_id, debug, lazy_discover) @@ -243,7 +240,7 @@ def __init__( "Side Brush Life Level: {result.brush_life_level2}%\n" "Clean Area: {result.clean_area}\n" "Clean Time: {result.clean_time}\n" -# "Total Clean Area: {result.total_clean_area}\n" + # "Total Clean Area: {result.total_clean_area}\n" "Total Clean Count: {result.total_clean_count}\n", ) ) @@ -259,6 +256,7 @@ def status(self) -> G1Status: ) def call_action(self, siid, aiid, params=None): + """Call Action""" # {"did":"","siid":18,"aiid":1,"in":[{"piid":1,"value":2}] if params is None: params = [] @@ -304,7 +302,7 @@ def reset_filter_life(self) -> None: def reset_brush_life2(self) -> None: """Reset Brush Life""" return self.call_action(15, 1) - + @command( click.argument("fan_speed", type=EnumType(FanSpeed)), default_output=format_output("Setting fan speed to {fan_speed}"), @@ -312,5 +310,5 @@ def reset_brush_life2(self) -> None: def set_fan_speed(self, fan_speed: FanSpeed): """Set fan speed.""" return self.set_property("fan_speed", fan_speed.value) - + From d4c0c0f27c7a0cb250c87f0f3dbed44dc4a30779 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 26 Nov 2020 10:58:20 +0100 Subject: [PATCH 05/30] Update g1vacuum.py --- miio/g1vacuum.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 2327f3778..e18406f88 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -310,5 +310,3 @@ def reset_brush_life2(self) -> None: def set_fan_speed(self, fan_speed: FanSpeed): """Set fan speed.""" return self.set_property("fan_speed", fan_speed.value) - - From ace52ca3455b0d8a784dd2228233682c0382bf3c Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Sat, 3 Jul 2021 13:57:57 +0200 Subject: [PATCH 06/30] Add files via upload --- miio/__init__.py | 132 ++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/miio/__init__.py b/miio/__init__.py index 9350ef6be..686accfd8 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -1,65 +1,67 @@ -# flake8: noqa -try: - # python 3.7 and earlier - from importlib_metadata import version # type: ignore -except ImportError: - # python 3.8 and later - from importlib.metadata import version # type: ignore - -from miio.airconditioner_miot import AirConditionerMiot -from miio.airconditioningcompanion import ( - AirConditioningCompanion, - AirConditioningCompanionV3, -) -from miio.airconditioningcompanionMCN import AirConditioningCompanionMcn02 -from miio.airdehumidifier import AirDehumidifier -from miio.airfresh import AirFresh, AirFreshVA4 -from miio.airfresh_t2017 import AirFreshT2017 -from miio.airhumidifier import AirHumidifier, AirHumidifierCA1, AirHumidifierCB1 -from miio.airhumidifier_jsq import AirHumidifierJsq -from miio.airhumidifier_miot import AirHumidifierMiot -from miio.airhumidifier_mjjsq import AirHumidifierMjjsq -from miio.airpurifier import AirPurifier -from miio.airpurifier_miot import AirPurifierMiot -from miio.airqualitymonitor import AirQualityMonitor -from miio.aqaracamera import AqaraCamera -from miio.ceil import Ceil -from miio.chuangmi_camera import ChuangmiCamera -from miio.chuangmi_ir import ChuangmiIr -from miio.chuangmi_plug import ChuangmiPlug, Plug, PlugV1, PlugV3 -from miio.cooker import Cooker -from miio.curtain_youpin import CurtainMiot -from miio.device import Device -from miio.exceptions import DeviceError, DeviceException -from miio.fan import Fan, FanP5, FanSA1, FanV2, FanZA1, FanZA4 -from miio.fan_miot import FanMiot, FanP9, FanP10, FanP11 -from miio.gateway import Gateway -from miio.heater import Heater -from miio.philips_bulb import PhilipsBulb, PhilipsWhiteBulb -from miio.philips_eyecare import PhilipsEyecare -from miio.philips_moonlight import PhilipsMoonlight -from miio.philips_rwread import PhilipsRwread -from miio.powerstrip import PowerStrip -from miio.protocol import Message, Utils -from miio.pwzn_relay import PwznRelay -from miio.toiletlid import Toiletlid -from miio.vacuum import Vacuum, VacuumException -from miio.vacuum_tui import VacuumTUI -from miio.vacuumcontainers import ( - CleaningDetails, - CleaningSummary, - ConsumableStatus, - DNDStatus, - Timer, - VacuumStatus, -) -from miio.viomivacuum import ViomiVacuum -from miio.waterpurifier import WaterPurifier -from miio.waterpurifier_yunmi import WaterPurifierYunmi -from miio.wifirepeater import WifiRepeater -from miio.wifispeaker import WifiSpeaker -from miio.yeelight import Yeelight - -from miio.discovery import Discovery - -__version__ = version("python-miio") +# flake8: noqa +try: + # python 3.7 and earlier + from importlib_metadata import version # type: ignore +except ImportError: + # python 3.8 and later + from importlib.metadata import version # type: ignore + +from miio.airconditioner_miot import AirConditionerMiot +from miio.airconditioningcompanion import ( + AirConditioningCompanion, + AirConditioningCompanionV3, +) +from miio.airconditioningcompanionMCN import AirConditioningCompanionMcn02 +from miio.airdehumidifier import AirDehumidifier +from miio.airfresh import AirFresh, AirFreshVA4 +from miio.airfresh_t2017 import AirFreshT2017 +from miio.airhumidifier import AirHumidifier, AirHumidifierCA1, AirHumidifierCB1 +from miio.airhumidifier_jsq import AirHumidifierJsq +from miio.airhumidifier_miot import AirHumidifierMiot +from miio.airhumidifier_mjjsq import AirHumidifierMjjsq +from miio.airpurifier import AirPurifier +from miio.airpurifier_miot import AirPurifierMiot +from miio.airqualitymonitor import AirQualityMonitor +from miio.aqaracamera import AqaraCamera +from miio.ceil import Ceil +from miio.chuangmi_camera import ChuangmiCamera +from miio.chuangmi_ir import ChuangmiIr +from miio.chuangmi_plug import ChuangmiPlug, Plug, PlugV1, PlugV3 +from miio.cooker import Cooker +from miio.curtain_youpin import CurtainMiot +from miio.device import Device +from miio.exceptions import DeviceError, DeviceException +from miio.fan import Fan, FanP5, FanSA1, FanV2, FanZA1, FanZA4 +from miio.fan_miot import Fan1C, FanMiot, FanP9, FanP10, FanP11 +from miio.fan_leshow import FanLeshow +from miio.g1vacuum import G1Vacuum +from miio.gateway import Gateway +from miio.heater import Heater +from miio.philips_bulb import PhilipsBulb, PhilipsWhiteBulb +from miio.philips_eyecare import PhilipsEyecare +from miio.philips_moonlight import PhilipsMoonlight +from miio.philips_rwread import PhilipsRwread +from miio.powerstrip import PowerStrip +from miio.protocol import Message, Utils +from miio.pwzn_relay import PwznRelay +from miio.toiletlid import Toiletlid +from miio.vacuum import Vacuum, VacuumException +from miio.vacuum_tui import VacuumTUI +from miio.vacuumcontainers import ( + CleaningDetails, + CleaningSummary, + ConsumableStatus, + DNDStatus, + Timer, + VacuumStatus, +) +from miio.viomivacuum import ViomiVacuum +from miio.waterpurifier import WaterPurifier +from miio.waterpurifier_yunmi import WaterPurifierYunmi +from miio.wifirepeater import WifiRepeater +from miio.wifispeaker import WifiSpeaker +from miio.yeelight import Yeelight + +from miio.discovery import Discovery + +__version__ = version("python-miio") From de626c2eb149505fe67d5c441b07fbc9ac7b03d4 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Sat, 3 Jul 2021 14:04:02 +0200 Subject: [PATCH 07/30] Update __init__.py Resolved little conflict --- miio/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miio/__init__.py b/miio/__init__.py index bf52319c3..67aecbbe7 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -32,7 +32,8 @@ from miio.device import Device from miio.exceptions import DeviceError, DeviceException from miio.fan import Fan, FanP5, FanSA1, FanV2, FanZA1, FanZA4 -from miio.fan_miot import FanMiot, FanP9, FanP10, FanP11 +from miio.fan_miot import Fan1C, FanMiot, FanP9, FanP10, FanP11 +from miio.fan_leshow import FanLeshow from miio.g1vacuum import G1Vacuum from miio.gateway import Gateway from miio.heater import Heater From 0ea5c053d2cb9ee0122979f3143210c568141c9f Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Sat, 3 Jul 2021 14:05:32 +0200 Subject: [PATCH 08/30] Update __init__.py --- miio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miio/__init__.py b/miio/__init__.py index 67aecbbe7..5f7b3f766 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -32,8 +32,8 @@ from miio.device import Device from miio.exceptions import DeviceError, DeviceException from miio.fan import Fan, FanP5, FanSA1, FanV2, FanZA1, FanZA4 -from miio.fan_miot import Fan1C, FanMiot, FanP9, FanP10, FanP11 from miio.fan_leshow import FanLeshow +from miio.fan_miot import Fan1C, FanMiot, FanP9, FanP10, FanP11 from miio.g1vacuum import G1Vacuum from miio.gateway import Gateway from miio.heater import Heater From 8d1928a610a445d29dd93bfd2e149b4aa127f7c4 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 6 Jul 2021 11:19:54 +0200 Subject: [PATCH 09/30] Update g1vacuum.py --- miio/g1vacuum.py | 277 +++++++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 154 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index e18406f88..7e0db12e0 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -1,101 +1,113 @@ import logging from typing import Any, Dict +from datetime import timedelta from enum import Enum import click from .click_common import EnumType, command, format_output -from .miot_device import MiotDevice +from .miot_device import DeviceStatus, MiotDevice _LOGGER = logging.getLogger(__name__) +MIJIA_VACUUM_V2 = "mijia.vacuum.v2" -_MAPPING = { +MIOT_MAPPING = { + MIJIA_VACUUM_V2: { # https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 "battery": {"siid": 3, "piid": 1}, "charge_state": {"siid": 3, "piid": 2}, - "error": {"siid": 2, "piid": 2}, + "error_code": {"siid": 2, "piid": 2}, "state": {"siid": 2, "piid": 1}, "fan_speed": {"siid": 2, "piid": 6}, "operating_mode": {"siid": 2, "piid": 4}, "mop_state": {"siid": 16, "piid": 1}, "water_level": {"siid": 2, "piid": 5}, - "brush_life_level": {"siid": 14, "piid": 1}, - # "brush_life_time": {"siid": 14, "piid": 2}, - "brush_life_level2": {"siid": 15, "piid": 1}, - # "brush_life_time2": {"siid": 15, "piid": 2}, + "main_brush_life_level": {"siid": 14, "piid": 1}, + # "main_brush_life_time": {"siid": 14, "piid": 2}, + "side_brush_life_level": {"siid": 15, "piid": 1}, + # "side_brush_life_time": {"siid": 15, "piid": 2}, "filter_life_level": {"siid": 11, "piid": 1}, # "filter_life_time": {"siid": 11, "piid": 2}, "clean_area": {"siid": 9, "piid": 1}, "clean_time": {"siid": 18, "piid": 5}, "total_clean_count": {"siid": 9, "piid": 5}, - # "total_clean_area": {"siid": 9, "piid": 3}, + # "total_clean_area": {"siid": 9, "piid": 3}, #throws error # "dnd_enabled": {"siid": 12, "piid": 2}, # "audio_volume": {"siid": 4, "piid": 2}, # "direction_key": {"siid": 8, "piid": 1} + "home": {"siid": 2, "aiid": 3}, + "find": {"siid": 6, "aiid": 1}, + "start": {"siid": 2, "aiid": 1}, + "stop": {"siid": 2, "aiid": 2}, + "reset_main_brush_life_level": {"siid": 14, "aiid": 1}, + "reset_side_brush_life_level": {"siid": 15, "aiid": 1}, + "reset_filter_life_level": {"siid": 11, "aiid": 1} + } } -class ChargeState(Enum): - Not_charging = 0 +error_codes = { + 0: "No error", + 1: "Left Wheel stuck", + 2: "Right Wheel stuck", + 3: "Cliff error", + 4: "Low battery", + 5: "Bump error", + 6: "Main Brush Error", + 7: "Side Brush Error", + 8: "Fan Motor Error", + 9: "Dustbin Error", + 10: "Charging Error", + 11: "No Water Error", + 12: "Pick Up Error" +} + +class G1ChargeState(Enum): + Discharging = 0 Charging = 1 - Charging_competely = 2 - -class Error(Enum): - Left_wheel_error = 1 - Right_wheel_error = 2 - Cliff_error = 3 - Low_battery_error = 4 - Bump_error = 5 - Main_brush_error = 6 - Side_brush_error = 7 - Fan_motor_error = 8 - Dustbin_error = 9 - Charging_error = 10 - No_water_error = 11 - Everything_is_ok = 0 - Pick_up_error = 12 - -class State(Enum): + FullyCharged = 2 + +class G1State(Enum): """Vacuum Status""" Idle = 1 Sweeping = 2 Paused = 3 Error = 4 Charging = 5 - Go_Charging = 6 + GoCharging = 6 + +class G1Consumable(Enum): + """Consumables""" + MainBrush = "main_brush_life_level" + SideBrush = "side_brush_life_level" + Filter = "filter_life_level" -class VacuumMode(Enum): +class G1VacuumMode(Enum): """Vacuum Mode""" - Global_clean = 1 - Spot_clean = 2 + GlobalClean = 1 + SpotClean = 2 Wiping = 3 -class WaterLevel(Enum): +class G1WaterLevel(Enum): """Water Flow Level""" Level1 = 1 Level2 = 2 Level3 = 3 -class FanSpeed(Enum): +class G1FanSpeed(Enum): """Fan speeds, same as for ViomiVacuum.""" Mute = 0 Standard = 1 Medium = 2 High = 3 -class Languages(Enum): +class G1Languages(Enum): Chinese = 0 English = 1 -class MopState(Enum): +class G1MopState(Enum): Off = 0 On = 1 -class MovementDirection(Enum): - Left = 0 - Right = 1 - Forward = 2 - Backward = 3 - Stop = 4 -class G1Status: +class G1Status(DeviceStatus): """Container for status reports from the Mijia Vacuum G1.""" def __init__(self, data: Dict[str, Any]) -> None: @@ -107,63 +119,71 @@ def battery(self) -> int: return self.data["battery"] @property - def charge_state(self) -> ChargeState: + def charge_state(self) -> G1ChargeState: """Charging State.""" - return ChargeState[ChargeState(self.data["charge_state"]).name] + return G1ChargeState[G1ChargeState(self.data["charge_state"]).name] @property - def error(self) -> Error: - """Error Message.""" - return Error[Error(self.data["error"]).name] + def error_code(self) -> int: + """Error code as returned by the device.""" + return int(self.data["error_code"]) @property - def state(self) -> State: + def error(self) -> str: + """Human readable error description, see also :func:`error_code`.""" + try: + return error_codes[self.error_code] + except KeyError: + return "Definition missing for error %s" % self.error_code + + @property + def state(self) -> G1State: """Vacuum Status.""" - return State[State(self.data["state"]).name] + return G1State[G1State(self.data["state"]).name] @property - def fan_speed(self) -> FanSpeed: + def fan_speed(self) -> G1FanSpeed: """Fan Speed.""" - return FanSpeed[FanSpeed(self.data["fan_speed"]).name] + return G1FanSpeed[G1FanSpeed(self.data["fan_speed"]).name] @property - def operating_mode(self) -> VacuumMode: + def operating_mode(self) -> G1VacuumMode: """Operating Mode.""" - return VacuumMode[VacuumMode(self.data["operating_mode"]).name] + return G1VacuumMode[G1VacuumMode(self.data["operating_mode"]).name] @property - def mop_state(self) -> MopState: + def mop_state(self) -> G1MopState: """Mop State.""" - return MopState[MopState(self.data["mop_state"]).name] + return G1MopState[G1MopState(self.data["mop_state"]).name] @property - def water_level(self) -> WaterLevel: + def water_level(self) -> G1WaterLevel: """Mop State.""" - return WaterLevel[WaterLevel(self.data["water_level"]).name] + return G1WaterLevel[G1WaterLevel(self.data["water_level"]).name] @property - def brush_life_level(self) -> int: - """Brush Life Level.""" - return self.data["brush_life_level"] + def main_brush_life_level(self) -> int: + """Main Brush Life Level in %.""" + return self.data["main_brush_life_level"] @property - def brush_life_level2(self) -> int: - """Side Brush Life Level.""" - return self.data["brush_life_level2"] + def side_brush_life_level(self) -> int: + """Side Brush Life Level in %.""" + return self.data["side_brush_life_level"] @property def filter_life_level(self) -> int: - """Filter Life Level.""" + """Filter Life Level in %.""" return self.data["filter_life_level"] @property def clean_area(self) -> int: - """Clean Area.""" + """Clean Area in cm2.""" return self.data["clean_area"] @property - def clean_time(self) -> int: - """Clean Time.""" + def clean_time(self) -> timedelta: + """Clean Time in Minutes.""" return self.data["clean_time"] @property @@ -171,58 +191,25 @@ def total_clean_count(self) -> int: """Total Clean Count.""" return self.data["total_clean_count"] - # @property - # def total_clean_area(self) -> int: - # """Total Clean Area.""" - # return self.data["total_clean_area"] - - def __repr__(self) -> str: - ret = ( - " None: - super().__init__(_MAPPING, ip, token, start_id, debug, lazy_discover) + super().__init__(ip, token, start_id, debug, lazy_discover) + self.model = model @command( default_output=format_output( @@ -236,11 +223,10 @@ def __init__( "Fan speed: {result.fan_speed}\n" "Water level: {result.water_level}\n" "Filter Life Level: {result.filter_life_level}%\n" - "Brush Life Level: {result.brush_life_level}%\n" - "Side Brush Life Level: {result.brush_life_level2}%\n" + "Main Brush Life Level: {result.main_brush_life_level}%\n" + "Side Brush Life Level: {result.side_brush_life_level}%\n" "Clean Area: {result.clean_area}\n" "Clean Time: {result.clean_time}\n" - # "Total Clean Area: {result.total_clean_area}\n" "Total Clean Count: {result.total_clean_count}\n", ) ) @@ -255,58 +241,41 @@ def status(self) -> G1Status: } ) - def call_action(self, siid, aiid, params=None): - """Call Action""" - # {"did":"","siid":18,"aiid":1,"in":[{"piid":1,"value":2}] - if params is None: - params = [] - payload = { - "did": f"call-{siid}-{aiid}", - "siid": siid, - "aiid": aiid, - "in": params, - } - return self.send("action", payload) @command() - def return_home(self) -> None: - """Return Home.""" - return self.call_action(2, 3) + def home(self): + """Home.""" + return self.call_action("home") @command() def start(self) -> None: """Start Cleaning""" - return self.call_action(2, 1) + return self.call_action("start") @command() - def stop(self) -> None: + def stop(self): """Stop Cleaning""" - return self.call_action(2, 2) + return self.call_action("stop") @command() def find(self) -> None: """Find the robot.""" - return self.call_action(6, 1) - - @command() - def reset_brush_life(self) -> None: - """Reset Brush Life.""" - return self.call_action(14, 1) - - @command() - def reset_filter_life(self) -> None: - """Reset Filter Life.""" - return self.call_action(11, 1) - - @command() - def reset_brush_life2(self) -> None: - """Reset Brush Life""" - return self.call_action(15, 1) + return self.call_action("find") + + @command(click.argument("consumable", type=G1Consumable)) + def consumable_reset(self, consumable: G1Consumable): + """Reset consumable information. CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" + if consumable.name == "MainBrush": + return self.call_action("reset_main_brush_life_level") + elif consumable.name == "SideBrush": + return self.call_action("reset_side_brush_life_level") + elif consumable.name == "Filter": + return self.call_action("reset_filter_life_level") @command( - click.argument("fan_speed", type=EnumType(FanSpeed)), + click.argument("fan_speed", type=EnumType(G1FanSpeed)), default_output=format_output("Setting fan speed to {fan_speed}"), ) - def set_fan_speed(self, fan_speed: FanSpeed): + def set_fan_speed(self, fan_speed: G1FanSpeed): """Set fan speed.""" - return self.set_property("fan_speed", fan_speed.value) + return self.set_property("fan_speed", fan_speed.value) \ No newline at end of file From d43b457dedf44369cfde284ed8611e49ee529e61 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 8 Jul 2021 18:56:41 +0200 Subject: [PATCH 10/30] Update g1vacuum.py --- miio/g1vacuum.py | 211 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 167 insertions(+), 44 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 7e0db12e0..bdc5bde96 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -4,7 +4,7 @@ from enum import Enum import click from .click_common import EnumType, command, format_output -from .miot_device import DeviceStatus, MiotDevice +from .miot_device import DeviceStatus,MiotDevice _LOGGER = logging.getLogger(__name__) MIJIA_VACUUM_V2 = "mijia.vacuum.v2" @@ -21,18 +21,16 @@ "mop_state": {"siid": 16, "piid": 1}, "water_level": {"siid": 2, "piid": 5}, "main_brush_life_level": {"siid": 14, "piid": 1}, - # "main_brush_life_time": {"siid": 14, "piid": 2}, + "main_brush_time_left": {"siid": 14, "piid": 2}, "side_brush_life_level": {"siid": 15, "piid": 1}, - # "side_brush_life_time": {"siid": 15, "piid": 2}, + "side_brush_time_left": {"siid": 15, "piid": 2}, "filter_life_level": {"siid": 11, "piid": 1}, - # "filter_life_time": {"siid": 11, "piid": 2}, + "filter_time_left": {"siid": 11, "piid": 2}, "clean_area": {"siid": 9, "piid": 1}, - "clean_time": {"siid": 18, "piid": 5}, - "total_clean_count": {"siid": 9, "piid": 5}, - # "total_clean_area": {"siid": 9, "piid": 3}, #throws error - # "dnd_enabled": {"siid": 12, "piid": 2}, - # "audio_volume": {"siid": 4, "piid": 2}, - # "direction_key": {"siid": 8, "piid": 1} + "clean_time": {"siid": 9, "piid": 2}, + "total_clean_area": {"siid": 9, "piid": 3}, #always returns 0 + "total_clean_time": {"siid": 9, "piid": 4}, #always returns 0 + "total_clean_count": {"siid": 9, "piid": 5}, #always returns 0 "home": {"siid": 2, "aiid": 3}, "find": {"siid": 6, "aiid": 1}, "start": {"siid": 2, "aiid": 1}, @@ -108,9 +106,30 @@ class G1MopState(Enum): class G1Status(DeviceStatus): - """Container for status reports from the Mijia Vacuum G1.""" - - def __init__(self, data: Dict[str, Any]) -> None: + """Container for status reports from Mijia Vacuum G1.""" + """ + Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) + [ + {'did': 'battery', 'siid': 3, 'piid': 1, 'code': 0, 'value': 100}, + {'did': 'charge_state', 'siid': 3, 'piid': 2, 'code': 0, 'value': 2}, + {'did': 'error_code', 'siid': 2, 'piid': 2, 'code': 0, 'value': 0}, + {'did': 'state', 'siid': 2, 'piid': 1, 'code': 0, 'value': 5}, + {'did': 'fan_speed', 'siid': 2, 'piid': 6, 'code': 0, 'value': 1}, + {'did': 'operating_mode', 'siid': 2, 'piid': 4, 'code': 0, 'value': 1}, + {'did': 'mop_state', 'siid': 16, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'water_level', 'siid': 2, 'piid': 5, 'code': 0, 'value': 2}, + {'did': 'main_brush_life_level', 'siid': 14, 'piid': 1, 'code': 0, 'value': 99}, + {'did': 'main_brush_time_left', 'siid': 14, 'piid': 2, 'code': 0, 'value': 17959}, + {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1}, + {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2}, + {'did': 'filter_life_level', 'siid': 11, 'piid': 1}, + {'did': 'filter_time_left', 'siid': 11, 'piid': 2}, + {'did': 'clean_area', 'siid': 9, 'piid': 1}, + {'did': 'clean_time', 'siid': 9, 'piid': 2} + ] + + """ + def __init__(self, data): self.data = data @property @@ -139,57 +158,120 @@ def error(self) -> str: @property def state(self) -> G1State: """Vacuum Status.""" - return G1State[G1State(self.data["state"]).name] + return G1State(self.data["state"]) @property def fan_speed(self) -> G1FanSpeed: """Fan Speed.""" - return G1FanSpeed[G1FanSpeed(self.data["fan_speed"]).name] + return G1FanSpeed(self.data["fan_speed"]) @property def operating_mode(self) -> G1VacuumMode: """Operating Mode.""" - return G1VacuumMode[G1VacuumMode(self.data["operating_mode"]).name] + return G1VacuumMode(self.data["operating_mode"]) @property def mop_state(self) -> G1MopState: """Mop State.""" - return G1MopState[G1MopState(self.data["mop_state"]).name] + return G1MopState(self.data["mop_state"]) @property def water_level(self) -> G1WaterLevel: - """Mop State.""" - return G1WaterLevel[G1WaterLevel(self.data["water_level"]).name] + """Water Level.""" + return G1WaterLevel(self.data["water_level"]) + + @property + def clean_area(self) -> int: + """Clean Area in cm2.""" + return self.data["clean_area"] + + @property + def clean_time(self) -> int: + """Clean Time in Minutes.""" + return self.data["clean_time"] + + +class G1CleaningSummary(DeviceStatus): + """Container for cleaning summary from Mijia Vacuum G1.""" + """ + Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) + [ + {'did': 'total_clean_area', 'siid': 9, 'piid': 3}, + {'did': 'total_clean_time', 'siid': 9, 'piid': 4}, + {'did': 'total_clean_count', 'siid': 9, 'piid': 5} + ] + + """ + + def __init__(self, data) -> None: + self.data = data + + @property + def total_clean_count(self) -> int: + """Total Number of Cleanings.""" + return self.data["total_clean_count"] + + @property + def total_clean_area(self) -> int: + """Total Area Cleaned in m2.""" + return self.data["total_clean_area"] + + @property + def total_clean_time(self) -> timedelta: + """Total Cleaning Time.""" + return timedelta(hours=self.data["total_clean_area"]) + + +class G1ConsumableStatus(DeviceStatus): + """Container for consumable status information, including information about brushes + and duration until they should be changed. + The methods returning time left are based values returned from the device. + """ + """ + Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) + [ + {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2, 'code': 0, 'value': 0}, + {'did': 'filter_life_level', 'siid': 11, 'piid': 1, 'code': 0, 'value': 99}, + {'did': 'filter_time_left', 'siid': 11, 'piid': 2, 'code': 0, 'value': 8959}, + {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'clean_time', 'siid': 9, 'piid': 2, 'code': 0, 'value': 0} + ] + + """ + + def __init__(self, data): + self.data = data @property def main_brush_life_level(self) -> int: """Main Brush Life Level in %.""" return self.data["main_brush_life_level"] + @property + def main_brush_time_left(self) -> timedelta: + """Main Brush Remaining Time in Minutes.""" + return timedelta(seconds=self.data["main_brush_time_left"]) + @property def side_brush_life_level(self) -> int: """Side Brush Life Level in %.""" return self.data["side_brush_life_level"] + @property + def side_brush_time_left(self) -> timedelta: + """Side Brush Remaining Time in Minutes.""" + return timedelta(minutes=self.data["side_brush_time_left"]) + @property def filter_life_level(self) -> int: """Filter Life Level in %.""" return self.data["filter_life_level"] @property - def clean_area(self) -> int: - """Clean Area in cm2.""" - return self.data["clean_area"] - - @property - def clean_time(self) -> timedelta: - """Clean Time in Minutes.""" - return self.data["clean_time"] - - @property - def total_clean_count(self) -> int: - """Total Clean Count.""" - return self.data["total_clean_count"] + def filter_time_left(self) -> timedelta: + """Filter Remaining Time in Minutes.""" + return timedelta(minutes=self.data["filter_time_left"]) @@ -211,8 +293,9 @@ def __init__( super().__init__(ip, token, start_id, debug, lazy_discover) self.model = model + @command( - default_output=format_output( + default_output=format_output( "", "State: {result.state}\n" "Error: {result.error}\n" @@ -222,22 +305,61 @@ def __init__( "Charge Status: {result.charge_state}\n" "Fan speed: {result.fan_speed}\n" "Water level: {result.water_level}\n" - "Filter Life Level: {result.filter_life_level}%\n" - "Main Brush Life Level: {result.main_brush_life_level}%\n" - "Side Brush Life Level: {result.side_brush_life_level}%\n" "Clean Area: {result.clean_area}\n" "Clean Time: {result.clean_time}\n" - "Total Clean Count: {result.total_clean_count}\n", - ) + ) ) - def status(self) -> G1Status: """Retrieve properties.""" return G1Status( { prop["did"]: prop["value"] if prop["code"] == 0 else None - for prop in self.get_properties_for_mapping() + # max_properties limmit to 10 to avoid "Checksum error" messages from the device. + for prop in self.get_properties_for_mapping(max_properties=10) + } + ) + + + @command( + default_output=format_output( + "", + "Main Brush Life Level: {result.main_brush_life_level}%\n" + "Main Brush Life Time: {result.main_brush_time_left}\n" + "Side Brush Life Level: {result.side_brush_life_level}%\n" + "Side Brush Life Time: {result.side_brush_time_left}\n" + "Filter Life Level: {result.filter_life_level}%\n" + "Filter Life Time: {result.filter_time_left}\n" + ) + ) + def consumable_status(self) -> G1ConsumableStatus: + """Retrieve properties.""" + + return G1ConsumableStatus( + { + prop["did"]: prop["value"] if prop["code"] == 0 else None + # max_properties limmit to 10 to avoid "Checksum error" messages from the device. + for prop in self.get_properties_for_mapping(max_properties=10) + } + ) + + + @command( + default_output=format_output( + "", + "Total Cleaning Count: {result.total_clean_count}\n" + "Total Cleaning Time: {result.total_clean_time}\n" + "Total Cleaning Area: {result.total_clean_area}\n" + ) + ) + def cleaning_summary(self) -> G1CleaningSummary: + """Retrieve properties.""" + + return G1CleaningSummary( + { + prop["did"]: prop["value"] if prop["code"] == 0 else None + # max_properties limmit to 10 to avoid "Checksum error" messages from the device. + for prop in self.get_properties_for_mapping(max_properties=10) } ) @@ -265,11 +387,11 @@ def find(self) -> None: @command(click.argument("consumable", type=G1Consumable)) def consumable_reset(self, consumable: G1Consumable): """Reset consumable information. CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" - if consumable.name == "MainBrush": + if consumable.name == G1Consumable.MainBrush: return self.call_action("reset_main_brush_life_level") - elif consumable.name == "SideBrush": + elif consumable.name == G1Consumable.SideBrush: return self.call_action("reset_side_brush_life_level") - elif consumable.name == "Filter": + elif consumable.name == G1Consumable.Filter: return self.call_action("reset_filter_life_level") @command( @@ -278,4 +400,5 @@ def consumable_reset(self, consumable: G1Consumable): ) def set_fan_speed(self, fan_speed: G1FanSpeed): """Set fan speed.""" - return self.set_property("fan_speed", fan_speed.value) \ No newline at end of file + return self.set_property("fan_speed", fan_speed.value) + From 742fc665933737814d8f6bf4e4210d46ec0459fc Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 8 Jul 2021 20:41:06 +0200 Subject: [PATCH 11/30] Update g1vacuum.py --- miio/g1vacuum.py | 118 +++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 80 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index bdc5bde96..4e6ece698 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -179,6 +179,36 @@ def mop_state(self) -> G1MopState: def water_level(self) -> G1WaterLevel: """Water Level.""" return G1WaterLevel(self.data["water_level"]) + + @property + def main_brush_life_level(self) -> int: + """Main Brush Life Level in %.""" + return self.data["main_brush_life_level"] + + @property + def main_brush_time_left(self) -> timedelta: + """Main Brush Remaining Time in Minutes.""" + return timedelta(seconds=self.data["main_brush_time_left"]) + + @property + def side_brush_life_level(self) -> int: + """Side Brush Life Level in %.""" + return self.data["side_brush_life_level"] + + @property + def side_brush_time_left(self) -> timedelta: + """Side Brush Remaining Time in Minutes.""" + return timedelta(minutes=self.data["side_brush_time_left"]) + + @property + def filter_life_level(self) -> int: + """Filter Life Level in %.""" + return self.data["filter_life_level"] + + @property + def filter_time_left(self) -> timedelta: + """Filter Remaining Time in Minutes.""" + return timedelta(minutes=self.data["filter_time_left"]) @property def clean_area(self) -> int: @@ -196,9 +226,9 @@ class G1CleaningSummary(DeviceStatus): """ Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) [ - {'did': 'total_clean_area', 'siid': 9, 'piid': 3}, - {'did': 'total_clean_time', 'siid': 9, 'piid': 4}, - {'did': 'total_clean_count', 'siid': 9, 'piid': 5} + {'did': 'total_clean_area', 'siid': 9, 'piid': 3, 'code': 0, 'value': 0}, + {'did': 'total_clean_time', 'siid': 9, 'piid': 4, 'code': 0, 'value': 0}, + {'did': 'total_clean_count', 'siid': 9, 'piid': 5, 'code': 0, 'value': 0} ] """ @@ -222,60 +252,6 @@ def total_clean_time(self) -> timedelta: return timedelta(hours=self.data["total_clean_area"]) -class G1ConsumableStatus(DeviceStatus): - """Container for consumable status information, including information about brushes - and duration until they should be changed. - The methods returning time left are based values returned from the device. - """ - """ - Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) - [ - {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0}, - {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2, 'code': 0, 'value': 0}, - {'did': 'filter_life_level', 'siid': 11, 'piid': 1, 'code': 0, 'value': 99}, - {'did': 'filter_time_left', 'siid': 11, 'piid': 2, 'code': 0, 'value': 8959}, - {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, - {'did': 'clean_time', 'siid': 9, 'piid': 2, 'code': 0, 'value': 0} - ] - - """ - - def __init__(self, data): - self.data = data - - @property - def main_brush_life_level(self) -> int: - """Main Brush Life Level in %.""" - return self.data["main_brush_life_level"] - - @property - def main_brush_time_left(self) -> timedelta: - """Main Brush Remaining Time in Minutes.""" - return timedelta(seconds=self.data["main_brush_time_left"]) - - @property - def side_brush_life_level(self) -> int: - """Side Brush Life Level in %.""" - return self.data["side_brush_life_level"] - - @property - def side_brush_time_left(self) -> timedelta: - """Side Brush Remaining Time in Minutes.""" - return timedelta(minutes=self.data["side_brush_time_left"]) - - @property - def filter_life_level(self) -> int: - """Filter Life Level in %.""" - return self.data["filter_life_level"] - - @property - def filter_time_left(self) -> timedelta: - """Filter Remaining Time in Minutes.""" - return timedelta(minutes=self.data["filter_time_left"]) - - - - class G1Vacuum(MiotDevice): """Support for G1 vacuum (G1, mijia.vacuum.v2).""" @@ -305,37 +281,20 @@ def __init__( "Charge Status: {result.charge_state}\n" "Fan speed: {result.fan_speed}\n" "Water level: {result.water_level}\n" - "Clean Area: {result.clean_area}\n" - "Clean Time: {result.clean_time}\n" - ) - ) - def status(self) -> G1Status: - """Retrieve properties.""" - - return G1Status( - { - prop["did"]: prop["value"] if prop["code"] == 0 else None - # max_properties limmit to 10 to avoid "Checksum error" messages from the device. - for prop in self.get_properties_for_mapping(max_properties=10) - } - ) - - - @command( - default_output=format_output( - "", "Main Brush Life Level: {result.main_brush_life_level}%\n" "Main Brush Life Time: {result.main_brush_time_left}\n" "Side Brush Life Level: {result.side_brush_life_level}%\n" "Side Brush Life Time: {result.side_brush_time_left}\n" "Filter Life Level: {result.filter_life_level}%\n" "Filter Life Time: {result.filter_time_left}\n" - ) + "Clean Area: {result.clean_area}\n" + "Clean Time: {result.clean_time}\n" + ) ) - def consumable_status(self) -> G1ConsumableStatus: + def status(self) -> G1Status: """Retrieve properties.""" - return G1ConsumableStatus( + return G1Status( { prop["did"]: prop["value"] if prop["code"] == 0 else None # max_properties limmit to 10 to avoid "Checksum error" messages from the device. @@ -343,7 +302,6 @@ def consumable_status(self) -> G1ConsumableStatus: } ) - @command( default_output=format_output( "", From 5a49a23a21b205dd68ebe10c72897c97318d84e9 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Fri, 9 Jul 2021 09:17:50 +0200 Subject: [PATCH 12/30] Update miio/g1vacuum.py Co-authored-by: Teemu R. --- miio/g1vacuum.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 4e6ece698..a522ded4c 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -140,7 +140,7 @@ def battery(self) -> int: @property def charge_state(self) -> G1ChargeState: """Charging State.""" - return G1ChargeState[G1ChargeState(self.data["charge_state"]).name] + return G1ChargeState(self.data["charge_state"]) @property def error_code(self) -> int: @@ -359,4 +359,3 @@ def consumable_reset(self, consumable: G1Consumable): def set_fan_speed(self, fan_speed: G1FanSpeed): """Set fan speed.""" return self.set_property("fan_speed", fan_speed.value) - From 55175bcdcbcdf9689fab1cc270b6944c2bbcedb7 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Fri, 9 Jul 2021 09:18:36 +0200 Subject: [PATCH 13/30] Update miio/g1vacuum.py Co-authored-by: Teemu R. --- miio/g1vacuum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index a522ded4c..0bf8aa1e7 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -217,7 +217,7 @@ def clean_area(self) -> int: @property def clean_time(self) -> int: - """Clean Time in Minutes.""" + """Clean time.""" return self.data["clean_time"] From 359ceba696a9043f98bccabbc68dc9586698c728 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Fri, 9 Jul 2021 09:18:56 +0200 Subject: [PATCH 14/30] Update miio/g1vacuum.py Co-authored-by: Teemu R. --- miio/g1vacuum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 0bf8aa1e7..270b883cb 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -207,7 +207,7 @@ def filter_life_level(self) -> int: @property def filter_time_left(self) -> timedelta: - """Filter Remaining Time in Minutes.""" + """Filter remaining time.""" return timedelta(minutes=self.data["filter_time_left"]) @property From 87198b41e288cd888414f86d6ca3e4d456b654a2 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:41:25 +0200 Subject: [PATCH 15/30] Update g1vacuum.py --- miio/g1vacuum.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 270b883cb..4ac2de060 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -120,12 +120,12 @@ class G1Status(DeviceStatus): {'did': 'water_level', 'siid': 2, 'piid': 5, 'code': 0, 'value': 2}, {'did': 'main_brush_life_level', 'siid': 14, 'piid': 1, 'code': 0, 'value': 99}, {'did': 'main_brush_time_left', 'siid': 14, 'piid': 2, 'code': 0, 'value': 17959}, - {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1}, - {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2}, - {'did': 'filter_life_level', 'siid': 11, 'piid': 1}, - {'did': 'filter_time_left', 'siid': 11, 'piid': 2}, - {'did': 'clean_area', 'siid': 9, 'piid': 1}, - {'did': 'clean_time', 'siid': 9, 'piid': 2} + {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0 }, + {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2', 'code': 0, 'value': 0}, + {'did': 'filter_life_level', 'siid': 11, 'piid': 1, 'code': 0, 'value': 99}, + {'did': 'filter_time_left', 'siid': 11, 'piid': 2, 'code': 0, 'value': 8959}, + {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'clean_time', 'siid': 9, 'piid': 2, 'code': 0, 'value': 0} ] """ From 9fdfcbf0cace08d7abe9dd73384f6f90dd957101 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:50:41 +0200 Subject: [PATCH 16/30] Update g1vacuum.py Cleaning Time now also timedelta, corrected a small glitch. --- miio/g1vacuum.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 4ac2de060..d252d61ca 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -188,7 +188,7 @@ def main_brush_life_level(self) -> int: @property def main_brush_time_left(self) -> timedelta: """Main Brush Remaining Time in Minutes.""" - return timedelta(seconds=self.data["main_brush_time_left"]) + return timedelta(minutes=self.data["main_brush_time_left"]) @property def side_brush_life_level(self) -> int: @@ -216,9 +216,9 @@ def clean_area(self) -> int: return self.data["clean_area"] @property - def clean_time(self) -> int: + def clean_time(self) -> timedelta: """Clean time.""" - return self.data["clean_time"] + return timedelta(minutes=self.data["clean_time"]) class G1CleaningSummary(DeviceStatus): From 696b3379cb0d5baa57ec86a15a9ae97476ab140b Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Sat, 10 Jul 2021 15:56:12 +0200 Subject: [PATCH 17/30] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 169ff721f..2aa0a703d 100644 --- a/README.rst +++ b/README.rst @@ -97,6 +97,7 @@ Supported devices - Xiaomi Mijia 360 1080p - Xiaomi Mijia STYJ02YM (Viomi) - Xiaomi Mijia 1C STYTJ01ZHM (Dreame) +- XiaomiMi Home (Mijia) G1 Robot Vacuum Mop MJSTG1 - Xiaomi Mi Smart WiFi Socket - Xiaomi Chuangmi Plug V1 (1 Socket, 1 USB Port) - Xiaomi Chuangmi Plug V3 (1 Socket, 2 USB Ports) From 4fe5b76c22fd938fd6b4f953087d7b11a52dc5c6 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Sat, 10 Jul 2021 16:03:05 +0200 Subject: [PATCH 18/30] Update README.rst typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2aa0a703d..bcfb8af4c 100644 --- a/README.rst +++ b/README.rst @@ -97,7 +97,7 @@ Supported devices - Xiaomi Mijia 360 1080p - Xiaomi Mijia STYJ02YM (Viomi) - Xiaomi Mijia 1C STYTJ01ZHM (Dreame) -- XiaomiMi Home (Mijia) G1 Robot Vacuum Mop MJSTG1 +- Xiaomi Mi Home (Mijia) G1 Robot Vacuum Mop MJSTG1 - Xiaomi Mi Smart WiFi Socket - Xiaomi Chuangmi Plug V1 (1 Socket, 1 USB Port) - Xiaomi Chuangmi Plug V3 (1 Socket, 2 USB Ports) From d8572e306dfd26a68745944062e4dfbf919a39c5 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Mon, 12 Jul 2021 09:20:49 +0200 Subject: [PATCH 19/30] Fixed Linting Errors --- .vscode/settings.json | 6 ++ miio/g1vacuum.py | 161 +++++++++++++++++++++--------------------- 2 files changed, 85 insertions(+), 82 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9e1574b2e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "python.linting.pylintEnabled": true, + "python.linting.enabled": true, + "python.linting.pycodestyleEnabled": false, + "python.formatting.provider": "black" +} \ No newline at end of file diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index d252d61ca..4cc76e493 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -1,47 +1,47 @@ import logging -from typing import Any, Dict from datetime import timedelta from enum import Enum import click from .click_common import EnumType, command, format_output -from .miot_device import DeviceStatus,MiotDevice +from .miot_device import DeviceStatus, MiotDevice _LOGGER = logging.getLogger(__name__) MIJIA_VACUUM_V2 = "mijia.vacuum.v2" MIOT_MAPPING = { MIJIA_VACUUM_V2: { - # https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 - "battery": {"siid": 3, "piid": 1}, - "charge_state": {"siid": 3, "piid": 2}, - "error_code": {"siid": 2, "piid": 2}, - "state": {"siid": 2, "piid": 1}, - "fan_speed": {"siid": 2, "piid": 6}, - "operating_mode": {"siid": 2, "piid": 4}, - "mop_state": {"siid": 16, "piid": 1}, - "water_level": {"siid": 2, "piid": 5}, - "main_brush_life_level": {"siid": 14, "piid": 1}, - "main_brush_time_left": {"siid": 14, "piid": 2}, - "side_brush_life_level": {"siid": 15, "piid": 1}, - "side_brush_time_left": {"siid": 15, "piid": 2}, - "filter_life_level": {"siid": 11, "piid": 1}, - "filter_time_left": {"siid": 11, "piid": 2}, - "clean_area": {"siid": 9, "piid": 1}, - "clean_time": {"siid": 9, "piid": 2}, - "total_clean_area": {"siid": 9, "piid": 3}, #always returns 0 - "total_clean_time": {"siid": 9, "piid": 4}, #always returns 0 - "total_clean_count": {"siid": 9, "piid": 5}, #always returns 0 - "home": {"siid": 2, "aiid": 3}, - "find": {"siid": 6, "aiid": 1}, - "start": {"siid": 2, "aiid": 1}, - "stop": {"siid": 2, "aiid": 2}, - "reset_main_brush_life_level": {"siid": 14, "aiid": 1}, - "reset_side_brush_life_level": {"siid": 15, "aiid": 1}, - "reset_filter_life_level": {"siid": 11, "aiid": 1} + # https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1 + "battery": {"siid": 3, "piid": 1}, + "charge_state": {"siid": 3, "piid": 2}, + "error_code": {"siid": 2, "piid": 2}, + "state": {"siid": 2, "piid": 1}, + "fan_speed": {"siid": 2, "piid": 6}, + "operating_mode": {"siid": 2, "piid": 4}, + "mop_state": {"siid": 16, "piid": 1}, + "water_level": {"siid": 2, "piid": 5}, + "main_brush_life_level": {"siid": 14, "piid": 1}, + "main_brush_time_left": {"siid": 14, "piid": 2}, + "side_brush_life_level": {"siid": 15, "piid": 1}, + "side_brush_time_left": {"siid": 15, "piid": 2}, + "filter_life_level": {"siid": 11, "piid": 1}, + "filter_time_left": {"siid": 11, "piid": 2}, + "clean_area": {"siid": 9, "piid": 1}, + "clean_time": {"siid": 9, "piid": 2}, + # totals always return 0 + "total_clean_area": {"siid": 9, "piid": 3}, + "total_clean_time": {"siid": 9, "piid": 4}, + "total_clean_count": {"siid": 9, "piid": 5}, + "home": {"siid": 2, "aiid": 3}, + "find": {"siid": 6, "aiid": 1}, + "start": {"siid": 2, "aiid": 1}, + "stop": {"siid": 2, "aiid": 2}, + "reset_main_brush_life_level": {"siid": 14, "aiid": 1}, + "reset_side_brush_life_level": {"siid": 15, "aiid": 1}, + "reset_filter_life_level": {"siid": 11, "aiid": 1} } } -error_codes = { +ERROR_CODES = { 0: "No error", 1: "Left Wheel stuck", 2: "Right Wheel stuck", @@ -56,12 +56,11 @@ 11: "No Water Error", 12: "Pick Up Error" } - class G1ChargeState(Enum): + """Charging Status""" Discharging = 0 Charging = 1 FullyCharged = 2 - class G1State(Enum): """Vacuum Status""" Idle = 1 @@ -90,45 +89,44 @@ class G1WaterLevel(Enum): Level3 = 3 class G1FanSpeed(Enum): - """Fan speeds, same as for ViomiVacuum.""" + """Fan speeds""" Mute = 0 Standard = 1 Medium = 2 High = 3 class G1Languages(Enum): + """Languages""" Chinese = 0 English = 1 class G1MopState(Enum): + """Mop Status""" Off = 0 On = 1 class G1Status(DeviceStatus): """Container for status reports from Mijia Vacuum G1.""" - """ - Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) + """Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) [ - {'did': 'battery', 'siid': 3, 'piid': 1, 'code': 0, 'value': 100}, - {'did': 'charge_state', 'siid': 3, 'piid': 2, 'code': 0, 'value': 2}, - {'did': 'error_code', 'siid': 2, 'piid': 2, 'code': 0, 'value': 0}, - {'did': 'state', 'siid': 2, 'piid': 1, 'code': 0, 'value': 5}, - {'did': 'fan_speed', 'siid': 2, 'piid': 6, 'code': 0, 'value': 1}, - {'did': 'operating_mode', 'siid': 2, 'piid': 4, 'code': 0, 'value': 1}, - {'did': 'mop_state', 'siid': 16, 'piid': 1, 'code': 0, 'value': 0}, - {'did': 'water_level', 'siid': 2, 'piid': 5, 'code': 0, 'value': 2}, - {'did': 'main_brush_life_level', 'siid': 14, 'piid': 1, 'code': 0, 'value': 99}, - {'did': 'main_brush_time_left', 'siid': 14, 'piid': 2, 'code': 0, 'value': 17959}, - {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0 }, - {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2', 'code': 0, 'value': 0}, - {'did': 'filter_life_level', 'siid': 11, 'piid': 1, 'code': 0, 'value': 99}, + {'did': 'battery', 'siid': 3, 'piid': 1, 'code': 0, 'value': 100}, + {'did': 'charge_state', 'siid': 3, 'piid': 2, 'code': 0, 'value': 2}, + {'did': 'error_code', 'siid': 2, 'piid': 2, 'code': 0, 'value': 0}, + {'did': 'state', 'siid': 2, 'piid': 1, 'code': 0, 'value': 5}, + {'did': 'fan_speed', 'siid': 2, 'piid': 6, 'code': 0, 'value': 1}, + {'did': 'operating_mode', 'siid': 2, 'piid': 4, 'code': 0, 'value': 1}, + {'did': 'mop_state', 'siid': 16, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'water_level', 'siid': 2, 'piid': 5, 'code': 0, 'value': 2}, + {'did': 'main_brush_life_level', 'siid': 14, 'piid': 1, 'code': 0, 'value': 99}, + {'did': 'main_brush_time_left', 'siid': 14, 'piid': 2, 'code': 0, 'value': 17959} + {'did': 'side_brush_life_level', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0 }, + {'did': 'side_brush_time_left', 'siid': 15, 'piid': 2', 'code': 0, 'value': 0}, + {'did': 'filter_life_level', 'siid': 11, 'piid': 1, 'code': 0, 'value': 99}, {'did': 'filter_time_left', 'siid': 11, 'piid': 2, 'code': 0, 'value': 8959}, - {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, + {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, {'did': 'clean_time', 'siid': 9, 'piid': 2, 'code': 0, 'value': 0} - ] - - """ + ]""" def __init__(self, data): self.data = data @@ -151,7 +149,7 @@ def error_code(self) -> int: def error(self) -> str: """Human readable error description, see also :func:`error_code`.""" try: - return error_codes[self.error_code] + return ERROR_CODES[self.error_code] except KeyError: return "Definition missing for error %s" % self.error_code @@ -179,7 +177,7 @@ def mop_state(self) -> G1MopState: def water_level(self) -> G1WaterLevel: """Water Level.""" return G1WaterLevel(self.data["water_level"]) - + @property def main_brush_life_level(self) -> int: """Main Brush Life Level in %.""" @@ -189,7 +187,7 @@ def main_brush_life_level(self) -> int: def main_brush_time_left(self) -> timedelta: """Main Brush Remaining Time in Minutes.""" return timedelta(minutes=self.data["main_brush_time_left"]) - + @property def side_brush_life_level(self) -> int: """Side Brush Life Level in %.""" @@ -209,7 +207,7 @@ def filter_life_level(self) -> int: def filter_time_left(self) -> timedelta: """Filter remaining time.""" return timedelta(minutes=self.data["filter_time_left"]) - + @property def clean_area(self) -> int: """Clean Area in cm2.""" @@ -223,15 +221,12 @@ def clean_time(self) -> timedelta: class G1CleaningSummary(DeviceStatus): """Container for cleaning summary from Mijia Vacuum G1.""" - """ - Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) + """Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) [ - {'did': 'total_clean_area', 'siid': 9, 'piid': 3, 'code': 0, 'value': 0}, - {'did': 'total_clean_time', 'siid': 9, 'piid': 4, 'code': 0, 'value': 0}, + {'did': 'total_clean_area', 'siid': 9, 'piid': 3, 'code': 0, 'value': 0}, + {'did': 'total_clean_time', 'siid': 9, 'piid': 4, 'code': 0, 'value': 0}, {'did': 'total_clean_count', 'siid': 9, 'piid': 5, 'code': 0, 'value': 0} - ] - - """ + ]""" def __init__(self, data) -> None: self.data = data @@ -258,20 +253,19 @@ class G1Vacuum(MiotDevice): mapping = MIOT_MAPPING[MIJIA_VACUUM_V2] def __init__( - self, - ip: str = None, - token: str = None, - start_id: int = 0, - debug: int = 0, - lazy_discover: bool = True, - model: str = MIJIA_VACUUM_V2, + self, + ip: str = None, + token: str = None, + start_id: int = 0, + debug: int = 0, + lazy_discover: bool = True, + model: str = MIJIA_VACUUM_V2, ) -> None: super().__init__(ip, token, start_id, debug, lazy_discover) self.model = model - @command( - default_output=format_output( + default_output=format_output( "", "State: {result.state}\n" "Error: {result.error}\n" @@ -289,7 +283,7 @@ def __init__( "Filter Life Time: {result.filter_time_left}\n" "Clean Area: {result.clean_area}\n" "Clean Time: {result.clean_time}\n" - ) + ) ) def status(self) -> G1Status: """Retrieve properties.""" @@ -297,12 +291,13 @@ def status(self) -> G1Status: return G1Status( { prop["did"]: prop["value"] if prop["code"] == 0 else None - # max_properties limmit to 10 to avoid "Checksum error" messages from the device. + # max_properties limmit to 10 to avoid "Checksum error" + # messages from the device. for prop in self.get_properties_for_mapping(max_properties=10) } ) - @command( + @command( default_output=format_output( "", "Total Cleaning Count: {result.total_clean_count}\n" @@ -316,7 +311,8 @@ def cleaning_summary(self) -> G1CleaningSummary: return G1CleaningSummary( { prop["did"]: prop["value"] if prop["code"] == 0 else None - # max_properties limmit to 10 to avoid "Checksum error" messages from the device. + # max_properties limmit to 10 to avoid "Checksum error" + # messages from the device. for prop in self.get_properties_for_mapping(max_properties=10) } ) @@ -344,13 +340,14 @@ def find(self) -> None: @command(click.argument("consumable", type=G1Consumable)) def consumable_reset(self, consumable: G1Consumable): - """Reset consumable information. CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" - if consumable.name == G1Consumable.MainBrush: - return self.call_action("reset_main_brush_life_level") + """Reset consumable information. + CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" + if consumable.name == G1Consumable.MainBrush: + return self.call_action("reset_main_brush_life_level") elif consumable.name == G1Consumable.SideBrush: - return self.call_action("reset_side_brush_life_level") + return self.call_action("reset_side_brush_life_level") elif consumable.name == G1Consumable.Filter: - return self.call_action("reset_filter_life_level") + return self.call_action("reset_filter_life_level") @command( click.argument("fan_speed", type=EnumType(G1FanSpeed)), @@ -358,4 +355,4 @@ def consumable_reset(self, consumable: G1Consumable): ) def set_fan_speed(self, fan_speed: G1FanSpeed): """Set fan speed.""" - return self.set_property("fan_speed", fan_speed.value) + return self.set_property("fan_speed", fan_speed.value) \ No newline at end of file From d54a8b3c310cedfb14f70b481a5df1742ddf538d Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Mon, 12 Jul 2021 09:26:44 +0200 Subject: [PATCH 20/30] Delete settings.json --- .vscode/settings.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9e1574b2e..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.linting.pycodestyleEnabled": false, - "python.formatting.provider": "black" -} \ No newline at end of file From 3e695704fd5ba426472dd2aefe12b74bed955a7d Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Mon, 12 Jul 2021 15:16:54 +0200 Subject: [PATCH 21/30] Hope black won't error out again this time --- miio/g1vacuum.py | 56 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index 4cc76e493..d9e0152d9 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -35,9 +35,9 @@ "find": {"siid": 6, "aiid": 1}, "start": {"siid": 2, "aiid": 1}, "stop": {"siid": 2, "aiid": 2}, - "reset_main_brush_life_level": {"siid": 14, "aiid": 1}, - "reset_side_brush_life_level": {"siid": 15, "aiid": 1}, - "reset_filter_life_level": {"siid": 11, "aiid": 1} + "reset_main_brush_life_level": {"siid": 14, "aiid": 1}, + "reset_side_brush_life_level": {"siid": 15, "aiid": 1}, + "reset_filter_life_level": {"siid": 11, "aiid": 1}, } } @@ -54,15 +54,21 @@ 9: "Dustbin Error", 10: "Charging Error", 11: "No Water Error", - 12: "Pick Up Error" + 12: "Pick Up Error", } + + class G1ChargeState(Enum): """Charging Status""" + Discharging = 0 Charging = 1 FullyCharged = 2 + + class G1State(Enum): """Vacuum Status""" + Idle = 1 Sweeping = 2 Paused = 3 @@ -70,44 +76,57 @@ class G1State(Enum): Charging = 5 GoCharging = 6 + class G1Consumable(Enum): """Consumables""" + MainBrush = "main_brush_life_level" SideBrush = "side_brush_life_level" Filter = "filter_life_level" + class G1VacuumMode(Enum): """Vacuum Mode""" + GlobalClean = 1 SpotClean = 2 Wiping = 3 + class G1WaterLevel(Enum): """Water Flow Level""" + Level1 = 1 Level2 = 2 Level3 = 3 + class G1FanSpeed(Enum): """Fan speeds""" + Mute = 0 Standard = 1 Medium = 2 High = 3 + class G1Languages(Enum): """Languages""" + Chinese = 0 English = 1 + class G1MopState(Enum): """Mop Status""" + Off = 0 On = 1 class G1Status(DeviceStatus): """Container for status reports from Mijia Vacuum G1.""" + """Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) [ {'did': 'battery', 'siid': 3, 'piid': 1, 'code': 0, 'value': 100}, @@ -127,6 +146,7 @@ class G1Status(DeviceStatus): {'did': 'clean_area', 'siid': 9, 'piid': 1, 'code': 0, 'value': 0}, {'did': 'clean_time', 'siid': 9, 'piid': 2, 'code': 0, 'value': 0} ]""" + def __init__(self, data): self.data = data @@ -221,6 +241,7 @@ def clean_time(self) -> timedelta: class G1CleaningSummary(DeviceStatus): """Container for cleaning summary from Mijia Vacuum G1.""" + """Response (MIoT format) of a Mijia Vacuum G1 (mijia.vacuum.v2) [ {'did': 'total_clean_area', 'siid': 9, 'piid': 3, 'code': 0, 'value': 0}, @@ -253,13 +274,13 @@ class G1Vacuum(MiotDevice): mapping = MIOT_MAPPING[MIJIA_VACUUM_V2] def __init__( - self, - ip: str = None, - token: str = None, - start_id: int = 0, - debug: int = 0, - lazy_discover: bool = True, - model: str = MIJIA_VACUUM_V2, + self, + ip: str = None, + token: str = None, + start_id: int = 0, + debug: int = 0, + lazy_discover: bool = True, + model: str = MIJIA_VACUUM_V2, ) -> None: super().__init__(ip, token, start_id, debug, lazy_discover) self.model = model @@ -282,7 +303,7 @@ def __init__( "Filter Life Level: {result.filter_life_level}%\n" "Filter Life Time: {result.filter_time_left}\n" "Clean Area: {result.clean_area}\n" - "Clean Time: {result.clean_time}\n" + "Clean Time: {result.clean_time}\n", ) ) def status(self) -> G1Status: @@ -290,9 +311,9 @@ def status(self) -> G1Status: return G1Status( { + # max_properties limited to 10 to avoid "Checksum error" + # messages from the device. prop["did"]: prop["value"] if prop["code"] == 0 else None - # max_properties limmit to 10 to avoid "Checksum error" - # messages from the device. for prop in self.get_properties_for_mapping(max_properties=10) } ) @@ -302,7 +323,7 @@ def status(self) -> G1Status: "", "Total Cleaning Count: {result.total_clean_count}\n" "Total Cleaning Time: {result.total_clean_time}\n" - "Total Cleaning Area: {result.total_clean_area}\n" + "Total Cleaning Area: {result.total_clean_area}\n", ) ) def cleaning_summary(self) -> G1CleaningSummary: @@ -310,14 +331,13 @@ def cleaning_summary(self) -> G1CleaningSummary: return G1CleaningSummary( { + # max_properties limited to 10 to avoid "Checksum error" + # messages from the device. prop["did"]: prop["value"] if prop["code"] == 0 else None - # max_properties limmit to 10 to avoid "Checksum error" - # messages from the device. for prop in self.get_properties_for_mapping(max_properties=10) } ) - @command() def home(self): """Home.""" From 617ae75b1aebecd92665bc4c1404120a3abcd94b Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:24:37 +0200 Subject: [PATCH 22/30] Update g1vacuum.py *sigh --- miio/g1vacuum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index d9e0152d9..cd9dbdd3d 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -361,7 +361,7 @@ def find(self) -> None: @command(click.argument("consumable", type=G1Consumable)) def consumable_reset(self, consumable: G1Consumable): """Reset consumable information. - CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" + CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" if consumable.name == G1Consumable.MainBrush: return self.call_action("reset_main_brush_life_level") elif consumable.name == G1Consumable.SideBrush: @@ -375,4 +375,4 @@ def consumable_reset(self, consumable: G1Consumable): ) def set_fan_speed(self, fan_speed: G1FanSpeed): """Set fan speed.""" - return self.set_property("fan_speed", fan_speed.value) \ No newline at end of file + return self.set_property("fan_speed", fan_speed.value) From 8109ef772b5ebcd18e4e256732c90c551e755c78 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 13 Jul 2021 18:33:09 +0200 Subject: [PATCH 23/30] changes by local pre-commit now in vscode workflow --- README.rst | 2 +- miio/g1vacuum.py | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index a52a9e666..fc5cf9420 100644 --- a/README.rst +++ b/README.rst @@ -97,7 +97,7 @@ Supported devices - Xiaomi Mijia 360 1080p - Xiaomi Mijia STYJ02YM (Viomi) - Xiaomi Mijia 1C STYTJ01ZHM (Dreame) -- Xiaomi Mi Home (Mijia) G1 Robot Vacuum Mop MJSTG1 +- Xiaomi Mi Home (Mijia) G1 Robot Vacuum Mop MJSTG1 - Xiaomi Roidmi Eve - Xiaomi Mi Smart WiFi Socket - Xiaomi Chuangmi Plug V1 (1 Socket, 1 USB Port) diff --git a/miio/g1vacuum.py b/miio/g1vacuum.py index cd9dbdd3d..1aca787e0 100644 --- a/miio/g1vacuum.py +++ b/miio/g1vacuum.py @@ -1,7 +1,9 @@ import logging from datetime import timedelta from enum import Enum + import click + from .click_common import EnumType, command, format_output from .miot_device import DeviceStatus, MiotDevice @@ -59,7 +61,7 @@ class G1ChargeState(Enum): - """Charging Status""" + """Charging Status.""" Discharging = 0 Charging = 1 @@ -67,7 +69,7 @@ class G1ChargeState(Enum): class G1State(Enum): - """Vacuum Status""" + """Vacuum Status.""" Idle = 1 Sweeping = 2 @@ -78,7 +80,7 @@ class G1State(Enum): class G1Consumable(Enum): - """Consumables""" + """Consumables.""" MainBrush = "main_brush_life_level" SideBrush = "side_brush_life_level" @@ -86,7 +88,7 @@ class G1Consumable(Enum): class G1VacuumMode(Enum): - """Vacuum Mode""" + """Vacuum Mode.""" GlobalClean = 1 SpotClean = 2 @@ -94,7 +96,7 @@ class G1VacuumMode(Enum): class G1WaterLevel(Enum): - """Water Flow Level""" + """Water Flow Level.""" Level1 = 1 Level2 = 2 @@ -102,7 +104,7 @@ class G1WaterLevel(Enum): class G1FanSpeed(Enum): - """Fan speeds""" + """Fan speeds.""" Mute = 0 Standard = 1 @@ -111,14 +113,14 @@ class G1FanSpeed(Enum): class G1Languages(Enum): - """Languages""" + """Languages.""" Chinese = 0 English = 1 class G1MopState(Enum): - """Mop Status""" + """Mop Status.""" Off = 0 On = 1 @@ -345,12 +347,12 @@ def home(self): @command() def start(self) -> None: - """Start Cleaning""" + """Start Cleaning.""" return self.call_action("start") @command() def stop(self): - """Stop Cleaning""" + """Stop Cleaning.""" return self.call_action("stop") @command() @@ -361,7 +363,9 @@ def find(self) -> None: @command(click.argument("consumable", type=G1Consumable)) def consumable_reset(self, consumable: G1Consumable): """Reset consumable information. - CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level""" + + CONSUMABLE=main_brush_life_level|side_brush_life_level|filter_life_level + """ if consumable.name == G1Consumable.MainBrush: return self.call_action("reset_main_brush_life_level") elif consumable.name == G1Consumable.SideBrush: From 60cad51485ee81144c4968444de89d5790bcf50f Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:29:44 +0200 Subject: [PATCH 24/30] Create test_g1vacuum.py --- miio/tests/test_g1vacuum.py | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 miio/tests/test_g1vacuum.py diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py new file mode 100644 index 000000000..8c97970cd --- /dev/null +++ b/miio/tests/test_g1vacuum.py @@ -0,0 +1,92 @@ +from unittest import TestCase + +import pytest + +from miio import G1Vacuum +from miio.g1vacuum import ( + G1ChargeState, + G1FanSpeed, + G1State, + G1Status, + G1VacuumMode, + G1MopState, + G1WaterLevel, +) + +from .dummies import DummyMiotDevice + +_INITIAL_STATE = { + "battery_level": 42, + "charge_state": G1ChargeState.Charging, + "error_code": 0, + "state": G1State.Paused, + "fan_speed": G1FanSpeed.Medium, + "operating_mode": G1VacuumMode.GlobalClean, + "mop_state": G1MopState.Off, + "water_level": G1WaterLevel.Level1, + "fan_speed": G1FanSpeed.Medium, + "main_brush_time_left": 235, + "main_brush_life_level": 85, + "filter_life_level": 66, + "filter_left_time": 154, + "side_brush_life_left": 187, + "side_brush_life_level": 57, + "clean_area": 12, + "clean_time": 17, + "total_clean_area": 0, + "total_clean_time": 0, + "total_clean_count": 0, + } + +class DummyG1Vacuum(DummyMiotDevice, G1Vacuum): + def __init__(self, *args, **kwargs): + self.state = _INITIAL_STATE + super().__init__(*args, **kwargs) + + +@pytest.fixture(scope="function") +def dummyg1vacuum(request): + request.cls.device = DummyG1Vacuum() + + +@pytest.mark.usefixtures("dummyg1vacuum") +class TestG1Vacuum(TestCase): + def test_status(self): + status = self.device.status() + assert status.battery == _INITIAL_STATE["battery"] + assert status.error_code == _INITIAL_STATE["error_code"] + assert status.main_brush_time_left == _INITIAL_STATE["main_brush_time_left"] + assert status.side_brush_life_left == _INITIAL_STATE["side_brush_life_left"] + assert status.side_brush_life_level == _INITIAL_STATE["side_brush_life_level"] + assert status.main_brush_time_level == _INITIAL_STATE["main_brush_time_level"] + assert status.filter_left_time == _INITIAL_STATE["filter_left_time"] + assert status.filter_life_level == _INITIAL_STATE["filter_life_level"] + assert status.clean_area == _INITIAL_STATE["clean_area"] + assert status.clean_time == _INITIAL_STATE["clean_time"] + assert status.total_clean_area == _INITIAL_STATE["total_clean_area"] + assert status.total_clean_time == _INITIAL_STATE["total_clean_time"] + assert status.total_clean_count == _INITIAL_STATE["total_clean_count"] + assert status.charge_state == ChargingState(_INITIAL_STATE["charge_state"]) + assert repr(status.charge_state) == repr( + ChargingState(_INITIAL_STATE["charge_state"]) + ) + assert status.fan_speed == G1FanSpeed(_INITIAL_STATE["fan_speed"]) + assert repr(status.fan_speed) == repr( + G1FanSpeed(_INITIAL_STATE["fan_speed"]) + ) + assert status.state == G1State(_INITIAL_STATE["state"]) + assert repr(status.state) == repr( + G1State(_INITIAL_STATE["state"]) + ) + assert status.operating_mode == G1VacuumMode(_INITIAL_STATE["operating_mode"]) + assert repr(status.operating_mode) == repr( + G1VacuumMode(_INITIAL_STATE["operating_mode"]) + ) + assert status.mop_state == G1MopState(_INITIAL_STATE["mop_state"]) + assert repr(status.mop_state) == repr( + G1MopState(_INITIAL_STATE["mop_state"]) + ) + assert status.water_level == G1WaterLevel(_INITIAL_STATE["water_level"]) + assert repr(status.water_level) == repr( + G1WaterLevel(_INITIAL_STATE["water_level"]) + ) \ No newline at end of file From 1a7e7078f2236b0b76ed4489b798750a0047abc8 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 3 Aug 2021 18:49:27 +0200 Subject: [PATCH 25/30] Update test_g1vacuum.py --- miio/tests/test_g1vacuum.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py index 8c97970cd..e44834c08 100644 --- a/miio/tests/test_g1vacuum.py +++ b/miio/tests/test_g1vacuum.py @@ -36,7 +36,8 @@ "total_clean_area": 0, "total_clean_time": 0, "total_clean_count": 0, - } +} + class DummyG1Vacuum(DummyMiotDevice, G1Vacuum): def __init__(self, *args, **kwargs): @@ -71,21 +72,15 @@ def test_status(self): ChargingState(_INITIAL_STATE["charge_state"]) ) assert status.fan_speed == G1FanSpeed(_INITIAL_STATE["fan_speed"]) - assert repr(status.fan_speed) == repr( - G1FanSpeed(_INITIAL_STATE["fan_speed"]) - ) + assert repr(status.fan_speed) == repr(G1FanSpeed(_INITIAL_STATE["fan_speed"])) assert status.state == G1State(_INITIAL_STATE["state"]) - assert repr(status.state) == repr( - G1State(_INITIAL_STATE["state"]) - ) + assert repr(status.state) == repr(G1State(_INITIAL_STATE["state"])) assert status.operating_mode == G1VacuumMode(_INITIAL_STATE["operating_mode"]) assert repr(status.operating_mode) == repr( G1VacuumMode(_INITIAL_STATE["operating_mode"]) ) assert status.mop_state == G1MopState(_INITIAL_STATE["mop_state"]) - assert repr(status.mop_state) == repr( - G1MopState(_INITIAL_STATE["mop_state"]) - ) + assert repr(status.mop_state) == repr(G1MopState(_INITIAL_STATE["mop_state"])) assert status.water_level == G1WaterLevel(_INITIAL_STATE["water_level"]) assert repr(status.water_level) == repr( G1WaterLevel(_INITIAL_STATE["water_level"]) From f58a4b9bd56b52eee9134713b8c0696c8dd04c88 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Tue, 3 Aug 2021 21:05:46 +0200 Subject: [PATCH 26/30] Update test_g1vacuum.py --- miio/tests/test_g1vacuum.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py index e44834c08..6133438d1 100644 --- a/miio/tests/test_g1vacuum.py +++ b/miio/tests/test_g1vacuum.py @@ -67,9 +67,9 @@ def test_status(self): assert status.total_clean_area == _INITIAL_STATE["total_clean_area"] assert status.total_clean_time == _INITIAL_STATE["total_clean_time"] assert status.total_clean_count == _INITIAL_STATE["total_clean_count"] - assert status.charge_state == ChargingState(_INITIAL_STATE["charge_state"]) + assert status.charge_state == G1ChargeState(_INITIAL_STATE["charge_state"]) assert repr(status.charge_state) == repr( - ChargingState(_INITIAL_STATE["charge_state"]) + G1ChargeState(_INITIAL_STATE["charge_state"]) ) assert status.fan_speed == G1FanSpeed(_INITIAL_STATE["fan_speed"]) assert repr(status.fan_speed) == repr(G1FanSpeed(_INITIAL_STATE["fan_speed"])) @@ -84,4 +84,4 @@ def test_status(self): assert status.water_level == G1WaterLevel(_INITIAL_STATE["water_level"]) assert repr(status.water_level) == repr( G1WaterLevel(_INITIAL_STATE["water_level"]) - ) \ No newline at end of file + ) From e1f653da9ff75477b26decfae22544d20c9b9a2d Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Wed, 11 Aug 2021 19:04:41 +0200 Subject: [PATCH 27/30] Update test_g1vacuum.py --- miio/tests/test_g1vacuum.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py index 6133438d1..02f1748cd 100644 --- a/miio/tests/test_g1vacuum.py +++ b/miio/tests/test_g1vacuum.py @@ -7,7 +7,6 @@ G1ChargeState, G1FanSpeed, G1State, - G1Status, G1VacuumMode, G1MopState, G1WaterLevel, @@ -24,7 +23,6 @@ "operating_mode": G1VacuumMode.GlobalClean, "mop_state": G1MopState.Off, "water_level": G1WaterLevel.Level1, - "fan_speed": G1FanSpeed.Medium, "main_brush_time_left": 235, "main_brush_life_level": 85, "filter_life_level": 66, From a897001149208359d4f40a1e43f986ace2fb623a Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Wed, 11 Aug 2021 19:30:25 +0200 Subject: [PATCH 28/30] Update test_g1vacuum.py --- miio/tests/test_g1vacuum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py index 02f1748cd..af8877cdf 100644 --- a/miio/tests/test_g1vacuum.py +++ b/miio/tests/test_g1vacuum.py @@ -2,13 +2,13 @@ import pytest -from miio import G1Vacuum from miio.g1vacuum import ( G1ChargeState, G1FanSpeed, + G1MopState, G1State, + G1Vacuum, G1VacuumMode, - G1MopState, G1WaterLevel, ) From 71c7fbf7f579481b78be026ea1bda01c56b55c38 Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Wed, 11 Aug 2021 19:56:54 +0200 Subject: [PATCH 29/30] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 57c105412..cb43877a8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ __pycache__ .coverage docs/_build/ +.vscode/settings.json From 5f9445d0c8848bd326f03bd39bd9d96edd14984d Mon Sep 17 00:00:00 2001 From: neturmel <74895293+neturmel@users.noreply.github.com> Date: Thu, 2 Sep 2021 13:50:08 +0200 Subject: [PATCH 30/30] Delete test_g1vacuum.py Test removed --- miio/tests/test_g1vacuum.py | 85 ------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 miio/tests/test_g1vacuum.py diff --git a/miio/tests/test_g1vacuum.py b/miio/tests/test_g1vacuum.py deleted file mode 100644 index af8877cdf..000000000 --- a/miio/tests/test_g1vacuum.py +++ /dev/null @@ -1,85 +0,0 @@ -from unittest import TestCase - -import pytest - -from miio.g1vacuum import ( - G1ChargeState, - G1FanSpeed, - G1MopState, - G1State, - G1Vacuum, - G1VacuumMode, - G1WaterLevel, -) - -from .dummies import DummyMiotDevice - -_INITIAL_STATE = { - "battery_level": 42, - "charge_state": G1ChargeState.Charging, - "error_code": 0, - "state": G1State.Paused, - "fan_speed": G1FanSpeed.Medium, - "operating_mode": G1VacuumMode.GlobalClean, - "mop_state": G1MopState.Off, - "water_level": G1WaterLevel.Level1, - "main_brush_time_left": 235, - "main_brush_life_level": 85, - "filter_life_level": 66, - "filter_left_time": 154, - "side_brush_life_left": 187, - "side_brush_life_level": 57, - "clean_area": 12, - "clean_time": 17, - "total_clean_area": 0, - "total_clean_time": 0, - "total_clean_count": 0, -} - - -class DummyG1Vacuum(DummyMiotDevice, G1Vacuum): - def __init__(self, *args, **kwargs): - self.state = _INITIAL_STATE - super().__init__(*args, **kwargs) - - -@pytest.fixture(scope="function") -def dummyg1vacuum(request): - request.cls.device = DummyG1Vacuum() - - -@pytest.mark.usefixtures("dummyg1vacuum") -class TestG1Vacuum(TestCase): - def test_status(self): - status = self.device.status() - assert status.battery == _INITIAL_STATE["battery"] - assert status.error_code == _INITIAL_STATE["error_code"] - assert status.main_brush_time_left == _INITIAL_STATE["main_brush_time_left"] - assert status.side_brush_life_left == _INITIAL_STATE["side_brush_life_left"] - assert status.side_brush_life_level == _INITIAL_STATE["side_brush_life_level"] - assert status.main_brush_time_level == _INITIAL_STATE["main_brush_time_level"] - assert status.filter_left_time == _INITIAL_STATE["filter_left_time"] - assert status.filter_life_level == _INITIAL_STATE["filter_life_level"] - assert status.clean_area == _INITIAL_STATE["clean_area"] - assert status.clean_time == _INITIAL_STATE["clean_time"] - assert status.total_clean_area == _INITIAL_STATE["total_clean_area"] - assert status.total_clean_time == _INITIAL_STATE["total_clean_time"] - assert status.total_clean_count == _INITIAL_STATE["total_clean_count"] - assert status.charge_state == G1ChargeState(_INITIAL_STATE["charge_state"]) - assert repr(status.charge_state) == repr( - G1ChargeState(_INITIAL_STATE["charge_state"]) - ) - assert status.fan_speed == G1FanSpeed(_INITIAL_STATE["fan_speed"]) - assert repr(status.fan_speed) == repr(G1FanSpeed(_INITIAL_STATE["fan_speed"])) - assert status.state == G1State(_INITIAL_STATE["state"]) - assert repr(status.state) == repr(G1State(_INITIAL_STATE["state"])) - assert status.operating_mode == G1VacuumMode(_INITIAL_STATE["operating_mode"]) - assert repr(status.operating_mode) == repr( - G1VacuumMode(_INITIAL_STATE["operating_mode"]) - ) - assert status.mop_state == G1MopState(_INITIAL_STATE["mop_state"]) - assert repr(status.mop_state) == repr(G1MopState(_INITIAL_STATE["mop_state"])) - assert status.water_level == G1WaterLevel(_INITIAL_STATE["water_level"]) - assert repr(status.water_level) == repr( - G1WaterLevel(_INITIAL_STATE["water_level"]) - )