python-roborock 2.17.0__tar.gz → 2.18.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.17.0 → python_roborock-2.18.0}/PKG-INFO +2 -1
- {python_roborock-2.17.0 → python_roborock-2.18.0}/pyproject.toml +2 -1
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/exceptions.py +4 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/web_api.py +43 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/LICENSE +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/README.md +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/__init__.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/api.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/cli.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/cloud_api.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/code_mappings.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/command_cache.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/const.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/containers.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/local_api.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/protocol.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/py.typed +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/roborock_future.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/roborock_message.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/util.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
- {python_roborock-2.17.0 → python_roborock-2.18.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.18.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
|
|
@@ -24,6 +24,7 @@ Requires-Dist: construct (>=2.10.57,<3.0.0)
|
|
|
24
24
|
Requires-Dist: paho-mqtt (>=1.6.1,<3.0.0)
|
|
25
25
|
Requires-Dist: pycryptodome (>=3.18,<4.0)
|
|
26
26
|
Requires-Dist: pycryptodomex (>=3.18,<4.0) ; sys_platform == "darwin"
|
|
27
|
+
Requires-Dist: pyrate-limiter (>=3.7.0,<4.0.0)
|
|
27
28
|
Requires-Dist: vacuum-map-parser-roborock
|
|
28
29
|
Project-URL: Documentation, https://python-roborock.readthedocs.io/
|
|
29
30
|
Project-URL: Repository, https://github.com/humbertogontijo/python-roborock
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-roborock"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.18.0"
|
|
4
4
|
description = "A package to control Roborock vacuums."
|
|
5
5
|
authors = ["humbertogontijo <humbertogontijo@users.noreply.github.com>"]
|
|
6
6
|
license = "GPL-3.0-only"
|
|
@@ -30,6 +30,7 @@ pycryptodomex = {version = "^3.18", markers = "sys_platform == 'darwin'"}
|
|
|
30
30
|
paho-mqtt = ">=1.6.1,<3.0.0"
|
|
31
31
|
construct = "^2.10.57"
|
|
32
32
|
vacuum-map-parser-roborock = "*"
|
|
33
|
+
pyrate-limiter = "^3.7.0"
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
[build-system]
|
|
@@ -10,6 +10,7 @@ import time
|
|
|
10
10
|
|
|
11
11
|
import aiohttp
|
|
12
12
|
from aiohttp import ContentTypeError, FormData
|
|
13
|
+
from pyrate_limiter import BucketFullException, Duration, Limiter, Rate
|
|
13
14
|
|
|
14
15
|
from roborock.containers import HomeData, HomeDataRoom, HomeDataScene, ProductResponse, RRiot, UserData
|
|
15
16
|
from roborock.exceptions import (
|
|
@@ -21,6 +22,7 @@ from roborock.exceptions import (
|
|
|
21
22
|
RoborockInvalidUserAgreement,
|
|
22
23
|
RoborockMissingParameters,
|
|
23
24
|
RoborockNoUserAgreement,
|
|
25
|
+
RoborockRateLimit,
|
|
24
26
|
RoborockTooFrequentCodeRequests,
|
|
25
27
|
RoborockTooManyRequest,
|
|
26
28
|
RoborockUrlException,
|
|
@@ -30,6 +32,22 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
class RoborockApiClient:
|
|
35
|
+
_LOGIN_RATES = [
|
|
36
|
+
Rate(1, Duration.SECOND),
|
|
37
|
+
Rate(3, Duration.MINUTE),
|
|
38
|
+
Rate(10, Duration.HOUR),
|
|
39
|
+
Rate(20, Duration.DAY),
|
|
40
|
+
]
|
|
41
|
+
_HOME_DATA_RATES = [
|
|
42
|
+
Rate(1, Duration.SECOND),
|
|
43
|
+
Rate(5, Duration.MINUTE),
|
|
44
|
+
Rate(15, Duration.HOUR),
|
|
45
|
+
Rate(40, Duration.DAY),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
_login_limiter = Limiter(_LOGIN_RATES)
|
|
49
|
+
_home_data_limiter = Limiter(_HOME_DATA_RATES)
|
|
50
|
+
|
|
33
51
|
def __init__(self, username: str, base_url=None, session: aiohttp.ClientSession | None = None) -> None:
|
|
34
52
|
"""Sample API Client."""
|
|
35
53
|
self._username = username
|
|
@@ -175,6 +193,11 @@ class RoborockApiClient:
|
|
|
175
193
|
return add_device_response["result"]
|
|
176
194
|
|
|
177
195
|
async def request_code(self) -> None:
|
|
196
|
+
try:
|
|
197
|
+
self._login_limiter.try_acquire("login")
|
|
198
|
+
except BucketFullException as ex:
|
|
199
|
+
_LOGGER.info(ex.meta_info)
|
|
200
|
+
raise RoborockRateLimit("Reached maximum requests for login. Please try again later.") from ex
|
|
178
201
|
base_url = await self._get_base_url()
|
|
179
202
|
header_clientid = self._get_header_client_id()
|
|
180
203
|
code_request = PreparedRequest(base_url, self.session, {"header_clientid": header_clientid})
|
|
@@ -199,6 +222,11 @@ class RoborockApiClient:
|
|
|
199
222
|
raise RoborockException(f"{code_response.get('msg')} - response code: {code_response.get('code')}")
|
|
200
223
|
|
|
201
224
|
async def pass_login(self, password: str) -> UserData:
|
|
225
|
+
try:
|
|
226
|
+
self._login_limiter.try_acquire("login")
|
|
227
|
+
except BucketFullException as ex:
|
|
228
|
+
_LOGGER.info(ex.meta_info)
|
|
229
|
+
raise RoborockRateLimit("Reached maximum requests for login. Please try again later.") from ex
|
|
202
230
|
base_url = await self._get_base_url()
|
|
203
231
|
header_clientid = self._get_header_client_id()
|
|
204
232
|
|
|
@@ -289,6 +317,11 @@ class RoborockApiClient:
|
|
|
289
317
|
return home_id_response["data"]["rrHomeId"]
|
|
290
318
|
|
|
291
319
|
async def get_home_data(self, user_data: UserData) -> HomeData:
|
|
320
|
+
try:
|
|
321
|
+
self._home_data_limiter.try_acquire("home_data")
|
|
322
|
+
except BucketFullException as ex:
|
|
323
|
+
_LOGGER.info(ex.meta_info)
|
|
324
|
+
raise RoborockRateLimit("Reached maximum requests for home data. Please try again later.") from ex
|
|
292
325
|
rriot = user_data.rriot
|
|
293
326
|
if rriot is None:
|
|
294
327
|
raise RoborockException("rriot is none")
|
|
@@ -313,6 +346,11 @@ class RoborockApiClient:
|
|
|
313
346
|
|
|
314
347
|
async def get_home_data_v2(self, user_data: UserData) -> HomeData:
|
|
315
348
|
"""This is the same as get_home_data, but uses a different endpoint and includes non-robotic vacuums."""
|
|
349
|
+
try:
|
|
350
|
+
self._home_data_limiter.try_acquire("home_data")
|
|
351
|
+
except BucketFullException as ex:
|
|
352
|
+
_LOGGER.info(ex.meta_info)
|
|
353
|
+
raise RoborockRateLimit("Reached maximum requests for home data. Please try again later.") from ex
|
|
316
354
|
rriot = user_data.rriot
|
|
317
355
|
if rriot is None:
|
|
318
356
|
raise RoborockException("rriot is none")
|
|
@@ -337,6 +375,11 @@ class RoborockApiClient:
|
|
|
337
375
|
|
|
338
376
|
async def get_home_data_v3(self, user_data: UserData) -> HomeData:
|
|
339
377
|
"""This is the same as get_home_data, but uses a different endpoint and includes non-robotic vacuums."""
|
|
378
|
+
try:
|
|
379
|
+
self._home_data_limiter.try_acquire("home_data")
|
|
380
|
+
except BucketFullException as ex:
|
|
381
|
+
_LOGGER.info(ex.meta_info)
|
|
382
|
+
raise RoborockRateLimit("Reached maximum requests for home data. Please try again later.") from ex
|
|
340
383
|
rriot = user_data.rriot
|
|
341
384
|
home_id = await self._get_home_id(user_data)
|
|
342
385
|
if rriot.r.a is None:
|
|
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.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.17.0 → python_roborock-2.18.0}/roborock/version_a01_apis/roborock_client_a01.py
RENAMED
|
File without changes
|
|
File without changes
|