python-roborock 2.14.0__tar.gz → 2.16.0__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.
- {python_roborock-2.14.0 → python_roborock-2.16.0}/PKG-INFO +3 -3
- {python_roborock-2.14.0 → python_roborock-2.16.0}/README.md +2 -2
- {python_roborock-2.14.0 → python_roborock-2.16.0}/pyproject.toml +1 -1
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/roborock_client_v1.py +3 -3
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/web_api.py +36 -26
- {python_roborock-2.14.0 → python_roborock-2.16.0}/LICENSE +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/__init__.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/api.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/cli.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/cloud_api.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/code_mappings.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/command_cache.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/const.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/containers.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/exceptions.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/local_api.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/protocol.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/py.typed +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/roborock_future.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/roborock_message.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/util.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
- {python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-roborock
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.16.0
|
|
4
4
|
Summary: A package to control Roborock vacuums.
|
|
5
5
|
Home-page: https://github.com/humbertogontijo/python-roborock
|
|
6
6
|
License: GPL-3.0-only
|
|
@@ -49,7 +49,7 @@ Install this via pip (or your favourite package manager):
|
|
|
49
49
|
|
|
50
50
|
## Functionality
|
|
51
51
|
|
|
52
|
-
You can see all of the commands supported [here](
|
|
52
|
+
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
53
53
|
|
|
54
54
|
## Sending Commands
|
|
55
55
|
|
|
@@ -98,7 +98,7 @@ asyncio.run(main())
|
|
|
98
98
|
## Supported devices
|
|
99
99
|
|
|
100
100
|
You can find what devices are supported
|
|
101
|
-
[here](
|
|
101
|
+
[here](https://python-roborock.readthedocs.io/en/latest/supported_devices.html).
|
|
102
102
|
Please note this may not immediately contain the latest devices.
|
|
103
103
|
|
|
104
104
|
|
|
@@ -18,7 +18,7 @@ Install this via pip (or your favourite package manager):
|
|
|
18
18
|
|
|
19
19
|
## Functionality
|
|
20
20
|
|
|
21
|
-
You can see all of the commands supported [here](
|
|
21
|
+
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
22
22
|
|
|
23
23
|
## Sending Commands
|
|
24
24
|
|
|
@@ -67,7 +67,7 @@ asyncio.run(main())
|
|
|
67
67
|
## Supported devices
|
|
68
68
|
|
|
69
69
|
You can find what devices are supported
|
|
70
|
-
[here](
|
|
70
|
+
[here](https://python-roborock.readthedocs.io/en/latest/supported_devices.html).
|
|
71
71
|
Please note this may not immediately contain the latest devices.
|
|
72
72
|
|
|
73
73
|
|
{python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
@@ -107,9 +107,9 @@ class AttributeCache:
|
|
|
107
107
|
raise err
|
|
108
108
|
return self._value
|
|
109
109
|
|
|
110
|
-
async def async_value(self):
|
|
110
|
+
async def async_value(self, force: bool = False):
|
|
111
111
|
async with self._mutex:
|
|
112
|
-
if self._value is None:
|
|
112
|
+
if self._value is None or force:
|
|
113
113
|
return await self.task.reset()
|
|
114
114
|
return self._value
|
|
115
115
|
|
|
@@ -175,7 +175,7 @@ class RoborockClientV1(RoborockClient, ABC):
|
|
|
175
175
|
return self._status_type
|
|
176
176
|
|
|
177
177
|
async def get_status(self) -> Status:
|
|
178
|
-
data = self._status_type.from_dict(await self.cache[CacheableAttribute.status].async_value())
|
|
178
|
+
data = self._status_type.from_dict(await self.cache[CacheableAttribute.status].async_value(force=True))
|
|
179
179
|
if data is None:
|
|
180
180
|
return self._status_type()
|
|
181
181
|
return data
|
|
@@ -30,16 +30,19 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class RoborockApiClient:
|
|
33
|
-
def __init__(self, username: str, base_url=None) -> None:
|
|
33
|
+
def __init__(self, username: str, base_url=None, session: aiohttp.ClientSession | None = None) -> None:
|
|
34
34
|
"""Sample API Client."""
|
|
35
35
|
self._username = username
|
|
36
36
|
self._default_url = "https://euiot.roborock.com"
|
|
37
37
|
self.base_url = base_url
|
|
38
38
|
self._device_identifier = secrets.token_urlsafe(16)
|
|
39
|
+
if session is None:
|
|
40
|
+
session = aiohttp.ClientSession()
|
|
41
|
+
self.session = session
|
|
39
42
|
|
|
40
43
|
async def _get_base_url(self) -> str:
|
|
41
44
|
if not self.base_url:
|
|
42
|
-
url_request = PreparedRequest(self._default_url)
|
|
45
|
+
url_request = PreparedRequest(self._default_url, self.session)
|
|
43
46
|
response = await url_request.request(
|
|
44
47
|
"post",
|
|
45
48
|
"/api/v1/getUrlByEmail",
|
|
@@ -113,7 +116,7 @@ class RoborockApiClient:
|
|
|
113
116
|
):
|
|
114
117
|
raise RoborockException("Your userdata is missing critical attributes.")
|
|
115
118
|
base_url = user_data.rriot.r.a
|
|
116
|
-
prepare_request = PreparedRequest(base_url)
|
|
119
|
+
prepare_request = PreparedRequest(base_url, self.session)
|
|
117
120
|
hid = await self._get_home_id(user_data)
|
|
118
121
|
|
|
119
122
|
data = FormData()
|
|
@@ -151,7 +154,7 @@ class RoborockApiClient:
|
|
|
151
154
|
):
|
|
152
155
|
raise RoborockException("Your userdata is missing critical attributes.")
|
|
153
156
|
base_url = user_data.rriot.r.a
|
|
154
|
-
add_device_request = PreparedRequest(base_url)
|
|
157
|
+
add_device_request = PreparedRequest(base_url, self.session)
|
|
155
158
|
|
|
156
159
|
add_device_response = await add_device_request.request(
|
|
157
160
|
"GET",
|
|
@@ -176,7 +179,7 @@ class RoborockApiClient:
|
|
|
176
179
|
async def request_code(self) -> None:
|
|
177
180
|
base_url = await self._get_base_url()
|
|
178
181
|
header_clientid = self._get_header_client_id()
|
|
179
|
-
code_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
182
|
+
code_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
180
183
|
|
|
181
184
|
code_response = await code_request.request(
|
|
182
185
|
"post",
|
|
@@ -201,7 +204,7 @@ class RoborockApiClient:
|
|
|
201
204
|
base_url = await self._get_base_url()
|
|
202
205
|
header_clientid = self._get_header_client_id()
|
|
203
206
|
|
|
204
|
-
login_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
207
|
+
login_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
205
208
|
login_response = await login_request.request(
|
|
206
209
|
"post",
|
|
207
210
|
"/api/v1/login",
|
|
@@ -239,7 +242,7 @@ class RoborockApiClient:
|
|
|
239
242
|
base_url = await self._get_base_url()
|
|
240
243
|
header_clientid = self._get_header_client_id()
|
|
241
244
|
|
|
242
|
-
login_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
245
|
+
login_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
243
246
|
login_response = await login_request.request(
|
|
244
247
|
"post",
|
|
245
248
|
"/api/v1/loginWithCode",
|
|
@@ -270,7 +273,7 @@ class RoborockApiClient:
|
|
|
270
273
|
async def _get_home_id(self, user_data: UserData):
|
|
271
274
|
base_url = await self._get_base_url()
|
|
272
275
|
header_clientid = self._get_header_client_id()
|
|
273
|
-
home_id_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
276
|
+
home_id_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
274
277
|
home_id_response = await home_id_request.request(
|
|
275
278
|
"get",
|
|
276
279
|
"/api/v1/getHomeDetail",
|
|
@@ -296,6 +299,7 @@ class RoborockApiClient:
|
|
|
296
299
|
raise RoborockException("Missing field 'a' in rriot reference")
|
|
297
300
|
home_request = PreparedRequest(
|
|
298
301
|
rriot.r.a,
|
|
302
|
+
self.session,
|
|
299
303
|
{
|
|
300
304
|
"Authorization": self._get_hawk_authentication(rriot, f"/user/homes/{str(home_id)}"),
|
|
301
305
|
},
|
|
@@ -319,6 +323,7 @@ class RoborockApiClient:
|
|
|
319
323
|
raise RoborockException("Missing field 'a' in rriot reference")
|
|
320
324
|
home_request = PreparedRequest(
|
|
321
325
|
rriot.r.a,
|
|
326
|
+
self.session,
|
|
322
327
|
{
|
|
323
328
|
"Authorization": self._get_hawk_authentication(rriot, "/v2/user/homes/" + str(home_id)),
|
|
324
329
|
},
|
|
@@ -362,6 +367,7 @@ class RoborockApiClient:
|
|
|
362
367
|
raise RoborockException("Missing field 'a' in rriot reference")
|
|
363
368
|
room_request = PreparedRequest(
|
|
364
369
|
rriot.r.a,
|
|
370
|
+
self.session,
|
|
365
371
|
{
|
|
366
372
|
"Authorization": self._get_hawk_authentication(rriot, "/v2/user/homes/" + str(home_id)),
|
|
367
373
|
},
|
|
@@ -386,6 +392,7 @@ class RoborockApiClient:
|
|
|
386
392
|
raise RoborockException("Missing field 'a' in rriot reference")
|
|
387
393
|
scenes_request = PreparedRequest(
|
|
388
394
|
rriot.r.a,
|
|
395
|
+
self.session,
|
|
389
396
|
{
|
|
390
397
|
"Authorization": self._get_hawk_authentication(rriot, f"/user/scene/device/{str(device_id)}"),
|
|
391
398
|
},
|
|
@@ -407,6 +414,7 @@ class RoborockApiClient:
|
|
|
407
414
|
raise RoborockException("Missing field 'a' in rriot reference")
|
|
408
415
|
execute_scene_request = PreparedRequest(
|
|
409
416
|
rriot.r.a,
|
|
417
|
+
self.session,
|
|
410
418
|
{
|
|
411
419
|
"Authorization": self._get_hawk_authentication(rriot, f"/user/scene/{str(scene_id)}/execute"),
|
|
412
420
|
},
|
|
@@ -419,7 +427,7 @@ class RoborockApiClient:
|
|
|
419
427
|
"""Gets all products and their schemas, good for determining status codes and model numbers."""
|
|
420
428
|
base_url = await self._get_base_url()
|
|
421
429
|
header_clientid = self._get_header_client_id()
|
|
422
|
-
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
430
|
+
product_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
423
431
|
product_response = await product_request.request(
|
|
424
432
|
"get",
|
|
425
433
|
"/api/v4/product",
|
|
@@ -437,7 +445,7 @@ class RoborockApiClient:
|
|
|
437
445
|
async def download_code(self, user_data: UserData, product_id: int):
|
|
438
446
|
base_url = await self._get_base_url()
|
|
439
447
|
header_clientid = self._get_header_client_id()
|
|
440
|
-
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
448
|
+
product_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
441
449
|
request = {"apilevel": 99999, "productids": [product_id], "type": 2}
|
|
442
450
|
response = await product_request.request(
|
|
443
451
|
"post",
|
|
@@ -450,7 +458,7 @@ class RoborockApiClient:
|
|
|
450
458
|
async def download_category_code(self, user_data: UserData):
|
|
451
459
|
base_url = await self._get_base_url()
|
|
452
460
|
header_clientid = self._get_header_client_id()
|
|
453
|
-
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
|
|
461
|
+
product_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
454
462
|
response = await product_request.request(
|
|
455
463
|
"get",
|
|
456
464
|
"api/v1/plugins?apiLevel=99999&type=2",
|
|
@@ -462,25 +470,27 @@ class RoborockApiClient:
|
|
|
462
470
|
|
|
463
471
|
|
|
464
472
|
class PreparedRequest:
|
|
465
|
-
def __init__(self, base_url: str, base_headers: dict | None = None) -> None:
|
|
473
|
+
def __init__(self, base_url: str, session: aiohttp.ClientSession, base_headers: dict | None = None) -> None:
|
|
466
474
|
self.base_url = base_url
|
|
467
475
|
self.base_headers = base_headers or {}
|
|
476
|
+
self.session = session
|
|
468
477
|
|
|
469
478
|
async def request(self, method: str, url: str, params=None, data=None, headers=None, json=None) -> dict:
|
|
470
479
|
_url = "/".join(s.strip("/") for s in [self.base_url, url])
|
|
471
480
|
_headers = {**self.base_headers, **(headers or {})}
|
|
472
|
-
|
|
481
|
+
try:
|
|
482
|
+
async with self.session.request(
|
|
483
|
+
method, _url, params=params, data=data, headers=_headers, json=json
|
|
484
|
+
) as resp:
|
|
485
|
+
return await resp.json()
|
|
486
|
+
except ContentTypeError as err:
|
|
487
|
+
"""If we get an error, lets log everything for debugging."""
|
|
473
488
|
try:
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
except ContentTypeError as
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
_LOGGER.info(err_2)
|
|
483
|
-
resp_raw = await resp.read()
|
|
484
|
-
_LOGGER.info("Resp raw: %s", resp_raw)
|
|
485
|
-
# Still raise the err so that it's clear it failed.
|
|
486
|
-
raise err
|
|
489
|
+
resp_json = await resp.json(content_type=None)
|
|
490
|
+
_LOGGER.info("Resp: %s", resp_json)
|
|
491
|
+
except ContentTypeError as err_2:
|
|
492
|
+
_LOGGER.info(err_2)
|
|
493
|
+
resp_raw = await resp.read()
|
|
494
|
+
_LOGGER.info("Resp raw: %s", resp_raw)
|
|
495
|
+
# Still raise the err so that it's clear it failed.
|
|
496
|
+
raise err
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.14.0 → python_roborock-2.16.0}/roborock/version_a01_apis/roborock_client_a01.py
RENAMED
|
File without changes
|
|
File without changes
|