python-roborock 2.50.2__tar.gz → 2.50.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {python_roborock-2.50.2 → python_roborock-2.50.4}/PKG-INFO +1 -1
  2. {python_roborock-2.50.2 → python_roborock-2.50.4}/pyproject.toml +1 -1
  3. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/containers.py +132 -71
  4. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_1_apis/roborock_client_v1.py +2 -1
  5. {python_roborock-2.50.2 → python_roborock-2.50.4}/LICENSE +0 -0
  6. {python_roborock-2.50.2 → python_roborock-2.50.4}/README.md +0 -0
  7. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/__init__.py +0 -0
  8. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/api.py +0 -0
  9. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/b01_containers.py +0 -0
  10. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/broadcast_protocol.py +0 -0
  11. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/callbacks.py +0 -0
  12. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/clean_modes.py +0 -0
  13. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/cli.py +0 -0
  14. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/cloud_api.py +0 -0
  15. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/code_mappings.py +0 -0
  16. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/command_cache.py +0 -0
  17. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/const.py +0 -0
  18. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/device_features.py +0 -0
  19. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/README.md +0 -0
  20. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/__init__.py +0 -0
  21. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/a01_channel.py +0 -0
  22. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/b01_channel.py +0 -0
  23. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/cache.py +0 -0
  24. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/channel.py +0 -0
  25. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/device.py +0 -0
  26. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/device_manager.py +0 -0
  27. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/local_channel.py +0 -0
  28. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/mqtt_channel.py +0 -0
  29. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/__init__.py +0 -0
  30. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/a01/__init__.py +0 -0
  31. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/b01/__init__.py +0 -0
  32. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/traits_mixin.py +0 -0
  33. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/__init__.py +0 -0
  34. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/clean_summary.py +0 -0
  35. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/common.py +0 -0
  36. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  37. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/maps.py +0 -0
  38. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/status.py +0 -0
  39. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/traits/v1/volume.py +0 -0
  40. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/v1_channel.py +0 -0
  41. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/devices/v1_rpc_channel.py +0 -0
  42. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/exceptions.py +0 -0
  43. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/map/map_parser.py +0 -0
  44. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/mqtt/__init__.py +0 -0
  45. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/mqtt/roborock_session.py +0 -0
  46. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/mqtt/session.py +0 -0
  47. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/protocol.py +0 -0
  48. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/protocols/a01_protocol.py +0 -0
  49. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/protocols/b01_protocol.py +0 -0
  50. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/protocols/v1_protocol.py +0 -0
  51. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/py.typed +0 -0
  52. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/roborock_future.py +0 -0
  53. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/roborock_message.py +0 -0
  54. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/roborock_typing.py +0 -0
  55. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/util.py +0 -0
  56. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_1_apis/__init__.py +0 -0
  57. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
  58. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
  59. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_a01_apis/__init__.py +0 -0
  60. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
  61. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
  62. {python_roborock-2.50.2 → python_roborock-2.50.4}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-roborock
3
- Version: 2.50.2
3
+ Version: 2.50.4
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Home-page: https://github.com/humbertogontijo/python-roborock
6
6
  License: GPL-3.0-only
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-roborock"
3
- version = "2.50.2"
3
+ version = "2.50.4"
4
4
  description = "A package to control Roborock vacuums."
5
5
  authors = ["humbertogontijo <humbertogontijo@users.noreply.github.com>"]
6
6
  license = "GPL-3.0-only"
@@ -108,8 +108,32 @@ def _decamelize(s: str):
108
108
  return re.sub("([A-Z]+)", "_\\1", s).lower()
109
109
 
110
110
 
111
- @dataclass
111
+ def _attr_repr(obj: Any) -> str:
112
+ """Return a string representation of the object including specified attributes.
113
+
114
+ This reproduces the default repr behavior of dataclasses, but also includes
115
+ properties. This must be called by the child class's __repr__ method since
116
+ the parent RoborockBase class does not know about the child class's attributes.
117
+ """
118
+ # Reproduce default repr behavior
119
+ parts = []
120
+ for k in dir(obj):
121
+ if k.startswith("_"):
122
+ continue
123
+ try:
124
+ v = getattr(obj, k)
125
+ except (RuntimeError, Exception):
126
+ continue
127
+ if callable(v):
128
+ continue
129
+ parts.append(f"{k}={v!r}")
130
+ return f"{type(obj).__name__}({', '.join(parts)})"
131
+
132
+
133
+ @dataclass(repr=False)
112
134
  class RoborockBase:
