diff --git a/roborock/api.py b/roborock/api.py index 747e3cb..3b396db 100644 --- a/roborock/api.py +++ b/roborock/api.py @@ -70,7 +70,6 @@ _LOGGER = logging.getLogger(__name__) KEEPALIVE = 60 -QUEUE_TIMEOUT = 4 COMMANDS_SECURED = [ RoborockCommand.GET_MAP_V1, RoborockCommand.GET_MULTI_MAP, @@ -166,7 +165,7 @@ async def refresh_value(self): class RoborockClient: - def __init__(self, endpoint: str, device_info: DeviceData) -> None: + def __init__(self, endpoint: str, device_info: DeviceData, queue_timeout: int = 4) -> None: self.event_loop = get_running_loop_or_create_one() self.device_info = device_info self._endpoint = endpoint @@ -185,6 +184,8 @@ def __init__(self, endpoint: str, device_info: DeviceData) -> None: device_cache[device_info.device.duid] = cache self.cache: dict[CacheableAttribute, AttributeCache] = cache self._listeners: list[Callable[[str, CacheableAttribute, RoborockBase], None]] = [] + self.is_available: bool = False + self.queue_timeout = queue_timeout def __del__(self) -> None: self.release() @@ -322,12 +323,12 @@ async def validate_connection(self) -> None: async def _wait_response(self, request_id: int, queue: RoborockFuture) -> tuple[Any, VacuumError | None]: try: - (response, err) = await queue.async_get(QUEUE_TIMEOUT) + (response, err) = await queue.async_get(self.queue_timeout) if response == "unknown_method": raise UnknownMethodError("Unknown method") return response, err except (asyncio.TimeoutError, asyncio.CancelledError): - raise RoborockTimeout(f"id={request_id} Timeout after {QUEUE_TIMEOUT} seconds") from None + raise RoborockTimeout(f"id={request_id} Timeout after {self.queue_timeout} seconds") from None finally: self._waiting_queue.pop(request_id, None) diff --git a/roborock/cloud_api.py b/roborock/cloud_api.py index fbcc5ff..51e3e5e 100644 --- a/roborock/cloud_api.py +++ b/roborock/cloud_api.py @@ -29,12 +29,12 @@ class RoborockMqttClient(RoborockClient, mqtt.Client): _thread: threading.Thread _client_id: str - def __init__(self, user_data: UserData, device_info: DeviceData) -> None: + def __init__(self, user_data: UserData, device_info: DeviceData, queue_timeout: int = 10) -> None: rriot = user_data.rriot if rriot is None: raise RoborockException("Got no rriot data from user_data") endpoint = base64.b64encode(Utils.md5(rriot.k.encode())[8:14]).decode() - RoborockClient.__init__(self, endpoint, device_info) + RoborockClient.__init__(self, endpoint, device_info, queue_timeout) mqtt.Client.__init__(self, protocol=mqtt.MQTTv5) self._logger = RoborockLoggerAdapter(device_info.device.name, _LOGGER) self._mqtt_user = rriot.u diff --git a/roborock/containers.py b/roborock/containers.py index 327f5ec..0082181 100644 --- a/roborock/containers.py +++ b/roborock/containers.py @@ -4,6 +4,7 @@ import logging import re from dataclasses import asdict, dataclass +from datetime import timezone from enum import Enum from typing import Any, NamedTuple @@ -408,7 +409,9 @@ def __post_init__(self) -> None: @dataclass class CleanRecord(RoborockBase): begin: int | None = None + begin_datetime: datetime.datetime | None = None end: int | None = None + end_datetime: datetime.datetime | None = None duration: int | None = None area: int | None = None square_meter_area: float | None = None @@ -424,6 +427,10 @@ class CleanRecord(RoborockBase): def __post_init__(self) -> None: self.square_meter_area = round(self.area / 1000000, 1) if self.area is not None else None + self.begin_datetime = ( + datetime.datetime.fromtimestamp(self.begin).astimezone(timezone.utc) if self.begin else None + ) + self.end_datetime = datetime.datetime.fromtimestamp(self.end).astimezone(timezone.utc) if self.end else None @dataclass diff --git a/roborock/local_api.py b/roborock/local_api.py index 32b9239..73dcd3a 100644 --- a/roborock/local_api.py +++ b/roborock/local_api.py @@ -7,7 +7,7 @@ import async_timeout from . import DeviceData -from .api import COMMANDS_SECURED, QUEUE_TIMEOUT, RoborockClient +from .api import COMMANDS_SECURED, RoborockClient from .exceptions import CommandVacuumError, RoborockConnectionException, RoborockException from .protocol import MessageParser from .roborock_message import MessageRetry, RoborockMessage, RoborockMessageProtocol @@ -18,10 +18,10 @@ class RoborockLocalClient(RoborockClient, asyncio.Protocol): - def __init__(self, device_data: DeviceData): + def __init__(self, device_data: DeviceData, queue_timeout: int = 4): if device_data.host is None: raise RoborockException("Host is required") - super().__init__("abc", device_data) + super().__init__("abc", device_data, queue_timeout) self.host = device_data.host self._batch_structs: list[RoborockMessage] = [] self._executing = False @@ -58,7 +58,7 @@ async def async_connect(self) -> None: try: if not self.is_connected(): self.sync_disconnect() - async with async_timeout.timeout(QUEUE_TIMEOUT): + async with async_timeout.timeout(self.queue_timeout): self._logger.info(f"Connecting to {self.host}") self.transport, _ = await self.event_loop.create_connection( # type: ignore lambda: self, self.host, 58867