python-roborock 0.4.9__tar.gz → 0.4.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-roborock
3
- Version: 0.4.9
3
+ Version: 0.4.11
4
4
  Summary:
5
5
  License: GPL-3.0-only
6
6
  Author: humbertogontijo
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-roborock"
3
- version = "0.4.9"
3
+ version = "0.4.11"
4
4
  description = ""
5
5
  authors = ["humbertogontijo <humbertogontijo@users.noreply.github.com>"]
6
6
  license = "GPL-3.0-only"
@@ -35,14 +35,14 @@ from .containers import (
35
35
  HomeData,
36
36
  MultiMapsList,
37
37
  SmartWashParameters,
38
+ RoborockDeviceInfo,
38
39
 
39
40
  )
40
41
  from .roborock_queue import RoborockQueue
41
42
  from .typing import (
42
43
  RoborockDeviceProp,
43
44
  RoborockCommand,
44
- RoborockDockSummary,
45
- RoborockDeviceInfo,
45
+ RoborockDockSummary
46
46
  )
47
47
 
48
48
  _LOGGER = logging.getLogger(__name__)
@@ -147,7 +147,7 @@ class RoborockClient:
147
147
  }
148
148
 
149
149
  def _encode_msg(self, device_id, request_id, protocol, timestamp, payload, prefix=None) -> bytes:
150
- local_key = self.devices_info[device_id].local_key
150
+ local_key = self.devices_info[device_id].device.local_key
151
151
  aes_key = md5bin(encode_timestamp(timestamp) + local_key + self._salt)
152
152
  cipher = AES.new(aes_key, AES.MODE_ECB)
153
153
  encrypted = cipher.encrypt(pad(payload, AES.block_size))
@@ -173,7 +173,7 @@ class RoborockClient:
173
173
 
174
174
  async def on_message(self, device_id, msg) -> bool:
175
175
  try:
176
- data = self._decode_msg(msg, self.devices_info[device_id].local_key)
176
+ data = self._decode_msg(msg, self.devices_info[device_id].device.local_key)
177
177
  protocol = data.get("protocol")
178
178
  if protocol == 102 or protocol == 4:
179
179
  payload = json.loads(data.get("payload").decode())
@@ -371,11 +371,14 @@ class RoborockClient:
371
371
  )
372
372
 
373
373
  async def get_multi_maps_list(self, device_id) -> MultiMapsList:
374
- multi_maps_list = await self.send_command(
375
- device_id, RoborockCommand.GET_MULTI_MAPS_LIST
376
- )
377
- if isinstance(multi_maps_list, dict):
378
- return MultiMapsList(multi_maps_list)
374
+ try:
375
+ multi_maps_list = await self.send_command(
376
+ device_id, RoborockCommand.GET_MULTI_MAPS_LIST
377
+ )
378
+ if isinstance(multi_maps_list, dict):
379
+ return MultiMapsList(multi_maps_list)
380
+ except RoborockTimeout as e:
381
+ _LOGGER.error(e)
379
382
 
380
383
  async def get_map_v1(self, device_id):
381
384
  return await self.send_command(device_id, RoborockCommand.GET_MAP_V1)
@@ -8,7 +8,7 @@ import click
8
8
  from roborock import RoborockException
9
9
  from roborock.api import RoborockApiClient
10
10
  from roborock.cloud_api import RoborockMqttClient
11
- from roborock.containers import LoginData
11
+ from roborock.containers import LoginData, RoborockDeviceInfo
12
12
  from roborock.util import run_sync
13
13
 
14
14
  _LOGGER = logging.getLogger(__name__)
@@ -116,9 +116,9 @@ async def command(ctx, cmd, params):
116
116
  await _discover(ctx)
117
117
  login_data = context.login_data()
118
118
  home_data = login_data.home_data
119
- device_map: dict[str, str] = {}
119
+ device_map: dict[str, RoborockDeviceInfo] = {}
120
120
  for device in home_data.devices + home_data.received_devices:
121
- device_map[device.duid] = device.local_key
121
+ device_map[device.duid] = RoborockDeviceInfo({"device": device})
122
122
  mqtt_client = RoborockMqttClient(login_data.user_data, device_map)
