roborock.data.v1.v1_containers

  1import datetime
  2import logging
  3from dataclasses import dataclass, field
  4from enum import StrEnum
  5from typing import Any
  6
  7from roborock.const import (
  8    CLEANING_BRUSH_REPLACE_TIME,
  9    DUST_COLLECTION_REPLACE_TIME,
 10    FILTER_REPLACE_TIME,
 11    MAIN_BRUSH_REPLACE_TIME,
 12    MOP_ROLLER_REPLACE_TIME,
 13    NO_MAP,
 14    SENSOR_DIRTY_REPLACE_TIME,
 15    SIDE_BRUSH_REPLACE_TIME,
 16    STRAINER_REPLACE_TIME,
 17)
 18from roborock.roborock_message import RoborockDataProtocol
 19
 20from ..containers import NamedRoomMapping, RoborockBase, RoborockBaseTimer, _attr_repr, field_metadata
 21from .v1_clean_modes import WashTowelModes
 22from .v1_code_mappings import (
 23    CleanFluidStatus,
 24    ClearWaterBoxStatus,
 25    DirtyWaterBoxStatus,
 26    DustBagStatus,
 27    RoborockChargeStatus,
 28    RoborockCleanType,
 29    RoborockDockDustCollectionModeCode,
 30    RoborockDockErrorCode,
 31    RoborockDockState,
 32    RoborockDockTypeCode,
 33    RoborockErrorCode,
 34    RoborockFinishReason,
 35    RoborockInCleaning,
 36    RoborockStartType,
 37    RoborockStateCode,
 38)
 39
 40_LOGGER = logging.getLogger(__name__)
 41
 42
 43class FieldNameBase(StrEnum):
 44    """A base enum class that represents a field name in a RoborockBase dataclass."""
 45
 46
 47class StatusField(FieldNameBase):
 48    """An enum that represents a field in the `StatusV2` class.
 49
 50    This is used with `roborock.devices.traits.v1.status.DeviceFeaturesTrait`
 51    to understand if a feature is supported by the device using `is_field_supported`.
 52
 53    The enum values are names of fields in the `StatusV2` class. Each field is
 54    annotated with `dps` metadata to map the field to a `RoborockDataProtocol`
 55    value used to check support against the product schema.
 56    """
 57
 58    STATE = "state"
 59    BATTERY = "battery"
 60    FAN_POWER = "fan_power"
 61    WATER_BOX_MODE = "water_box_mode"
 62    CHARGE_STATUS = "charge_status"
 63    DRY_STATUS = "dry_status"
 64    ERROR_CODE = "error_code"
 65    WATER_BOX_CARRIAGE_STATUS = "water_box_carriage_status"
 66    WATER_BOX_STATUS = "water_box_status"
 67    WATER_SHORTAGE_STATUS = "water_shortage_status"
 68    DIRTY_WATER_BOX_STATUS = "dirty_water_box_status"
 69    CLEAR_WATER_BOX_STATUS = "clear_water_box_status"
 70    CLEAN_FLUID_STATUS = "clean_fluid_status"
 71    CLEAN_PERCENT = "clean_percent"
 72    DOCK_ERROR_STATUS = "dock_error_status"
 73    RDT = "rdt"
 74
 75
 76@dataclass
 77class StatusV2(RoborockBase):
 78    """The result of a GET_STATUS API request."""
 79
 80    msg_ver: int | None = None
 81    msg_seq: int | None = None
 82    state: RoborockStateCode | None = field(default=None, metadata={"dps": RoborockDataProtocol.STATE})
 83    battery: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.BATTERY})
 84    clean_time: int | None = None
 85    clean_area: int | None = None
 86    error_code: RoborockErrorCode | None = field(default=None, metadata={"dps": RoborockDataProtocol.ERROR_CODE})
 87    map_present: int | None = None
 88    in_cleaning: RoborockInCleaning | None = None
 89    in_returning: int | None = None
 90    in_fresh_state: int | None = None
 91    lab_status: int | None = None
 92    water_box_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
 93    back_type: int | None = None
 94    wash_phase: int | None = None
 95    wash_ready: int | None = None
 96    fan_power: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.FAN_POWER})
 97    dnd_enabled: int | None = None
 98    map_status: int | None = None
 99    is_locating: int | None = None