135
+ """Base class for all Roborock data classes."""
136
+
113
137
  @staticmethod
114
138
  def _convert_to_class_obj(class_type: type, value):
115
139
  if get_origin(class_type) is list:
@@ -194,6 +218,9 @@ class RoborockBaseTimer(RoborockBase):
194
218
  else None
195
219
  )
196
220
 
221
+ def __repr__(self) -> str:
222
+ return _attr_repr(self)
223
+
197
224
 
198
225
  @dataclass
199
226
  class Reference(RoborockBase):
@@ -346,7 +373,6 @@ class Status(RoborockBase):
346
373
  battery: int | None = None
347
374
  clean_time: int | None = None
348
375
  clean_area: int | None = None
349
- square_meter_clean_area: float | None = None
350
376
  error_code: RoborockErrorCode | None = None
351
377
  map_present: int | None = None
352
378
  in_cleaning: RoborockInCleaning | None = None
@@ -393,26 +419,36 @@ class Status(RoborockBase):
393
419
  dss: int | None = None
394
420
  common_status: int | None = None
395
421
  corner_clean_mode: int | None = None
396
- error_code_name: str | None = None
397
- state_name: str | None = None
398
- water_box_mode_name: str | None = None
399
- fan_power_options: list[str] = field(default_factory=list)
400
- fan_power_name: str | None = None
401
- mop_mode_name: str | None = None
402
-
403
- def __post_init__(self) -> None:
404
- self.square_meter_clean_area = round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
405
- if self.error_code is not None:
406
- self.error_code_name = self.error_code.name
407
- if self.state is not None:
408
- self.state_name = self.state.name
409
- if self.water_box_mode is not None:
410
- self.water_box_mode_name = self.water_box_mode.name
411
- if self.fan_power is not None:
412
- self.fan_power_options = self.fan_power.keys()
413
- self.fan_power_name = self.fan_power.name
414
- if self.mop_mode is not None:
415
- self.mop_mode_name = self.mop_mode.name
422
+
423
+ @property
424
+ def square_meter_clean_area(self) -> float | None:
425
+ return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
426
+
427
+ @property
428
+ def error_code_name(self) -> str | None:
429
+ return self.error_code.name if self.error_code else None
430
+
431
+ @property
432
+ def state_name(self) -> str | None:
433
+ return self.state.name if self.state else None
434
+
435
+ @property
436
+ def water_box_mode_name(self) -> str | None:
437
+ return self.water_box_mode.name if self.water_box_mode else None
438
+
439
+ @property
440
+ def fan_power_options(self) -> list[str]:
441
+ if self.fan_power is None:
442
+ return []
443
+ return list(self.fan_power.keys())
444
+
445
+ @property
446
+ def fan_power_name(self) -> str | None:
447
+ return self.fan_power.name if self.fan_power else None
448
+
449
+ @property
450
+ def mop_mode_name(self) -> str | None:
451
+ return self.mop_mode.name if self.mop_mode else None
416
452
 
417
453
  def get_fan_speed_code(self, fan_speed: str) -> int:
418
454
  if self.fan_power is None:
@@ -438,6 +474,9 @@ class Status(RoborockBase):
438
474
  return map_flag
439
475
  return None
440
476
 
477
+ def __repr__(self) -> str:
478
+ return _attr_repr(self)
479
+
441
480
 
442
481
  @dataclass
443
482
  class S4MaxStatus(Status):
@@ -588,28 +627,30 @@ class ValleyElectricityTimer(RoborockBaseTimer):
588
627
  class CleanSummary(RoborockBase):
589
628
  clean_time: int | None = None
590
629
  clean_area: int | None = None
591
- square_meter_clean_area: float | None = None
592
630
  clean_count: int | None = None
593
631
  dust_collection_count: int | None = None
594
632
  records: list[int] | None = None
595
633
  last_clean_t: int | None = None
596
634
 
