Skip to content

Commit a0913cd

Browse files
committed
feat: add product v4 and downloading code
1 parent 6777dd7 commit a0913cd

File tree

3 files changed

+59
-30
lines changed

3 files changed

+59
-30
lines changed

roborock/containers.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -881,26 +881,28 @@ class RoborockProductSpec(RoborockBase):
881881

882882
@dataclass
883883
class RoborockProduct(RoborockBase):
884-
id: int
885-
name: str
886-
model: str
887-
packagename: str
888-
ssid: str
889-
picurl: str
890-
cardpicurl: str
891-
medium_cardpicurl: str
892-
resetwifipicurl: str
893-
resetwifitext: dict
894-
tuyaid: str
895-
status: int
896-
rriotid: str
897-
cardspec: str
898-
pictures: list
899-
nc_mode: str
900-
scope: None
901-
product_tags: list
902-
agreements: list
903-
plugin_pic_url: None
884+
id: int | None = None
885+
name: str | None = None
886+
model: str | None = None
887+
packagename: str | None = None
888+
ssid: str | None = None
889+
picurl: str | None = None
890+
cardpicurl: str | None = None
891+
mediumCardpicurl: str | None = None
892+
resetwifipicurl: str | None = None
893+
configPicUrl: str | None = None
894+
pluginPicUrl: str | None = None
895+
resetwifitext: dict | None = None
896+
tuyaid: str | None = None
897+
status: int | None = None
898+
rriotid: str | None = None
899+
pictures: list | None = None
900+
ncMode: str | None = None
901+
scope: str | None = None
902+
product_tags: list | None = None
903+
agreements: list | None = None
904+
cardspec: str | None = None
905+
plugin_pic_url: str | None = None
904906
products_specification: RoborockProductSpec | None = None
905907

906908
def __post_init__(self):

roborock/version_1_apis/roborock_client_v1.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
363363
try:
364364
self._last_device_msg_in = self.time_func()
365365
for data in messages:
366+
self._logger.debug(f"Got message: {data}")
366367
protocol = data.protocol
367368
if data.payload and protocol in [
368369
RoborockMessageProtocol.RPC_RESPONSE,
@@ -418,6 +419,12 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
418419
consumable = Consumable.from_dict(value)
419420
for listener in self.listener_model.protocol_handlers.get(data_protocol, []):
420421
listener(consumable)
422+
else:
423+
self._logger.warning(
424+
f"Unknown data protocol {data_point_number}, please create an "
425+
f"issue on the python-roborock repository"
426+
)
427+
self._logger.info(data)
421428
return
422429
except ValueError:
423430
self._logger.warning(

roborock/web_api.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async def _get_base_url(self) -> str:
5454
raise RoborockMissingParameters(
5555
"You are missing parameters for this request, are you sure you " "entered your username?"
5656
)
57-
raise RoborockUrlException(response.get("error"))
57+
raise RoborockUrlException(f"error code: {response_code} msg: {response.get('error')}")
5858
response_data = response.get("data")
5959
if response_data is None:
6060
raise RoborockUrlException("response does not have 'data'")
@@ -276,7 +276,7 @@ async def get_products(self, user_data: UserData) -> ProductResponse:
276276
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
277277
product_response = await product_request.request(
278278
"get",
279-
"/api/v3/product",
279+
"/api/v4/product",
280280
headers={"Authorization": user_data.token},
281281
)
282282
if product_response is None:
@@ -288,24 +288,44 @@ async def get_products(self, user_data: UserData) -> ProductResponse:
288288
return ProductResponse.from_dict(result)
289289
raise RoborockException("product result was an unexpected type")
290290

291+
async def download_code(self, user_data: UserData, product_id: int):
292+
base_url = await self._get_base_url()
293+
header_clientid = self._get_header_client_id()
294+
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
295+
request = {"apilevel": 99999, "productids": [product_id], "type": 2}
296+
response = await product_request.request(
297+
"post",
298+
"/api/v1/appplugin",
299+
json=request,
300+
headers={"Authorization": user_data.token, "Content-Type": "application/json"},
301+
)
302+
return response["data"][0]["url"]
303+
304+
async def download_category_code(self, user_data: UserData):
305+
base_url = await self._get_base_url()
306+
header_clientid = self._get_header_client_id()
307+
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
308+
response = await product_request.request(
309+
"get",
310+
"api/v1/plugins?apiLevel=99999&type=2",
311+
headers={
312+
"Authorization": user_data.token,
313+
},
314+
)
315+
return {r["category"]: r["url"] for r in response["data"]["categoryPluginList"]}
316+
291317

292318
class PreparedRequest:
293319
def __init__(self, base_url: str, base_headers: dict | None = None) -> None:
294320
self.base_url = base_url
295321
self.base_headers = base_headers or {}
296322

297-
async def request(self, method: str, url: str, params=None, data=None, headers=None) -> dict:
323+
async def request(self, method: str, url: str, params=None, data=None, headers=None, json=None) -> dict:
298324
_url = "/".join(s.strip("/") for s in [self.base_url, url])
299325
_headers = {**self.base_headers, **(headers or {})}
300326
async with aiohttp.ClientSession() as session:
301327
try:
302-
async with session.request(
303-
method,
304-
_url,
305-
params=params,
306-
data=data,
307-
headers=_headers,
308-
) as resp:
328+
async with session.request(method, _url, params=params, data=data, headers=_headers, json=json) as resp:
309329
return await resp.json()
310330
except ContentTypeError as err:
311331
"""If we get an error, lets log everything for debugging."""

0 commit comments

Comments
 (0)