File: b01_q7_containers.py

package info (click to toggle)
python-roborock 4.12.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,480 kB
  • sloc: python: 16,602; makefile: 17; sh: 6
file content (302 lines) | stat: -rw-r--r-- 9,290 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
import datetime
import json
from dataclasses import dataclass, field
from functools import cached_property

from ...exceptions import RoborockException
from ..containers import RoborockBase
from .b01_q7_code_mappings import (
    B01Fault,
    CleanPathPreferenceMapping,
    CleanRepeatMapping,
    CleanTypeMapping,
    SCWindMapping,
    WaterLevelMapping,
    WorkModeMapping,
    WorkStatusMapping,
)


@dataclass
class NetStatus(RoborockBase):
    """Represents the network status of the device."""

    rssi: str
    loss: int
    ping: int
    ip: str
    mac: str
    ssid: str
    frequency: int
    bssid: str


@dataclass
class OrderTotal(RoborockBase):
    """Represents the order total information."""

    total: int
    enable: int


@dataclass
class Privacy(RoborockBase):
    """Represents the privacy settings of the device."""

    ai_recognize: int
    dirt_recognize: int
    pet_recognize: int
    carpet_turbo: int
    carpet_avoid: int
    carpet_show: int
    map_uploads: int
    ai_agent: int
    ai_avoidance: int
    record_uploads: int
    along_floor: int
    auto_upgrade: int


@dataclass
class PvCharging(RoborockBase):
    """Represents the photovoltaic charging status."""

    status: int
    begin_time: int
    end_time: int


@dataclass
class Recommend(RoborockBase):
    """Represents cleaning recommendations."""

    sill: int
    wall: int
    room_id: list[int] = field(default_factory=list)


@dataclass
class B01Props(RoborockBase):
    """
    Represents the complete properties and status for a Roborock B01 model.
    This dataclass is generated based on the device's status JSON object.
    """

    status: WorkStatusMapping | None = None
    fault: B01Fault | None = None
    wind: SCWindMapping | None = None
    water: WaterLevelMapping | None = None
    mode: CleanTypeMapping | None = None
    quantity: int | None = None
    alarm: int | None = None
    volume: int | None = None
    hypa: int | None = None
    main_brush: int | None = None
    side_brush: int | None = None
    mop_life: int | None = None
    main_sensor: int | None = None
    net_status: NetStatus | None = None
    repeat_state: CleanRepeatMapping | None = None
    tank_state: int | None = None
    sweep_type: int | None = None
    clean_path_preference: CleanPathPreferenceMapping | None = None
    cloth_state: int | None = None
    time_zone: int | None = None
    time_zone_info: str | None = None
    language: int | None = None
    cleaning_time: int | None = None
    real_clean_time: int | None = None
    cleaning_area: int | None = None
    custom_type: int | None = None
    sound: int | None = None
    work_mode: WorkModeMapping | None = None
    station_act: int | None = None
    charge_state: int | None = None
    current_map_id: int | None = None
    map_num: int | None = None
    dust_action: int | None = None
    quiet_is_open: int | None = None
    quiet_begin_time: int | None = None
    quiet_end_time: int | None = None
    clean_finish: int | None = None
    voice_type: int | None = None
    voice_type_version: int | None = None
    order_total: OrderTotal | None = None
    build_map: int | None = None
    privacy: Privacy | None = None
    dust_auto_state: int | None = None
    dust_frequency: int | None = None
    child_lock: int | None = None
    multi_floor: int | None = None
    map_save: int | None = None
    light_mode: int | None = None
    green_laser: int | None = None
    dust_bag_used: int | None = None
    order_save_mode: int | None = None
    manufacturer: str | None = None
    back_to_wash: int | None = None
    charge_station_type: int | None = None
    pv_cut_charge: int | None = None
    pv_charging: PvCharging | None = None
    serial_number: str | None = None
    recommend: Recommend | None = None
    add_sweep_status: int | None = None

    @property
    def main_brush_time_left(self) -> int | None:
        """
        Returns estimated remaining life of the main brush in minutes.
        Total life is 300 hours (18000 minutes).
        """
        if self.main_brush is None:
            return None
        return max(0, 18000 - self.main_brush)

    @property
    def side_brush_time_left(self) -> int | None:
        """
        Returns estimated remaining life of the side brush in minutes.
        Total life is 200 hours (12000 minutes).
        """
        if self.side_brush is None:
            return None
        return max(0, 12000 - self.side_brush)

    @property
    def filter_time_left(self) -> int | None:
        """
        Returns estimated remaining life of the filter (hypa) in minutes.
        Total life is 150 hours (9000 minutes).
        """
        if self.hypa is None:
            return None
        return max(0, 9000 - self.hypa)

    @property
    def mop_life_time_left(self) -> int | None:
        """
        Returns estimated remaining life of the mop in minutes.
        Total life is 180 hours (10800 minutes).
        """
        if self.mop_life is None:
            return None
        return max(0, 10800 - self.mop_life)

    @property
    def sensor_dirty_time_left(self) -> int | None:
        """
        Returns estimated time until sensors need cleaning in minutes.
        Maintenance interval is typically 30 hours (1800 minutes).
        """
        if self.main_sensor is None:
            return None
        return max(0, 1800 - self.main_sensor)

    @property
    def status_name(self) -> str | None:
        """Returns the name of the current status."""
        return self.status.value if self.status is not None else None

    @property
    def fault_name(self) -> str | None:
        """Returns the name of the current fault."""
        return self.fault.value if self.fault is not None else None

    @property
    def wind_name(self) -> str | None:
        """Returns the name of the current fan speed (wind)."""
        return self.wind.value if self.wind is not None else None

    @property
    def work_mode_name(self) -> str | None:
        """Returns the name of the current work mode."""
        return self.work_mode.value if self.work_mode is not None else None

    @property
    def repeat_state_name(self) -> str | None:
        """Returns the name of the current repeat state."""
        return self.repeat_state.value if self.repeat_state is not None else None

    @property
    def clean_path_preference_name(self) -> str | None:
        """Returns the name of the current clean path preference."""
        return self.clean_path_preference.value if self.clean_path_preference is not None else None