100    lock_status: int | None = None
101    water_box_mode: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.WATER_BOX_MODE})
102    water_box_carriage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
103    mop_forbidden_enable: int | None = None
104    camera_status: int | None = None
105    is_exploring: int | None = None
106    home_sec_status: int | None = None
107    home_sec_enable_password: int | None = None
108    adbumper_status: list[int] | None = None
109    water_shortage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
110    dock_type: RoborockDockTypeCode | None = None
111    dust_collection_status: int | None = None
112    auto_dust_collection: int | None = None
113    avoid_count: int | None = None
114    mop_mode: int | None = None
115    debug_mode: int | None = None
116    collision_avoid_status: int | None = None
117    switch_map_mode: int | None = None
118    dock_error_status: RoborockDockErrorCode | None = field(default=None, metadata={"dock_feature": "has_dock"})
119
120    charge_status: RoborockChargeStatus | None = field(
121        default=None, metadata={"dps": RoborockDataProtocol.CHARGE_STATUS}
122    )
123    unsave_map_reason: int | None = None
124    unsave_map_flag: int | None = None
125    wash_status: int | None = None
126    distance_off: int | None = None
127    in_warmup: int | None = None
128    dry_status: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.DRYING_STATUS})
129    rdt: int | None = field(default=None, metadata={"feature": "is_supported_drying"})
130    clean_percent: int | None = field(default=None, metadata={"feature": "is_support_clean_estimate"})
131    rss: int | None = None
132    dss: int | None = None
133    common_status: int | None = None
134    corner_clean_mode: int | None = None
135    last_clean_t: int | None = None
136    replenish_mode: int | None = None
137    repeat: int | None = None
138    kct: int | None = None
139    subdivision_sets: int | None = None
140
141    @property
142    def square_meter_clean_area(self) -> float | None:
143        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
144
145    @property
146    def error_code_name(self) -> str | None:
147        return self.error_code.display_name if self.error_code is not None else None
148
149    @property
150    def state_name(self) -> str | None:
151        return self.state.display_name if self.state is not None else None
152
153    @property
154    def current_map(self) -> int | None:
155        """Returns the current map ID if the map is present."""
156        if self.map_status is not None:
157            map_flag = self.map_status >> 2
158            if map_flag != NO_MAP:
159                return map_flag
160        return None
161
162    @property
163    def has_am(self) -> bool | None:
164        if self.dss is None:
165            return None
166        return (self.dss & 3) == 2
167
168    @property
169    @field_metadata(dock_feature="is_washable")
170    def clear_water_box_status(self) -> ClearWaterBoxStatus | None:
171        if self.dss:
172            return ClearWaterBoxStatus((self.dss >> 2) & 3)
173        return None
174
175    @property
176    @field_metadata(dock_feature="is_washable")
177    def dirty_water_box_status(self) -> DirtyWaterBoxStatus | None:
178        if self.dss:
179            return DirtyWaterBoxStatus((self.dss >> 4) & 3)
180        return None
181
182    @property
183    def dust_bag_status(self) -> DustBagStatus | None:
184        if self.dss:
185            return DustBagStatus((self.dss >> 6) & 3)
186        return None
187
188    @property
189    def water_box_filter_status(self) -> int | None:
190        if self.dss:
191            return (self.dss >> 8) & 3
192        return None
193
194    @property
195    @field_metadata(
196        dock_feature="is_clean_fluid_auto_delivery_supported",
197    )
198    def clean_fluid_status(self) -> CleanFluidStatus | None:
199        if self.dss:
200            value = (self.dss >> 10) & 3
201            if value == 0:
202                return None  # Feature not supported by this device
203            return CleanFluidStatus(value)
204        return None
205
206    @property
207    def hatch_door_status(self) -> int | None:
208        if self.dss:
209            return (self.dss >> 12) & 7
210        return None
211
212    @property
213    def dock_cool_fan_status(self) -> int | None:
214        if self.dss:
215            return (self.dss >> 15) & 3
216        return None
217
218    @property
219    def dock_state(self) -> RoborockDockState:
220        """A synthesized, high-level dock state reflecting the UI's display.
221
222        This property simplifies integration by handling the complex logic
223        of checking state, charge_status, and battery level simultaneously. It handles
224        newer off-peak charging logic seamlessly while maintaining backwards compatibility
225        with older devices.
226        """
227        if self.state is None or self.state == RoborockStateCode.unknown:
228            return RoborockDockState.unknown
229
230        # 6. DUSTING
231        if self.state == RoborockStateCode.emptying_the_bin:
232            return RoborockDockState.dusting
233
234        # 5. FULL
235        if self.state == RoborockStateCode.charging_complete or (
236            self.state == RoborockStateCode.charging and self.battery == 100
237        ):
238            return RoborockDockState.full
239
240        # 3 & 4. CHARGING and CHARGE_WAITING
241        if self.state == RoborockStateCode.charging:
242            if self.charge_status == RoborockChargeStatus.charge_waiting:
243                return RoborockDockState.off_peak_waiting
244            return RoborockDockState.charging
245
246        # 2. RECHARGING
247        if self.state in (RoborockStateCode.returning_home, RoborockStateCode.docking):
248            return RoborockDockState.returning
249
250        # 1. IDLE (Not on dock, or doing something else)
251        return RoborockDockState.idle
252
253    def __repr__(self) -> str:
254        return _attr_repr(self)
255
256
257@dataclass
258class DnDTimer(RoborockBaseTimer):
259    """DnDTimer"""
260
261
262@dataclass
263class ValleyElectricityTimer(RoborockBaseTimer):
264    """ValleyElectricityTimer"""
265
266
267@dataclass
268class CleanSummary(RoborockBase):
269    clean_time: int | None = None
270    clean_area: int | None = None
271    clean_count: int | None = None
272    dust_collection_count: int | None = None
273    records: list[int] | None = None
274    last_clean_t: int | None = None
275
276    @property
277    def square_meter_clean_area(self) -> float | None:
278        """Returns the clean area in square meters."""
279        if isinstance(self.clean_area, list | str):
280            _LOGGER.warning(f"Clean area is a unexpected type! Please give the following in a issue: {self.clean_area}")
281            return None
282        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
283
284    def __repr__(self) -> str:
285        """Return a string representation of the object including all attributes."""
286        return _attr_repr(self)
287
288
289@dataclass
290class CleanRecord(RoborockBase):
291    begin: int | None = None
292    end: int | None = None
293    duration: int | None = None
294    area: int | None = None
295    error: int | None = None
296    complete: int | None = None
297    start_type: RoborockStartType | None = None
298    clean_type: RoborockCleanType | None = None
299    finish_reason: RoborockFinishReason | None = None
300    dust_collection_status: int | None = None
301    avoid_count: int | None = None
302    wash_count: int | None = None
303    map_flag: int | None = None
304
305    @property
306    def square_meter_area(self) -> float | None:
307        return round(self.area / 1000000, 1) if self.area is not None else None
308
309    @property
310    def begin_datetime(self) -> datetime.datetime | None:
311        return datetime.datetime.fromtimestamp(self.begin).astimezone(datetime.UTC) if self.begin else None
312
313    @property
314    def end_datetime(self) -> datetime.datetime | None:
315        return datetime.datetime.fromtimestamp(self.end).astimezone(datetime.UTC) if self.end else None
316
317    def __repr__(self) -> str:
318        return _attr_repr(self)
319
320
321class CleanSummaryWithDetail(CleanSummary):
322    """CleanSummary with the last CleanRecord included."""
323
324    last_clean_record: CleanRecord | None = None
325
326
327class ConsumableField(FieldNameBase):
328    """An enum that represents a field in the `Consumable` class.
329
330    This is used with `roborock.devices.traits.v1.status.DeviceFeaturesTrait`
331    to understand if a feature is supported by the device using `is_field_supported`.
332
333    The enum values are names of fields in the `Consumable` class. Each field is
334    annotated with `dps` metadata to map the field to a `RoborockDataProtocol`
335    value used to check support against the product schema.
336    """
337
338    MAIN_BRUSH_WORK_TIME = "main_brush_work_time"
339    SIDE_BRUSH_WORK_TIME = "side_brush_work_time"
340    FILTER_WORK_TIME = "filter_work_time"
341
342
343@dataclass
344class Consumable(RoborockBase):
345    main_brush_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.MAIN_BRUSH_WORK_TIME})
346    side_brush_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.SIDE_BRUSH_WORK_TIME})
347    filter_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.FILTER_WORK_TIME})
348    filter_element_work_time: int | None = None
349    sensor_dirty_time: int | None = None
350    strainer_work_times: int | None = None
351    dust_collection_work_times: int | None = None
352    cleaning_brush_work_times: int | None = None
353    moproller_work_time: int | None = None
354
355    @property
356    def main_brush_time_left(self) -> int | None:
357        return MAIN_BRUSH_REPLACE_TIME - self.main_brush_work_time if self.main_brush_work_time is not None else None
358
359    @property
360    def side_brush_time_left(self) -> int | None:
361        return SIDE_BRUSH_REPLACE_TIME - self.side_brush_work_time if self.side_brush_work_time is not None else None
362
363    @property
364    def filter_time_left(self) -> int | None:
365        return FILTER_REPLACE_TIME - self.filter_work_time if self.filter_work_time is not None else None
366
367    @property
368    def sensor_time_left(self) -> int | None:
369        return SENSOR_DIRTY_REPLACE_TIME - self.sensor_dirty_time if self.sensor_dirty_time is not None else None
370
371    @property
372    def strainer_time_left(self) -> int | None:
373        return STRAINER_REPLACE_TIME - self.strainer_work_times if self.strainer_work_times is not None else None
374
375    @property
376    def dust_collection_time_left(self) -> int | None:
377        return (
378            DUST_COLLECTION_REPLACE_TIME - self.dust_collection_work_times
379            if self.dust_collection_work_times is not None
380            else None
381        )
382
383    @property
384    def cleaning_brush_time_left(self) -> int | None:
385        return (
386            CLEANING_BRUSH_REPLACE_TIME - self.cleaning_brush_work_times
387            if self.cleaning_brush_work_times is not None
388            else None
389        )
390
391    @property
392    def mop_roller_time_left(self) -> int | None:
393        return MOP_ROLLER_REPLACE_TIME - self.moproller_work_time if self.moproller_work_time is not None else None
394
395    def __repr__(self) -> str:
396        return _attr_repr(self)
397
398
399@dataclass
400class MultiMapsListRoom(RoborockBase):
401    id: int | None = None
402    tag: int | None = None
403    iot_name_id: str | None = None
404    iot_name: str | None = None
405
406    @property
407    def named_room_mapping(self) -> NamedRoomMapping | None:
408        """Returns a NamedRoomMapping object if valid."""
409        if self.id is None or self.iot_name_id is None:
410            return None
411        return NamedRoomMapping(
412            segment_id=self.id,
413            iot_id=self.iot_name_id,
414            raw_name=self.iot_name,
415        )
416
417
418@dataclass
419class MultiMapsListMapInfoBakMaps(RoborockBase):
420    mapflag: Any | None = None
421    add_time: Any | None = None
422
423
424@dataclass
425class MultiMapsListMapInfo(RoborockBase):
426    map_flag: int
427    name: str
428    add_time: Any | None = None
429    length: Any | None = None
430    bak_maps: list[MultiMapsListMapInfoBakMaps] | None = None
431    rooms: list[MultiMapsListRoom] | None = None
432
433    @property
434    def mapFlag(self) -> int:
435        """Alias for map_flag, returns the map flag as an integer."""
436        return self.map_flag
437
438    @property
439    def rooms_map(self) -> dict[int, NamedRoomMapping]:
440        """Returns a dictionary of room mappings by segment id."""
441        return {
442            room.id: mapping
443            for room in self.rooms or ()
444            if room.id is not None and (mapping := room.named_room_mapping) is not None
445        }
446
447
448@dataclass
449class MultiMapsList(RoborockBase):
450    max_multi_map: int | None = None
451    max_bak_map: int | None = None
452    multi_map_count: int | None = None
453    map_info: list[MultiMapsListMapInfo] | None = None
454
455
456@dataclass
457class SmartWashParams(RoborockBase):
458    smart_wash: int | None = None
459    wash_interval: int | None = None
460
461
462@dataclass
463class DustCollectionMode(RoborockBase):
464    mode: RoborockDockDustCollectionModeCode | None = None
465
466
467@dataclass
468class WashTowelMode(RoborockBase):
469    wash_mode: WashTowelModes | None = None
470
471
472@dataclass
473class NetworkInfo(RoborockBase):
474    ip: str
475    ssid: str | None = None
476    mac: str | None = None
477    bssid: str | None = None
478    rssi: int | None = None
479
480
481@dataclass
482class AppInitStatusLocalInfo(RoborockBase):
483    location: str
484    bom: str | None = None
485    featureset: int | None = None
486    language: str | None = None
487    logserver: str | None = None
488    wifiplan: str | None = None
489    timezone: str | None = None
490    name: str | None = None
491
492
493@dataclass
494class AppInitStatus(RoborockBase):
495    local_info: AppInitStatusLocalInfo
496    feature_info: list[int]
497    new_feature_info: int = 0
498    new_feature_info_str: str = ""
499    new_feature_info_2: int | None = None
500    carriage_type: int | None = None
501    dsp_version: str | None = None
502
503
504@dataclass
505class ChildLockStatus(RoborockBase):
506    lock_status: int = 0
507
508
509@dataclass
510class FlowLedStatus(RoborockBase):
511    status: int = 0
512
513
514@dataclass
515class LedStatus(RoborockBase):
516    status: int = 0
class FieldNameBase(enum.StrEnum):
44class FieldNameBase(StrEnum):
45    """A base enum class that represents a field name in a RoborockBase dataclass."""

