Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add product v4 and downloading code #267

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions roborock/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,26 +881,28 @@ class RoborockProductSpec(RoborockBase):

@dataclass
class RoborockProduct(RoborockBase):
id: int
name: str
model: str
packagename: str
ssid: str
picurl: str
cardpicurl: str
medium_cardpicurl: str
resetwifipicurl: str
resetwifitext: dict
tuyaid: str
status: int
rriotid: str
cardspec: str
pictures: list
nc_mode: str
scope: None
product_tags: list
agreements: list
plugin_pic_url: None
id: int | None = None
name: str | None = None
model: str | None = None
packagename: str | None = None
ssid: str | None = None
picurl: str | None = None
cardpicurl: str | None = None
mediumCardpicurl: str | None = None
resetwifipicurl: str | None = None
configPicUrl: str | None = None
pluginPicUrl: str | None = None
resetwifitext: dict | None = None
tuyaid: str | None = None
status: int | None = None
rriotid: str | None = None
pictures: list | None = None
ncMode: str | None = None
scope: str | None = None
product_tags: list | None = None
agreements: list | None = None
cardspec: str | None = None
plugin_pic_url: str | None = None
products_specification: RoborockProductSpec | None = None

def __post_init__(self):
Expand Down
6 changes: 6 additions & 0 deletions roborock/version_1_apis/roborock_client_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,12 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
consumable = Consumable.from_dict(value)
for listener in self.listener_model.protocol_handlers.get(data_protocol, []):
listener(consumable)
else:
self._logger.warning(
f"Unknown data protocol {data_point_number}, please create an "
f"issue on the python-roborock repository"
)
self._logger.info(data)
return
except ValueError:
self._logger.warning(
Expand Down
40 changes: 30 additions & 10 deletions roborock/web_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def _get_base_url(self) -> str:
raise RoborockMissingParameters(
"You are missing parameters for this request, are you sure you " "entered your username?"
)
raise RoborockUrlException(response.get("error"))
raise RoborockUrlException(f"error code: {response_code} msg: {response.get('error')}")
response_data = response.get("data")
if response_data is None:
raise RoborockUrlException("response does not have 'data'")
Expand Down Expand Up @@ -276,7 +276,7 @@ async def get_products(self, user_data: UserData) -> ProductResponse:
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
product_response = await product_request.request(
"get",
"/api/v3/product",
"/api/v4/product",
headers={"Authorization": user_data.token},
)
if product_response is None:
Expand All @@ -288,24 +288,44 @@ async def get_products(self, user_data: UserData) -> ProductResponse:
return ProductResponse.from_dict(result)
raise RoborockException("product result was an unexpected type")

async def download_code(self, user_data: UserData, product_id: int):
base_url = await self._get_base_url()
header_clientid = self._get_header_client_id()
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
request = {"apilevel": 99999, "productids": [product_id], "type": 2}
response = await product_request.request(
"post",
"/api/v1/appplugin",
json=request,
headers={"Authorization": user_data.token, "Content-Type": "application/json"},
)
return response["data"][0]["url"]

async def download_category_code(self, user_data: UserData):
base_url = await self._get_base_url()
header_clientid = self._get_header_client_id()
product_request = PreparedRequest(base_url, {"header_clientid": header_clientid})
response = await product_request.request(
"get",
"api/v1/plugins?apiLevel=99999&type=2",
headers={
"Authorization": user_data.token,
},
)
return {r["category"]: r["url"] for r in response["data"]["categoryPluginList"]}


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

async def request(self, method: str, url: str, params=None, data=None, headers=None) -> dict:
async def request(self, method: str, url: str, params=None, data=None, headers=None, json=None) -> dict:
_url = "/".join(s.strip("/") for s in [self.base_url, url])
_headers = {**self.base_headers, **(headers or {})}
async with aiohttp.ClientSession() as session:
try:
async with session.request(
method,
_url,
params=params,
data=data,
headers=_headers,
) as resp:
async with session.request(method, _url, params=params, data=data, headers=_headers, json=json) as resp:
return await resp.json()
except ContentTypeError as err:
"""If we get an error, lets log everything for debugging."""
Expand Down
Loading