|
14 | 14 | decode_rpc_response, |
15 | 15 | encode_mqtt_payload, |
16 | 16 | ) |
17 | | -from roborock.roborock_message import RoborockMessage |
| 17 | +from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol |
18 | 18 |
|
19 | 19 | _LOGGER = logging.getLogger(__name__) |
20 | 20 | _TIMEOUT = 10.0 |
@@ -99,3 +99,52 @@ def find_response(response_message: RoborockMessage) -> None: |
99 | 99 | raise |
100 | 100 | finally: |
101 | 101 | unsub() |
| 102 | + |
| 103 | + |
| 104 | +async def send_map_command(mqtt_channel: MqttChannel, request_message: Q7RequestMessage) -> bytes: |
| 105 | + """Send map upload command and wait for MAP_RESPONSE payload bytes.""" |
| 106 | + |
| 107 | + roborock_message = encode_mqtt_payload(request_message) |
| 108 | + future: asyncio.Future[bytes] = asyncio.get_running_loop().create_future() |
| 109 | + |
| 110 | + def find_response(response_message: RoborockMessage) -> None: |
| 111 | + if future.done(): |
| 112 | + return |
| 113 | + |
| 114 | + if response_message.protocol == RoborockMessageProtocol.MAP_RESPONSE and response_message.payload: |
| 115 | + future.set_result(response_message.payload) |
| 116 | + return |
| 117 | + |
| 118 | + try: |
| 119 | + decoded_dps = decode_rpc_response(response_message) |
| 120 | + except RoborockException: |
| 121 | + return |
| 122 | + |
| 123 | + for dps_value in decoded_dps.values(): |
| 124 | + if not isinstance(dps_value, str): |
| 125 | + continue |
| 126 | + try: |
| 127 | + inner = json.loads(dps_value) |
| 128 | + except (json.JSONDecodeError, TypeError): |
| 129 | + continue |
| 130 | + if not isinstance(inner, dict) or inner.get("msgId") != str(request_message.msg_id): |
| 131 | + continue |
| 132 | + code = inner.get("code", 0) |
| 133 | + if code != 0: |
| 134 | + future.set_exception(RoborockException(f"B01 command failed with code {code} ({request_message})")) |
| 135 | + return |
| 136 | + data = inner.get("data") |
| 137 | + if isinstance(data, dict) and isinstance(data.get("payload"), str): |
| 138 | + try: |
| 139 | + future.set_result(bytes.fromhex(data["payload"])) |
| 140 | + except ValueError: |
| 141 | + pass |
| 142 | + |
| 143 | + unsub = await mqtt_channel.subscribe(find_response) |
| 144 | + try: |
| 145 | + await mqtt_channel.publish(roborock_message) |
| 146 | + return await asyncio.wait_for(future, timeout=_TIMEOUT) |
| 147 | + except TimeoutError as ex: |
| 148 | + raise RoborockException(f"B01 map command timed out after {_TIMEOUT}s ({request_message})") from ex |
| 149 | + finally: |
| 150 | + unsub() |
0 commit comments