Skip to content
Open
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
27 changes: 6 additions & 21 deletions roborock/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,9 +594,9 @@ async def maps(ctx, device_id: str):
await _display_v1_trait(context, device_id, lambda v1: v1.maps)


# The Q10 publishes its map asynchronously after a dpMultiMap list/get request.
# Firmware throttles pushes to ~once per 60-70s, so rapid re-requests may not be
# answered immediately. This bounds how long a one-shot CLI command waits.
# The Q10 publishes its current map asynchronously after a REQUEST_DPS. Firmware
# throttles pushes to ~once per 60-70s, so rapid re-requests may not be answered
# immediately. This bounds how long a one-shot CLI command waits.
_Q10_MAP_PUSH_TIMEOUT = 30.0


Expand All @@ -609,10 +609,9 @@ async def _await_q10_map_push(
) -> bool:
"""Request Q10 map content and wait for usable map-trait state.
A Q10 needs a saved-map ID before it can request content. The map list and
content have independent refresh schedules, so the list is requested only
when no ID is stored. The content then arrives as a later ``MAP_RESPONSE``
and is published through the standard trait update interface.
The read-only ``REQUEST_DPS`` request returns immediately; current map
content arrives as a later ``MAP_RESPONSE`` and is published through the
standard trait update interface.
"""
loop = asyncio.get_running_loop()
updated: asyncio.Future[None] = loop.create_future()
Expand All @@ -624,20 +623,6 @@ def on_update() -> None:
unsub = properties.map.add_update_listener(on_update)
try:
async with asyncio.timeout(timeout):
if properties.maps.current_map_id is None:
map_list_updated: asyncio.Future[None] = loop.create_future()

def on_map_list_update() -> None:
if properties.maps.current_map_id is not None and not map_list_updated.done():
map_list_updated.set_result(None)

unsub_maps = properties.maps.add_update_listener(on_map_list_update)
try:
await properties.maps.refresh()
if properties.maps.current_map_id is None:
await map_list_updated
finally:
unsub_maps()
await properties.map.refresh()
await updated
return True
Expand Down
29 changes: 11 additions & 18 deletions roborock/devices/traits/b01/q10/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
* restricted zones, virtual walls and dock state arrive as ordinary DPS values.

``MapDpsTrait`` owns the low-level map-specific DPS read model.
``MapContentTrait`` uses a stored ID from ``MapsTrait`` only when it requests
content. It combines the latest map and trace packets with the map DPS state
through the pure functions in :mod:`roborock.map.b01_q10_render`. Map-list
updates do not refresh content.
``MapContentTrait`` requests a current-map push through ``REQUEST_DPS`` and
combines the latest map and trace packets with the map DPS state through the
pure functions in :mod:`roborock.map.b01_q10_render`. Saved-map list/detail
operations remain on ``MapsTrait``.
"""

import logging
Expand Down Expand Up @@ -107,20 +107,13 @@ def __init__(
self._map_dps.add_update_listener(self._map_dps_updated)

async def refresh(self) -> None:
"""Request content for the first map in the latest saved-map list."""
if (map_id := self._maps.current_map_id) is None:
raise RoborockException("Cannot request Q10 map content before the map list is available")
# Map lists and map content can change at different times. Reuse the
# stored ID so a content refresh does not also refresh the list.
await self._command.send(
B01_Q10_DP.COMMON,
{
str(B01_Q10_DP.MULTI_MAP.code): {
"op": "get",
"id": map_id,
}
},
)
"""Request a safe asynchronous current-map/status push.

Some ss07 firmware treats ``dpMultiMap op:get`` as an active
cleaning/relocation command. ``REQUEST_DPS`` is the device's read-only
current-map request and does not depend on a saved-map ID.
"""
await self._command.send(B01_Q10_DP.REQUEST_DPS, params={})

@property
def image_content(self) -> bytes | None:
Expand Down
Loading
Loading