A base enum class that represents a field name in a RoborockBase dataclass.

class StatusField(FieldNameBase):
48class StatusField(FieldNameBase):
49    """An enum that represents a field in the `StatusV2` class.
50
51    This is used with `roborock.devices.traits.v1.status.DeviceFeaturesTrait`
52    to understand if a feature is supported by the device using `is_field_supported`.
53
54    The enum values are names of fields in the `StatusV2` class. Each field is
55    annotated with `dps` metadata to map the field to a `RoborockDataProtocol`
56    value used to check support against the product schema.
57    """
58
59    STATE = "state"
60    BATTERY = "battery"
61    FAN_POWER = "fan_power"
62    WATER_BOX_MODE = "water_box_mode"
63    CHARGE_STATUS = "charge_status"
64    DRY_STATUS = "dry_status"
65    ERROR_CODE = "error_code"
66    WATER_BOX_CARRIAGE_STATUS = "water_box_carriage_status"
67    WATER_BOX_STATUS = "water_box_status"
68    WATER_SHORTAGE_STATUS = "water_shortage_status"
69    DIRTY_WATER_BOX_STATUS = "dirty_water_box_status"
70    CLEAR_WATER_BOX_STATUS = "clear_water_box_status"
71    CLEAN_FLUID_STATUS = "clean_fluid_status"
72    CLEAN_PERCENT = "clean_percent"
73    DOCK_ERROR_STATUS = "dock_error_status"
74    RDT = "rdt"

An enum that represents a field in the StatusV2 class.

This is used with roborock.devices.traits.v1.status.DeviceFeaturesTrait to understand if a feature is supported by the device using is_field_supported.

The enum values are names of fields in the StatusV2 class. Each field is annotated with dps metadata to map the field to a RoborockDataProtocol value used to check support against the product schema.

