Skip to content

Commit 57fe737

Browse files
committed
chore: remove more complicated changes
1 parent 6e00244 commit 57fe737

File tree

4 files changed

+33
-200
lines changed

4 files changed

+33
-200
lines changed

roborock/clean_modes.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,6 @@ def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]:
9595
modes.append(VacuumModes.SMART_MODE)
9696
if features.is_customized_clean_supported:
9797
modes.append(VacuumModes.CUSTOMIZED)
98-
99-
def get_clean_modes(features: DeviceFeatures) -> list[CleanModes]:
100-
"""Get the valid clean modes for the device - also known as 'fan power' or 'suction mode'"""
101-
modes = [CleanModes.QUIET, CleanModes.BALANCED, CleanModes.TURBO, CleanModes.MAX]
102-
if features.is_max_plus_mode_supported or features.is_none_pure_clean_mop_with_max_plus:
103-
# If the vacuum has max plus mode supported
104-
modes.append(CleanModes.MAX_PLUS)
105-
if features.is_pure_clean_mop_supported:
106-
# If the vacuum is capable of 'pure mop clean' aka no vacuum
107-
modes.append(CleanModes.OFF)
108-
else:
109-
# If not, we can add gentle
110-
modes.append(CleanModes.GENTLE)
11198
return modes
11299

113100

roborock/containers.py

Lines changed: 26 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,8 @@
88
from datetime import timezone
99
from enum import Enum
1010
from functools import cached_property
11-
from typing import Any, NamedTuple, TypeVar, get_args, get_origin
12-
13-
from .clean_modes import (
14-
CleanRoutes,
15-
RoborockModeEnum,
16-
VacuumModes,
17-
WaterModes,
18-
get_clean_modes,
19-
get_clean_routes,
20-
get_water_modes,
21-
)
11+
from typing import Any, NamedTuple, get_args, get_origin
12+
2213
from .code_mappings import (
2314
SHORT_MODEL_TO_ENUM,
2415
RoborockCategory,
@@ -28,6 +19,7 @@
2819
RoborockDockTypeCode,
2920
RoborockDockWashTowelModeCode,
3021
RoborockErrorCode,
22+
RoborockFanPowerCode,
3123
RoborockFanSpeedP10,
3224
RoborockFanSpeedQ7Max,
3325
RoborockFanSpeedQRevoCurv,
@@ -41,6 +33,7 @@
4133
RoborockFanSpeedSaros10R,
4234
RoborockFinishReason,
4335
RoborockInCleaning,
36+
RoborockMopIntensityCode,
4437
RoborockMopIntensityP10,
4538
RoborockMopIntensityQ7Max,
4639
RoborockMopIntensityQRevoCurv,
@@ -52,6 +45,7 @@
5245
RoborockMopIntensityS8MaxVUltra,
5346
RoborockMopIntensitySaros10,
5447
RoborockMopIntensitySaros10R,
48+
RoborockMopModeCode,
5549
RoborockMopModeQRevoCurv,
5650
RoborockMopModeQRevoMaster,
5751
RoborockMopModeQRevoMaxV,
@@ -96,9 +90,9 @@
9690
ROBOROCK_G20S_Ultra,
9791
)
9892
from .device_features import DeviceFeatures
93+
from .exceptions import RoborockException
9994

10095
_LOGGER = logging.getLogger(__name__)
101-
T = TypeVar("T", bound="RoborockModeEnum")
10296

10397

