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": "get"}`` request. 148 """ 149 150 id: str 151 name: str | None = None 152 timestamp: int | None = None 153 154 155@dataclass 156class dpMultiMap(RoborockBase): 157 """Response envelope for the Q10 ``dpMultiMap`` data point.""" 158 159 op: str 160 result: int 161 data: list[Q10MapInfo] = field(default_factory=list) 162 163 @property 164 def current_map_id(self) -> str | None: 165 """Return the first saved-map identifier, if one was reported.""" 166 first = next((map_info for map_info in self.data if map_info.id), None) 167 return first.id if first else None 168 169 170@dataclass 171class dpGetCarpet(RoborockBase): 172 op: str 173 result: int 174 data: str 175 176 177@dataclass 178class dpSelfIdentifyingCarpet(RoborockBase): 179 op: str 180 result: int 181 data: str 182 183 184@dataclass 185class dpNetInfo(RoborockBase): 186 wifi_name: str | None = None 187 # "ip_adress" intentionally mirrors the device's "ipAdress" key (sic). 188 ip_adress: str | None = None 189 mac: str | None = None 190 signal: int | None = None 191 192 @property 193 def ip_address(self) -> str | None: 194 """Correctly-spelled alias for :attr:`ip_adress`.""" 195 return self.ip_adress 196 197 198@dataclass 199class dpNotDisturbExpand(RoborockBase): 200 disturb_dust_enable: int | None = None 201 disturb_light: int | None = None 202 disturb_resume_clean: int | None = None 203 disturb_voice: int | None = None 204 205 206@dataclass 207class dpCurrentCleanRoomIds(RoborockBase): 208 room_id_list: list 209 210 211@dataclass 212class dpVoiceVersion(RoborockBase): 213 version: int 214 215 216@dataclass 217class dpTimeZone(RoborockBase): 218 time_zone_city: str | None = None 219 time_zone_sec: int | None = None 220 221 222@dataclass 223class Q10Status(RoborockBase): 224 """Core vacuum status for Q10 devices. 225 226 Fields are mapped to DPS values using metadata. Objects of this class can be 227 automatically updated using the `UpdatableTrait` helper. Settings that have 228 their own trait (volume, child lock, do-not-disturb, dust collection, 229 network info, consumables) live on those traits instead of here. 230 """ 231 232 clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TIME}) 233 clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_AREA}) 234 battery: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BATTERY}) 235 status: YXDeviceState | None = field(default=None, metadata={"dps": B01_Q10_DP.STATUS}) 236 fan_level: YXFanLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.FAN_LEVEL}) 237 water_level: YXWaterLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.WATER_LEVEL}) 238 clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_COUNT}) 239 total_clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_AREA}) 240 total_clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_COUNT}) 241 total_clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_TIME}) 242 clean_mode: YXCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_MODE}) 243 clean_task_type: YXDeviceCleanTask | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TASK_TYPE}) 244 back_type: YXBackType | None = field(default=None, metadata={"dps": B01_Q10_DP.BACK_TYPE}) 245 cleaning_progress: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_PROGRESS}) 246 fault: YXFault | None = field(default=None, metadata={"dps": B01_Q10_DP.FAULT}) 247 248 # Additional state reported in the device's full status dump. 249 clean_line: YXCleanLine | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_LINE}) 250 carpet_clean_type: YXCarpetCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CARPET_CLEAN_TYPE}) 251 area_unit: YXAreaUnit | None = field(default=None, metadata={"dps": B01_Q10_DP.AREA_UNIT}) 252 auto_boost: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.AUTO_BOOST}) 253 multi_map_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MULTI_MAP_SWITCH}) 254 map_save_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MAP_SAVE_SWITCH}) 255 recent_clean_record: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.RECENT_CLEAN_RECORD}) 256 valley_point_charging: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.VALLEY_POINT_CHARGING}) 257 line_laser_obstacle_avoidance: bool | None = field( 258 default=None, metadata={"dps": B01_Q10_DP.LINE_LASER_OBSTACLE_AVOIDANCE} 259 ) 260 # Whether a mop module is attached, and whether "clean along floor direction" is on. 261 mop_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MOP_STATE}) 262 ground_clean: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.GROUND_CLEAN}) 263 # True while an "add area" / re-clean (the app's draw-a-rectangle "re cleaning") 264 # request is in progress; pulses back to False once the robot has the area. 265 add_clean_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.ADD_CLEAN_STATE}) 266 robot_country_code: str | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_COUNTRY_CODE}) 267 time_zone: dpTimeZone | None = field(default=None, metadata={"dps": B01_Q10_DP.TIME_ZONE}) 268 269 # TODO(#846): value mappings for these ints are not yet decoded (no app 270 # control found / internal / constant); keep as int until reverse-engineered. 271 breakpoint_clean: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BREAKPOINT_CLEAN}) 272 timer_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TIMER_TYPE}) 273 user_plan: int | None = field(default=None, metadata={"dps": B01_Q10_DP.USER_PLAN}) 274 robot_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_TYPE}) 275 276 # DEPRECATED: consumable/accessory remaining-life now lives on the 277 # ``Q10Consumable`` trait. These aliases are kept here for backwards 278 # compatibility and will be removed in a follow-up release. See PR #846. 279 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 280 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 281 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 282 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 283 284 @property 285 def fault_name(self) -> str | None: 286 """Returns the name of the current fault.""" 287 return self.fault.value if self.fault is not None else None 288 289 290@dataclass 291class SoundVolume(RoborockBase): 292 """Speaker volume read-model (0-100).""" 293 294 volume: int | None = field(default=None, metadata={"dps": B01_Q10_DP.VOLUME}) 295 296 297@dataclass 298class ChildLock(RoborockBase): 299 """Child-lock read-model.""" 300 301 child_lock: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.CHILD_LOCK}) 302 303 304@dataclass 305class DoNotDisturb(RoborockBase): 306 """Do Not Disturb read-model.""" 307 308 not_disturb: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB}) 309 not_disturb_expand: dpNotDisturbExpand | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB_EXPAND}) 310 311 312@dataclass 313class DustCollection(RoborockBase): 314 """Dock auto-empty (dust collection) read-model.""" 315 316 dust_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.DUST_SWITCH}) 317 dust_setting: YXDeviceDustCollectionFrequency | None = field( 318 default=None, metadata={"dps": B01_Q10_DP.DUST_SETTING} 319 ) 320 321 322@dataclass 323class Q10Consumable(RoborockBase): 324 """Consumable / accessory remaining-life read-model. 325 326 Named with a ``Q10`` prefix to avoid shadowing the v1 ``Consumable`` when both 327 are star-imported into the ``roborock.data`` namespace. 328 """ 329 330 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 331 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 332 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 333 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 334 335 336@dataclass 337class Q10NetworkInfo(RoborockBase): 338 """Network information read-model. 339 340 Named with a ``Q10`` prefix to avoid shadowing the v1 ``NetworkInfo`` when both 341 are star-imported into the ``roborock.data`` namespace. 342 """ 343 344 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": "get"}`` request. 149 """ 150 151 id: str 152 name: str | None = None 153 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": "get"} request.
Inherited Members
156@dataclass 157class dpMultiMap(RoborockBase): 158 """Response envelope for the Q10 ``dpMultiMap`` data point.""" 159 160 op: str 161 result: int 162 data: list[Q10MapInfo] = field(default_factory=list) 163 164 @property 165 def current_map_id(self) -> str | None: 166 """Return the first saved-map identifier, if one was reported.""" 167 first = next((map_info for map_info in self.data if map_info.id), None) 168 return first.id if first else None
Response envelope for the Q10 dpMultiMap data point.
164 @property 165 def current_map_id(self) -> str | None: 166 """Return the first saved-map identifier, if one was reported.""" 167 first = next((map_info for map_info in self.data if map_info.id), None) 168 return first.id if first else None
Return the first saved-map identifier, if one was reported.
Inherited Members
Inherited Members
178@dataclass 179class dpSelfIdentifyingCarpet(RoborockBase): 180 op: str 181 result: int 182 data: str
Inherited Members
185@dataclass 186class dpNetInfo(RoborockBase): 187 wifi_name: str | None = None 188 # "ip_adress" intentionally mirrors the device's "ipAdress" key (sic). 189 ip_adress: str | None = None 190 mac: str | None = None 191 signal: int | None = None 192 193 @property 194 def ip_address(self) -> str | None: 195 """Correctly-spelled alias for :attr:`ip_adress`.""" 196 return self.ip_adress
193 @property 194 def ip_address(self) -> str | None: 195 """Correctly-spelled alias for :attr:`ip_adress`.""" 196 return self.ip_adress
Correctly-spelled alias for ip_adress.
Inherited Members
199@dataclass 200class dpNotDisturbExpand(RoborockBase): 201 disturb_dust_enable: int | None = None 202 disturb_light: int | None = None 203 disturb_resume_clean: int | None = None 204 disturb_voice: int | None = None
Inherited Members
Inherited Members
Inherited Members
217@dataclass 218class dpTimeZone(RoborockBase): 219 time_zone_city: str | None = None 220 time_zone_sec: int | None = None
Inherited Members
223@dataclass 224class Q10Status(RoborockBase): 225 """Core vacuum status for Q10 devices. 226 227 Fields are mapped to DPS values using metadata. Objects of this class can be 228 automatically updated using the `UpdatableTrait` helper. Settings that have 229 their own trait (volume, child lock, do-not-disturb, dust collection, 230 network info, consumables) live on those traits instead of here. 231 """ 232 233 clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TIME}) 234 clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_AREA}) 235 battery: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BATTERY}) 236 status: YXDeviceState | None = field(default=None, metadata={"dps": B01_Q10_DP.STATUS}) 237 fan_level: YXFanLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.FAN_LEVEL}) 238 water_level: YXWaterLevel | None = field(default=None, metadata={"dps": B01_Q10_DP.WATER_LEVEL}) 239 clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_COUNT}) 240 total_clean_area: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_AREA}) 241 total_clean_count: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_COUNT}) 242 total_clean_time: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TOTAL_CLEAN_TIME}) 243 clean_mode: YXCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_MODE}) 244 clean_task_type: YXDeviceCleanTask | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_TASK_TYPE}) 245 back_type: YXBackType | None = field(default=None, metadata={"dps": B01_Q10_DP.BACK_TYPE}) 246 cleaning_progress: int | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_PROGRESS}) 247 fault: YXFault | None = field(default=None, metadata={"dps": B01_Q10_DP.FAULT}) 248 249 # Additional state reported in the device's full status dump. 250 clean_line: YXCleanLine | None = field(default=None, metadata={"dps": B01_Q10_DP.CLEAN_LINE}) 251 carpet_clean_type: YXCarpetCleanType | None = field(default=None, metadata={"dps": B01_Q10_DP.CARPET_CLEAN_TYPE}) 252 area_unit: YXAreaUnit | None = field(default=None, metadata={"dps": B01_Q10_DP.AREA_UNIT}) 253 auto_boost: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.AUTO_BOOST}) 254 multi_map_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MULTI_MAP_SWITCH}) 255 map_save_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MAP_SAVE_SWITCH}) 256 recent_clean_record: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.RECENT_CLEAN_RECORD}) 257 valley_point_charging: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.VALLEY_POINT_CHARGING}) 258 line_laser_obstacle_avoidance: bool | None = field( 259 default=None, metadata={"dps": B01_Q10_DP.LINE_LASER_OBSTACLE_AVOIDANCE} 260 ) 261 # Whether a mop module is attached, and whether "clean along floor direction" is on. 262 mop_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.MOP_STATE}) 263 ground_clean: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.GROUND_CLEAN}) 264 # True while an "add area" / re-clean (the app's draw-a-rectangle "re cleaning") 265 # request is in progress; pulses back to False once the robot has the area. 266 add_clean_state: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.ADD_CLEAN_STATE}) 267 robot_country_code: str | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_COUNTRY_CODE}) 268 time_zone: dpTimeZone | None = field(default=None, metadata={"dps": B01_Q10_DP.TIME_ZONE}) 269 270 # TODO(#846): value mappings for these ints are not yet decoded (no app 271 # control found / internal / constant); keep as int until reverse-engineered. 272 breakpoint_clean: int | None = field(default=None, metadata={"dps": B01_Q10_DP.BREAKPOINT_CLEAN}) 273 timer_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.TIMER_TYPE}) 274 user_plan: int | None = field(default=None, metadata={"dps": B01_Q10_DP.USER_PLAN}) 275 robot_type: int | None = field(default=None, metadata={"dps": B01_Q10_DP.ROBOT_TYPE}) 276 277 # DEPRECATED: consumable/accessory remaining-life now lives on the 278 # ``Q10Consumable`` trait. These aliases are kept here for backwards 279 # compatibility and will be removed in a follow-up release. See PR #846. 280 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 281 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 282 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 283 sensor_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SENSOR_LIFE}) 284 285 @property 286 def fault_name(self) -> str | None: 287 """Returns the name of the current fault.""" 288 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.
285 @property 286 def fault_name(self) -> str | None: 287 """Returns the name of the current fault.""" 288 return self.fault.value if self.fault is not None else None
Returns the name of the current fault.
Inherited Members
291@dataclass 292class SoundVolume(RoborockBase): 293 """Speaker volume read-model (0-100).""" 294 295 volume: int | None = field(default=None, metadata={"dps": B01_Q10_DP.VOLUME})
Speaker volume read-model (0-100).
Inherited Members
298@dataclass 299class ChildLock(RoborockBase): 300 """Child-lock read-model.""" 301 302 child_lock: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.CHILD_LOCK})
Child-lock read-model.
Inherited Members
305@dataclass 306class DoNotDisturb(RoborockBase): 307 """Do Not Disturb read-model.""" 308 309 not_disturb: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB}) 310 not_disturb_expand: dpNotDisturbExpand | None = field(default=None, metadata={"dps": B01_Q10_DP.NOT_DISTURB_EXPAND})
Do Not Disturb read-model.
Inherited Members
313@dataclass 314class DustCollection(RoborockBase): 315 """Dock auto-empty (dust collection) read-model.""" 316 317 dust_switch: bool | None = field(default=None, metadata={"dps": B01_Q10_DP.DUST_SWITCH}) 318 dust_setting: YXDeviceDustCollectionFrequency | None = field( 319 default=None, metadata={"dps": B01_Q10_DP.DUST_SETTING} 320 )
Dock auto-empty (dust collection) read-model.
Inherited Members
323@dataclass 324class Q10Consumable(RoborockBase): 325 """Consumable / accessory remaining-life read-model. 326 327 Named with a ``Q10`` prefix to avoid shadowing the v1 ``Consumable`` when both 328 are star-imported into the ``roborock.data`` namespace. 329 """ 330 331 main_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.MAIN_BRUSH_LIFE}) 332 side_brush_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.SIDE_BRUSH_LIFE}) 333 filter_life: int | None = field(default=None, metadata={"dps": B01_Q10_DP.FILTER_LIFE}) 334 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
337@dataclass 338class Q10NetworkInfo(RoborockBase): 339 """Network information read-model. 340 341 Named with a ``Q10`` prefix to avoid shadowing the v1 ``NetworkInfo`` when both 342 are star-imported into the ``roborock.data`` namespace. 343 """ 344 345 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.