STATE = <StatusField.STATE: 'state'>
BATTERY = <StatusField.BATTERY: 'battery'>
FAN_POWER = <StatusField.FAN_POWER: 'fan_power'>
WATER_BOX_MODE = <StatusField.WATER_BOX_MODE: 'water_box_mode'>
CHARGE_STATUS = <StatusField.CHARGE_STATUS: 'charge_status'>
DRY_STATUS = <StatusField.DRY_STATUS: 'dry_status'>
ERROR_CODE = <StatusField.ERROR_CODE: 'error_code'>
WATER_BOX_CARRIAGE_STATUS = <StatusField.WATER_BOX_CARRIAGE_STATUS: 'water_box_carriage_status'>
WATER_BOX_STATUS = <StatusField.WATER_BOX_STATUS: 'water_box_status'>
WATER_SHORTAGE_STATUS = <StatusField.WATER_SHORTAGE_STATUS: 'water_shortage_status'>
DIRTY_WATER_BOX_STATUS = <StatusField.DIRTY_WATER_BOX_STATUS: 'dirty_water_box_status'>
CLEAR_WATER_BOX_STATUS = <StatusField.CLEAR_WATER_BOX_STATUS: 'clear_water_box_status'>
CLEAN_FLUID_STATUS = <StatusField.CLEAN_FLUID_STATUS: 'clean_fluid_status'>
CLEAN_PERCENT = <StatusField.CLEAN_PERCENT: 'clean_percent'>
DOCK_ERROR_STATUS = <StatusField.DOCK_ERROR_STATUS: 'dock_error_status'>
RDT = <StatusField.RDT: 'rdt'>
@dataclass
class StatusV2(roborock.data.containers.RoborockBase):
 77@dataclass
 78class StatusV2(RoborockBase):
 79    """The result of a GET_STATUS API request."""
 80
 81    msg_ver: int | None = None
 82    msg_seq: int | None = None
 83    state: RoborockStateCode | None = field(default=None, metadata={"dps": RoborockDataProtocol.STATE})
 84    battery: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.BATTERY})
 85    clean_time: int | None = None
 86    clean_area: int | None = None
 87    error_code: RoborockErrorCode | None = field(default=None, metadata={"dps": RoborockDataProtocol.ERROR_CODE})
 88    map_present: int | None = None
 89    in_cleaning: RoborockInCleaning | None = None
 90    in_returning: int | None = None
 91    in_fresh_state: int | None = None
 92    lab_status: int | None = None
 93    water_box_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
 94    back_type: int | None = None
 95    wash_phase: int | None = None
 96    wash_ready: int | None = None
 97    fan_power: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.FAN_POWER})
 98    dnd_enabled: int | None = None
 99    map_status: int | None = None
100    is_locating: int | None = None
101    lock_status: int | None = None
102    water_box_mode: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.WATER_BOX_MODE})
103    water_box_carriage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
104    mop_forbidden_enable: int | None = None
105    camera_status: int | None = None
106    is_exploring: int | None = None
107    home_sec_status: int | None = None
108    home_sec_enable_password: int | None = None
109    adbumper_status: list[int] | None = None
110    water_shortage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
111    dock_type: RoborockDockTypeCode | None = None
112    dust_collection_status: int | None = None
113    auto_dust_collection: int | None = None
114    avoid_count: int | None = None
115    mop_mode: int | None = None
116    debug_mode: int | None = None
117    collision_avoid_status: int | None = None
118    switch_map_mode: int | None = None
119    dock_error_status: RoborockDockErrorCode | None = field(default=None, metadata={"dock_feature": "has_dock"})
120
121    charge_status: RoborockChargeStatus | None = field(
122        default=None, metadata={"dps": RoborockDataProtocol.CHARGE_STATUS}
123    )
124    unsave_map_reason: int | None = None
125    unsave_map_flag: int | None = None
126    wash_status: int | None = None
127    distance_off: int | None = None
128    in_warmup: int | None = None
129    dry_status: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.DRYING_STATUS})
130    rdt: int | None = field(default=None, metadata={"feature": "is_supported_drying"})
131    clean_percent: int | None = field(default=None, metadata={"feature": "is_support_clean_estimate"})
132    rss: int | None = None
133    dss: int | None = None
134    common_status: int | None = None
135    corner_clean_mode: int | None = None
136    last_clean_t: int | None = None
137    replenish_mode: int | None = None
138    repeat: int | None = None
139    kct: int | None = None
140    subdivision_sets: int | None = None
141
142    @property
143    def square_meter_clean_area(self) -> float | None:
144        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
145
146    @property
147    def error_code_name(self) -> str | None:
148        return self.error_code.display_name if self.error_code is not None else None
149
150    @property
151    def state_name(self) -> str | None:
152        return self.state.display_name if self.state is not None else None
153
154    @property
155    def current_map(self) -> int | None:
156        """Returns the current map ID if the map is present."""
157        if self.map_status is not None:
158            map_flag = self.map_status >> 2
159            if map_flag != NO_MAP:
160                return map_flag
161        return None
162
163    @property
164    def has_am(self) -> bool | None:
165        if self.dss is None:
166            return None
167        return (self.dss & 3) == 2
168
169    @property
170    @field_metadata(dock_feature="is_washable")
171    def clear_water_box_status(self) -> ClearWaterBoxStatus | None:
172        if self.dss:
173            return ClearWaterBoxStatus((self.dss >> 2) & 3)
174        return None
175
176    @property
177    @field_metadata(dock_feature="is_washable")
178    def dirty_water_box_status(self) -> DirtyWaterBoxStatus | None:
179        if self.dss:
180            return DirtyWaterBoxStatus((self.dss >> 4) & 3)
181        return None
182
183    @property
184    def dust_bag_status(self) -> DustBagStatus | None:
185        if self.dss:
186            return DustBagStatus((self.dss >> 6) & 3)
187        return None
188
189    @property
190    def water_box_filter_status(self) -> int | None:
191        if self.dss:
192            return (self.dss >> 8) & 3
193        return None
194
195    @property
196    @field_metadata(
197        dock_feature="is_clean_fluid_auto_delivery_supported",
198    )
199    def clean_fluid_status(self) -> CleanFluidStatus | None:
200        if self.dss:
201            value = (self.dss >> 10) & 3
202            if value == 0:
203                return None  # Feature not supported by this device
204            return CleanFluidStatus(value)
205        return None
206
207    @property
208    def hatch_door_status(self) -> int | None:
209        if self.dss:
210            return (self.dss >> 12) & 7
211        return None
212
213    @property
214    def dock_cool_fan_status(self) -> int | None:
215        if self.dss:
216            return (self.dss >> 15) & 3
217        return None
218
219    @property
220    def dock_state(self) -> RoborockDockState:
221        """A synthesized, high-level dock state reflecting the UI's display.
222
223        This property simplifies integration by handling the complex logic
224        of checking state, charge_status, and battery level simultaneously. It handles
225        newer off-peak charging logic seamlessly while maintaining backwards compatibility
226        with older devices.
227        """
228        if self.state is None or self.state == RoborockStateCode.unknown:
229            return RoborockDockState.unknown
230
231        # 6. DUSTING
232        if self.state == RoborockStateCode.emptying_the_bin:
233            return RoborockDockState.dusting
234
235        # 5. FULL
236        if self.state == RoborockStateCode.charging_complete or (
237            self.state == RoborockStateCode.charging and self.battery == 100
238        ):
239            return RoborockDockState.full
240
241        # 3 & 4. CHARGING and CHARGE_WAITING
242        if self.state == RoborockStateCode.charging:
243            if self.charge_status == RoborockChargeStatus.charge_waiting:
244                return RoborockDockState.off_peak_waiting
245            return RoborockDockState.charging
246
247        # 2. RECHARGING
248        if self.state in (RoborockStateCode.returning_home, RoborockStateCode.docking):
249            return RoborockDockState.returning
250
251        # 1. IDLE (Not on dock, or doing something else)
252        return RoborockDockState.idle
253
254    def __repr__(self) -> str:
255        return _attr_repr(self)