10498
def _camelize(s: str):
@@ -359,12 +353,12 @@ class Status(RoborockBase):
359353
back_type: int | None = None
360354
wash_phase: int | None = None
361355
wash_ready: int | None = None
362-
fan_power: int | None = None
356+
fan_power: RoborockFanPowerCode | None = None
363357
dnd_enabled: int | None = None
364358
map_status: int | None = None
365359
is_locating: int | None = None
366360
lock_status: int | None = None
367-
water_box_mode: int | None = None
361+
water_box_mode: RoborockMopIntensityCode | None = None
368362
water_box_carriage_status: int | None = None
369363
mop_forbidden_enable: int | None = None
370364
camera_status: int | None = None
@@ -377,7 +371,7 @@ class Status(RoborockBase):
377371
dust_collection_status: int | None = None
378372
auto_dust_collection: int | None = None
379373
avoid_count: int | None = None
380-
mop_mode: int | None = None
374+
mop_mode: RoborockMopModeCode | None = None
381375
debug_mode: int | None = None
382376
collision_avoid_status: int | None = None
383377
switch_map_mode: int | None = None
@@ -398,64 +392,38 @@ class Status(RoborockBase):
398392
error_code_name: str | None = None
399393
state_name: str | None = None
400394
water_box_mode_name: str | None = None
395+
fan_power_options: list[str] = field(default_factory=list)
401396
fan_power_name: str | None = None
402397
mop_mode_name: str | None = None
403-
supported_fan_powers: list[VacuumModes] = field(default_factory=list, init=False, repr=False)
404-
supported_water_modes: list[WaterModes] = field(default_factory=list, init=False, repr=False)
405-
supported_mop_modes: list[CleanRoutes] = field(default_factory=list, init=False, repr=False)
406398

407399
def __post_init__(self) -> None:
408400
self.square_meter_clean_area = round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
409401
if self.error_code is not None:
410402
self.error_code_name = self.error_code.name
411403
if self.state is not None:
412404
self.state_name = self.state.name
413-
414-
@staticmethod
415-
def _find_enum_by_code(code: int | None, enums: list[T]) -> T | None:
416-
"""Helper to find an enum member in a list by its code."""
417-
if code is None:
418-
return None
419-
for enum_member in enums:
420-
if enum_member.code == code:
421-
return enum_member
422-
return None
423-
424-
@staticmethod
425-
def _find_code_by_name(name: str, enums: list[T]) -> int | None:
426-
"""Helper to find an enum member in a list by its code."""
427-
for enum_member in enums:
428-
if enum_member.value == name:
429-
return enum_member.code
430-
return None
431-
432-
def configure(self, features: DeviceFeatures, region: str) -> None:
433-
"""
434-
Configures the status object with device-specific capabilities and processes the data.
435-
This method should be called immediately after creating the Status object.
436-
"""
437-
self.supported_fan_powers = get_clean_modes(features)
438-
self.supported_water_modes = get_water_modes(features)
439-
self.supported_mop_modes = get_clean_routes(features, region)
440-
fan_power_enum = self._find_enum_by_code(self.fan_power, self.supported_fan_powers)
441-
self.fan_power_name = fan_power_enum.value if fan_power_enum else None
442-
443-
# Resolve Water Mode
444-
water_box_mode_enum = self._find_enum_by_code(self.water_box_mode, self.supported_water_modes)
445-
self.water_box_mode_name = water_box_mode_enum.value if water_box_mode_enum else None
446-
447-
# Resolve Mop Mode (Clean Route)
448-
mop_mode_enum = self._find_enum_by_code(self.mop_mode, self.supported_mop_modes)
449-
self.mop_mode_name = mop_mode_enum.value if mop_mode_enum else None
405+
if self.water_box_mode is not None:
406+
self.water_box_mode_name = self.water_box_mode.name
407+
if self.fan_power is not None:
408+
self.fan_power_options = self.fan_power.keys()
409+
self.fan_power_name = self.fan_power.name
410+
if self.mop_mode is not None:
411+
self.mop_mode_name = self.mop_mode.name
450412

451413
def get_fan_speed_code(self, fan_speed: str) -> int:
452-
return self._find_code_by_name(fan_speed, self.supported_fan_powers)
414+
if self.fan_power is None:
415+
raise RoborockException("Attempted to get fan speed before status has been updated.")
416+
return self.fan_power.as_dict().get(fan_speed)
453417

454418
def get_mop_intensity_code(self, mop_intensity: str) -> int:
455-
return self._find_code_by_name(mop_intensity, self.supported_water_modes)
419+
if self.water_box_mode is None:
420+
raise RoborockException("Attempted to get mop_intensity before status has been updated.")
421+
return self.water_box_mode.as_dict().get(mop_intensity)
456422

457423
def get_mop_mode_code(self, mop_mode: str) -> int:
458-
return self._find_code_by_name(mop_mode, self.supported_mop_modes)
424+
if self.mop_mode is None:
425+
raise RoborockException("Attempted to get mop_mode before status has been updated.")
426+
return self.mop_mode.as_dict().get(mop_mode)
459427

