88from datetime import timezone
99from enum import Enum
1010from 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+
2213from .code_mappings import (
2314 SHORT_MODEL_TO_ENUM ,
2415 RoborockCategory ,
2819 RoborockDockTypeCode ,
2920 RoborockDockWashTowelModeCode ,
3021 RoborockErrorCode ,
22+ RoborockFanPowerCode ,
3123 RoborockFanSpeedP10 ,
3224 RoborockFanSpeedQ7Max ,
3325 RoborockFanSpeedQRevoCurv ,
4133 RoborockFanSpeedSaros10R ,
4234 RoborockFinishReason ,
4335 RoborockInCleaning ,
36+ RoborockMopIntensityCode ,
4437 RoborockMopIntensityP10 ,
4538 RoborockMopIntensityQ7Max ,
4639 RoborockMopIntensityQRevoCurv ,
5245 RoborockMopIntensityS8MaxVUltra ,
5346 RoborockMopIntensitySaros10 ,
5447 RoborockMopIntensitySaros10R ,
48+ RoborockMopModeCode ,
5549 RoborockMopModeQRevoCurv ,
5650 RoborockMopModeQRevoMaster ,
5751 RoborockMopModeQRevoMaxV ,
9690 ROBOROCK_G20S_Ultra ,
9791)
9892from .device_features import DeviceFeatures
93+ from .exceptions import RoborockException
9994
10095_LOGGER = logging .getLogger (__name__ )
101- T = TypeVar ("T" , bound = "RoborockModeEnum" )
10296
10397
10498def _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
496437class 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
0 commit comments