The result of a GET_STATUS API request.

StatusV2( msg_ver: int | None = None, msg_seq: int | None = None, state: roborock.data.v1.v1_code_mappings.RoborockStateCode | None = None, battery: int | None = None, clean_time: int | None = None, clean_area: int | None = None, error_code: roborock.data.v1.v1_code_mappings.RoborockErrorCode | None = None, map_present: int | None = None, in_cleaning: roborock.data.v1.v1_code_mappings.RoborockInCleaning | None = None, in_returning: int | None = None, in_fresh_state: int | None = None, lab_status: int | None = None, water_box_status: int | None = None, back_type: int | None = None, wash_phase: int | None = None, wash_ready: int | None = None, fan_power: int | None = None, dnd_enabled: int | None = None, map_status: int | None = None, is_locating: int | None = None, lock_status: int | None = None, water_box_mode: int | None = None, water_box_carriage_status: int | None = None, mop_forbidden_enable: int | None = None, camera_status: int | None = None, is_exploring: int | None = None, home_sec_status: int | None = None, home_sec_enable_password: int | None = None, adbumper_status: list[int] | None = None, water_shortage_status: int | None = None, dock_type: roborock.data.v1.v1_code_mappings.RoborockDockTypeCode | None = None, dust_collection_status: int | None = None, auto_dust_collection: int | None = None, avoid_count: int | None = None, mop_mode: int | None = None, debug_mode: int | None = None, collision_avoid_status: int | None = None, switch_map_mode: int | None = None, dock_error_status: roborock.data.v1.v1_code_mappings.RoborockDockErrorCode | None = None, charge_status: roborock.data.v1.v1_code_mappings.RoborockChargeStatus | None = None, unsave_map_reason: int | None = None, unsave_map_flag: int | None = None, wash_status: int | None = None, distance_off: int | None = None, in_warmup: int | None = None, dry_status: int | None = None, rdt: int | None = None, clean_percent: int | None = None, rss: int | None = None, dss: int | None = None, common_status: int | None = None, corner_clean_mode: int | None = None, last_clean_t: int | None = None, replenish_mode: int | None = None, repeat: int | None = None, kct: int | None = None, subdivision_sets: int | None = None)
msg_ver: int | None = None
msg_seq: int | None = None
battery: int | None = None
clean_time: int | None = None
clean_area: int | None = None
map_present: int | None = None
in_returning: int | None = None
in_fresh_state: int | None = None
lab_status: int | None = None
water_box_status: int | None = None
back_type: int | None = None
wash_phase: int | None = None
wash_ready: int | None = None
fan_power: int | None = None
dnd_enabled: int | None = None
map_status: int | None = None
is_locating: int | None = None
lock_status: int | None = None
water_box_mode: int | None = None
water_box_carriage_status: int | None = None
mop_forbidden_enable: int | None = None
camera_status: int | None = None
is_exploring: int | None = None
home_sec_status: int | None = None
home_sec_enable_password: int | None = None
adbumper_status: list[int] | None = None
water_shortage_status: int | None = None
dust_collection_status: int | None = None
auto_dust_collection: int | None = None
avoid_count: int | None = None
mop_mode: int | None = None
debug_mode: int | None = None
collision_avoid_status: int | None = None
switch_map_mode: int | None = None
unsave_map_reason: int | None = None
unsave_map_flag: int | None = None
wash_status: int | None = None
distance_off: int | None = None
in_warmup: int | None = None
dry_status: int | None = None
rdt: int | None = None
clean_percent: int | None = None
rss: int | None = None
dss: int | None = None
common_status: int | None = None
corner_clean_mode: int | None = None
last_clean_t: int | None = None
replenish_mode: int | None = None
repeat: int | None = None
kct: int | None = None
subdivision_sets: int | None = None
square_meter_clean_area: float | None
142    @property
143    def square_meter_clean_area(self) -> float | None:
144        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
error_code_name: str | None
146    @property
147    def error_code_name(self) -> str | None:
148        return self.error_code.display_name if self.error_code is not None else None
state_name: str | None
150    @property
151    def state_name(self) -> str | None:
152        return self.state.display_name if self.state is not None else None
current_map: int | None
154    @property
155    def current_map(self) -> int | None:
156        """Returns the current map ID if the map is present."""
157        if self.map_status is not None:
158            map_flag = self.map_status >> 2
159            if map_flag != NO_MAP:
160                return map_flag
161        return None

Returns the current map ID if the map is present.

has_am: bool | None
163    @property
164    def has_am(self) -> bool | None:
165        if self.dss is None:
166            return None
167        return (self.dss & 3) == 2
clear_water_box_status: roborock.data.v1.v1_code_mappings.ClearWaterBoxStatus | None
169    @property
170    @field_metadata(dock_feature="is_washable")
171    def clear_water_box_status(self) -> ClearWaterBoxStatus | None:
172        if self.dss:
173            return ClearWaterBoxStatus((self.dss >> 2) & 3)
174        return None
dirty_water_box_status: roborock.data.v1.v1_code_mappings.DirtyWaterBoxStatus | None
176    @property
177    @field_metadata(dock_feature="is_washable")
178    def dirty_water_box_status(self) -> DirtyWaterBoxStatus | None:
179        if self.dss:
180            return DirtyWaterBoxStatus((self.dss >> 4) & 3)
181        return None
dust_bag_status: roborock.data.v1.v1_code_mappings.DustBagStatus | None
183    @property
184    def dust_bag_status(self) -> DustBagStatus | None:
185        if self.dss:
186            return DustBagStatus((self.dss >> 6) & 3)
187        return None
water_box_filter_status: int | None
189    @property
190    def water_box_filter_status(self) -> int | None:
191        if self.dss:
192            return (self.dss >> 8) & 3
193        return None
clean_fluid_status: roborock.data.v1.v1_code_mappings.CleanFluidStatus | None
195    @property
196    @field_metadata(
197        dock_feature="is_clean_fluid_auto_delivery_supported",
198    )
199    def clean_fluid_status(self) -> CleanFluidStatus | None:
200        if self.dss:
201            value = (self.dss >> 10) & 3
202            if value == 0:
203                return None  # Feature not supported by this device
204            return CleanFluidStatus(value)
205        return None
hatch_door_status: int | None
207    @property
208    def hatch_door_status(self) -> int | None:
209        if self.dss:
210            return (self.dss >> 12) & 7
211        return None
dock_cool_fan_status: int | None
213    @property
214    def dock_cool_fan_status(self) -> int | None:
215        if self.dss:
216            return (self.dss >> 15) & 3
217        return None
219    @property
220    def dock_state(self) -> RoborockDockState:
221        """A synthesized, high-level dock state reflecting the UI's display.
222
223        This property simplifies integration by handling the complex logic
224        of checking state, charge_status, and battery level simultaneously. It handles
225        newer off-peak charging logic seamlessly while maintaining backwards compatibility
226        with older devices.
227        """
228        if self.state is None or self.state == RoborockStateCode.unknown:
229            return RoborockDockState.unknown
230
231        # 6. DUSTING
232        if self.state == RoborockStateCode.emptying_the_bin:
233            return RoborockDockState.dusting
234
235        # 5. FULL
236        if self.state == RoborockStateCode.charging_complete or (
237            self.state == RoborockStateCode.charging and self.battery == 100
238        ):
239            return RoborockDockState.full
240
241        # 3 & 4. CHARGING and CHARGE_WAITING
242        if self.state == RoborockStateCode.charging:
243            if self.charge_status == RoborockChargeStatus.charge_waiting:
244                return RoborockDockState.off_peak_waiting
245            return RoborockDockState.charging
246
247        # 2. RECHARGING
248        if self.state in (RoborockStateCode.returning_home, RoborockStateCode.docking):
249            return RoborockDockState.returning
250
251        # 1. IDLE (Not on dock, or doing something else)
252        return RoborockDockState.idle