460428
@property
461429
def current_map(self) -> int | None:
@@ -465,33 +433,6 @@ def current_map(self) -> int | None:
465433
return None
466434

467435

468-
class CustomStatus:
469-
"""A factory for creating fully configured Status objects for a specific device."""
470-
471-
def __init__(self, features: DeviceFeatures, region: str):
472-
"""
473-
Initializes the factory with the device-specific configuration.
474-
475-
Args:
476-
features: The DeviceFeatures object for the target device.
477-
region: The region code for the device (e.g., "US", "CN").
478-
"""
479-
self._features = features
480-
self._region = region
481-
482-
def from_dict(self, data: dict) -> Status:
483-
"""
484-
Creates a Status instance from a dictionary and immediately configures it.
485-
"""
486-
# Step 1: Create the base Status object from the raw API data.
487-
instance = Status.from_dict(data)
488-
489-
# Step 2: Configure it with the stored features and region.
490-
instance.configure(features=self._features, region=self._region)
491-
492-
return instance
493-
494-
495436
@dataclass
496437
class S4MaxStatus(Status):
497438
fan_power: RoborockFanSpeedS6Pure | None = None
@@ -789,7 +730,6 @@ class DeviceData(RoborockBase):
789730
device: HomeDataDevice
790731
model: str
791732
host: str | None = None
792-
region: str = "us"
793733
product_nickname: RoborockProductNickname | None = None
794734
device_features: DeviceFeatures | None = None
795735

roborock/version_1_apis/roborock_client_v1.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from typing import Any, TypeVar, final
88