123
123
  await mqtt_client.send_command(home_data.devices[0].duid, cmd, params)
124
124
  mqtt_client.__del__()
@@ -9,9 +9,9 @@ from typing import Any
9
9
  from urllib.parse import urlparse
10
10
 
11
11
  import paho.mqtt.client as mqtt
12
- from roborock.code_mappings import RoborockDockType
13
12
 
14
13
  from roborock.api import md5hex, md5bin, RoborockClient, SPECIAL_COMMANDS
14
+ from roborock.code_mappings import RoborockDockType
15
15
  from roborock.exceptions import (
16
16
  RoborockException,
17
17
  CommandVacuumError,
@@ -19,10 +19,11 @@ from roborock.exceptions import (
19
19
  )
20
20
  from .containers import (
21
21
  UserData,
22
+ RoborockDeviceInfo,
22
23
  )
23
24
  from .roborock_queue import RoborockQueue
24
25
  from .typing import (
25
- RoborockCommand, RoborockDeviceProp, RoborockDeviceInfo,
26
+ RoborockCommand, RoborockDeviceProp,
26
27
  )
27
28
  from .util import run_in_executor
28
29
 
@@ -237,6 +237,15 @@ class NetworkInfoField(str, Enum):
237
237
  RSSI = "rssi"
238
238
 
239
239
 
240
+ class RoborockDeviceInfoField(str, Enum):
241
+ DEVICE = "device"
242
+ PRODUCT = "product"
243
+
244
+
245
+ class RoborockLocalDeviceInfoField(str, Enum):
246
+ NETWORK_INFO = "network_info"
247
+
248
+
240
249
  class RoborockBase(dict):
241
250
  def __init__(self, data: dict[str, any]) -> None:
242
251
  super().__init__()
@@ -248,8 +257,6 @@ class RoborockBase(dict):
248
257
 
249
258
 
250
259
  class Reference(RoborockBase):
251
- def __init__(self, data: dict[str, any]) -> None:
252
- super().__init__(data)
253
260
 
254
261
  @property
255
262
  def region(self) -> str:
@@ -269,8 +276,6 @@ class Reference(RoborockBase):
269
276
 
270
277
 
271
278
  class RRiot(RoborockBase):
272
- def __init__(self, data: dict[str, any]) -> None:
273
- super().__init__(data)
274
279
 
275
280
  @property
276
281
  def user(self) -> str:
@@ -294,8 +299,6 @@ class RRiot(RoborockBase):
294
299
 
295
300
 
296
301
  class UserData(RoborockBase):
297
- def __init__(self, data: dict[str, any]) -> None:
298
- super().__init__(data)
299
302
 
300
303
  @property
301
304
  def uid(self) -> int:
@@ -343,8 +346,6 @@ class UserData(RoborockBase):
343
346
 
344
347
 
345
348
  class LoginData(RoborockBase):
346
- def __init__(self, data: dict[str, any]) -> None:
347
- super().__init__(data)
348
349
 
349
350
  @property
350
351
  def user_data(self) -> UserData:
@@ -364,8 +365,6 @@ class LoginData(RoborockBase):
364
365
 
365
366
 
366
367
  class HomeDataProductSchema(RoborockBase):
367
- def __init__(self, data: dict[str, any]) -> None:
368
- super().__init__(data)
369
368
 
370
369
  @property
371
370
  def id(self):
@@ -397,8 +396,6 @@ class HomeDataProductSchema(RoborockBase):
397
396
 
398
397
 
399
398
  class HomeDataProduct(RoborockBase):
400
- def __init__(self, data: dict[str, any]) -> None:
401
- super().__init__(data)
402
399
 
403
400
  @property
404
401
  def id(self) -> str:
@@ -438,8 +435,6 @@ class HomeDataProduct(RoborockBase):
438
435
 
439
436
 
440
437
  class HomeDataDeviceStatus(RoborockBase):
441
- def __init__(self, data: dict[str, any]) -> None:
442
- super().__init__(data)
443
438
 
444
439
  @property
445
440
  def id(self):
@@ -479,8 +474,6 @@ class HomeDataDeviceStatus(RoborockBase):
479
474
 
480
475
 
481
476
  class HomeDataDevice(RoborockBase):
482
- def __init__(self, data: dict[str, any]) -> None:
483
- super().__init__(data)
484
477
 
485
478
  @property
486
479
  def duid(self) -> str:
@@ -584,8 +577,6 @@ class HomeDataDevice(RoborockBase):
584
577
 
585
578
 
586
579
  class HomeDataRoom(RoborockBase):
587
- def __init__(self, data: dict[str, any]) -> None:
588
- super().__init__(data)
589
580
 
590
581
  @property
591
582
  def id(self):
@@ -597,8 +588,6 @@ class HomeDataRoom(RoborockBase):
597
588
 
598
589
 
599
590
  class HomeData(RoborockBase):
600
- def __init__(self, data: dict[str, any]) -> None:
601
- super().__init__(data)
602
591
 
603
592
  @property
604
593
  def id(self) -> int:
@@ -638,8 +627,6 @@ class HomeData(RoborockBase):
638
627
 
639
628
 
640
629
  class Status(RoborockBase):
641
- def __init__(self, data: dict[str, any]) -> None:
642
- super().__init__(data)
643
630
 
644
631
  @property
645
632
  def msg_ver(self) -> int:
@@ -839,8 +826,6 @@ class Status(RoborockBase):
839
826
 
840
827
 
841
828
  class DNDTimer(RoborockBase):
842
- def __init__(self, data: dict[str, any]) -> None:
843
- super().__init__(data)
844
829
 
845
830
  @property
846
831
  def start_hour(self) -> int:
@@ -864,8 +849,6 @@ class DNDTimer(RoborockBase):
864
849
 
865
850
 
866
851
  class CleanSummary(RoborockBase):
867
- def __init__(self, data: dict[str, any]) -> None:
868
- super().__init__(data)
869
852
 
870
853
  @property
871
854
  def clean_time(self) -> int:
@@ -889,8 +872,6 @@ class CleanSummary(RoborockBase):
889
872
 
890
873
 
891
874
  class CleanRecord(RoborockBase):
892
- def __init__(self, data: dict[str, any]) -> None:
893
- super().__init__(data)
894
875
 
895
876
  @property
896
877
  def begin(self) -> int:
@@ -946,8 +927,6 @@ class CleanRecord(RoborockBase):
946
927
 
947
928
 
948
929
  class Consumable(RoborockBase):
949
- def __init__(self, data: dict[str, any]) -> None:
950
- super().__init__(data)
951
930
 
952
931
  @property
953
932
  def main_brush_work_time(self) -> int:
@@ -983,8 +962,6 @@ class Consumable(RoborockBase):
983
962
 
984
963
 
985
964
  class MultiMapsListMapInfoBakMaps(RoborockBase):
986
- def __init__(self, data: dict[str, any]) -> None:
987
- super().__init__(data)
988
965
 
989
966
  @property
990
967
  def mapflag(self):
@@ -996,8 +973,6 @@ class MultiMapsListMapInfoBakMaps(RoborockBase):
996
973
 
997
974
 
998
975
  class MultiMapsListMapInfo(RoborockBase):
999
- def __init__(self, data: dict[str, any]) -> None:
1000
- super().__init__(data)
1001
976
 
1002
977
  @property
1003
978
  def mapflag(self):
@@ -1021,8 +996,6 @@ class MultiMapsListMapInfo(RoborockBase):
1021
996
 
1022
997
 
1023
998
  class MultiMapsList(RoborockBase):
1024
- def __init__(self, data: dict[str, any]) -> None:
1025
- super().__init__(data)
1026
999
 
1027
1000
  @property
1028
1001
  def max_multi_map(self) -> int:
@@ -1042,8 +1015,6 @@ class MultiMapsList(RoborockBase):
1042
1015
 
1043
1016
 
1044
1017
  class SmartWashParameters(RoborockBase):
1045
- def __init__(self, data: dict[str, any]) -> None:
1046
- super().__init__(data)
1047
1018
 
1048
1019
  @property
1049
1020
  def smart_wash(self) -> int:
@@ -1053,22 +1024,40 @@ class SmartWashParameters(RoborockBase):
1053
1024
  def wash_interval(self) -> int:
1054
1025
  return self.get(SmartWashField.WASH_INTERVAL)
1055
1026
 
1056
- class NetworkInfo(RoborockBase):
1057
- def __init__(self, data: dict[str, any]) -> None:
1058
- super().__init__(data)
1059
1027
 
1028
+ class NetworkInfo(RoborockBase):
1060
1029
  @property
1061
1030
  def ssid(self) -> str:
1062
1031
  return self.get(NetworkInfoField.SSID)
1032
+
1063
1033
  @property
1064
1034
  def ip(self) -> str:
1065
1035
  return self.get(NetworkInfoField.IP)
1036
+
1066
1037
  @property
1067
1038
  def mac(self) -> str:
1068
1039
  return self.get(NetworkInfoField.MAC)
1040
+
1069
1041
  @property
1070
1042
  def bssid(self) -> str:
1071
1043
  return self.get(NetworkInfoField.BSSID)
1044
+
1072
1045
  @property
1073
1046
  def rssi(self) -> int:
1074
1047
  return self.get(NetworkInfoField.RSSI)
1048
+
1049
+
1050
+ class RoborockDeviceInfo(RoborockBase):
1051
+ @property
1052
+ def device(self) -> HomeDataDevice:
1053
+ return HomeDataDevice(self.get(RoborockDeviceInfoField.DEVICE))
1054
+
1055
+ @property
1056
+ def product(self) -> HomeDataProduct:
1057
+ return HomeDataProduct(self.get(RoborockDeviceInfoField.PRODUCT))
1058
+
1059
+
1060
+ class RoborockLocalDeviceInfo(RoborockDeviceInfo):
1061
+ @property
1062
+ def network_info(self) -> NetworkInfo:
1063
+ return NetworkInfo(self.get(RoborockLocalDeviceInfoField.NETWORK_INFO))
@@ -9,8 +9,9 @@ from typing import Callable, Coroutine, Any
9
9
  import async_timeout
10
10
 
11
11
  from roborock.api import RoborockClient, SPECIAL_COMMANDS
12
+ from roborock.containers import RoborockLocalDeviceInfo
12
13
  from roborock.exceptions import RoborockTimeout, CommandVacuumError
13
- from roborock.typing import RoborockCommand, RoborockLocalDeviceInfo
14
+ from roborock.typing import RoborockCommand
14
15
  from roborock.util import get_running_loop_or_create_one
15
16
 
16
17
  secured_prefix = 199
@@ -39,7 +40,7 @@ class RoborockLocalClient(RoborockClient):
39
40
  super().__init__("abc", devices_info)
40
41
  self.loop = get_running_loop_or_create_one()
41
42
  self.device_listener: dict[str, RoborockSocketListener] = {
42
- device_id: RoborockSocketListener(device_info.ip, device_id, self.on_message)
43
+ device_id: RoborockSocketListener(device_info.network_info.ip, device_id, self.on_message)
43
44
  for device_id, device_info in devices_info.items()
44
45
  }
45
46
  self._mutex = Lock()
@@ -72,6 +73,7 @@ class RoborockLocalClient(RoborockClient):
72
73
  _LOGGER.debug(f"id={request_id} Response from {method}: {response}")
73
74
  return response
74
75
 
76
+
75
77
  class RoborockSocket(socket.socket):
76
78
  _closed = None
77
79
 
@@ -79,6 +81,7 @@ class RoborockSocket(socket.socket):
79
81
  def is_closed(self):
80
82
  return self._closed
81
83
 
84
+
82
85
  class RoborockSocketListener:
83
86
  roborock_port = 58867
84
87
 
@@ -0,0 +1,41 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from roborock.containers import HomeDataDevice, HomeDataDeviceField, HomeDataProduct, HomeDataProductField, NetworkInfo, \
5
+ NetworkInfoField
6
+ from roborock.containers import RoborockLocalDeviceInfo
7
+ from roborock.local_api import RoborockLocalClient
8
+
9
+ local_ip = "<local_ip>"
10
+ local_key = "<local_key>"
11
+ device_id = "<device_id>"
12
+
13
+
14
+ async def main():
15
+ logging_config = {
16
+ "level": logging.DEBUG
17
+ }
18
+ logging.basicConfig(**logging_config)
19
+ localdevices_info = RoborockLocalDeviceInfo({
20
+ "device": HomeDataDevice({
21
+ HomeDataDeviceField.NAME: "test_name",
22
+ HomeDataDeviceField.DUID: device_id,
23
+ HomeDataDeviceField.FV: "1",
24
+ HomeDataDeviceField.LOCAL_KEY: local_key
25
+ }),
26
+ "product": HomeDataProduct({
27
+ HomeDataProductField.MODEL: "test_model"
28
+ }),
29
+ "network_info": NetworkInfo({
30
+ NetworkInfoField.IP: local_ip
31
+ })})
32
+ client = RoborockLocalClient({
33
+ device_id: localdevices_info
34
+ })
35
+ await client.async_connect()
36
+ props = await client.get_prop(device_id)
37
+ print(props)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ asyncio.run(main())
@@ -68,7 +68,7 @@ class RoborockCommand(str, Enum):
68
68
  GET_SERVER_TIMER = "get_server_timer"
69
69
  GET_CUSTOMIZE_CLEAN_MODE = "get_customize_clean_mode"
70
70
  GET_CLEAN_SEQUENCE = "get_clean_sequence"
71
- SET_FDS_ENDPOINT = "set_fds_endpoint" # Seems to be logging server
71
+ SET_FDS_ENDPOINT = "set_fds_endpoint" # Seems to be logging server
72
72
  ENABLE_LOG_UPLOAD = "enable_log_upload"
73
73
  APP_WAKEUP_ROBOT = "app_wakeup_robot"
74
74
  GET_LED_STATUS = "get_led_status"
@@ -82,21 +82,12 @@ class RoborockCommand(str, Enum):
82
82
  SET_CARPET_MODE = "set_carpet_mode"
83
83
  GET_CARPET_CLEAN_MODE = "get_carpet_clean_mode"
84
84
  SET_CARPET_CLEAN_MODE = "set_carpet_clean_mode"
85
- UPD_SERVER_TIMER = "upd_server_timer" # Server timer seems to be with schedules
85
+ UPD_SERVER_TIMER = "upd_server_timer" # Server timer seems to be with schedules
86
86
  SET_SERVER_TIMER = "set_server_timer"
87
87
  APP_GET_INIT_STATUS = "get_init_status"
88
88
  SET_APP_TIMEZONE = "set_app_timezone"
89
89
  GET_NETWORK_INFO = "get_network_info"
90
90
 
91
- class RoborockDeviceInfo:
92
- def __init__(self, local_key: str, model: str):
93
- self.local_key = local_key
94
- self.model = model
95
-
96
- class RoborockLocalDeviceInfo(RoborockDeviceInfo):
97
- def __init__(self, local_key: str, model: str, ip: str):
98
- super().__init__(local_key, model)
99
- self.ip = ip
100
91
 
101
92
  class RoborockDockSummary:
102
93
  def __init__(self, dust_collection_mode: RoborockDockDustCollectionType,
@@ -1,26 +0,0 @@
1
- import asyncio
2
- import logging
3
-
4
- from roborock.local_api import RoborockLocalClient
5
- from roborock.typing import RoborockLocalDeviceInfo
6
-
7
- local_ip = "<local_ip>"
8
- local_key = "<local_key>"
9
- device_id = "<device_id>"
10
-
11
-
12
- async def main():
13
- logging_config = {
14
- "level": logging.DEBUG
15
- }
16
- logging.basicConfig(**logging_config)
17
- client = RoborockLocalClient({
18
- device_id: RoborockLocalDeviceInfo(local_key, "model_test", local_ip)
19
- })
20
- await client.async_connect()
21
- props = await client.get_prop(device_id)
22
- print(props)
23
-
24
-
25
- if __name__ == "__main__":
26
- asyncio.run(main())