A synthesized, high-level dock state reflecting the UI's display.

This property simplifies integration by handling the complex logic of checking state, charge_status, and battery level simultaneously. It handles newer off-peak charging logic seamlessly while maintaining backwards compatibility with older devices.

@dataclass
class DnDTimer(roborock.data.containers.RoborockBaseTimer):
258@dataclass
259class DnDTimer(RoborockBaseTimer):
260    """DnDTimer"""

DnDTimer

DnDTimer( start_hour: int | None = None, start_minute: int | None = None, end_hour: int | None = None, end_minute: int | None = None, enabled: int | None = None)
@dataclass
class ValleyElectricityTimer(roborock.data.containers.RoborockBaseTimer):
263@dataclass
264class ValleyElectricityTimer(RoborockBaseTimer):
265    """ValleyElectricityTimer"""

ValleyElectricityTimer

ValleyElectricityTimer( start_hour: int | None = None, start_minute: int | None = None, end_hour: int | None = None, end_minute: int | None = None, enabled: int | None = None)
@dataclass
class CleanSummary(roborock.data.containers.RoborockBase):
268@dataclass
269class CleanSummary(RoborockBase):
270    clean_time: int | None = None
271    clean_area: int | None = None
272    clean_count: int | None = None
273    dust_collection_count: int | None = None
274    records: list[int] | None = None
275    last_clean_t: int | None = None
276
277    @property
278    def square_meter_clean_area(self) -> float | None:
279        """Returns the clean area in square meters."""
280        if isinstance(self.clean_area, list | str):
281            _LOGGER.warning(f"Clean area is a unexpected type! Please give the following in a issue: {self.clean_area}")
282            return None
283        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
284
285    def __repr__(self) -> str:
286        """Return a string representation of the object including all attributes."""
287        return _attr_repr(self)
CleanSummary( clean_time: int | None = None, clean_area: int | None = None, clean_count: int | None = None, dust_collection_count: int | None = None, records: list[int] | None = None, last_clean_t: int | None = None)
clean_time: int | None = None
clean_area: int | None = None
clean_count: int | None = None
dust_collection_count: int | None = None
records: list[int] | None = None
last_clean_t: int | None = None
square_meter_clean_area: float | None
277    @property
278    def square_meter_clean_area(self) -> float | None:
279        """Returns the clean area in square meters."""
280        if isinstance(self.clean_area, list | str):
281            _LOGGER.warning(f"Clean area is a unexpected type! Please give the following in a issue: {self.clean_area}")
282            return None
283        return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None

Returns the clean area in square meters.

@dataclass
class CleanRecord(roborock.data.containers.RoborockBase):
290@dataclass
291class CleanRecord(RoborockBase):
292    begin: int | None = None
293    end: int | None = None
294    duration: int | None = None
295    area: int | None = None
296    error: int | None = None
297    complete: int | None = None
298    start_type: RoborockStartType | None = None
299    clean_type: RoborockCleanType | None = None
300    finish_reason: RoborockFinishReason | None = None
301    dust_collection_status: int | None = None
302    avoid_count: int | None = None
303    wash_count: int | None = None
304    map_flag: int | None = None
305
306    @property
307    def square_meter_area(self) -> float | None:
308        return round(self.area / 1000000, 1) if self.area is not None else None
309
310    @property
311    def begin_datetime(self) -> datetime.datetime | None:
312        return datetime.datetime.fromtimestamp(self.begin).astimezone(datetime.UTC) if self.begin else None
313
314    @property
315    def end_datetime(self) -> datetime.datetime | None:
316        return datetime.datetime.fromtimestamp(self.end).astimezone(datetime.UTC) if self.end else None
317
318    def __repr__(self) -> str:
319        return _attr_repr(self)
CleanRecord( begin: int | None = None, end: int | None = None, duration: int | None = None, area: int | None = None, error: int | None = None, complete: int | None = None, start_type: roborock.data.v1.v1_code_mappings.RoborockStartType | None = None, clean_type: roborock.data.v1.v1_code_mappings.RoborockCleanType | None = None, finish_reason: roborock.data.v1.v1_code_mappings.RoborockFinishReason | None = None, dust_collection_status: int | None = None, avoid_count: int | None = None, wash_count: int | None = None, map_flag: int | None = None)
begin: int | None = None
end: int | None = None
duration: int | None = None
area: int | None = None
error: int | None = None
complete: int | None = None
dust_collection_status: int | None = None
avoid_count: int | None = None
wash_count: int | None = None
map_flag: int | None = None
square_meter_area: float | None
306    @property
307    def square_meter_area(self) -> float | None:
308        return round(self.area / 1000000, 1) if self.area is not None else None
begin_datetime: datetime.datetime | None
310    @property
311    def begin_datetime(self) -> datetime.datetime | None:
312        return datetime.datetime.fromtimestamp(self.begin).astimezone(datetime.UTC) if self.begin else None
end_datetime: datetime.datetime | None
314    @property
315    def end_datetime(self) -> datetime.datetime | None:
316        return datetime.datetime.fromtimestamp(self.end).astimezone(datetime.UTC) if self.end else None
class CleanSummaryWithDetail(CleanSummary):
322class CleanSummaryWithDetail(CleanSummary):
323    """CleanSummary with the last CleanRecord included."""
324
325    last_clean_record: CleanRecord | None = None

CleanSummary with the last CleanRecord included.

last_clean_record: CleanRecord | None = None
class ConsumableField(FieldNameBase):
328class ConsumableField(FieldNameBase):
329    """An enum that represents a field in the `Consumable` class.
330
331    This is used with `roborock.devices.traits.v1.status.DeviceFeaturesTrait`
332    to understand if a feature is supported by the device using `is_field_supported`.
333
334    The enum values are names of fields in the `Consumable` class. Each field is
335    annotated with `dps` metadata to map the field to a `RoborockDataProtocol`
336    value used to check support against the product schema.
337    """
338
339    MAIN_BRUSH_WORK_TIME = "main_brush_work_time"
340    SIDE_BRUSH_WORK_TIME = "side_brush_work_time"
341    FILTER_WORK_TIME = "filter_work_time"

