Skip to content

Commit def2514

Browse files
Merge pull request #10 from Lash-L/docks
Add Docking Information
2 parents 06f410f + ffaa839 commit def2514

File tree

5 files changed

+174
-29
lines changed

5 files changed

+174
-29
lines changed

roborock/api.py

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""The Roborock api."""
2+
23
from __future__ import annotations
34

45
import asyncio
@@ -23,9 +24,16 @@
2324
import paho.mqtt.client as mqtt
2425
from Crypto.Cipher import AES
2526
from Crypto.Util.Padding import pad, unpad
26-
from roborock.code_mappings import STATE_CODE_TO_STATUS
2727

28-
from roborock.containers import (
28+
from roborock.exceptions import (
29+
RoborockException,
30+
CommandVacuumError,
31+
VacuumError,
32+
RoborockTimeout,
33+
)
34+
from .code_mappings import STATE_CODE_TO_STATUS, WASH_MODE_MAP, DUST_COLLECTION_MAP, RoborockDockType, \
35+
RoborockDockDustCollectionType, RoborockDockWashingModeType
36+
from .containers import (
2937
UserData,
3038
HomeDataDevice,
3139
Status,
@@ -35,20 +43,17 @@
3543
CleanRecord,
3644
HomeData,
3745
MultiMapsList,
46+
SmartWashParameters,
47+
3848
)
39-
from roborock.exceptions import (
40-
RoborockException,
41-
CommandVacuumError,
42-
VacuumError,
43-
RoborockTimeout,
44-
)
45-
from roborock.roborock_queue import RoborockQueue
46-
from roborock.typing import (
49+
from .roborock_queue import RoborockQueue
50+
from .typing import (
4751
RoborockDeviceInfo,
4852
RoborockDeviceProp,
4953
RoborockCommand,
54+
RoborockDockSummary,
5055
)
51-
from roborock.util import run_in_executor
56+
from .util import run_in_executor
5257

5358
_LOGGER = logging.getLogger(__name__)
5459
QUEUE_TIMEOUT = 4
@@ -78,17 +83,17 @@ def __init__(self, base_url: str, base_headers: dict = None) -> None:
7883
self.base_headers = base_headers or {}
7984

8085
async def request(
81-
self, method: str, url: str, params=None, data=None, headers=None
86+
self, method: str, url: str, params=None, data=None, headers=None
8287
) -> dict | list:
8388
_url = "/".join(s.strip("/") for s in [self.base_url, url])
8489
_headers = {**self.base_headers, **(headers or {})}
8590
async with aiohttp.ClientSession() as session:
8691
async with session.request(
87-
method,
88-
_url,
89-
params=params,
90-
data=data,
91-
headers=_headers,
92+
method,
93+
_url,
94+
params=params,
95+
data=data,
96+
headers=_headers,
9297
) as resp:
9398
return await resp.json()
9499

@@ -369,7 +374,7 @@ def _send_msg_raw(self, device_id, protocol, timestamp, payload) -> None:
369374
raise RoborockException(f"Failed to publish (rc: {info.rc})")
370375

371376
async def send_command(
372-
self, device_id: str, method: RoborockCommand, params: list = None
377+
self, device_id: str, method: RoborockCommand, params: list = None
373378
):
374379
await self.validate_connection()
375380
timestamp = math.floor(time.time())
@@ -439,6 +444,29 @@ async def get_consumable(self, device_id: str) -> Consumable:
439444
if isinstance(consumable, dict):
440445
return Consumable(consumable)
441446

447+
async def get_washing_mode(self, device_id: str) -> RoborockDockWashingModeType:
448+
washing_mode = await self.send_command(device_id, RoborockCommand.GET_WASH_TOWEL_MODE)
449+
return WASH_MODE_MAP.get(washing_mode)
450+
451+
async def get_dust_collection_mode(self, device_id: str) -> RoborockDockDustCollectionType:
452+
dust_collection = await self.send_command(device_id, RoborockCommand.GET_DUST_COLLECTION_MODE)
453+
return DUST_COLLECTION_MAP.get(dust_collection)
454+
455+
async def get_mop_wash_mode(self, device_id: str) -> SmartWashParameters:
456+
mop_wash_mode = await self.send_command(device_id, RoborockCommand.GET_SMART_WASH_PARAMS)
457+
if isinstance(mop_wash_mode, dict):
458+
return SmartWashParameters(mop_wash_mode)
459+
460+
async def get_dock_summary(self, device_id: str, dock_type: RoborockDockType) -> RoborockDockSummary:
461+
collection_mode = await self.get_dust_collection_mode(device_id)
462+
mop_wash = None
463+
washing_mode = None
464+
if dock_type == RoborockDockType.EMPTY_WASH_FILL_DOCK:
465+
[mop_wash, washing_mode] = await asyncio.gather(
466+
*[self.get_mop_wash_mode(device_id), self.get_washing_mode(device_id)])
467+
468+
return RoborockDockSummary(collection_mode, washing_mode, mop_wash)
469+
442470
async def get_prop(self, device_id: str) -> RoborockDeviceProp:
443471
[status, dnd_timer, clean_summary, consumable] = await asyncio.gather(
444472
*[
@@ -453,9 +481,12 @@ async def get_prop(self, device_id: str) -> RoborockDeviceProp:
453481
last_clean_record = await self.get_clean_record(
454482
device_id, clean_summary.records[0]
455483
)
484+
dock_summary = None
485+
if status.dock_type != RoborockDockType.NO_DOCK:
486+
dock_summary = await self.get_dock_summary(device_id, status.dock_type)
456487
if any([status, dnd_timer, clean_summary, consumable]):
457488
return RoborockDeviceProp(
458-
status, dnd_timer, clean_summary, consumable, last_clean_record
489+
status, dnd_timer, clean_summary, consumable, last_clean_record, dock_summary
459490
)
460491

461492
async def get_multi_maps_list(self, device_id) -> MultiMapsList:

roborock/code_mappings.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
11
from __future__ import annotations
22

3+
from enum import Enum
34
from typing import Any
45

6+
7+
class RoborockDockType(str, Enum):
8+
NO_DOCK = "No dock"
9+
AUTO_EMPTY = "Roborock auto-empty dock" # Dust collection
10+
EMPTY_WASH_FILL_DOCK = "Roborock empty wash fill dock"
11+
AUTO_EMPTY_PURE = "Roborock auto-empty pure dock"
12+
UNKNOWN = "Unknown Dock - please submit an issue"
13+
14+
15+
class RoborockDockDustCollectionType(str, Enum):
16+
SMART = "smart"
17+
QUICK = "quick"
18+
DAILY = "daily"
19+
STRONG = "strong"
20+
MAX = "max"
21+
22+
23+
class RoborockDockWashingModeType(str, Enum):
24+
LIGHT = "light"
25+
BALANCED = "balanced"
26+
DEEP = "deep"
27+
28+
529
STATE_CODE_TO_STATUS: dict[int | Any, str | Any] = {
630
1: "starting",
731
2: "charger_disconnected",
@@ -82,3 +106,28 @@
82106
203: "intense",
83107
204: "custom",
84108
}
109+
110+
DOCK_ERROR_TO_TEXT = {
111+
0: "ok",
112+
38: 'water empty',
113+
39: 'waste water tank full',
114+
}
115+
116+
DOCK_TYPE_MAP = {
117+
0: RoborockDockType.NO_DOCK,
118+
3: RoborockDockType.EMPTY_WASH_FILL_DOCK,
119+
}
120+
121+
DUST_COLLECTION_MAP = {
122+
0: RoborockDockDustCollectionType.SMART,
123+
1: RoborockDockDustCollectionType.QUICK,
124+
2: RoborockDockDustCollectionType.DAILY,
125+
3: RoborockDockDustCollectionType.STRONG,
126+
4: RoborockDockDustCollectionType.MAX,
127+
}
128+
129+
WASH_MODE_MAP = {
130+
0: RoborockDockWashingModeType.LIGHT,
131+
1: RoborockDockWashingModeType.BALANCED,
132+
2: RoborockDockWashingModeType.DEEP,
133+
}

roborock/containers.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from enum import Enum
22

3-
from roborock.code_mappings import STATE_CODE_TO_STATUS, ERROR_CODE_TO_TEXT, FAN_SPEED_CODES, MOP_MODE_CODES, \
4-
MOP_INTENSITY_CODES
3+
from .code_mappings import STATE_CODE_TO_STATUS, ERROR_CODE_TO_TEXT, FAN_SPEED_CODES, MOP_MODE_CODES, \
4+
MOP_INTENSITY_CODES, DOCK_ERROR_TO_TEXT, DOCK_TYPE_MAP, RoborockDockType
55

66

77
class UserDataRRiotReferenceField(str, Enum):
@@ -220,6 +220,15 @@ class MultiMapListField(str, Enum):
220220
MAP_INFO = "map_info"
221221

222222

223+
class SmartWashField(str, Enum):
224+
SMART_WASH = "smart_wash"
225+
WASH_INTERVAL = "wash_interval"
226+
227+
228+
class WashTowelField(str, Enum):
229+
Wash_MODE = "wash_mode"
230+
231+
223232
class RoborockBase(dict):
224233
def __init__(self, data: dict[str, any]) -> None:
225234
super().__init__()
@@ -761,9 +770,13 @@ def water_shortage_status(self) -> int:
761770
return self.get(StatusField.WATER_SHORTAGE_STATUS)
762771

763772
@property
764-
def dock_type(self) -> int:
773+
def dock_type_code(self) -> int:
765774
return self.get(StatusField.DOCK_TYPE)
766775

776+
@property
777+
def dock_type(self) -> RoborockDockType:
778+
return DOCK_TYPE_MAP.get(self.get(StatusField.DOCK_TYPE), RoborockDockType.UNKNOWN)
779+
767780
@property
768781
def dust_collection_status(self) -> int:
769782
return self.get(StatusField.DUST_COLLECTION_STATUS)
@@ -797,9 +810,13 @@ def switch_map_mode(self) -> int:
797810
return self.get(StatusField.SWITCH_MAP_MODE)
798811

799812
@property
800-
def dock_error_status(self) -> int:
813+
def dock_error_status_code(self) -> int:
801814
return self.get(StatusField.DOCK_ERROR_STATUS)
802815

816+
@property
817+
def dock_error_status(self) -> str:
818+
return DOCK_ERROR_TO_TEXT.get(self.get(StatusField.DOCK_ERROR_STATUS))
819+
803820
@property
804821
def charge_status(self) -> int:
805822
return self.get(StatusField.CHARGE_STATUS)
@@ -1014,3 +1031,16 @@ def multi_map_count(self) -> int:
10141031
@property
10151032
def map_info(self) -> list[MultiMapsListMapInfo]:
10161033
return [MultiMapsListMapInfo(map_info) for map_info in self.get(MultiMapListField.MAP_INFO)]
1034+
1035+
1036+
class SmartWashParameters(RoborockBase):
1037+
def __init__(self, data: dict[str, any]) -> None:
1038+
super().__init__(data)
1039+
1040+
@property
1041+
def smart_wash(self) -> int:
1042+
return self.get(SmartWashField.SMART_WASH)
1043+
1044+
@property
1045+
def wash_interval(self) -> int:
1046+
return self.get(SmartWashField.WASH_INTERVAL)

roborock/typing.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from enum import Enum
22

3-
from roborock.containers import HomeDataDevice, HomeDataProduct, Status, CleanSummary, Consumable, \
4-
DNDTimer, CleanRecord
3+
from .code_mappings import RoborockDockDustCollectionType, RoborockDockWashingModeType
4+
from .containers import HomeDataDevice, HomeDataProduct, Status, CleanSummary, Consumable, \
5+
DNDTimer, CleanRecord, SmartWashParameters
56

67

78
class RoborockDevicePropField(str, Enum):
@@ -10,6 +11,14 @@ class RoborockDevicePropField(str, Enum):
1011
CLEAN_SUMMARY = "clean_summary"
1112
CONSUMABLE = "consumable"
1213
LAST_CLEAN_RECORD = "last_clean_record"
14+
DOCK_SUMMARY = "dock_summary"
15+
16+
17+
class RoborockDockSummaryField(str, Enum):
18+
DUST_COLLECTION_MODE = "dust_collection_mode"
19+
WASHING_MODE_TYPE = "washing_mode_type"
20+
MOP_WASH = "mop_wash"
21+
1322

1423
class RoborockCommand(str, Enum):
1524
GET_MAP_V1 = "get_map_v1",
@@ -38,6 +47,19 @@ class RoborockCommand(str, Enum):
3847
APP_GOTO_TARGET = "app_goto_target",
3948
APP_SEGMENT_CLEAN = "app_segment_clean",
4049
APP_ZONED_CLEAN = "app_zoned_clean",
50+
APP_GET_DRYER_SETTING = "app_get_dryer_setting"
51+
APP_SET_DRYER_SETTING = "app_set_dryer_setting"
52+
APP_START_WASH = "app_start_wash"
53+
APP_STOP_WASH = "app_stop_wash"
54+
GET_DUST_COLLECTION_MODE = "get_dust_collection_mode"
55+
SET_DUST_COLLECTION_MODE = "set_dust_collection_mode"
56+
GET_SMART_WASH_PARAMS = "get_smart_wash_params"
57+
SET_SMART_WASH_PARAMS = "set_smart_wash_params"
58+
GET_WASH_TOWEL_MODE = "get_wash_towel_mode"
59+
SET_WASH_TOWEL_MODE = "set_wash_towel_mode"
60+
SET_CHILD_LOCK_STATUS = "set_child_lock_status"
61+
GET_CHILD_LOCK_STATUS = "get_child_lock_status"
62+
START_WASH_THEN_CHARGE = "start_wash_then_charge"
4163

4264

4365
class RoborockDeviceInfo:
@@ -46,14 +68,23 @@ def __init__(self, device: HomeDataDevice, product: HomeDataProduct):
4668
self.product = product
4769

4870

71+
class RoborockDockSummary:
72+
def __init__(self, dust_collection_mode: RoborockDockDustCollectionType,
73+
washing_mode_type: RoborockDockWashingModeType, mop_wash: SmartWashParameters) -> None:
74+
self.dust_collection_mode = dust_collection_mode
75+
self.washing_mode_type = washing_mode_type
76+
self.mop_wash = mop_wash
77+
78+
4979
class RoborockDeviceProp:
5080
def __init__(self, status: Status, dnd_timer: DNDTimer, clean_summary: CleanSummary, consumable: Consumable,
51-
last_clean_record: CleanRecord):
81+
last_clean_record: CleanRecord, dock_summary: RoborockDockSummary):
5282
self.status = status
5383
self.dnd_timer = dnd_timer
5484
self.clean_summary = clean_summary
5585
self.consumable = consumable
5686
self.last_clean_record = last_clean_record
87+
self.dock_summary = dock_summary
5788

5889
def update(self, device_prop: 'RoborockDeviceProp'):
5990
if device_prop.status:
@@ -66,3 +97,5 @@ def update(self, device_prop: 'RoborockDeviceProp'):
6697
self.consumable = device_prop.consumable
6798
if device_prop.last_clean_record:
6899
self.last_clean_record = device_prop.last_clean_record
100+
if device_prop.dock_summary:
101+
self.dock_summary = device_prop.dock_summary

tests/test_containers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from roborock import UserData, HomeData, Consumable, Status, DNDTimer, CleanSummary, CleanRecord
1+
from roborock import UserData, HomeData, Consumable, Status, DNDTimer, CleanSummary, CleanRecord, RoborockDockType
22
from .mock_data import USER_DATA, HOME_DATA_RAW, CONSUMABLE, STATUS, DND_TIMER, CLEAN_SUMMARY, CLEAN_RECORD
33

44

@@ -124,7 +124,8 @@ def test_status():
124124
assert s.home_sec_enable_password == 0
125125
assert s.adbumper_status == [0, 0, 0]
126126
assert s.water_shortage_status == 0
127-
assert s.dock_type == 3
127+
assert s.dock_type_code == 3
128+
assert s.dock_type == RoborockDockType.EMPTY_WASH_FILL_DOCK
128129
assert s.dust_collection_status == 0
129130
assert s.auto_dust_collection == 1
130131
assert s.avoid_count == 19
@@ -133,7 +134,8 @@ def test_status():
133134
assert s.debug_mode == 0
134135
assert s.collision_avoid_status == 1
135136
assert s.switch_map_mode == 0
136-
assert s.dock_error_status == 0
137+
assert s.dock_error_status_code == 0
138+
assert s.dock_error_status == "ok"
137139
assert s.charge_status == 1
138140
assert s.unsave_map_reason == 0
139141
assert s.unsave_map_flag == 0

0 commit comments

Comments
 (0)