99
from roborock import (
10-
CustomStatus,
1110
DeviceProp,
1211
DockSummary,
1312
RoborockCommand,
@@ -33,10 +32,12 @@
3332
DnDTimer,
3433
DustCollectionMode,
3534
FlowLedStatus,
35+
ModelStatus,
3636
MultiMapsList,
3737
NetworkInfo,
3838
RoborockBase,
3939
RoomMapping,
40+
S7MaxVStatus,
4041
ServerTimer,
4142
SmartWashParams,
4243
Status,
@@ -153,11 +154,11 @@ class RoborockClientV1(RoborockClient, ABC):
153154
def __init__(self, device_info: DeviceData, security_data: SecurityData | None) -> None:
154155
"""Initializes the Roborock client."""
155156
super().__init__(device_info)
156-
self._status_type = CustomStatus(device_info.device_features, region=device_info.region)
157157
if security_data is not None:
158158
self._diagnostic_data.update({"misc_info": security_data.to_diagnostic_data()})
159159
self._map_response_decoder = create_map_response_decoder(security_data)
160160

161+
self._status_type: type[Status] = ModelStatus.get(device_info.model, S7MaxVStatus)
161162
self.cache: dict[CacheableAttribute, AttributeCache] = {
162163
cacheable_attribute: AttributeCache(attr, self._send_command)
163164
for cacheable_attribute, attr in get_cache_map().items()
@@ -171,14 +172,14 @@ async def async_release(self) -> None:
171172
[item.stop() for item in self.cache.values()]
172173

173174
@property
174-
def status_type(self) -> CustomStatus:
175+
def status_type(self) -> type[Status]:
175176
"""Gets the status type for this device"""
176177
return self._status_type
177178

178179
async def get_status(self) -> Status:
179180
data = self._status_type.from_dict(await self.cache[CacheableAttribute.status].async_value(force=True))
180181
if data is None:
181-
return self._status_type.from_dict({})
182+
return self._status_type()
182183
return data
183184

184185
async def get_dnd_timer(self) -> DnDTimer | None:

tests/test_containers.py

Lines changed: 2 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,8 @@
33
from dataclasses import dataclass
44
from typing import Any
55

6-
from roborock import (
7-
CleanRecord,
8-
CleanRoutes,
9-
CleanSummary,
10-
Consumable,
11-
DeviceFeatures,
12-
DnDTimer,
13-
HomeData,
14-
S7MaxVStatus,
15-
UserData,
16-
VacuumModes,
17-
WaterModes,
18-
)
6+
from roborock import CleanRecord, CleanSummary, Consumable, DnDTimer, HomeData, S7MaxVStatus, UserData
197
from roborock.code_mappings import (
20-
SHORT_MODEL_TO_ENUM,
218
RoborockCategory,
229
RoborockDockErrorCode,
2310
RoborockDockTypeCode,
@@ -27,7 +14,7 @@
2714
RoborockMopModeS7,
2815
RoborockStateCode,
2916
)
30-
from roborock.containers import CustomStatus, RoborockBase
17+
from roborock.containers import RoborockBase
3118

3219
from .mock_data import (
3320
CLEAN_RECORD,
@@ -339,85 +326,3 @@ def test_no_value():
339326
assert s.dock_type == RoborockDockTypeCode.unknown
340327
assert -9999 not in RoborockDockTypeCode.keys()
341328
assert "missing" not in RoborockDockTypeCode.values()
342-
343-
344-
def test_status_s7():
345-
model = "roborock.vacuum.a15"
346-
product_nickname = SHORT_MODEL_TO_ENUM.get(model.split(".")[-1])
347-
device_features = DeviceFeatures.from_feature_flags(
348-
new_feature_info=636084721975295,
349-
new_feature_info_str="0000000000002000",
350-
feature_info=[111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125],
351-
product_nickname=product_nickname,
352-
)
353-
354-
status_type = CustomStatus(device_features, "US")
355-
status = status_type.from_dict(STATUS)
356-
print(status.supported_fan_powers)
357-
assert set(status.supported_fan_powers) == {
358-
VacuumModes.QUIET,
359-
VacuumModes.BALANCED,
360-
VacuumModes.TURBO,
361-
VacuumModes.MAX,
362-
VacuumModes.OFF,
363-
VacuumModes.CUSTOMIZED,
364-
}
365-
assert status.water_box_mode == 203
366-
assert status.water_box_mode_name == WaterModes.INTENSE.value
367-
assert set(status.supported_water_modes) == {
368-
WaterModes.MILD,
369-
WaterModes.STANDARD,
370-
WaterModes.INTENSE,
371-
WaterModes.CUSTOMIZED,
372-
WaterModes.OFF,
373-
}
374-
assert set(status.supported_mop_modes) == {
375-
CleanRoutes.STANDARD,
376-
CleanRoutes.DEEP,
377-
CleanRoutes.DEEP_PLUS,
378-
CleanRoutes.CUSTOMIZED,
379-
}
380-
381-
382-
def test_status_qrevo_maxv():
383-
model = "roborock.vacuum.a87"
384-
product_nickname = SHORT_MODEL_TO_ENUM.get(model.split(".")[-1])
385-
device_features = DeviceFeatures.from_feature_flags(
386-
new_feature_info=4499197267967999,
387-
new_feature_info_str="508A977F7EFEFFFF",
388-
feature_info=[111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125],
389-
product_nickname=product_nickname,
390-
)
391-
392-
status_type = CustomStatus(device_features, "US")
393-
status = status_type.from_dict(STATUS)
394-
print(status.supported_fan_powers)
395-
assert set(status.supported_fan_powers) == {
396-
VacuumModes.QUIET,
397-
VacuumModes.BALANCED,
398-
VacuumModes.TURBO,
399-
VacuumModes.MAX,
400-
VacuumModes.MAX_PLUS,
401-
VacuumModes.OFF,
402-
VacuumModes.CUSTOMIZED,
403-
VacuumModes.SMART_MODE,
404-
}
405-
assert status.water_box_mode == 203
406-
assert status.water_box_mode_name == WaterModes.HIGH.value
407-
assert set(status.supported_water_modes) == {
408-
WaterModes.LOW,
409-
WaterModes.MEDIUM,
410-
WaterModes.HIGH,
411-
WaterModes.CUSTOM,
412-
WaterModes.CUSTOMIZED,
413-
WaterModes.SMART_MODE,
414-
WaterModes.OFF,
415-
}
416-
assert set(status.supported_mop_modes) == {
417-
CleanRoutes.FAST,
418-
CleanRoutes.STANDARD,
419-
CleanRoutes.DEEP,
420-
CleanRoutes.DEEP_PLUS,
421-
CleanRoutes.CUSTOMIZED,
422-
CleanRoutes.SMART_MODE,
423-
}

0 commit comments

Comments
 (0)