An enum that represents a field in the Consumable class.

This is used with roborock.devices.traits.v1.status.DeviceFeaturesTrait to understand if a feature is supported by the device using is_field_supported.

The enum values are names of fields in the Consumable class. Each field is annotated with dps metadata to map the field to a RoborockDataProtocol value used to check support against the product schema.

MAIN_BRUSH_WORK_TIME = <ConsumableField.MAIN_BRUSH_WORK_TIME: 'main_brush_work_time'>
SIDE_BRUSH_WORK_TIME = <ConsumableField.SIDE_BRUSH_WORK_TIME: 'side_brush_work_time'>
FILTER_WORK_TIME = <ConsumableField.FILTER_WORK_TIME: 'filter_work_time'>
@dataclass
class Consumable(roborock.data.containers.RoborockBase):
344@dataclass
345class Consumable(RoborockBase):
346    main_brush_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.MAIN_BRUSH_WORK_TIME})
347    side_brush_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.SIDE_BRUSH_WORK_TIME})
348    filter_work_time: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.FILTER_WORK_TIME})
349    filter_element_work_time: int | None = None
350    sensor_dirty_time: int | None = None
351    strainer_work_times: int | None = None
352    dust_collection_work_times: int | None = None
353    cleaning_brush_work_times: int | None = None
354    moproller_work_time: int | None = None
355
356    @property
357    def main_brush_time_left(self) -> int | None:
358        return MAIN_BRUSH_REPLACE_TIME - self.main_brush_work_time if self.main_brush_work_time is not None else None
359
360    @property
361    def side_brush_time_left(self) -> int | None:
362        return SIDE_BRUSH_REPLACE_TIME - self.side_brush_work_time if self.side_brush_work_time is not None else None
363
364    @property
365    def filter_time_left(self) -> int | None:
366        return FILTER_REPLACE_TIME - self.filter_work_time if self.filter_work_time is not None else None
367
368    @property
369    def sensor_time_left(self) -> int | None:
370        return SENSOR_DIRTY_REPLACE_TIME - self.sensor_dirty_time if self.sensor_dirty_time is not None else None
371
372    @property
373    def strainer_time_left(self) -> int | None:
374        return STRAINER_REPLACE_TIME - self.strainer_work_times if self.strainer_work_times is not None else None
375
376    @property
377    def dust_collection_time_left(self) -> int | None:
378        return (
379            DUST_COLLECTION_REPLACE_TIME - self.dust_collection_work_times
380            if self.dust_collection_work_times is not None
381            else None
382        )
383
384    @property
385    def cleaning_brush_time_left(self) -> int | None:
386        return (
387            CLEANING_BRUSH_REPLACE_TIME - self.cleaning_brush_work_times
388            if self.cleaning_brush_work_times is not None
389            else None
390        )
391
392    @property
393    def mop_roller_time_left(self) -> int | None:
394        return MOP_ROLLER_REPLACE_TIME - self.moproller_work_time if self.moproller_work_time is not None else None
395
396    def __repr__(self) -> str:
397        return _attr_repr(self)
Consumable( main_brush_work_time: int | None = None, side_brush_work_time: int | None = None, filter_work_time: int | None = None, filter_element_work_time: int | None = None, sensor_dirty_time: int | None = None, strainer_work_times: int | None = None, dust_collection_work_times: int | None = None, cleaning_brush_work_times: int | None = None, moproller_work_time: int | None = None)
main_brush_work_time: int | None = None
side_brush_work_time: int | None = None
filter_work_time: int | None = None
filter_element_work_time: int | None = None
sensor_dirty_time: int | None = None
strainer_work_times: int | None = None
dust_collection_work_times: int | None = None
cleaning_brush_work_times: int | None = None
moproller_work_time: int | None = None
main_brush_time_left: int | None
356    @property
357    def main_brush_time_left(self) -> int | None:
358        return MAIN_BRUSH_REPLACE_TIME - self.main_brush_work_time if self.main_brush_work_time is not None else None
side_brush_time_left: int | None
360    @property
361    def side_brush_time_left(self) -> int | None:
362        return SIDE_BRUSH_REPLACE_TIME - self.side_brush_work_time if self.side_brush_work_time is not None else None
filter_time_left: int | None
364    @property
365    def filter_time_left(self) -> int | None:
366        return FILTER_REPLACE_TIME - self.filter_work_time if self.filter_work_time is not None else None
sensor_time_left: int | None
368    @property
369    def sensor_time_left(self) -> int | None:
370        return SENSOR_DIRTY_REPLACE_TIME - self.sensor_dirty_time if self.sensor_dirty_time is not None else None
strainer_time_left: int | None
372    @property
373    def strainer_time_left(self) -> int | None:
374        return STRAINER_REPLACE_TIME - self.strainer_work_times if self.strainer_work_times is not None else None
dust_collection_time_left: int | None
376    @property
377    def dust_collection_time_left(self) -> int | None:
378        return (
379            DUST_COLLECTION_REPLACE_TIME - self.dust_collection_work_times
380            if self.dust_collection_work_times is not None
381            else None
382        )
cleaning_brush_time_left: int | None
384    @property
385    def cleaning_brush_time_left(self) -> int | None:
386        return (
387            CLEANING_BRUSH_REPLACE_TIME - self.cleaning_brush_work_times
388            if self.cleaning_brush_work_times is not None
389            else None
390        )
mop_roller_time_left: int | None
392    @property
393    def mop_roller_time_left(self) -> int | None:
394        return MOP_ROLLER_REPLACE_TIME - self.moproller_work_time if self.moproller_work_time is not None else None
@dataclass
class MultiMapsListRoom(roborock.data.containers.RoborockBase):
400@dataclass
401class MultiMapsListRoom(RoborockBase):
402    id: int | None = None
403    tag: int | None = None
404    iot_name_id: str | None = None
405    iot_name: str | None = None
406
407    @property
408    def named_room_mapping(self) -> NamedRoomMapping | None:
409        """Returns a NamedRoomMapping object if valid."""
410        if self.id is None or self.iot_name_id is None:
411            return None
412        return NamedRoomMapping(
413            segment_id=self.id,
414            iot_id=self.iot_name_id,
415            raw_name=self.iot_name,
416        )
MultiMapsListRoom( id: int | None = None, tag: int | None = None, iot_name_id: str | None = None, iot_name: str | None = None)
id: int | None = None
tag: int | None = None
iot_name_id: str | None = None
iot_name: str | None = None
named_room_mapping: roborock.data.containers.NamedRoomMapping | None
407    @property
408    def named_room_mapping(self) -> NamedRoomMapping | None:
409        """Returns a NamedRoomMapping object if valid."""
410        if self.id is None or self.iot_name_id is None:
411            return None
412        return NamedRoomMapping(
413            segment_id=self.id,
414            iot_id=self.iot_name_id,
415            raw_name=self.iot_name,
416        )

