44import logging
55from collections.abc import Callable
66from dataclasses import dataclass
7- from json import JSONDecodeError
87
98from roborock.exceptions import RoborockConnectionException, RoborockException
109from roborock.protocol import Decoder, Encoder, create_local_decoder, create_local_encoder
1110from roborock.roborock_message import RoborockMessage
1211
1312from .channel import Channel
14- from .pending import PendingRpcs
1513
1614_LOGGER = logging.getLogger(__name__)
1715_PORT = 58867
@@ -47,8 +45,6 @@ def __init__(self, host: str, local_key: str):
4745 self._subscribers: list[Callable[[RoborockMessage], None]] = []
4846 self._is_connected = False
4947
50- # RPC support
51- self._pending_rpcs: PendingRpcs[int, RoborockMessage] = PendingRpcs()
5248 self._decoder: Decoder = create_local_decoder(local_key)
5349 self._encoder: Encoder = create_local_encoder(local_key)
5450
@@ -87,7 +83,6 @@ def _data_received(self, data: bytes) -> None:
8783 return
8884 for message in messages:
8985 _LOGGER.debug("Received message: %s", message)
90- asyncio.create_task(self._resolve_future_with_lock(message))
9186 for callback in self._subscribers:
9287 try:
9388 callback(message)
@@ -109,37 +104,24 @@ def unsubscribe() -> None:
109104
110105 return unsubscribe
111106
112- async def _resolve_future_with_lock(self, message: RoborockMessage) -> None:
113- """Resolve waiting future with proper locking."""
114- if (request_id := message.get_request_id()) is None:
115- _LOGGER.debug("Received message with no request_id")
116- return
117- await self._pending_rpcs.resolve(request_id, message)
107+ async def publish(self, message: RoborockMessage) -> None:
108+ """Send a command message.
118109
119- async def send_message(self, message: RoborockMessage, timeout: float = 10.0) -> RoborockMessage:
120- """Send a command message and wait for the response message."""
110+ The caller is responsible for associating the message with its response.
111+ """
121112 if not self._transport or not self._is_connected:
122113 raise RoborockConnectionException("Not connected to device")
123114
124- try:
125- if (request_id := message.get_request_id()) is None:
126- raise RoborockException("Message must have a request_id for RPC calls")
127- except (ValueError, JSONDecodeError) as err:
128- _LOGGER.exception("Error getting request_id from message: %s", err)
129- raise RoborockException(f"Invalid message format, Message must have a request_id: {err}") from err
130-
131- future: asyncio.Future[RoborockMessage] = await self._pending_rpcs.start(request_id)
132115 try:
133116 encoded_msg = self._encoder(message)
117+ except Exception as err:
118+ _LOGGER.exception("Error encoding MQTT message: %s", err)
119+ raise RoborockException(f"Failed to encode MQTT message: {err}") from err
120+ try:
134121 self._transport.write(encoded_msg)
135- return await asyncio.wait_for(future, timeout=timeout)
136- except asyncio.TimeoutError as ex:
137- await self._pending_rpcs.pop(request_id)
138- raise RoborockException(f"Command timed out after {timeout}s") from ex
139- except Exception:
122+ except Exception as err:
140123 logging.exception("Uncaught error sending command")
141- await self._pending_rpcs.pop(request_id)
142- raise
124+ raise RoborockException(f"Failed to send message: {message}") from err
143125
144126
145127# This module provides a factory function to create LocalChannel instances.
0 commit comments