roborock.data.v1.v1_clean_modes
1from __future__ import annotations 2 3import typing 4from enum import StrEnum 5from typing import TypeVar 6 7from ...exceptions import RoborockUnsupportedFeature 8from ..code_mappings import RoborockModeEnum 9 10if typing.TYPE_CHECKING: 11 from roborock.device_features import DeviceFeatures 12 13 14class VacuumModes(RoborockModeEnum): 15 GENTLE = ("gentle", 105) 16 OFF = ("off", 105) 17 QUIET = ("quiet", 101) 18 BALANCED = ("balanced", 102) 19 TURBO = ("turbo", 103) 20 MAX = ("max", 104) 21 MAX_PLUS = ("max_plus", 108) 22 OFF_RAISE_MAIN_BRUSH = ("off_raise_main_brush", 109) 23 CUSTOMIZED = ("custom", 106) 24 SMART_MODE = ("smart_mode", 110) 25 26 27class CleanRoutes(RoborockModeEnum): 28 STANDARD = ("standard", 300) 29 DEEP = ("deep", 301) 30 DEEP_PLUS = ("deep_plus", 303) 31 FAST = ("fast", 304) 32 DEEP_PLUS_CN = ("deep_plus_cn", 305, "deep_plus") 33 SMART_MODE = ("smart_mode", 306) 34 CUSTOMIZED = ("custom", 302) 35 36 37class VacuumModesOld(RoborockModeEnum): 38 QUIET = ("quiet", 38) 39 BALANCED = ("balanced", 60) 40 TURBO = ("turbo", 75) 41 MAX = ("max", 100) 42 43 44class WaterModes(RoborockModeEnum): 45 OFF = ("off", 200) 46 LOW = ("low", 201) 47 MILD = ("mild", 201) 48 MEDIUM = ("medium", 202) 49 STANDARD = ("standard", 202) 50 HIGH = ("high", 203) 51 INTENSE = ("intense", 203) 52 MIN = ("min", 205) 53 MAX = ("max", 206) 54 CUSTOMIZED = ("custom", 204) 55 CUSTOM = ("custom_water_flow", 207) 56 EXTREME = ("extreme", 208) 57 SMART_MODE = ("smart_mode", 209) 58 SMART_WATER = ("smart_water", 210) 59 PURE_WATER_FLOW_START = ("slight", 221) 60 PURE_WATER_FLOW_SMALL = ("pure_water_flow_small", 225, "low") 61 PURE_WATER_FLOW_GENTLE = ("gentle", 230) 62 PURE_WATER_FLOW_MIDDLE = ("pure_water_flow_middle", 235, "medium") 63 PURE_WATER_FLOW_LARGE = ("moderate", 240) 64 PURE_WATER_SUPER_BEGIN = ("pure_water_super_begin", 245, "high") 65 PURE_WATER_FLOW_END = ("pure_water_flow_end", 250, "extreme") 66 67 68class WashTowelModes(RoborockModeEnum): 69 SMART = ("smart", 10) 70 LIGHT = ("light", 0) 71 BALANCED = ("balanced", 1) 72 DEEP = ("deep", 2) 73 SUPER_DEEP = ("super_deep", 8) 74 75 76class CleaningMode(StrEnum): 77 """High-level cleaning intent derived from the lower-level motor settings. 78 79 Prefer this abstraction when you want to present or switch between the 80 user-facing cleaning behaviors exposed by the app. The lower-level 81 `VacuumModes`, `WaterModes`, and `CleanRoutes` enums are still useful for 82 fine-grained selection. 83 """ 84 85 VACUUM = "vacuum" 86 VAC_AND_MOP = "vac_and_mop" 87 MOP = "mop" 88 CUSTOM = "custom" 89 SMART_MODE = "smart_mode" 90 91 92_WATER_SLIDE_MODES: tuple[WaterModes, ...] = ( 93 WaterModes.OFF, 94 WaterModes.PURE_WATER_FLOW_START, 95 WaterModes.PURE_WATER_FLOW_SMALL, 96 WaterModes.PURE_WATER_FLOW_GENTLE, 97 WaterModes.PURE_WATER_FLOW_MIDDLE, 98 WaterModes.PURE_WATER_FLOW_LARGE, 99 WaterModes.PURE_WATER_SUPER_BEGIN, 100 WaterModes.PURE_WATER_FLOW_END, 101) 102 103# Water slide devices report the raw slider position (1-30) as 220 + position. 104# The app groups positions into named ranges, keyed here by their last position. 105_WATER_SLIDE_RANGES: tuple[tuple[int, WaterModes], ...] = ( 106 (3, WaterModes.PURE_WATER_FLOW_START), 107 (7, WaterModes.PURE_WATER_FLOW_SMALL), 108 (12, WaterModes.PURE_WATER_FLOW_GENTLE), 109 (17, WaterModes.PURE_WATER_FLOW_MIDDLE), 110 (22, WaterModes.PURE_WATER_FLOW_LARGE), 111 (27, WaterModes.PURE_WATER_SUPER_BEGIN), 112 (30, WaterModes.PURE_WATER_FLOW_END), 113) 114 115ModeEnumT = TypeVar("ModeEnumT", bound=RoborockModeEnum) 116 117 118def get_wash_towel_modes(features: DeviceFeatures) -> list[WashTowelModes]: 119 """Get the valid wash towel modes for the device""" 120 modes = [WashTowelModes.LIGHT, WashTowelModes.BALANCED, WashTowelModes.DEEP] 121 if features.is_super_deep_wash_supported and not features.is_dirty_replenish_clean_supported: 122 modes.append(WashTowelModes.SUPER_DEEP) 123 elif features.is_dirty_replenish_clean_supported: 124 modes.append(WashTowelModes.SMART) 125 return modes 126 127 128def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]: 129 """Get the valid clean modes for the device - also known as 'fan power' or 'suction mode'""" 130 modes = [VacuumModes.QUIET, VacuumModes.BALANCED, VacuumModes.TURBO, VacuumModes.MAX] 131 if features.is_max_plus_mode_supported or features.is_none_pure_clean_mop_with_max_plus: 132 # If the vacuum has max plus mode supported 133 modes.append(VacuumModes.MAX_PLUS) 134 if features.is_pure_clean_mop_supported: 135 # If the vacuum is capable of 'pure mop clean' aka no vacuum 136 modes.append(VacuumModes.OFF) 137 else: 138 # If not, we can add gentle 139 modes.append(VacuumModes.GENTLE) 140 if features.is_smart_clean_mode_set_supported: 141 modes.append(VacuumModes.SMART_MODE) 142 if features.is_customized_clean_supported: 143 modes.append(VacuumModes.CUSTOMIZED) 144 return modes 145 146 147def get_clean_routes(features: DeviceFeatures, region: str) -> list[CleanRoutes]: 148 """The routes that the vacuum will take while mopping""" 149 if not features.is_clean_route_setting_supported: 150 return [] 151 if features.is_none_pure_clean_mop_with_max_plus: 152 return [CleanRoutes.FAST, CleanRoutes.STANDARD] 153 supported = [CleanRoutes.STANDARD] 154 if not features.is_clean_efficiency_supported: 155 supported.append(CleanRoutes.DEEP) 156 if features.is_careful_slow_mop_supported: 157 if ( 158 not features.is_corner_clean_mode_supported 159 and features.is_clean_route_deep_slow_plus_supported 160 and region == "cn" 161 ): 162 supported.append(CleanRoutes.DEEP_PLUS_CN) 163 else: 164 supported.append(CleanRoutes.DEEP_PLUS) 165 166 if features.is_clean_route_fast_mode_supported: 167 supported.append(CleanRoutes.FAST) 168 if features.is_smart_clean_mode_set_supported: 169 supported.append(CleanRoutes.SMART_MODE) 170 if features.is_customized_clean_supported: 171 supported.append(CleanRoutes.CUSTOMIZED) 172 173 return supported 174 175 176def get_water_modes(features: DeviceFeatures) -> list[WaterModes]: 177 """Get the valid water modes for the device - also known as 'water flow' or 'water level'""" 178 # Water slide mode supports a separate set of water flow codes. 179 if features.is_water_slide_mode_supported: 180 return list(_WATER_SLIDE_MODES) 181 182 supported_modes = [WaterModes.OFF] 183 if features.is_mop_shake_module_supported: 184 # For mops that have the vibrating mop pad, they do mild standard intense 185 supported_modes.extend([WaterModes.MILD, WaterModes.STANDARD, WaterModes.INTENSE]) 186 else: 187 supported_modes.extend([WaterModes.LOW, WaterModes.MEDIUM, WaterModes.HIGH]) 188 if features.is_custom_water_box_distance_supported: 189 # This is for devices that allow you to set a custom water flow from 0-100 190 supported_modes.append(WaterModes.CUSTOM) 191 if features.is_mop_shake_module_supported and features.is_mop_shake_water_max_supported: 192 supported_modes.append(WaterModes.EXTREME) 193 if features.is_smart_clean_mode_set_supported: 194 supported_modes.append(WaterModes.SMART_MODE) 195 if features.is_customized_clean_supported: 196 supported_modes.append(WaterModes.CUSTOMIZED) 197 198 return supported_modes 199 200 201def get_water_slide_mode_name(code: int) -> str | None: 202 """Get the app's range name for a water slide code, or None if out of range.""" 203 mode = _resolve_water_slide_mode(code) 204 return mode.display_name if mode is not None else None 205 206 207def _resolve_water_slide_mode(code: int) -> WaterModes | None: 208 """Resolve a raw slider code to the water mode for its app range.""" 209 if code == 200: 210 return WaterModes.OFF 211 if code == WaterModes.SMART_WATER.code: 212 return WaterModes.SMART_WATER 213 position = code - 220 214 if position < 1: 215 return None 216 for last_position, mode in _WATER_SLIDE_RANGES: 217 if position <= last_position: 218 return mode 219 return None 220 221 222def get_water_mode_mapping(features: DeviceFeatures) -> dict[int, str]: 223 """Get water mode mapping by supported feature set. 224 225 Water slide modes share user-facing names with legacy modes (e.g. "low" is 226 201 or 225), so the mapping uses display_name rather than the enum value. 227 """ 228 return {mode.code: mode.display_name for mode in get_water_modes(features)} 229 230 231def get_cleaning_mode_options(features: DeviceFeatures) -> list[CleaningMode]: 232 """Return the supported high-level cleaning modes for the device. 233 234 These options are the preferred user-facing choices because they bundle the 235 correct fan, water, and mop-route settings together for the device. Callers 236 should generally present these instead of mixing lower-level mode enums 237 unless they explicitly need fine-grained control. 238 """ 239 if not features.is_support_water_mode: 240 return [] 241 242 supported_water_modes = get_water_modes(features) 243 options = [CleaningMode.VACUUM, CleaningMode.VAC_AND_MOP] 244 if features.is_pure_clean_mop_supported: 245 options.append(CleaningMode.MOP) 246 if features.is_customized_clean_supported and WaterModes.CUSTOMIZED in supported_water_modes: 247 options.append(CleaningMode.CUSTOM) 248 if features.is_smart_clean_mode_set_supported and WaterModes.SMART_MODE in supported_water_modes: 249 options.append(CleaningMode.SMART_MODE) 250 return options 251 252 253def get_mop_only_vacuum_mode(features: DeviceFeatures) -> VacuumModes: 254 """Return the vacuum mode used by the app for mop-only cleaning.""" 255 if not features.is_pure_clean_mop_supported: 256 raise RoborockUnsupportedFeature("Mop-only cleaning is not supported") 257 # Main-brush lift is a device capability, not an alternate fan-power 258 # command. The app still sends CleanModeZero (105) for mop-only cleaning. 259 return VacuumModes.OFF 260 261 262def _get_default_mopping_water_mode(features: DeviceFeatures) -> WaterModes: 263 """Pick a sensible default water mode when mopping for the device.""" 264 # Water-slide devices use a disjoint set of water codes; pick a mid-flow 265 # slide code instead of the standard 202, which they don't accept. 266 if features.is_water_slide_mode_supported: 267 return WaterModes.PURE_WATER_FLOW_MIDDLE 268 return WaterModes.STANDARD 269 270 271def _get_clean_motor_mode_params( 272 mode: CleaningMode, 273 features: DeviceFeatures, 274) -> tuple[VacuumModes, WaterModes, CleanRoutes]: 275 """Return (fan_power, water_box_mode, mop_mode) enums for the high-level mode.""" 276 if mode == CleaningMode.VACUUM: 277 return (VacuumModes.BALANCED, WaterModes.OFF, CleanRoutes.STANDARD) 278 if mode == CleaningMode.VAC_AND_MOP: 279 return (VacuumModes.BALANCED, _get_default_mopping_water_mode(features), CleanRoutes.STANDARD) 280 if mode == CleaningMode.MOP: 281 return ( 282 get_mop_only_vacuum_mode(features), 283 _get_default_mopping_water_mode(features), 284 CleanRoutes.STANDARD, 285 ) 286 if mode == CleaningMode.CUSTOM: 287 return (VacuumModes.CUSTOMIZED, WaterModes.CUSTOMIZED, CleanRoutes.CUSTOMIZED) 288 if mode == CleaningMode.SMART_MODE: 289 return (VacuumModes.SMART_MODE, WaterModes.SMART_MODE, CleanRoutes.SMART_MODE) 290 raise RoborockUnsupportedFeature(f"Cleaning mode {mode.value!r} is not supported") 291 292 293def resolve_cleaning_mode(cleaning_mode: str | CleaningMode) -> CleaningMode: 294 """Resolve a string or enum into a CleaningMode value.""" 295 if isinstance(cleaning_mode, CleaningMode): 296 return cleaning_mode 297 try: 298 return CleaningMode(cleaning_mode) 299 except ValueError as err: 300 raise RoborockUnsupportedFeature(f"Cleaning mode {cleaning_mode!r} is not supported") from err 301 302 303def get_cleaning_mode_parameters(cleaning_mode: CleaningMode, features: DeviceFeatures) -> list[dict[str, int]]: 304 """Get the RPC payload for switching the high-level cleaning mode.""" 305 if cleaning_mode not in get_cleaning_mode_options(features): 306 raise RoborockUnsupportedFeature(f"Cleaning mode {cleaning_mode.value!r} is not supported") 307 308 fan_power, water_box_mode, mop_mode = _get_clean_motor_mode_params(cleaning_mode, features) 309 params: dict[str, int] = {"fan_power": fan_power.code, "water_box_mode": water_box_mode.code} 310 if features.is_clean_route_setting_supported: 311 params["mop_mode"] = mop_mode.code 312 return [params] 313 314 315def _resolve_mode_code(value: int | ModeEnumT | None, mode_cls: type[ModeEnumT]) -> ModeEnumT | None: 316 """Resolve a raw code or enum into a RoborockModeEnum.""" 317 if value is None: 318 return None 319 if isinstance(value, mode_cls): 320 return value 321 return mode_cls.from_code_optional(int(value)) 322 323 324def _resolve_clean_mode(value: int | VacuumModes | None, features: DeviceFeatures) -> VacuumModes | None: 325 """Resolve a vacuum mode code, accounting for feature-specific code aliases.""" 326 if value is None or isinstance(value, VacuumModes): 327 return value 328 if value == VacuumModes.OFF.code: 329 if features.is_pure_clean_mop_supported: 330 return get_mop_only_vacuum_mode(features) 331 return VacuumModes.GENTLE 332 return VacuumModes.from_code_optional(value) 333 334 335def _resolve_water_mode(value: int | WaterModes | None, features: DeviceFeatures) -> WaterModes | None: 336 """Resolve a water mode code, mapping raw slider positions on water slide devices.""" 337 if value is None or isinstance(value, WaterModes): 338 return value 339 if features.is_water_slide_mode_supported: 340 return _resolve_water_slide_mode(value) or WaterModes.from_code_optional(value) 341 return WaterModes.from_code_optional(value) 342 343 344def get_current_cleaning_mode( 345 clean_mode: int | VacuumModes | None, 346 water_mode: int | WaterModes | None, 347 mop_mode: int | CleanRoutes | None, 348 features: DeviceFeatures, 349) -> CleaningMode | None: 350 """Classify the current high-level cleaning mode from individual mode codes.""" 351 if not features.is_support_water_mode: 352 return None 353 clean_mode_enum = _resolve_clean_mode(clean_mode, features) 354 water_mode_enum = _resolve_water_mode(water_mode, features) 355 mop_mode_enum = _resolve_mode_code(mop_mode, CleanRoutes) 356 if clean_mode_enum is None or water_mode_enum is None: 357 return None 358 359 if is_smart_mode_set(water_mode_enum, clean_mode_enum, mop_mode_enum): 360 return CleaningMode.SMART_MODE 361 if is_mode_customized(clean_mode_enum, water_mode_enum, mop_mode_enum): 362 return CleaningMode.CUSTOM 363 if water_mode_enum != WaterModes.OFF: 364 try: 365 if clean_mode_enum == get_mop_only_vacuum_mode(features): 366 return CleaningMode.MOP 367 except RoborockUnsupportedFeature: 368 pass 369 if water_mode_enum == WaterModes.OFF: 370 return CleaningMode.VACUUM 371 return CleaningMode.VAC_AND_MOP 372 373 374def is_mode_customized( 375 clean_mode: VacuumModes | None, 376 water_mode: WaterModes | None, 377 mop_mode: CleanRoutes | None, 378) -> bool: 379 """Check if any of the cleaning modes are set to a custom value.""" 380 return ( 381 clean_mode == VacuumModes.CUSTOMIZED 382 or water_mode == WaterModes.CUSTOMIZED 383 or mop_mode == CleanRoutes.CUSTOMIZED 384 ) 385 386 387def is_smart_mode_set( 388 water_mode: WaterModes | None, 389 clean_mode: VacuumModes | None, 390 mop_mode: CleanRoutes | None, 391) -> bool: 392 """Check if the smart mode is set for the given water mode and clean mode""" 393 return ( 394 water_mode == WaterModes.SMART_MODE 395 or clean_mode == VacuumModes.SMART_MODE 396 or mop_mode == CleanRoutes.SMART_MODE 397 )
15class VacuumModes(RoborockModeEnum): 16 GENTLE = ("gentle", 105) 17 OFF = ("off", 105) 18 QUIET = ("quiet", 101) 19 BALANCED = ("balanced", 102) 20 TURBO = ("turbo", 103) 21 MAX = ("max", 104) 22 MAX_PLUS = ("max_plus", 108) 23 OFF_RAISE_MAIN_BRUSH = ("off_raise_main_brush", 109) 24 CUSTOMIZED = ("custom", 106) 25 SMART_MODE = ("smart_mode", 110)
A custom StrEnum that also stores an integer code for each member.
28class CleanRoutes(RoborockModeEnum): 29 STANDARD = ("standard", 300) 30 DEEP = ("deep", 301) 31 DEEP_PLUS = ("deep_plus", 303) 32 FAST = ("fast", 304) 33 DEEP_PLUS_CN = ("deep_plus_cn", 305, "deep_plus") 34 SMART_MODE = ("smart_mode", 306) 35 CUSTOMIZED = ("custom", 302)
A custom StrEnum that also stores an integer code for each member.
38class VacuumModesOld(RoborockModeEnum): 39 QUIET = ("quiet", 38) 40 BALANCED = ("balanced", 60) 41 TURBO = ("turbo", 75) 42 MAX = ("max", 100)
A custom StrEnum that also stores an integer code for each member.
45class WaterModes(RoborockModeEnum): 46 OFF = ("off", 200) 47 LOW = ("low", 201) 48 MILD = ("mild", 201) 49 MEDIUM = ("medium", 202) 50 STANDARD = ("standard", 202) 51 HIGH = ("high", 203) 52 INTENSE = ("intense", 203) 53 MIN = ("min", 205) 54 MAX = ("max", 206) 55 CUSTOMIZED = ("custom", 204) 56 CUSTOM = ("custom_water_flow", 207) 57 EXTREME = ("extreme", 208) 58 SMART_MODE = ("smart_mode", 209) 59 SMART_WATER = ("smart_water", 210) 60 PURE_WATER_FLOW_START = ("slight", 221) 61 PURE_WATER_FLOW_SMALL = ("pure_water_flow_small", 225, "low") 62 PURE_WATER_FLOW_GENTLE = ("gentle", 230) 63 PURE_WATER_FLOW_MIDDLE = ("pure_water_flow_middle", 235, "medium") 64 PURE_WATER_FLOW_LARGE = ("moderate", 240) 65 PURE_WATER_SUPER_BEGIN = ("pure_water_super_begin", 245, "high") 66 PURE_WATER_FLOW_END = ("pure_water_flow_end", 250, "extreme")
A custom StrEnum that also stores an integer code for each member.
69class WashTowelModes(RoborockModeEnum): 70 SMART = ("smart", 10) 71 LIGHT = ("light", 0) 72 BALANCED = ("balanced", 1) 73 DEEP = ("deep", 2) 74 SUPER_DEEP = ("super_deep", 8)
A custom StrEnum that also stores an integer code for each member.
77class CleaningMode(StrEnum): 78 """High-level cleaning intent derived from the lower-level motor settings. 79 80 Prefer this abstraction when you want to present or switch between the 81 user-facing cleaning behaviors exposed by the app. The lower-level 82 `VacuumModes`, `WaterModes`, and `CleanRoutes` enums are still useful for 83 fine-grained selection. 84 """ 85 86 VACUUM = "vacuum" 87 VAC_AND_MOP = "vac_and_mop" 88 MOP = "mop" 89 CUSTOM = "custom" 90 SMART_MODE = "smart_mode"
High-level cleaning intent derived from the lower-level motor settings.
Prefer this abstraction when you want to present or switch between the
user-facing cleaning behaviors exposed by the app. The lower-level
VacuumModes, WaterModes, and CleanRoutes enums are still useful for
fine-grained selection.
119def get_wash_towel_modes(features: DeviceFeatures) -> list[WashTowelModes]: 120 """Get the valid wash towel modes for the device""" 121 modes = [WashTowelModes.LIGHT, WashTowelModes.BALANCED, WashTowelModes.DEEP] 122 if features.is_super_deep_wash_supported and not features.is_dirty_replenish_clean_supported: 123 modes.append(WashTowelModes.SUPER_DEEP) 124 elif features.is_dirty_replenish_clean_supported: 125 modes.append(WashTowelModes.SMART) 126 return modes
Get the valid wash towel modes for the device
129def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]: 130 """Get the valid clean modes for the device - also known as 'fan power' or 'suction mode'""" 131 modes = [VacuumModes.QUIET, VacuumModes.BALANCED, VacuumModes.TURBO, VacuumModes.MAX] 132 if features.is_max_plus_mode_supported or features.is_none_pure_clean_mop_with_max_plus: 133 # If the vacuum has max plus mode supported 134 modes.append(VacuumModes.MAX_PLUS) 135 if features.is_pure_clean_mop_supported: 136 # If the vacuum is capable of 'pure mop clean' aka no vacuum 137 modes.append(VacuumModes.OFF) 138 else: 139 # If not, we can add gentle 140 modes.append(VacuumModes.GENTLE) 141 if features.is_smart_clean_mode_set_supported: 142 modes.append(VacuumModes.SMART_MODE) 143 if features.is_customized_clean_supported: 144 modes.append(VacuumModes.CUSTOMIZED) 145 return modes
Get the valid clean modes for the device - also known as 'fan power' or 'suction mode'
148def get_clean_routes(features: DeviceFeatures, region: str) -> list[CleanRoutes]: 149 """The routes that the vacuum will take while mopping""" 150 if not features.is_clean_route_setting_supported: 151 return [] 152 if features.is_none_pure_clean_mop_with_max_plus: 153 return [CleanRoutes.FAST, CleanRoutes.STANDARD] 154 supported = [CleanRoutes.STANDARD] 155 if not features.is_clean_efficiency_supported: 156 supported.append(CleanRoutes.DEEP) 157 if features.is_careful_slow_mop_supported: 158 if ( 159 not features.is_corner_clean_mode_supported 160 and features.is_clean_route_deep_slow_plus_supported 161 and region == "cn" 162 ): 163 supported.append(CleanRoutes.DEEP_PLUS_CN) 164 else: 165 supported.append(CleanRoutes.DEEP_PLUS) 166 167 if features.is_clean_route_fast_mode_supported: 168 supported.append(CleanRoutes.FAST) 169 if features.is_smart_clean_mode_set_supported: 170 supported.append(CleanRoutes.SMART_MODE) 171 if features.is_customized_clean_supported: 172 supported.append(CleanRoutes.CUSTOMIZED) 173 174 return supported
The routes that the vacuum will take while mopping
177def get_water_modes(features: DeviceFeatures) -> list[WaterModes]: 178 """Get the valid water modes for the device - also known as 'water flow' or 'water level'""" 179 # Water slide mode supports a separate set of water flow codes. 180 if features.is_water_slide_mode_supported: 181 return list(_WATER_SLIDE_MODES) 182 183 supported_modes = [WaterModes.OFF] 184 if features.is_mop_shake_module_supported: 185 # For mops that have the vibrating mop pad, they do mild standard intense 186 supported_modes.extend([WaterModes.MILD, WaterModes.STANDARD, WaterModes.INTENSE]) 187 else: 188 supported_modes.extend([WaterModes.LOW, WaterModes.MEDIUM, WaterModes.HIGH]) 189 if features.is_custom_water_box_distance_supported: 190 # This is for devices that allow you to set a custom water flow from 0-100 191 supported_modes.append(WaterModes.CUSTOM) 192 if features.is_mop_shake_module_supported and features.is_mop_shake_water_max_supported: 193 supported_modes.append(WaterModes.EXTREME) 194 if features.is_smart_clean_mode_set_supported: 195 supported_modes.append(WaterModes.SMART_MODE) 196 if features.is_customized_clean_supported: 197 supported_modes.append(WaterModes.CUSTOMIZED) 198 199 return supported_modes
Get the valid water modes for the device - also known as 'water flow' or 'water level'
202def get_water_slide_mode_name(code: int) -> str | None: 203 """Get the app's range name for a water slide code, or None if out of range.""" 204 mode = _resolve_water_slide_mode(code) 205 return mode.display_name if mode is not None else None
Get the app's range name for a water slide code, or None if out of range.
223def get_water_mode_mapping(features: DeviceFeatures) -> dict[int, str]: 224 """Get water mode mapping by supported feature set. 225 226 Water slide modes share user-facing names with legacy modes (e.g. "low" is 227 201 or 225), so the mapping uses display_name rather than the enum value. 228 """ 229 return {mode.code: mode.display_name for mode in get_water_modes(features)}
Get water mode mapping by supported feature set.
Water slide modes share user-facing names with legacy modes (e.g. "low" is 201 or 225), so the mapping uses display_name rather than the enum value.
232def get_cleaning_mode_options(features: DeviceFeatures) -> list[CleaningMode]: 233 """Return the supported high-level cleaning modes for the device. 234 235 These options are the preferred user-facing choices because they bundle the 236 correct fan, water, and mop-route settings together for the device. Callers 237 should generally present these instead of mixing lower-level mode enums 238 unless they explicitly need fine-grained control. 239 """ 240 if not features.is_support_water_mode: 241 return [] 242 243 supported_water_modes = get_water_modes(features) 244 options = [CleaningMode.VACUUM, CleaningMode.VAC_AND_MOP] 245 if features.is_pure_clean_mop_supported: 246 options.append(CleaningMode.MOP) 247 if features.is_customized_clean_supported and WaterModes.CUSTOMIZED in supported_water_modes: 248 options.append(CleaningMode.CUSTOM) 249 if features.is_smart_clean_mode_set_supported and WaterModes.SMART_MODE in supported_water_modes: 250 options.append(CleaningMode.SMART_MODE) 251 return options
Return the supported high-level cleaning modes for the device.
These options are the preferred user-facing choices because they bundle the correct fan, water, and mop-route settings together for the device. Callers should generally present these instead of mixing lower-level mode enums unless they explicitly need fine-grained control.
254def get_mop_only_vacuum_mode(features: DeviceFeatures) -> VacuumModes: 255 """Return the vacuum mode used by the app for mop-only cleaning.""" 256 if not features.is_pure_clean_mop_supported: 257 raise RoborockUnsupportedFeature("Mop-only cleaning is not supported") 258 # Main-brush lift is a device capability, not an alternate fan-power 259 # command. The app still sends CleanModeZero (105) for mop-only cleaning. 260 return VacuumModes.OFF
Return the vacuum mode used by the app for mop-only cleaning.
294def resolve_cleaning_mode(cleaning_mode: str | CleaningMode) -> CleaningMode: 295 """Resolve a string or enum into a CleaningMode value.""" 296 if isinstance(cleaning_mode, CleaningMode): 297 return cleaning_mode 298 try: 299 return CleaningMode(cleaning_mode) 300 except ValueError as err: 301 raise RoborockUnsupportedFeature(f"Cleaning mode {cleaning_mode!r} is not supported") from err
Resolve a string or enum into a CleaningMode value.
304def get_cleaning_mode_parameters(cleaning_mode: CleaningMode, features: DeviceFeatures) -> list[dict[str, int]]: 305 """Get the RPC payload for switching the high-level cleaning mode.""" 306 if cleaning_mode not in get_cleaning_mode_options(features): 307 raise RoborockUnsupportedFeature(f"Cleaning mode {cleaning_mode.value!r} is not supported") 308 309 fan_power, water_box_mode, mop_mode = _get_clean_motor_mode_params(cleaning_mode, features) 310 params: dict[str, int] = {"fan_power": fan_power.code, "water_box_mode": water_box_mode.code} 311 if features.is_clean_route_setting_supported: 312 params["mop_mode"] = mop_mode.code 313 return [params]
Get the RPC payload for switching the high-level cleaning mode.
345def get_current_cleaning_mode( 346 clean_mode: int | VacuumModes | None, 347 water_mode: int | WaterModes | None, 348 mop_mode: int | CleanRoutes | None, 349 features: DeviceFeatures, 350) -> CleaningMode | None: 351 """Classify the current high-level cleaning mode from individual mode codes.""" 352 if not features.is_support_water_mode: 353 return None 354 clean_mode_enum = _resolve_clean_mode(clean_mode, features) 355 water_mode_enum = _resolve_water_mode(water_mode, features) 356 mop_mode_enum = _resolve_mode_code(mop_mode, CleanRoutes) 357 if clean_mode_enum is None or water_mode_enum is None: 358 return None 359 360 if is_smart_mode_set(water_mode_enum, clean_mode_enum, mop_mode_enum): 361 return CleaningMode.SMART_MODE 362 if is_mode_customized(clean_mode_enum, water_mode_enum, mop_mode_enum): 363 return CleaningMode.CUSTOM 364 if water_mode_enum != WaterModes.OFF: 365 try: 366 if clean_mode_enum == get_mop_only_vacuum_mode(features): 367 return CleaningMode.MOP 368 except RoborockUnsupportedFeature: 369 pass 370 if water_mode_enum == WaterModes.OFF: 371 return CleaningMode.VACUUM 372 return CleaningMode.VAC_AND_MOP
Classify the current high-level cleaning mode from individual mode codes.
375def is_mode_customized( 376 clean_mode: VacuumModes | None, 377 water_mode: WaterModes | None, 378 mop_mode: CleanRoutes | None, 379) -> bool: 380 """Check if any of the cleaning modes are set to a custom value.""" 381 return ( 382 clean_mode == VacuumModes.CUSTOMIZED 383 or water_mode == WaterModes.CUSTOMIZED 384 or mop_mode == CleanRoutes.CUSTOMIZED 385 )
Check if any of the cleaning modes are set to a custom value.
388def is_smart_mode_set( 389 water_mode: WaterModes | None, 390 clean_mode: VacuumModes | None, 391 mop_mode: CleanRoutes | None, 392) -> bool: 393 """Check if the smart mode is set for the given water mode and clean mode""" 394 return ( 395 water_mode == WaterModes.SMART_MODE 396 or clean_mode == VacuumModes.SMART_MODE 397 or mop_mode == CleanRoutes.SMART_MODE 398 )
Check if the smart mode is set for the given water mode and clean mode