Returns a NamedRoomMapping object if valid.

@dataclass
class MultiMapsListMapInfoBakMaps(roborock.data.containers.RoborockBase):
419@dataclass
420class MultiMapsListMapInfoBakMaps(RoborockBase):
421    mapflag: Any | None = None
422    add_time: Any | None = None
MultiMapsListMapInfoBakMaps( mapflag: typing.Any | None = None, add_time: typing.Any | None = None)
mapflag: typing.Any | None = None
add_time: typing.Any | None = None
@dataclass
class MultiMapsListMapInfo(roborock.data.containers.RoborockBase):
425@dataclass
426class MultiMapsListMapInfo(RoborockBase):
427    map_flag: int
428    name: str
429    add_time: Any | None = None
430    length: Any | None = None
431    bak_maps: list[MultiMapsListMapInfoBakMaps] | None = None
432    rooms: list[MultiMapsListRoom] | None = None
433
434    @property
435    def mapFlag(self) -> int:
436        """Alias for map_flag, returns the map flag as an integer."""
437        return self.map_flag
438
439    @property
440    def rooms_map(self) -> dict[int, NamedRoomMapping]:
441        """Returns a dictionary of room mappings by segment id."""
442        return {
443            room.id: mapping
444            for room in self.rooms or ()
445            if room.id is not None and (mapping := room.named_room_mapping) is not None
446        }
MultiMapsListMapInfo( map_flag: int, name: str, add_time: typing.Any | None = None, length: typing.Any | None = None, bak_maps: list[MultiMapsListMapInfoBakMaps] | None = None, rooms: list[MultiMapsListRoom] | None = None)
map_flag: int
name: str
add_time: typing.Any | None = None
length: typing.Any | None = None
bak_maps: list[MultiMapsListMapInfoBakMaps] | None = None
rooms: list[MultiMapsListRoom] | None = None
mapFlag: int
434    @property
435    def mapFlag(self) -> int:
436        """Alias for map_flag, returns the map flag as an integer."""
437        return self.map_flag

Alias for map_flag, returns the map flag as an integer.

rooms_map: dict[int, roborock.data.containers.NamedRoomMapping]
439    @property
440    def rooms_map(self) -> dict[int, NamedRoomMapping]:
441        """Returns a dictionary of room mappings by segment id."""
442        return {
443            room.id: mapping
444            for room in self.rooms or ()
445            if room.id is not None and (mapping := room.named_room_mapping) is not None
446        }

Returns a dictionary of room mappings by segment id.

@dataclass
class MultiMapsList(roborock.data.containers.RoborockBase):
449@dataclass
450class MultiMapsList(RoborockBase):
451    max_multi_map: int | None = None
452    max_bak_map: int | None = None
453    multi_map_count: int | None = None
454    map_info: list[MultiMapsListMapInfo] | None = None
MultiMapsList( max_multi_map: int | None = None, max_bak_map: int | None = None, multi_map_count: int | None = None, map_info: list[MultiMapsListMapInfo] | None = None)
max_multi_map: int | None = None
max_bak_map: int | None = None
multi_map_count: int | None = None
map_info: list[MultiMapsListMapInfo] | None = None
@dataclass
class SmartWashParams(roborock.data.containers.RoborockBase):
457@dataclass
458class SmartWashParams(RoborockBase):
459    smart_wash: int | None = None
460    wash_interval: int | None = None
SmartWashParams(smart_wash: int | None = None, wash_interval: int | None = None)
smart_wash: int | None = None
wash_interval: int | None = None
@dataclass
class DustCollectionMode(roborock.data.containers.RoborockBase):
463@dataclass
464class DustCollectionMode(RoborockBase):
465    mode: RoborockDockDustCollectionModeCode | None = None
@dataclass
class WashTowelMode(roborock.data.containers.RoborockBase):
468@dataclass
469class WashTowelMode(RoborockBase):
470    wash_mode: WashTowelModes | None = None
WashTowelMode( wash_mode: roborock.data.v1.v1_clean_modes.WashTowelModes | None = None)
@dataclass
class NetworkInfo(roborock.data.containers.RoborockBase):
473@dataclass
474class NetworkInfo(RoborockBase):
475    ip: str
476    ssid: str | None = None
477    mac: str | None = None
478    bssid: str | None = None
479    rssi: int | None = None
NetworkInfo( ip: str, ssid: str | None = None, mac: str | None = None, bssid: str | None = None, rssi: int | None = None)
ip: str
ssid: str | None = None
mac: str | None = None
bssid: str | None = None
rssi: int | None = None
@dataclass
class AppInitStatusLocalInfo(roborock.data.containers.RoborockBase):
482@dataclass
483class AppInitStatusLocalInfo(RoborockBase):
484    location: str
485    bom: str | None = None
486    featureset: int | None = None
487    language: str | None = None
488    logserver: str | None = None
489    wifiplan: str | None = None
490    timezone: str | None = None
491    name: str | None = None
AppInitStatusLocalInfo( location: str, bom: str | None = None, featureset: int | None = None, language: str | None = None, logserver: str | None = None, wifiplan: str | None = None, timezone: str | None = None, name: str | None = None)
location: str
bom: str | None = None
featureset: int | None = None
language: str | None = None
logserver: str | None = None
wifiplan: str | None = None
timezone: str | None = None
name: str | None = None
@dataclass
class AppInitStatus(roborock.data.containers.RoborockBase):
494@dataclass
495class AppInitStatus(RoborockBase):
496    local_info: AppInitStatusLocalInfo
497    feature_info: list[int]
498    new_feature_info: int = 0
499    new_feature_info_str: str = ""
500    new_feature_info_2: int | None = None
501    carriage_type: int | None = None
502    dsp_version: str | None = None
AppInitStatus( local_info: AppInitStatusLocalInfo, feature_info: list[int], new_feature_info: int = 0, new_feature_info_str: str = '', new_feature_info_2: int | None = None, carriage_type: int | None = None, dsp_version: str | None = None)
feature_info: list[int]
new_feature_info: int = 0
new_feature_info_str: str = ''
new_feature_info_2: int | None = None
carriage_type: int | None = None
dsp_version: str | None = None
@dataclass
class ChildLockStatus(roborock.data.containers.RoborockBase):
505@dataclass
506class ChildLockStatus(RoborockBase):
507    lock_status: int = 0
ChildLockStatus(lock_status: int = 0)
lock_status: int = 0
@dataclass
class FlowLedStatus(roborock.data.containers.RoborockBase):
510@dataclass
511class FlowLedStatus(RoborockBase):
512    status: int = 0
FlowLedStatus(status: int = 0)
status: int = 0
@dataclass
class LedStatus(roborock.data.containers.RoborockBase):
515@dataclass
516class LedStatus(RoborockBase):
517    status: int = 0
LedStatus(status: int = 0)
status: int = 0