roborock.data.b01_q10.b01_q10_containers
Data container classes for Q10 B01 devices.
Many of these classes use the field(metadata={"dps": ...}) convention to map
dataclass fields to device Data Points (DPS). This metadata is utilized by the
UpdatableTrait helper in roborock.devices.traits.b01.q10.common to
automatically update objects from raw device responses.
1"""Data container classes for Q10 B01 devices. 2 3Many of these classes use the `field(metadata={"dps": ...})` convention to map 4dataclass fields to device Data Points (DPS). This metadata is utilized by the 5`UpdatableTrait` helper in `roborock.devices.traits.b01.q10.common` to 6automatically update objects from raw device responses. 7""" 8 9import datetime 10from dataclasses import dataclass, field 11 12from ..containers import RoborockBase 13from .b01_q10_code_mappings import ( 14 B01_Q10_DP, 15 YXAreaUnit, 16 YXBackType, 17 YXCarpetCleanType, 18 YXCleaningResult, 19 YXCleanLine, 20 YXCleanScope, 21 YXCleanType, 22 YXDeviceCleanTask, 23 YXDeviceDustCollectionFrequency, 24 YXDeviceState, 25 YXFanLevel, 26 YXFault, 27 YXStartMethod, 28 YXWaterLevel, 29) 30 31_ROBOROCK_COORDINATE_OFFSET_MM = 25_500 32_Q10_TRACE_UNIT_MM = 2.5 33_Q10_VECTOR_UNIT_MM = 5 34 35 36@dataclass(frozen=True) 37class Q10RoborockPoint: 38 """A point in the common Roborock millimetre coordinate space. 39 40 Q10 trace and vector coordinates are firmware details. Public Q10 APIs use 41 this coordinate system, matching other Roborock devices and placing the dock 42 at ``(25500, 25500)``. 43 """ 44 45 x: int 46 y: int 47 48 @classmethod 49 def from_trace(cls, x: int, y: int) -> "Q10RoborockPoint": 50 """Convert Q10 trace coordinates to common Roborock coordinates.""" 51 for value in (x, y): 52 if isinstance(value, bool) or not isinstance(value, int): 53 raise ValueError("trace coordinates must be integers") 54 return cls( 55 x=round(_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_TRACE_UNIT_MM), 56 y=round(_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_TRACE_UNIT_MM), 57 ) 58 59 @classmethod 60 def from_vector(cls, x: int, y: int) -> "Q10RoborockPoint": 61 """Convert Q10 vector coordinates to common Roborock coordinates.""" 62 for value in (x, y): 63 if isinstance(value, bool) or not isinstance(value, int): 64 raise ValueError("vector coordinates must be integers") 65 if not -(2**15) <= value < 2**15: 66 raise ValueError("vector coordinates are outside the Q10 map range") 67 return cls( 68 x=_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_VECTOR_UNIT_MM, 69 y=_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_VECTOR_UNIT_MM, 70 ) 71 72 def to_vector(self) -> tuple[int, int]: 73 """Convert common Roborock coordinates to the Q10 vector grid.""" 74 coordinates: list[int] = [] 75 for value in (self.x, self.y): 76 if isinstance(value, bool) or not isinstance(value, int): 77 raise ValueError("coordinates must be integers") 78 relative_mm = value - _ROBOROCK_COORDINATE_OFFSET_MM 79 if relative_mm % _Q10_VECTOR_UNIT_MM: 80 raise ValueError("coordinates must align to the Q10 5 mm grid") 81 coordinate = relative_mm // _Q10_VECTOR_UNIT_MM 82 if not -(2**15) <= coordinate < 2**15: 83 raise ValueError("coordinates are outside the Q10 map range") 84 coordinates.append(coordinate) 85 return coordinates[0], coordinates[1] 86 87 88@dataclass 89class dpCleanRecord(RoborockBase): 90 op: str 91 result: int 92 id: str 93 data: list 94 95 96@dataclass 97class Q10CleanRecord(RoborockBase): 98 """A single Q10 (ss07) clean record decoded from a ``dpCleanRecord`` (DP 52) entry. 99 100 The device returns each record as a 12-field underscore-delimited string in the 101 ``data`` list of a ``{"op": "list"}`` query (or the ``id`` of an ``{"op": "notify"}`` 102 push). The ``*_len`` values are internal blob-length metrics whose units aren't 103 confirmed; the original ``raw`` string is always retained. The enum fields resolve 104 an unmapped/unset code to ``None`` rather than guessing. 105 """ 106 107 raw: str 108 record_id: str | None = None 109 start_time: int | None = None 110 """Clean start time, Unix seconds.""" 111 clean_time: int | None = None 112 """Cleaning time, minutes.""" 113 clean_area: int | None = None 114 """Cleaned area in square meters.""" 115 map_len: int | None = None 116 """Length of the saved map blob for this record (0 = none stored).""" 117 path_len: int | None = None 118 """Length of the saved path blob for this record (0 = none stored).""" 119 virtual_len: int | None = None 120 """Length of the saved virtual-restriction blob for this record (0 = none stored).""" 121 clean_mode: YXCleanScope | None = None 122 """Clean scope/type (full / selective-room / zone / spot). Same axis as the live 123 :class:`YXDeviceCleanTask` but a different record encoding -- see :class:`YXCleanScope`.""" 124 work_mode: YXCleanType | None = None 125 """Actual work performed (vac+mop / vacuum / mop) -- the same enum :class:`Q10Status` 126 uses for the live clean-mode DP. Records only ever carry 1/2/3 here.""" 127 cleaning_result: YXCleaningResult | None = None 128 """How the clean ended: 0 interrupted (fault), 1 completed, 2 stopped (no fault).""" 129 start_method: YXStartMethod | None = None 130 """What initiated the clean: 0 remote, 1 app, 2 timer, 3 button.""" 131 collect_dust_count: int | None = None 132 """Number of dock auto-empties during the clean.""" 133 134 @property 135 def start_datetime(self) -> datetime.datetime | None: 136 """The start time as a timezone-aware (UTC) datetime.""" 137 if self.start_time is not None: 138 return datetime.datetime.fromtimestamp(self.start_time).astimezone(datetime.UTC) 139 return None 140 141 142@dataclass 143class Q10MapInfo(RoborockBase): 144 """A saved map reported by ``dpMultiMap``. 145 146 Q10 firmware represents the map identifier as a string on the wire. The 147 value is sent back unchanged in a subsequent ``{"op": "select"}`` detail 148 request. On Q10 firmware, ``select`` previews a saved map without applying 149 it as the active map. 150 """ 151 152 id: str 153 name: str | None = None 154 timestamp: int | None = None 155 156 157@dataclass 158class dpMultiMap(RoborockBase): 159 """Response envelope for the Q10 ``dpMultiMap`` data point.""" 160 161 op: str 162 result: int 163 data: list[Q10MapInfo] = field(default_factory=list) 164 165 @property 166 def current_map_id(self) -> str | None: 167 """Return the first saved-map identifier, if one was reported.""" 168 first = next((map_info for map_info in self.data if map_info.id), None) 169 return first.id if first else None 170 171 172@dataclass 173class dpGetCarpet(RoborockBase): 174 op: str 175 result: int 176 data: str 177 178 179@dataclass 180class dpSelfIdentifyingCarpet(RoborockBase): 181 op: str 182 result: int 183 data: str 184 185 186@dataclass 187class dpNetInfo(RoborockBase): 188 wifi_name: str | None = None 189 # "ip_adress" intentionally mirrors the device's "ipAdress" key (sic). 190 ip_adress: str | None = None 191 mac: str | None = None 192 signal: int | None = None 193 194 @property 195 def ip_address(self) -> str | None: 196 """Correctly-spelled alias for :attr:`ip_adress`.""" 197 return self.ip_adress 198 199 200@dataclass 201class dpNotDisturbExpand(RoborockBase): 202 disturb_dust_enable: int | None = None 203 disturb_light: int | None = None 204 disturb_resume_clean: int | None = None 205 disturb_voice: int | None = None 206 207 208@dataclass 209class dpCurrentCleanRoomIds(RoborockBase): 210 room_id_list: list 211 212 213@dataclass 214class dpVoiceVersion(RoborockBase): 215 version: int 216 217 218@dataclass 219class dpTimeZone(RoborockBase): 220 time_zone_city: str | None = None 221 time_zone_sec: int | None = None 222 223 224@dataclass 225class Q10Status(RoborockBase): 226 """Core vacuum status for Q10 devices. 227 228 Fields are mapped to DPS values using metadata. Objects of this class can be 229 automatically updated using the `UpdatableTrait` helper. Settings that have 230 their own trait (volume, child lock, do-not-disturb, dust collection, 231 network info, consumables) live on those traits instead of here. 232 """ 233 234 clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TIME}) 235 clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_AREA}) 236 battery: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BATTERY}) 237 status: YXDeviceState | None = field(default=None, metadata={"dps": B01_Q10_DP.STATUS}) 238 fan_level: YXFanLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.FAN_LEVEL}) 239 water_level: YXWaterLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.WATER_LEVEL}) 240 clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_COUNT}) 241 total_clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_AREA}) 242 total_clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_COUNT}) 243 total_clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_TIME}) 244 clean_mode: YXCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_MODE}) 245 clean_task_type: YXDeviceCleanTask | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TASK_TYPE}) 246 back_type: YXBackType | None = field(default=None, metadata={"dps": B01_Q10_DP.BACK_TYPE}) 247 cleaning_progress: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_PROGRESS}) 248 fault: YXFault | None = field(default=None, metadata={"dps": B01_Q10_DP.FAULT}) 249 250 # Additional state reported in the device's full status dump. 251 clean_line: YXCleanLine | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_LINE}) 252 carpet_clean_type: YXCarpetCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CARPET_CLEAN_TYPE}) 253 area_unit: YXAreaUnit | None = field(default=None, metadata={"dps": B01_Q10_DP.AREA_UNIT}) 254 auto_boost: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.AUTO_BOOST}) 255 multi_map_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MULTI_MAP_SWITCH}) 256 map_save_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MAP_SAVE_SWITCH}) 257 recent_clean_record: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.RECENT_CLEAN_RECORD}) 258 valley_point_charging: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.VALLEY_POINT_CHARGING}) 259 line_laser_obstacle_avoidance: bool | None = field( 260 default=None, metadata={"dps": B01_Q10_DP.LINE_LASER_OBSTACLE_AVOIDANCE} 261 ) 262 # Whether a mop module is attached, and whether "clean along floor direction" is on. 263 mop_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MOP_STATE}) 264 ground_clean: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.GROUND_CLEAN}) 265 # True while an "add area" / re-clean (the app's draw-a-rectangle "re cleaning") 266 # request is in progress; pulses back to False once the robot has the area. 267 add_clean_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.ADD_CLEAN_STATE}) 268 robot_country_code: str | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_COUNTRY_CODE}) 269 time_zone: dpTimeZone | None = field(default=None, metadata={"dps": B01_Q10_DP.TIME_ZONE}) 270 271 # TODO(#846): value mappings for these ints are not yet decoded (no app 272 # control found / internal / constant); keep as int until reverse-engineered. 273 breakpoint_clean: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BREAKPOINT_CLEAN}) 274 timer_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TIMER_TYPE}) 275 user_plan: int | None = field(default=None, metadata={"dps": B01_Q10_DP.USER_PLAN}) 276 robot_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_TYPE}) 277 278 # DEPRECATED: consumable/accessory remaining-life now lives on the 279 # ``Q10Consumable`` trait. These aliases are kept here for backwards 280 # compatibility and will be removed in a follow-up release. See PR #846. 281 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 282 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 283 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 284 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 285 286 @property 287 def fault_name(self) -> str | None: 288 """Returns the name of the current fault.""" 289 return self.fault.value if self.fault is not None else None 290 291 292@dataclass 293class SoundVolume(RoborockBase): 294 """Speaker volume read-model (0-100).""" 295 296 volume: int | None = field(default=None, metadata={"dps": B01_Q10_DP.VOLUME}) 297 298 299@dataclass 300class ChildLock(RoborockBase): 301 """Child-lock read-model.""" 302 303 child_lock: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.CHILD_LOCK}) 304 305 306@dataclass 307class DoNotDisturb(RoborockBase): 308 """Do Not Disturb read-model.""" 309 310 not_disturb: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB}) 311 not_disturb_expand: dpNotDisturbExpand | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB_EXPAND}) 312 313 314@dataclass 315class DustCollection(RoborockBase): 316 """Dock auto-empty (dust collection) read-model.""" 317 318 dust_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.DUST_SWITCH}) 319 dust_setting: YXDeviceDustCollectionFrequency | None = field( 320 default=None, metadata={"dps": B01_Q10_DP.DUST_SETTING} 321 ) 322 323 324@dataclass 325class Q10Consumable(RoborockBase): 326 """Consumable / accessory remaining-life read-model. 327 328 Named with a ``Q10`` prefix to avoid shadowing the v1 ``Consumable`` when both 329 are star-imported into the ``roborock.data`` namespace. 330 """ 331 332 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 333 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 334 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 335 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 336 337 338@dataclass 339class Q10NetworkInfo(RoborockBase): 340 """Network information read-model. 341 342 Named with a ``Q10`` prefix to avoid shadowing the v1 ``NetworkInfo`` when both 343 are star-imported into the ``roborock.data`` namespace. 344 """ 345 346 net_info: dpNetInfo | None = field(default=None, metadata={"dps": B01_Q10_DP.NET_INFO})
37@dataclass(frozen=True) 38class Q10RoborockPoint: 39 """A point in the common Roborock millimetre coordinate space. 40 41 Q10 trace and vector coordinates are firmware details. Public Q10 APIs use 42 this coordinate system, matching other Roborock devices and placing the dock 43 at ``(25500, 25500)``. 44 """ 45 46 x: int 47 y: int 48 49 @classmethod 50 def from_trace(cls, x: int, y: int) -> "Q10RoborockPoint": 51 """Convert Q10 trace coordinates to common Roborock coordinates.""" 52 for value in (x, y): 53 if isinstance(value, bool) or not isinstance(value, int): 54 raise ValueError("trace coordinates must be integers") 55 return cls( 56 x=round(_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_TRACE_UNIT_MM), 57 y=round(_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_TRACE_UNIT_MM), 58 ) 59 60 @classmethod 61 def from_vector(cls, x: int, y: int) -> "Q10RoborockPoint": 62 """Convert Q10 vector coordinates to common Roborock coordinates.""" 63 for value in (x, y): 64 if isinstance(value, bool) or not isinstance(value, int): 65 raise ValueError("vector coordinates must be integers") 66 if not -(2**15) <= value < 2**15: 67 raise ValueError("vector coordinates are outside the Q10 map range") 68 return cls( 69 x=_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_VECTOR_UNIT_MM, 70 y=_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_VECTOR_UNIT_MM, 71 ) 72 73 def to_vector(self) -> tuple[int, int]: 74 """Convert common Roborock coordinates to the Q10 vector grid.""" 75 coordinates: list[int] = [] 76 for value in (self.x, self.y): 77 if isinstance(value, bool) or not isinstance(value, int): 78 raise ValueError("coordinates must be integers") 79 relative_mm = value - _ROBOROCK_COORDINATE_OFFSET_MM 80 if relative_mm % _Q10_VECTOR_UNIT_MM: 81 raise ValueError("coordinates must align to the Q10 5 mm grid") 82 coordinate = relative_mm // _Q10_VECTOR_UNIT_MM 83 if not -(2**15) <= coordinate < 2**15: 84 raise ValueError("coordinates are outside the Q10 map range") 85 coordinates.append(coordinate) 86 return coordinates[0], coordinates[1]
A point in the common Roborock millimetre coordinate space.
Q10 trace and vector coordinates are firmware details. Public Q10 APIs use
this coordinate system, matching other Roborock devices and placing the dock
at (25500, 25500).
49 @classmethod 50 def from_trace(cls, x: int, y: int) -> "Q10RoborockPoint": 51 """Convert Q10 trace coordinates to common Roborock coordinates.""" 52 for value in (x, y): 53 if isinstance(value, bool) or not isinstance(value, int): 54 raise ValueError("trace coordinates must be integers") 55 return cls( 56 x=round(_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_TRACE_UNIT_MM), 57 y=round(_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_TRACE_UNIT_MM), 58 )
Convert Q10 trace coordinates to common Roborock coordinates.
60 @classmethod 61 def from_vector(cls, x: int, y: int) -> "Q10RoborockPoint": 62 """Convert Q10 vector coordinates to common Roborock coordinates.""" 63 for value in (x, y): 64 if isinstance(value, bool) or not isinstance(value, int): 65 raise ValueError("vector coordinates must be integers") 66 if not -(2**15) <= value < 2**15: 67 raise ValueError("vector coordinates are outside the Q10 map range") 68 return cls( 69 x=_ROBOROCK_COORDINATE_OFFSET_MM + x * _Q10_VECTOR_UNIT_MM, 70 y=_ROBOROCK_COORDINATE_OFFSET_MM + y * _Q10_VECTOR_UNIT_MM, 71 )
Convert Q10 vector coordinates to common Roborock coordinates.
73 def to_vector(self) -> tuple[int, int]: 74 """Convert common Roborock coordinates to the Q10 vector grid.""" 75 coordinates: list[int] = [] 76 for value in (self.x, self.y): 77 if isinstance(value, bool) or not isinstance(value, int): 78 raise ValueError("coordinates must be integers") 79 relative_mm = value - _ROBOROCK_COORDINATE_OFFSET_MM 80 if relative_mm % _Q10_VECTOR_UNIT_MM: 81 raise ValueError("coordinates must align to the Q10 5 mm grid") 82 coordinate = relative_mm // _Q10_VECTOR_UNIT_MM 83 if not -(2**15) <= coordinate < 2**15: 84 raise ValueError("coordinates are outside the Q10 map range") 85 coordinates.append(coordinate) 86 return coordinates[0], coordinates[1]
Convert common Roborock coordinates to the Q10 vector grid.
89@dataclass 90class dpCleanRecord(RoborockBase): 91 op: str 92 result: int 93 id: str 94 data: list
Inherited Members
97@dataclass 98class Q10CleanRecord(RoborockBase): 99 """A single Q10 (ss07) clean record decoded from a ``dpCleanRecord`` (DP 52) entry. 100 101 The device returns each record as a 12-field underscore-delimited string in the 102 ``data`` list of a ``{"op": "list"}`` query (or the ``id`` of an ``{"op": "notify"}`` 103 push). The ``*_len`` values are internal blob-length metrics whose units aren't 104 confirmed; the original ``raw`` string is always retained. The enum fields resolve 105 an unmapped/unset code to ``None`` rather than guessing. 106 """ 107 108 raw: str 109 record_id: str | None = None 110 start_time: int | None = None 111 """Clean start time, Unix seconds.""" 112 clean_time: int | None = None 113 """Cleaning time, minutes.""" 114 clean_area: int | None = None 115 """Cleaned area in square meters.""" 116 map_len: int | None = None 117 """Length of the saved map blob for this record (0 = none stored).""" 118 path_len: int | None = None 119 """Length of the saved path blob for this record (0 = none stored).""" 120 virtual_len: int | None = None 121 """Length of the saved virtual-restriction blob for this record (0 = none stored).""" 122 clean_mode: YXCleanScope | None = None 123 """Clean scope/type (full / selective-room / zone / spot). Same axis as the live 124 :class:`YXDeviceCleanTask` but a different record encoding -- see :class:`YXCleanScope`.""" 125 work_mode: YXCleanType | None = None 126 """Actual work performed (vac+mop / vacuum / mop) -- the same enum :class:`Q10Status` 127 uses for the live clean-mode DP. Records only ever carry 1/2/3 here.""" 128 cleaning_result: YXCleaningResult | None = None 129 """How the clean ended: 0 interrupted (fault), 1 completed, 2 stopped (no fault).""" 130 start_method: YXStartMethod | None = None 131 """What initiated the clean: 0 remote, 1 app, 2 timer, 3 button.""" 132 collect_dust_count: int | None = None 133 """Number of dock auto-empties during the clean.""" 134 135 @property 136 def start_datetime(self) -> datetime.datetime | None: 137 """The start time as a timezone-aware (UTC) datetime.""" 138 if self.start_time is not None: 139 return datetime.datetime.fromtimestamp(self.start_time).astimezone(datetime.UTC) 140 return None
A single Q10 (ss07) clean record decoded from a dpCleanRecord (DP 52) entry.
The device returns each record as a 12-field underscore-delimited string in the
data list of a {"op": "list"} query (or the id of an {"op": "notify"}
push). The *_len values are internal blob-length metrics whose units aren't
confirmed; the original raw string is always retained. The enum fields resolve
an unmapped/unset code to None rather than guessing.
Length of the saved virtual-restriction blob for this record (0 = none stored).
Clean scope/type (full / selective-room / zone / spot). Same axis as the live
YXDeviceCleanTask but a different record encoding -- see YXCleanScope.
Actual work performed (vac+mop / vacuum / mop) -- the same enum Q10Status
uses for the live clean-mode DP. Records only ever carry 1/2/3 here.
135 @property 136 def start_datetime(self) -> datetime.datetime | None: 137 """The start time as a timezone-aware (UTC) datetime.""" 138 if self.start_time is not None: 139 return datetime.datetime.fromtimestamp(self.start_time).astimezone(datetime.UTC) 140 return None
The start time as a timezone-aware (UTC) datetime.
Inherited Members
143@dataclass 144class Q10MapInfo(RoborockBase): 145 """A saved map reported by ``dpMultiMap``. 146 147 Q10 firmware represents the map identifier as a string on the wire. The 148 value is sent back unchanged in a subsequent ``{"op": "select"}`` detail 149 request. On Q10 firmware, ``select`` previews a saved map without applying 150 it as the active map. 151 """ 152 153 id: str 154 name: str | None = None 155 timestamp: int | None = None
A saved map reported by dpMultiMap.
Q10 firmware represents the map identifier as a string on the wire. The
value is sent back unchanged in a subsequent {"op": "select"} detail
request. On Q10 firmware, select previews a saved map without applying
it as the active map.
Inherited Members
158@dataclass 159class dpMultiMap(RoborockBase): 160 """Response envelope for the Q10 ``dpMultiMap`` data point.""" 161 162 op: str 163 result: int 164 data: list[Q10MapInfo] = field(default_factory=list) 165 166 @property 167 def current_map_id(self) -> str | None: 168 """Return the first saved-map identifier, if one was reported.""" 169 first = next((map_info for map_info in self.data if map_info.id), None) 170 return first.id if first else None
Response envelope for the Q10 dpMultiMap data point.
166 @property 167 def current_map_id(self) -> str | None: 168 """Return the first saved-map identifier, if one was reported.""" 169 first = next((map_info for map_info in self.data if map_info.id), None) 170 return first.id if first else None
Return the first saved-map identifier, if one was reported.
Inherited Members
Inherited Members
180@dataclass 181class dpSelfIdentifyingCarpet(RoborockBase): 182 op: str 183 result: int 184 data: str
Inherited Members
187@dataclass 188class dpNetInfo(RoborockBase): 189 wifi_name: str | None = None 190 # "ip_adress" intentionally mirrors the device's "ipAdress" key (sic). 191 ip_adress: str | None = None 192 mac: str | None = None 193 signal: int | None = None 194 195 @property 196 def ip_address(self) -> str | None: 197 """Correctly-spelled alias for :attr:`ip_adress`.""" 198 return self.ip_adress
195 @property 196 def ip_address(self) -> str | None: 197 """Correctly-spelled alias for :attr:`ip_adress`.""" 198 return self.ip_adress
Correctly-spelled alias for ip_adress.
Inherited Members
201@dataclass 202class dpNotDisturbExpand(RoborockBase): 203 disturb_dust_enable: int | None = None 204 disturb_light: int | None = None 205 disturb_resume_clean: int | None = None 206 disturb_voice: int | None = None
Inherited Members
Inherited Members
Inherited Members
219@dataclass 220class dpTimeZone(RoborockBase): 221 time_zone_city: str | None = None 222 time_zone_sec: int | None = None
Inherited Members
225@dataclass 226class Q10Status(RoborockBase): 227 """Core vacuum status for Q10 devices. 228 229 Fields are mapped to DPS values using metadata. Objects of this class can be 230 automatically updated using the `UpdatableTrait` helper. Settings that have 231 their own trait (volume, child lock, do-not-disturb, dust collection, 232 network info, consumables) live on those traits instead of here. 233 """ 234 235 clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TIME}) 236 clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_AREA}) 237 battery: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BATTERY}) 238 status: YXDeviceState | None = field(default=None, metadata={"dps": B01_Q10_DP.STATUS}) 239 fan_level: YXFanLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.FAN_LEVEL}) 240 water_level: YXWaterLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.WATER_LEVEL}) 241 clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_COUNT}) 242 total_clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_AREA}) 243 total_clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_COUNT}) 244 total_clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_TIME}) 245 clean_mode: YXCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_MODE}) 246 clean_task_type: YXDeviceCleanTask | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TASK_TYPE}) 247 back_type: YXBackType | None = field(default=None, metadata={"dps": B01_Q10_DP.BACK_TYPE}) 248 cleaning_progress: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_PROGRESS}) 249 fault: YXFault | None = field(default=None, metadata={"dps": B01_Q10_DP.FAULT}) 250 251 # Additional state reported in the device's full status dump. 252 clean_line: YXCleanLine | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_LINE}) 253 carpet_clean_type: YXCarpetCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CARPET_CLEAN_TYPE}) 254 area_unit: YXAreaUnit | None = field(default=None, metadata={"dps": B01_Q10_DP.AREA_UNIT}) 255 auto_boost: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.AUTO_BOOST}) 256 multi_map_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MULTI_MAP_SWITCH}) 257 map_save_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MAP_SAVE_SWITCH}) 258 recent_clean_record: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.RECENT_CLEAN_RECORD}) 259 valley_point_charging: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.VALLEY_POINT_CHARGING}) 260 line_laser_obstacle_avoidance: bool | None = field( 261 default=None, metadata={"dps": B01_Q10_DP.LINE_LASER_OBSTACLE_AVOIDANCE} 262 ) 263 # Whether a mop module is attached, and whether "clean along floor direction" is on. 264 mop_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MOP_STATE}) 265 ground_clean: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.GROUND_CLEAN}) 266 # True while an "add area" / re-clean (the app's draw-a-rectangle "re cleaning") 267 # request is in progress; pulses back to False once the robot has the area. 268 add_clean_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.ADD_CLEAN_STATE}) 269 robot_country_code: str | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_COUNTRY_CODE}) 270 time_zone: dpTimeZone | None = field(default=None, metadata={"dps": B01_Q10_DP.TIME_ZONE}) 271 272 # TODO(#846): value mappings for these ints are not yet decoded (no app 273 # control found / internal / constant); keep as int until reverse-engineered. 274 breakpoint_clean: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BREAKPOINT_CLEAN}) 275 timer_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TIMER_TYPE}) 276 user_plan: int | None = field(default=None, metadata={"dps": B01_Q10_DP.USER_PLAN}) 277 robot_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_TYPE}) 278 279 # DEPRECATED: consumable/accessory remaining-life now lives on the 280 # ``Q10Consumable`` trait. These aliases are kept here for backwards 281 # compatibility and will be removed in a follow-up release. See PR #846. 282 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 283 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 284 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 285 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 286 287 @property 288 def fault_name(self) -> str | None: 289 """Returns the name of the current fault.""" 290 return self.fault.value if self.fault is not None else None
Core vacuum status for Q10 devices.
Fields are mapped to DPS values using metadata. Objects of this class can be
automatically updated using the UpdatableTrait helper. Settings that have
their own trait (volume, child lock, do-not-disturb, dust collection,
network info, consumables) live on those traits instead of here.
287 @property 288 def fault_name(self) -> str | None: 289 """Returns the name of the current fault.""" 290 return self.fault.value if self.fault is not None else None
Returns the name of the current fault.
Inherited Members
293@dataclass 294class SoundVolume(RoborockBase): 295 """Speaker volume read-model (0-100).""" 296 297 volume: int | None = field(default=None, metadata={"dps": B01_Q10_DP.VOLUME})
Speaker volume read-model (0-100).
Inherited Members
300@dataclass 301class ChildLock(RoborockBase): 302 """Child-lock read-model.""" 303 304 child_lock: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.CHILD_LOCK})
Child-lock read-model.
Inherited Members
307@dataclass 308class DoNotDisturb(RoborockBase): 309 """Do Not Disturb read-model.""" 310 311 not_disturb: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB}) 312 not_disturb_expand: dpNotDisturbExpand | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB_EXPAND})
Do Not Disturb read-model.
Inherited Members
315@dataclass 316class DustCollection(RoborockBase): 317 """Dock auto-empty (dust collection) read-model.""" 318 319 dust_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.DUST_SWITCH}) 320 dust_setting: YXDeviceDustCollectionFrequency | None = field( 321 default=None, metadata={"dps": B01_Q10_DP.DUST_SETTING} 322 )
Dock auto-empty (dust collection) read-model.
Inherited Members
325@dataclass 326class Q10Consumable(RoborockBase): 327 """Consumable / accessory remaining-life read-model. 328 329 Named with a ``Q10`` prefix to avoid shadowing the v1 ``Consumable`` when both 330 are star-imported into the ``roborock.data`` namespace. 331 """ 332 333 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 334 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 335 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 336 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE})
Consumable / accessory remaining-life read-model.
Named with a Q10 prefix to avoid shadowing the v1 Consumable when both
are star-imported into the roborock.data namespace.
Inherited Members
339@dataclass 340class Q10NetworkInfo(RoborockBase): 341 """Network information read-model. 342 343 Named with a ``Q10`` prefix to avoid shadowing the v1 ``NetworkInfo`` when both 344 are star-imported into the ``roborock.data`` namespace. 345 """ 346 347 net_info: dpNetInfo | None = field(default=None, metadata={"dps": B01_Q10_DP.NET_INFO})
Network information read-model.
Named with a Q10 prefix to avoid shadowing the v1 NetworkInfo when both
are star-imported into the roborock.data namespace.