Skip to content

Commit 761c4cb

Browse files
committed
fix: Don't perform discovery when the device is cleaning
1 parent 65ebb75 commit 761c4cb

File tree

4 files changed

+50
-8
lines changed

4 files changed

+50
-8
lines changed

roborock/devices/traits/v1/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def __init__(
7171
self.rooms = RoomsTrait(home_data)
7272
self.maps = MapsTrait(self.status)
7373
self.map_content = MapContentTrait(map_parser_config)
74-
self.home = HomeTrait(self.maps, self.rooms, cache)
74+
self.home = HomeTrait(self.status, self.maps, self.rooms, cache)
7575
# This is a hack to allow setting the rpc_channel on all traits. This is
7676
# used so we can preserve the dataclass behavior when the values in the
7777
# traits are updated, but still want to allow them to have a reference

roborock/devices/traits/v1/home.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
import logging
1414
from typing import Self
1515

16+
from roborock.code_mappings import RoborockStateCode
1617
from roborock.containers import CombinedMapInfo, RoborockBase
1718
from roborock.devices.cache import Cache
1819
from roborock.devices.traits.v1 import common
19-
from roborock.exceptions import RoborockException
20+
from roborock.exceptions import RoborockDeviceBusy, RoborockException
2021
from roborock.roborock_typing import RoborockCommand
2122

2223
from .maps import MapsTrait
2324
from .rooms import RoomsTrait
25+
from .status import StatusTrait
2426

2527
_LOGGER = logging.getLogger(__name__)
2628

@@ -32,7 +34,13 @@ class HomeTrait(RoborockBase, common.V1TraitMixin):
3234

3335
command = RoborockCommand.GET_MAP_V1 # This is not used
3436

35-
def __init__(self, maps_trait: MapsTrait, rooms_trait: RoomsTrait, cache: Cache) -> None:
37+
def __init__(
38+
self,
39+
status_trait: StatusTrait,
40+
maps_trait: MapsTrait,
41+
rooms_trait: RoomsTrait,
42+
cache: Cache,
43+
) -> None:
3644
"""Initialize the HomeTrait.
3745
3846
We keep track of the MapsTrait and RoomsTrait to provide a comprehensive
@@ -49,6 +57,7 @@ def __init__(self, maps_trait: MapsTrait, rooms_trait: RoomsTrait, cache: Cache)
4957
accuracy.
5058
"""
5159
super().__init__()
60+
self._status_trait = status_trait
5261
self._maps_trait = maps_trait
5362
self._rooms_trait = rooms_trait
5463
self._cache = cache
@@ -58,21 +67,29 @@ async def discover_home(self) -> None:
5867
"""Iterate through all maps to discover rooms and cache them.
5968
6069
This will be a no-op if the home cache is already populated.
70+
71+
This cannot be called while the device is cleaning, as that would interrupt the
72+
cleaning process. This will raise `RoborockDeviceBusy` if the device is
73+
currently cleaning.
74+
75+
After discovery, the home cache will be populated and can be accessed via the `home_cache` property.
6176
"""
6277
cache_data = await self._cache.get()
6378
if cache_data.home_cache:
6479
_LOGGER.debug("Home cache already populated, skipping discovery")
6580
self._home_cache = cache_data.home_cache
6681
return
6782

83+
if self._status_trait.state == RoborockStateCode.cleaning:
84+
raise RoborockDeviceBusy("Cannot perform home discovery while the device is cleaning")
85+
6886
await self._maps_trait.refresh()
6987
if self._maps_trait.current_map_info is None:
7088
raise RoborockException("Cannot perform home discovery without current map info")
7189

7290
home_cache = await self._build_home_cache()
7391
_LOGGER.debug("Home discovery complete, caching data for %d maps", len(home_cache))
7492
await self._update_home_cache(home_cache)
75-
self._home_cache = home_cache
7693

7794
async def _refresh_map_data(self, map_info) -> CombinedMapInfo:
7895
"""Collect room data for a specific map and return CombinedMapInfo."""
@@ -129,8 +146,7 @@ async def refresh(self) -> Self:
129146
if current_map_data:
130147
map_data = await self._refresh_map_data(current_map_info)
131148
if map_data != current_map_data:
132-
self._home_cache[map_flag] = map_data
133-
await self._update_home_cache(self._home_cache)
149+
await self._update_home_cache({**self._home_cache, map_flag: map_data})
134150

135151
return self
136152

@@ -155,3 +171,4 @@ async def _update_home_cache(self, home_cache: dict[int, CombinedMapInfo]) -> No
155171
cache_data = await self._cache.get()
156172
cache_data.home_cache = home_cache
157173
await self._cache.set(cache_data)
174+
self._home_cache = home_cache

roborock/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,7 @@ class RoborockRateLimit(RoborockException):
8181

8282
class RoborockNoResponseFromBaseURL(RoborockException):
8383
"""We could not find an url that had a record of the given account."""
84+
85+
86+
class RoborockDeviceBusy(RoborockException):
87+
"""Class for Roborock device busy exceptions."""

tests/devices/traits/v1/test_home.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
import pytest
77

8+
from roborock.code_mappings import RoborockStateCode
89
from roborock.containers import CombinedMapInfo
910
from roborock.devices.cache import InMemoryCache
1011
from roborock.devices.device import RoborockDevice
1112
from roborock.devices.traits.v1.home import HomeTrait
1213
from roborock.devices.traits.v1.maps import MapsTrait
1314
from roborock.devices.traits.v1.rooms import RoomsTrait
1415
from roborock.devices.traits.v1.status import StatusTrait
16+
from roborock.exceptions import RoborockDeviceBusy
1517
from roborock.roborock_typing import RoborockCommand
1618
from tests import mock_data
1719

@@ -97,9 +99,9 @@ def rooms_trait(device: RoborockDevice) -> RoomsTrait:
9799

98100

99101
@pytest.fixture
100-
def home_trait(maps_trait: MapsTrait, rooms_trait: RoomsTrait, cache) -> HomeTrait:
102+
def home_trait(status_trait: StatusTrait, maps_trait: MapsTrait, rooms_trait: RoomsTrait, cache) -> HomeTrait:
101103
"""Create a HomeTrait instance with mocked dependencies."""
102-
return HomeTrait(maps_trait, rooms_trait, cache)
104+
return HomeTrait(status_trait, maps_trait, rooms_trait, cache)
103105

104106

105107
async def test_discover_home_empty_cache(
@@ -279,6 +281,25 @@ async def test_current_map_data_property(
279281
assert home_trait.current_map_data is None
280282

281283

284+
async def test_discover_home_device_busy_cleaning(
285+
status_trait: StatusTrait,
286+
home_trait: HomeTrait,
287+
mock_rpc_channel: AsyncMock,
288+
mock_mqtt_rpc_channel: AsyncMock,
289+
) -> None:
290+
"""Test that discovery raises RoborockDeviceBusy when device is cleaning."""
291+
# Set the status trait state to cleaning
292+
status_trait.state = RoborockStateCode.cleaning
293+
294+
# Attempt to discover home while cleaning
295+
with pytest.raises(RoborockDeviceBusy, match="Cannot perform home discovery while the device is cleaning"):
296+
await home_trait.discover_home()
297+
298+
# Verify no RPC calls were made (discovery was prevented)
299+
assert mock_rpc_channel.send_command.call_count == 0
300+
assert mock_mqtt_rpc_channel.send_command.call_count == 0
301+
302+
282303
async def test_single_map_no_switching(
283304
home_trait: HomeTrait,
284305
mock_rpc_channel: AsyncMock,

0 commit comments

Comments
 (0)