597
- def __post_init__(self) -> None:
635
+ @property
636
+ def square_meter_clean_area(self) -> float | None:
637
+ """Returns the clean area in square meters."""
598
638
  if isinstance(self.clean_area, list | str):
599
639
  _LOGGER.warning(f"Clean area is a unexpected type! Please give the following in a issue: {self.clean_area}")
600
- else:
601
- self.square_meter_clean_area = round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
640
+ return None
641
+ return round(self.clean_area / 1000000, 1) if self.clean_area is not None else None
642
+
643
+ def __repr__(self) -> str:
644
+ """Return a string representation of the object including all attributes."""
645
+ return _attr_repr(self)
602
646
 
603
647
 
604
648
  @dataclass
605
649
  class CleanRecord(RoborockBase):
606
650
  begin: int | None = None
607
- begin_datetime: datetime.datetime | None = None
608
651
  end: int | None = None
609
- end_datetime: datetime.datetime | None = None
610
652
  duration: int | None = None
611
653
  area: int | None = None
612
- square_meter_area: float | None = None
613
654
  error: int | None = None
614
655
  complete: int | None = None
615
656
  start_type: RoborockStartType | None = None
@@ -620,12 +661,20 @@ class CleanRecord(RoborockBase):
620
661
  wash_count: int | None = None
621
662
  map_flag: int | None = None
622
663
 
623
- def __post_init__(self) -> None:
624
- self.square_meter_area = round(self.area / 1000000, 1) if self.area is not None else None
625
- self.begin_datetime = (
626
- datetime.datetime.fromtimestamp(self.begin).astimezone(timezone.utc) if self.begin else None
627
- )
628
- self.end_datetime = datetime.datetime.fromtimestamp(self.end).astimezone(timezone.utc) if self.end else None
664
+ @property
665
+ def square_meter_area(self) -> float | None:
666
+ return round(self.area / 1000000, 1) if self.area is not None else None
667
+
668
+ @property
669
+ def begin_datetime(self) -> datetime.datetime | None:
670
+ return datetime.datetime.fromtimestamp(self.begin).astimezone(timezone.utc) if self.begin else None
671
+
672
+ @property
673
+ def end_datetime(self) -> datetime.datetime | None:
674
+ return datetime.datetime.fromtimestamp(self.end).astimezone(timezone.utc) if self.end else None
675
+
676
+ def __repr__(self) -> str:
677
+ return _attr_repr(self)
629
678
 
630
679
 
631
680
  @dataclass
@@ -639,44 +688,49 @@ class Consumable(RoborockBase):
639
688
  dust_collection_work_times: int | None = None
640
689
  cleaning_brush_work_times: int | None = None
641
690
  moproller_work_time: int | None = None
