2
2
from datetime import datetime , time , timedelta
3
3
from enum import IntEnum
4
4
from typing import Any , Dict , List , Optional , Union
5
+ from urllib import parse
5
6
6
7
from croniter import croniter
7
8
from pytz import BaseTzInfo
@@ -110,7 +111,7 @@ def __init__(self, data: Dict[str, Any]) -> None:
110
111
111
112
self ._map_name_dict = {}
112
113
for map in self .data ["map_info" ]:
113
- self ._map_name_dict [map ["name" ]] = map ["mapFlag" ]
114
+ self ._map_name_dict [parse . unquote ( map ["name" ]) ] = map ["mapFlag" ]
114
115
115
116
@property
116
117
def map_count (self ) -> int :
@@ -185,7 +186,12 @@ def state_code(self) -> int:
185
186
return int (self .data ["state" ])
186
187
187
188
@property
188
- @sensor ("State" , entity_category = "diagnostic" )
189
+ @sensor (
190
+ "State" ,
191
+ device_class = "enum" ,
192
+ entity_category = "diagnostic" ,
193
+ options = list (STATE_CODE_TO_STRING .values ()),
194
+ )
189
195
def state (self ) -> str :
190
196
"""Human readable state description, see also :func:`state_code`."""
191
197
return STATE_CODE_TO_STRING .get (
@@ -198,6 +204,14 @@ def vacuum_state(self) -> VacuumState:
198
204
"""Return vacuum state."""
199
205
return STATE_CODE_TO_VACUUMSTATE .get (self .state_code , VacuumState .Unknown )
200
206
207
+ @property
208
+ @sensor ("Cleaning Progress" , icon = "mdi:progress-check" , unit = "%" )
209
+ def clean_percent (self ) -> Optional [int ]:
210
+ """Return progress of the current clean."""
211
+ if "clean_percent" in self .data :
212
+ return int (self .data ["clean_percent" ])
213
+ return None
214
+
201
215
@property
202
216
@sensor (
203
217
"Error code" ,
@@ -214,6 +228,8 @@ def error_code(self) -> int:
214
228
"Error string" ,
215
229
id = VacuumId .ErrorMessage ,
216
230
icon = "mdi:alert" ,
231
+ device_class = "enum" ,
232
+ options = list (ERROR_CODES .values ()),
217
233
entity_category = "diagnostic" ,
218
234
enabled_default = False ,
219
235
)
@@ -241,6 +257,8 @@ def dock_error_code(self) -> Optional[int]:
241
257
@sensor (
242
258
"Dock error string" ,
243
259
icon = "mdi:alert" ,
260
+ device_class = "enum" ,
261
+ options = list (dock_error_codes .values ()),
244
262
entity_category = "diagnostic" ,
245
263
enabled_default = False ,
246
264
)
@@ -254,14 +272,14 @@ def dock_error(self) -> Optional[str]:
254
272
return "Definition missing for dock error %s" % self .dock_error_code
255
273
256
274
@property
257
- @sensor ("Battery" , unit = "%" , id = VacuumId .Battery )
275
+ @sensor ("Battery" , unit = "%" , device_class = "battery" , id = VacuumId .Battery )
258
276
def battery (self ) -> int :
259
277
"""Remaining battery in percentage."""
260
278
return int (self .data ["battery" ])
261
279
262
280
@property
263
281
@setting (
264
- "Fanspeed " ,
282
+ "Fan speed " ,
265
283
unit = "%" ,
266
284
setter_name = "set_fan_speed" ,
267
285
min_value = 0 ,
@@ -326,7 +344,12 @@ def clean_time(self) -> timedelta:
326
344
return pretty_seconds (self .data ["clean_time" ])
327
345
328
346
@property
329
- @sensor ("Current clean area" , unit = "m²" , icon = "mdi:texture-box" )
347
+ @sensor (
348
+ "Current clean area" ,
349
+ unit = "m²" ,
350
+ icon = "mdi:texture-box" ,
351
+ suggested_display_precision = 2 ,
352
+ )
330
353
def clean_area (self ) -> float :
331
354
"""Cleaned area in m2."""
332
355
return pretty_area (self .data ["clean_area" ])
@@ -397,7 +420,7 @@ def is_water_box_carriage_attached(self) -> Optional[bool]:
397
420
return None
398
421
399
422
@property
400
- @sensor ("Water level low" , icon = "mdi:water-alert-outline" )
423
+ @sensor ("Water level low" , device_class = "problem" , icon = "mdi:water-alert-outline" )
401
424
def is_water_shortage (self ) -> Optional [bool ]:
402
425
"""Returns True if water is low in the tank, None if sensor not present."""
403
426
if "water_shortage_status" in self .data :
@@ -420,7 +443,10 @@ def auto_dust_collection(self) -> Optional[bool]:
420
443
421
444
@property
422
445
@sensor (
423
- "Error" , icon = "mdi:alert" , entity_category = "diagnostic" , enabled_default = False
446
+ "Error" ,
447
+ entity_category = "diagnostic" ,
448
+ device_class = "problem" ,
449
+ enabled_default = False ,
424
450
)
425
451
def got_error (self ) -> bool :
426
452
"""True if an error has occurred."""
@@ -432,6 +458,7 @@ def got_error(self) -> bool:
432
458
icon = "mdi:tumble-dryer" ,
433
459
entity_category = "diagnostic" ,
434
460
enabled_default = False ,
461
+ device_class = "heat" ,
435
462
)
436
463
def is_mop_drying (self ) -> Optional [bool ]:
437
464
"""Return if mop drying is running."""
@@ -444,6 +471,7 @@ def is_mop_drying(self) -> Optional[bool]:
444
471
"Dryer remaining seconds" ,
445
472
unit = "s" ,
446
473
entity_category = "diagnostic" ,
474
+ device_class = "duration" ,
447
475
enabled_default = False ,
448
476
)
449
477
def mop_dryer_remaining_seconds (self ) -> Optional [timedelta ]:
@@ -496,6 +524,7 @@ def total_duration(self) -> timedelta:
496
524
unit = "m²" ,
497
525
icon = "mdi:texture-box" ,
498
526
entity_category = "diagnostic" ,
527
+ suggested_display_precision = 2 ,
499
528
)
500
529
def total_area (self ) -> float :
501
530
"""Total cleaned area."""
@@ -592,6 +621,7 @@ def duration(self) -> timedelta:
592
621
unit = "m²" ,
593
622
icon = "mdi:texture-box" ,
594
623
entity_category = "diagnostic" ,
624
+ suggested_display_precision = 2 ,
595
625
)
596
626
def area (self ) -> float :
597
627
"""Total cleaned area."""
@@ -792,15 +822,15 @@ def __init__(self, data: Dict[str, Any]):
792
822
self .data = data
793
823
794
824
@property
795
- @sensor ("Do not disturb" , icon = "mdi:minus-circle-off " , entity_category = "diagnostic" )
825
+ @sensor ("Do not disturb" , icon = "mdi:bell-cancel " , entity_category = "diagnostic" )
796
826
def enabled (self ) -> bool :
797
827
"""True if DnD is enabled."""
798
828
return bool (self .data ["enabled" ])
799
829
800
830
@property
801
831
@sensor (
802
832
"Do not disturb start" ,
803
- icon = "mdi:minus-circle-off " ,
833
+ icon = "mdi:bell-cancel " ,
804
834
device_class = "timestamp" ,
805
835
entity_category = "diagnostic" ,
806
836
enabled_default = False ,
@@ -812,7 +842,7 @@ def start(self) -> time:
812
842
@property
813
843
@sensor (
814
844
"Do not disturb end" ,
815
- icon = "mdi:minus-circle-off " ,
845
+ icon = "mdi:bell-ring " ,
816
846
device_class = "timestamp" ,
817
847
entity_category = "diagnostic" ,
818
848
enabled_default = False ,
0 commit comments