-
-
Notifications
You must be signed in to change notification settings - Fork 572
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Update dreamevacuum_miot.py with Xaiomi X10 #1924
base: master
Are you sure you want to change the base?
Changes from 6 commits
c6ad2e0
0e9be5e
ba2e99b
4761561
62818fb
f5aaca0
486e929
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
DREAME_MOP_2 = "dreame.vacuum.p2150o" | ||
DREAME_TROUVER_FINDER = "dreame.vacuum.p2036" | ||
DREAME_D10_PLUS = "dreame.vacuum.r2205" | ||
DREAME_X10_MOP = "dreame.vacuum.r2209" | ||
|
||
_DREAME_1C_MAPPING: MiotMapping = { | ||
# https://home.miot-spec.com/spec/dreame.vacuum.mc1808 | ||
|
@@ -164,6 +165,55 @@ | |
"play_sound": {"siid": 7, "aiid": 2}, | ||
} | ||
|
||
_DREAME_X10_MOP_MAPPING: MiotMapping = { | ||
# https://home.miot-spec.com/spec/dreame.vacuum.r2209 | ||
"battery_level": {"siid": 3, "piid": 1}, | ||
"charging_state": {"siid": 3, "piid": 2}, | ||
"device_fault": {"siid": 2, "piid": 2}, | ||
"device_status": {"siid": 2, "piid": 1}, | ||
"brush_left_time": {"siid": 9, "piid": 1}, | ||
"brush_life_level": {"siid": 9, "piid": 2}, | ||
"brush_left_time2": {"siid": 10, "piid": 1}, | ||
"brush_life_level2": {"siid": 10, "piid": 2}, | ||
"filter_life_level": {"siid": 11, "piid": 1}, | ||
"filter_left_time": {"siid": 11, "piid": 2}, | ||
"sensor_life_level": {"siid": 16, "piid": 1}, | ||
"sensor_left_time": {"siid": 16, "piid": 2}, | ||
"operating_mode": {"siid": 4, "piid": 1}, # work-mode | ||
"cleaning_mode": {"siid": 4, "piid": 4}, | ||
"delete_timer": {"siid": 8, "aiid": 1}, | ||
"timer_enable": {"siid": 5, "piid": 1}, # do-not-disturb -> enable | ||
"cleaning_time": {"siid": 4, "piid": 2}, | ||
"cleaning_area": {"siid": 4, "piid": 3}, | ||
"first_clean_time": {"siid": 12, "piid": 1}, | ||
"total_clean_time": {"siid": 12, "piid": 2}, | ||
"total_clean_times": {"siid": 12, "piid": 3}, | ||
"total_clean_area": {"siid": 12, "piid": 4}, | ||
"start_time": {"siid": 5, "piid": 2}, | ||
"stop_time": {"siid": 5, "piid": 3}, # end-time | ||
"map_view": {"siid": 6, "piid": 1}, # map-data | ||
"frame_info": {"siid": 6, "piid": 2}, | ||
"volume": {"siid": 7, "piid": 1}, | ||
"voice_package": {"siid": 7, "piid": 2}, # voice-packet-id | ||
"water_flow": {"siid": 4, "piid": 5}, # mop-mode | ||
"water_box_carriage_status": {"siid": 4, "piid": 6}, # waterbox-status | ||
"dust_auto_collect": {"siid": 15, "piid": 1}, # auto-collect-dust | ||
"dust_collect_every": {"siid": 15, "piid": 2}, # Collect dust every n-th cleaing | ||
"timezone": {"siid": 8, "piid": 1}, # time-zone | ||
"home": {"siid": 3, "aiid": 1}, # start-charge | ||
"locate": {"siid": 7, "aiid": 1}, # audio -> position | ||
"start_clean": {"siid": 4, "aiid": 1}, | ||
"stop_clean": {"siid": 4, "aiid": 2}, | ||
"start_room_sweap": {"siid": 4, "aiid": 1}, | ||
"reset_mainbrush_life": {"siid": 9, "aiid": 1}, | ||
"reset_filter_life": {"siid": 11, "aiid": 1}, | ||
"reset_sidebrush_life": {"siid": 10, "aiid": 1}, | ||
"reset_sensor_life": {"siid": 16, "aiid": 1}, | ||
"start_dust_collect": {"siid": 15, "aiid": 1}, | ||
"move": {"siid": 21, "aiid": 1}, # not in documentation | ||
"play_sound": {"siid": 7, "aiid": 2}, | ||
} | ||
|
||
MIOT_MAPPING: Dict[str, MiotMapping] = { | ||
DREAME_1C: _DREAME_1C_MAPPING, | ||
DREAME_F9: _DREAME_F9_MAPPING, | ||
|
@@ -176,6 +226,7 @@ | |
DREAME_MOP_2: _DREAME_F9_MAPPING, | ||
DREAME_TROUVER_FINDER: _DREAME_TROUVER_FINDER_MAPPING, | ||
DREAME_D10_PLUS: _DREAME_TROUVER_FINDER_MAPPING, | ||
DREAME_X10_MOP: _DREAME_X10_MOP_MAPPING, | ||
} | ||
|
||
|
||
|
@@ -213,6 +264,7 @@ | |
ManualCleaning = 13 | ||
Sleeping = 14 | ||
ManualPaused = 17 | ||
RoomCleaning = 18 | ||
ZonedCleaning = 19 | ||
|
||
|
||
|
@@ -237,16 +289,42 @@ | |
Upgrading = 14 | ||
|
||
|
||
class DeviceStatusX10(FormattableEnum): | ||
Sweeping = 1 | ||
Idle = 2 | ||
Paused = 3 | ||
Error = 4 | ||
GoCharging = 5 | ||
Charging = 6 | ||
SweepingAndMopping = 7 | ||
Building = 11 | ||
Mopping = 12 | ||
ChargingComplete = 13 | ||
|
||
|
||
class WaterFlow(FormattableEnum): | ||
Low = 1 | ||
Medium = 2 | ||
High = 3 | ||
|
||
|
||
class DustAutoCollect(FormattableEnum): | ||
Off = 0 | ||
On = 1 | ||
|
||
|
||
def _enum_as_dict(cls): | ||
return {x.name: x.value for x in list(cls)} | ||
|
||
|
||
def _get_device_status_enum_class(model): | ||
"""Return device status enum class for model""" | ||
if model == DREAME_X10_MOP: | ||
return DeviceStatusX10 | ||
else: | ||
return DeviceStatus | ||
|
||
|
||
def _get_cleaning_mode_enum_class(model): | ||
"""Return cleaning mode enum class for model if found or None.""" | ||
if model == DREAME_1C: | ||
|
@@ -261,6 +339,7 @@ | |
DREAME_MOP_2_ULTRA, | ||
DREAME_MOP_2, | ||
DREAME_TROUVER_FINDER, | ||
DREAME_X10_MOP, | ||
): | ||
return CleaningModeDreameF9 | ||
return None | ||
|
@@ -333,6 +412,14 @@ | |
def filter_life_level(self) -> str: | ||
return self.data["filter_life_level"] | ||
|
||
@property | ||
def sensor_left_time(self) -> str: | ||
return self.data["sensor_left_time"] | ||
|
||
@property | ||
def sensor_life_level(self) -> str: | ||
return self.data["sensor_life_level"] | ||
|
||
@property | ||
def device_fault(self) -> Optional[FaultStatus]: | ||
try: | ||
|
@@ -358,11 +445,17 @@ | |
return None | ||
|
||
@property | ||
def device_status(self) -> Optional[DeviceStatus]: | ||
def device_status(self): | ||
device_status = self.data["device_status"] | ||
device_status_enum_class = _get_device_status_enum_class(self.model) | ||
|
||
if not device_status_enum_class: | ||
_LOGGER.error(f"Unknown model for device status ({self.model})") | ||
return None | ||
try: | ||
return DeviceStatus(self.data["device_status"]) | ||
except TypeError: | ||
_LOGGER.error("Unknown DeviceStatus (%s)", self.data["device_status"]) | ||
return device_status_enum_class(device_status) | ||
except ValueError: | ||
_LOGGER.error(f"Unknown DeviceStatus ({device_status})") | ||
return None | ||
|
||
@property | ||
|
@@ -444,6 +537,7 @@ | |
return self.data.get("life_brush_main") | ||
|
||
# TODO: get/set water flow for Dreame 1C | ||
|
||
@property | ||
def water_flow(self) -> Optional[WaterFlow]: | ||
try: | ||
|
@@ -464,6 +558,24 @@ | |
return self.data["water_box_carriage_status"] == 1 | ||
return None | ||
|
||
@property | ||
def dust_auto_collect(self) -> Optional[DustAutoCollect]: | ||
try: | ||
dust_auto_collect = self.data["dust_auto_collect"] | ||
except KeyError: | ||
return None | ||
try: | ||
return DustAutoCollect(dust_auto_collect) | ||
except ValueError: | ||
_LOGGER.error( | ||
"Unknown DustAutoCollect (%s)", self.data["dust_auto_collect"] | ||
) | ||
return None | ||
|
||
@property | ||
def dust_collect_every(self) -> str: | ||
return self.data["dust_collect_every"] | ||
|
||
|
||
class DreameVacuum(MiotDevice): | ||
_mappings = MIOT_MAPPING | ||
|
@@ -480,6 +592,8 @@ | |
"Device status: {result.device_status}\n" | ||
"Filter left level: {result.filter_left_time}\n" | ||
"Filter life level: {result.filter_life_level}\n" | ||
"Sensor left level: {result.sensor_left_time}\n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add descriptors to the status class(es) ( This makes them visible for the cli and the future homeassistant integration (https://github.com/rytilahti/homeassistant-xiaomi-ng) when it's all done across the library. |
||
"Sensor life level: {result.sensor_life_level}\n" | ||
"Life brush main: {result.life_brush_main}\n" | ||
"Life brush side: {result.life_brush_side}\n" | ||
"Life sieve: {result.life_sieve}\n" | ||
|
@@ -495,6 +609,8 @@ | |
"Volume: {result.volume}\n" | ||
"Water flow: {result.water_flow}\n" | ||
"Water box attached: {result.is_water_box_carriage_attached} \n" | ||
"Dust auto collect: {result.dust_auto_collect}\n" | ||
"Dust collect every n-th cleaning: {result.dust_collect_every} \n" | ||
"Cleaning time: {result.cleaning_time}\n" | ||
"Cleaning area: {result.cleaning_area}\n" | ||
"First clean time: {result.first_clean_time}\n" | ||
|
@@ -515,6 +631,7 @@ | |
) | ||
|
||
# TODO: check the actual limit for this | ||
|
||
MANUAL_ROTATION_MAX = 120 | ||
MANUAL_ROTATION_MIN = -MANUAL_ROTATION_MAX | ||
MANUAL_DISTANCE_MAX = 300 | ||
|
@@ -555,6 +672,16 @@ | |
"""Reset side brush life.""" | ||
return self.call_action_from_mapping("reset_sidebrush_life") | ||
|
||
@command() | ||
def reset_sensor_life(self) -> None: | ||
"""Reset sensor life.""" | ||
return self.call_action_from_mapping("reset_sensor_life") | ||
|
||
@command() | ||
def start_dust_collect(self) -> None: | ||
"""Start dust collect""" | ||
return self.call_action_from_mapping("start_dust_collect") | ||
|
||
@command() | ||
def play_sound(self) -> None: | ||
"""Play sound.""" | ||
|
@@ -692,6 +819,36 @@ | |
], | ||
) | ||
|
||
@command( | ||
click.argument("room", default=3, type=int), | ||
click.argument("clean_mode", default=1, type=int), | ||
) | ||
def start_room_sweap(self, room: int, clean_mode: int) -> None: | ||
"""Start room cleaning.""" | ||
|
||
cleaningmode_enum = _get_cleaning_mode_enum_class(self.model) | ||
cleaningmode = None | ||
if not cleaningmode_enum: | ||
return | ||
try: | ||
cleaningmode = cleaningmode_enum(clean_mode) | ||
except ValueError: | ||
_LOGGER.error(f"Unknown cleaning mode value passed {clean_mode}") | ||
return None | ||
self.call_action_from_mapping( | ||
"start_room_sweap", | ||
[ | ||
{ | ||
"piid": 1, | ||
"value": 18, | ||
}, | ||
{ | ||
"piid": 10, | ||
"value": f"\u007b\u0022selects\u0022:[[{room},1,{cleaningmode.value},3,1]]\u007d", | ||
}, | ||
], | ||
) | ||
|
||
@command( | ||
click.argument("url", type=str), | ||
click.argument("md5sum", type=str, required=False), | ||
|
@@ -724,7 +881,6 @@ | |
t = threading.Thread(target=server.serve_once) | ||
t.start() | ||
click.echo(f"Hosting file at {local_url}") | ||
|
||
params = [ | ||
{"piid": 3, "value": voice_id}, | ||
{"piid": 4, "value": local_url}, | ||
|
@@ -734,5 +890,4 @@ | |
result_status = self.call_action_from_mapping("set_voice", params=params) | ||
if result_status["code"] == 0: | ||
click.echo("Installation complete!") | ||
|
||
return result_status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use boolean instead.