@dataclass
class CleanRecordDetail(RoborockBase):
    """Represents a single clean record detail (from `record_list[].detail`)."""

    record_start_time: int | None = None
    method: int | None = None
    record_use_time: int | None = None
    clean_count: int | None = None
    # This is seemingly returned in meters (non-squared)
    record_clean_area: int | None = None
    record_clean_mode: int | None = None
    record_clean_way: int | None = None
    record_task_status: int | None = None
    record_faultcode: int | None = None
    record_dust_num: int | None = None
    clean_current_map: int | None = None
    record_map_url: str | None = None

    @property
    def start_datetime(self) -> datetime.datetime | None:
        """Convert the start datetime into a datetime object."""
        if self.record_start_time is not None:
            return datetime.datetime.fromtimestamp(self.record_start_time).astimezone(datetime.UTC)
        return None

    @property
    def square_meters_area_cleaned(self) -> float | None:
        """Returns the area cleaned in square meters."""
        if self.record_clean_area is not None:
            return self.record_clean_area / 100
        return None


@dataclass
class CleanRecordListItem(RoborockBase):
    """Represents an entry in the clean record list returned by `service.get_record_list`."""

    url: str | None = None
    detail: str | None = None

    @cached_property
    def detail_parsed(self) -> CleanRecordDetail | None:
        """Parse and return the detail as a CleanRecordDetail object."""
        if self.detail is None:
            return None
        try:
            parsed = json.loads(self.detail)
        except json.JSONDecodeError as ex:
            raise RoborockException(f"Invalid B01 record detail JSON: {self.detail!r}") from ex
        return CleanRecordDetail.from_dict(parsed)


@dataclass
class CleanRecordList(RoborockBase):
    """Represents the clean record list response from `service.get_record_list`."""

    total_area: int | None = None
    total_time: int | None = None  # stored in seconds
    total_count: int | None = None
    record_list: list[CleanRecordListItem] = field(default_factory=list)

    @property
    def square_meters_area_cleaned(self) -> float | None:
        """Returns the area cleaned in square meters."""
        if self.total_area is not None:
            return self.total_area / 100
        return None


@dataclass
class CleanRecordSummary(RoborockBase):
    """Represents clean record totals for B01/Q7 devices."""

    total_time: int | None = None
    total_area: int | None = None
    total_count: int | None = None
    last_record_detail: CleanRecordDetail | None = None