642
- main_brush_time_left: int | None = None
643
- side_brush_time_left: int | None = None
644
- filter_time_left: int | None = None
645
- sensor_time_left: int | None = None
646
- strainer_time_left: int | None = None
647
- dust_collection_time_left: int | None = None
648
- cleaning_brush_time_left: int | None = None
649
- mop_roller_time_left: int | None = None
650
-
651
- def __post_init__(self) -> None:
652
- self.main_brush_time_left = (
653
- MAIN_BRUSH_REPLACE_TIME - self.main_brush_work_time if self.main_brush_work_time is not None else None
654
- )
655
- self.side_brush_time_left = (
656
- SIDE_BRUSH_REPLACE_TIME - self.side_brush_work_time if self.side_brush_work_time is not None else None
657
- )
658
- self.filter_time_left = (
659
- FILTER_REPLACE_TIME - self.filter_work_time if self.filter_work_time is not None else None
660
- )
661
- self.sensor_time_left = (
662
- SENSOR_DIRTY_REPLACE_TIME - self.sensor_dirty_time if self.sensor_dirty_time is not None else None
663
- )
664
- self.strainer_time_left = (
665
- STRAINER_REPLACE_TIME - self.strainer_work_times if self.strainer_work_times is not None else None
666
- )
667
- self.dust_collection_time_left = (
691
+
692
+ @property
693
+ def main_brush_time_left(self) -> int | None:
694
+ return MAIN_BRUSH_REPLACE_TIME - self.main_brush_work_time if self.main_brush_work_time is not None else None
695
+
696
+ @property
697
+ def side_brush_time_left(self) -> int | None:
698
+ return SIDE_BRUSH_REPLACE_TIME - self.side_brush_work_time if self.side_brush_work_time is not None else None
699
+
700
+ @property
701
+ def filter_time_left(self) -> int | None:
702
+ return FILTER_REPLACE_TIME - self.filter_work_time if self.filter_work_time is not None else None
703
+
704
+ @property
705
+ def sensor_time_left(self) -> int | None:
706
+ return SENSOR_DIRTY_REPLACE_TIME - self.sensor_dirty_time if self.sensor_dirty_time is not None else None
707
+
708
+ @property
709
+ def strainer_time_left(self) -> int | None:
710
+ return STRAINER_REPLACE_TIME - self.strainer_work_times if self.strainer_work_times is not None else None
711
+
712
+ @property
713
+ def dust_collection_time_left(self) -> int | None:
714
+ return (
668
715
  DUST_COLLECTION_REPLACE_TIME - self.dust_collection_work_times
669
716
  if self.dust_collection_work_times is not None
670
717
  else None
671
718
  )
672
- self.cleaning_brush_time_left = (
719
+
720
+ @property
721
+ def cleaning_brush_time_left(self) -> int | None:
722
+ return (
673
723
  CLEANING_BRUSH_REPLACE_TIME - self.cleaning_brush_work_times
674
724
  if self.cleaning_brush_work_times is not None
675
725
  else None
676
726
  )
677
- self.mop_roller_time_left = (
678
- MOP_ROLLER_REPLACE_TIME - self.moproller_work_time if self.moproller_work_time is not None else None
679
- )
727
+
728
+ @property
729
+ def mop_roller_time_left(self) -> int | None:
730
+ return MOP_ROLLER_REPLACE_TIME - self.moproller_work_time if self.moproller_work_time is not None else None
731
+
732
+ def __repr__(self) -> str:
733
+ return _attr_repr(self)
680
734
 
681
735
 
682
736
  @dataclass
@@ -760,11 +814,14 @@ class DeviceData(RoborockBase):
760
814
  device: HomeDataDevice
761
815
  model: str
762
816
  host: str | None = None
763
- product_nickname: RoborockProductNickname | None = None
764
817
  device_features: DeviceFeatures | None = None
765
818
 
766
- def __post_init__(self):
767
- self.product_nickname = SHORT_MODEL_TO_ENUM.get(self.model.split(".")[-1], RoborockProductNickname.PEARLPLUS)
819
+ @property
820
+ def product_nickname(self) -> RoborockProductNickname:
821
+ return SHORT_MODEL_TO_ENUM.get(self.model.split(".")[-1], RoborockProductNickname.PEARLPLUS)
822
+
823
+ def __repr__(self) -> str:
824
+ return _attr_repr(self)
768
825
 
769
826
 
770
827
  @dataclass
@@ -849,11 +906,15 @@ class RoborockProduct(RoborockBase):
849
906
  agreements: list | None = None
850
907
  cardspec: str | None = None
851
908
  plugin_pic_url: str | None = None
852
- products_specification: RoborockProductSpec | None = None
853
909
 
854
- def __post_init__(self):
910
+ @property
911
+ def product_nickname(self) -> RoborockProductNickname | None:
855
912
  if self.cardspec:
856
- self.products_specification = RoborockProductSpec.from_dict(json.loads(self.cardspec).get("data"))
913
+ return RoborockProductSpec.from_dict(json.loads(self.cardspec).get("data"))
914
+ return None
915
+
916
+ def __repr__(self) -> str:
917
+ return _attr_repr(self)
857
918
 
858
919
 
859
920
  @dataclass
@@ -228,7 +228,8 @@ class RoborockClientV1(RoborockClient, ABC):
228
228
  final_record.square_meter_area += (
229
229
  rec.square_meter_area if rec.square_meter_area is not None else 0
230
230
  )
231
- finally:
231
+ except Exception:
232
+ # Return final record when an exception occurred
232
233
  return final_record
233
234
  # There are still a few unknown variables in this.
234
235
  begin, end, duration, area = unpack_list(record, 4)