python-roborock 4.2.2__tar.gz → 4.3.0__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 (93) hide show
  1. {python_roborock-4.2.2 → python_roborock-4.3.0}/PKG-INFO +1 -1
  2. {python_roborock-4.2.2 → python_roborock-4.3.0}/pyproject.toml +1 -1
  3. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/containers.py +7 -0
  4. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/v1/v1_containers.py +35 -7
  5. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/__init__.py +7 -1
  6. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/device_features.py +30 -6
  7. {python_roborock-4.2.2 → python_roborock-4.3.0}/.gitignore +0 -0
  8. {python_roborock-4.2.2 → python_roborock-4.3.0}/LICENSE +0 -0
  9. {python_roborock-4.2.2 → python_roborock-4.3.0}/README.md +0 -0
  10. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/__init__.py +0 -0
  11. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/broadcast_protocol.py +0 -0
  12. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/callbacks.py +0 -0
  13. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/cli.py +0 -0
  14. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/const.py +0 -0
  15. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/__init__.py +0 -0
  16. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q10/__init__.py +0 -0
  17. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  18. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  19. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q7/__init__.py +0 -0
  20. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  21. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  22. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/code_mappings.py +0 -0
  23. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/dyad/__init__.py +0 -0
  24. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  25. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/dyad/dyad_containers.py +0 -0
  26. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/v1/__init__.py +0 -0
  27. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/v1/v1_clean_modes.py +0 -0
  28. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/v1/v1_code_mappings.py +0 -0
  29. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/zeo/__init__.py +0 -0
  30. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  31. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/data/zeo/zeo_containers.py +0 -0
  32. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/device_features.py +0 -0
  33. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/README.md +0 -0
  34. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/__init__.py +0 -0
  35. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/cache.py +0 -0
  36. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/device.py +0 -0
  37. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/device_manager.py +0 -0
  38. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/file_cache.py +0 -0
  39. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/rpc/__init__.py +0 -0
  40. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/rpc/a01_channel.py +0 -0
  41. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  42. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  43. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/rpc/v1_channel.py +0 -0
  44. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/__init__.py +0 -0
  45. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/a01/__init__.py +0 -0
  46. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/b01/__init__.py +0 -0
  47. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  48. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/b01/q10/command.py +0 -0
  49. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  50. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/traits_mixin.py +0 -0
  51. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/child_lock.py +0 -0
  52. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
  53. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/command.py +0 -0
  54. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/common.py +0 -0
  55. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/consumeable.py +0 -0
  56. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  57. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  58. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  59. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/home.py +0 -0
  60. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/led_status.py +0 -0
  61. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/map_content.py +0 -0
  62. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/maps.py +0 -0
  63. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/network_info.py +0 -0
  64. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/rooms.py +0 -0
  65. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/routines.py +0 -0
  66. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  67. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/status.py +0 -0
  68. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  69. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/volume.py +0 -0
  70. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  71. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/transport/__init__.py +0 -0
  72. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/transport/channel.py +0 -0
  73. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/transport/local_channel.py +0 -0
  74. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/devices/transport/mqtt_channel.py +0 -0
  75. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/diagnostics.py +0 -0
  76. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/exceptions.py +0 -0
  77. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/map/__init__.py +0 -0
  78. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/map/map_parser.py +0 -0
  79. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/mqtt/__init__.py +0 -0
  80. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/mqtt/health_manager.py +0 -0
  81. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/mqtt/roborock_session.py +0 -0
  82. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/mqtt/session.py +0 -0
  83. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocol.py +0 -0
  84. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocols/__init__.py +0 -0
  85. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocols/a01_protocol.py +0 -0
  86. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocols/b01_q10_protocol.py +0 -0
  87. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocols/b01_q7_protocol.py +0 -0
  88. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/protocols/v1_protocol.py +0 -0
  89. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/py.typed +0 -0
  90. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/roborock_message.py +0 -0
  91. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/roborock_typing.py +0 -0
  92. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/util.py +0 -0
  93. {python_roborock-4.2.2 → python_roborock-4.3.0}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 4.2.2
3
+ Version: 4.3.0
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/humbertogontijo/python-roborock
6
6
  Project-URL: Documentation, https://python-roborock.readthedocs.io/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-roborock"
3
- version = "4.2.2"
3
+ version = "4.3.0"
4
4
  description = "A package to control Roborock vacuums."
5
5
  authors = [{ name = "humbertogontijo", email = "humbertogontijo@users.noreply.github.com" }, {name="Lash-L"}, {name="allenporter"}]
6
6
  requires-python = ">=3.11, <4"
@@ -232,6 +232,13 @@ class HomeDataProduct(RoborockBase):
232
232
  """Return a string with key product information for logging purposes."""
233
233
  return f"{self.name} (model={self.model}, category={self.category})"
234
234
 
235
+ @cached_property
236
+ def supported_schema_codes(self) -> set[str]:
237
+ """Return a set of fields that are supported by the device."""
238
+ if self.schema is None:
239
+ return set()
240
+ return {schema.code for schema in self.schema if schema.code is not None}
241
+
235
242
 
236
243
  @dataclass
237
244
  class HomeDataDevice(RoborockBase):
@@ -1,6 +1,7 @@
1
1
  import datetime
2
2
  import logging
3
- from dataclasses import dataclass
3
+ from dataclasses import dataclass, field
4
+ from enum import StrEnum
4
5
  from typing import Any
5
6
 
6
7
  from roborock.const import (
@@ -91,12 +92,39 @@ from .v1_code_mappings import (
91
92
  _LOGGER = logging.getLogger(__name__)
92
93
 
93
94
 
95
+ class FieldNameBase(StrEnum):
96
+ """A base enum class that represents a field name in a RoborockBase dataclass."""
97
+
98
+
99
+ class StatusField(FieldNameBase):
100
+ """An enum that represents a field in the `Status` class.
101
+
102
+ This is used with `roborock.devices.traits.v1.status.DeviceFeaturesTrait`
103
+ to understand if a feature is supported by the device using `is_field_supported`.
104
+
105
+ The enum values are names of fields in the `Status` class. Each field is
106
+ annotated with `requires_schema_code` metadata to map the field to a schema
107
+ code in the product schema, which may have a different name than the field/attribute name.
108
+ """
109
+
110
+ STATE = "state"
111
+ BATTERY = "battery"
112
+ FAN_POWER = "fan_power"
113
+ WATER_BOX_MODE = "water_box_mode"
114
+ CHARGE_STATUS = "charge_status"
115
+ DRY_STATUS = "dry_status"
116
+
117
+
118
+ def _requires_schema_code(requires_schema_code: str, default=None) -> Any:
119
+ return field(metadata={"requires_schema_code": requires_schema_code}, default=default)
120
+
121
+
94
122
  @dataclass
95
123
  class Status(RoborockBase):
96
124
  msg_ver: int | None = None
97
125
  msg_seq: int | None = None
98
- state: RoborockStateCode | None = None
99
- battery: int | None = None
126
+ state: RoborockStateCode | None = _requires_schema_code("state", default=None)
127
+ battery: int | None = _requires_schema_code("battery", default=None)
100
128
  clean_time: int | None = None
101
129
  clean_area: int | None = None
102
130
  error_code: RoborockErrorCode | None = None
@@ -109,12 +137,12 @@ class Status(RoborockBase):
109
137
  back_type: int | None = None
110
138
  wash_phase: int | None = None
111
139
  wash_ready: int | None = None
112
- fan_power: RoborockFanPowerCode | None = None
140
+ fan_power: RoborockFanPowerCode | None = _requires_schema_code("fan_power", default=None)
113
141
  dnd_enabled: int | None = None
114
142
  map_status: int | None = None
115
143
  is_locating: int | None = None
116
144
  lock_status: int | None = None
117
- water_box_mode: RoborockMopIntensityCode | None = None
145
+ water_box_mode: RoborockMopIntensityCode | None = _requires_schema_code("water_box_mode", default=None)
118
146
  water_box_carriage_status: int | None = None
119
147
  mop_forbidden_enable: int | None = None
120
148
  camera_status: int | None = None
@@ -132,13 +160,13 @@ class Status(RoborockBase):
132
160
  collision_avoid_status: int | None = None
133
161
  switch_map_mode: int | None = None
134
162
  dock_error_status: RoborockDockErrorCode | None = None
135
- charge_status: int | None = None
163
+ charge_status: int | None = _requires_schema_code("charge_status", default=None)
136
164
  unsave_map_reason: int | None = None
137
165
  unsave_map_flag: int | None = None
138
166
  wash_status: int | None = None
139
167
  distance_off: int | None = None
140
168
  in_warmup: int | None = None
141
- dry_status: int | None = None
169
+ dry_status: int | None = _requires_schema_code("drying_status", default=None)
142
170
  rdt: int | None = None
143
171
  clean_percent: int | None = None
144
172
  rss: int | None = None
@@ -44,6 +44,12 @@ optional traits:
44
44
  available features.
45
45
  - `requires_dock_type` - If set, this is a function that accepts a `RoborockDockTypeCode`
46
46
  and returns a boolean indicating whether the trait is supported for that dock type.
47
+
48
+ Additionally, DeviceFeaturesTrait has a method `is_field_supported` that is used to
49
+ check individual trait field values. This is a more fine grained version to allow
50
+ optional fields in a dataclass, vs the above feature checks that apply to an entire
51
+ trait. The `requires_schema_code` field metadata attribute is a string of the schema
52
+ code in HomeDataProduct Schema that is required for the field to be supported.
47
53
  """
48
54
 
49
55
  import logging
@@ -189,7 +195,7 @@ class PropertiesApi(Trait):
189
195
  self.maps = MapsTrait(self.status)
190
196
  self.map_content = MapContentTrait(map_parser_config)
191
197
  self.home = HomeTrait(self.status, self.maps, self.map_content, self.rooms, self._device_cache)
192
- self.device_features = DeviceFeaturesTrait(product.product_nickname, self._device_cache)
198
+ self.device_features = DeviceFeaturesTrait(product, self._device_cache)
193
199
  self.network_info = NetworkInfoTrait(device_uid, self._device_cache)
194
200
  self.routines = RoutinesTrait(device_uid, web_api)
195
201
 
@@ -1,6 +1,7 @@
1
- from dataclasses import fields
1
+ from dataclasses import Field, fields
2
2
 
3
- from roborock.data import AppInitStatus, RoborockProductNickname
3
+ from roborock.data import AppInitStatus, HomeDataProduct, RoborockBase
4
+ from roborock.data.v1.v1_containers import FieldNameBase
4
5
  from roborock.device_features import DeviceFeatures
5
6
  from roborock.devices.cache import DeviceCache
6
7
  from roborock.devices.traits.v1 import common
@@ -8,19 +9,42 @@ from roborock.roborock_typing import RoborockCommand
8
9
 
9
10
 
10
11
  class DeviceFeaturesTrait(DeviceFeatures, common.V1TraitMixin):
11
- """Trait for managing Do Not Disturb (DND) settings on Roborock devices."""
12
+ """Trait for managing supported features on Roborock devices."""
12
13
 
13
14
  command = RoborockCommand.APP_GET_INIT_STATUS
14
15
 
15
- def __init__(self, product_nickname: RoborockProductNickname, device_cache: DeviceCache) -> None: # pylint: disable=super-init-not-called
16
- """Initialize MapContentTrait."""
17
- self._nickname = product_nickname
16
+ def __init__(self, product: HomeDataProduct, device_cache: DeviceCache) -> None: # pylint: disable=super-init-not-called
17
+ """Initialize DeviceFeaturesTrait."""
18
+ self._product = product
19
+ self._nickname = product.product_nickname
18
20
  self._device_cache = device_cache
19
21
  # All fields of DeviceFeatures are required. Initialize them to False
20
22
  # so we have some known state.
21
23
  for field in fields(self):
22
24
  setattr(self, field.name, False)
23
25
 
26
+ def is_field_supported(self, cls: type[RoborockBase], field_name: FieldNameBase) -> bool:
27
+ """Determines if the specified field is supported by this device.
28
+
29
+ We use dataclass attributes on the field to specify the schema code that is required
30
+ for the field to be supported and it is compared against the list of
31
+ supported schema codes for the device returned in the product information.
32
+ """
33
+ dataclass_field: Field | None = None
34
+ for field in fields(cls):
35
+ if field.name == field_name:
36
+ dataclass_field = field
37
+ break
38
+ if dataclass_field is None:
39
+ raise ValueError(f"Field {field_name} not found in {cls}")
40
+
41
+ requires_schema_code = dataclass_field.metadata.get("requires_schema_code", None)
42
+ if requires_schema_code is None:
43
+ # We assume the field is supported
44
+ return True
45
+ # If the field requires a protocol that is not supported, we return False
46
+ return requires_schema_code in self._product.supported_schema_codes
47
+
24
48
  async def refresh(self) -> None:
25
49
  """Refresh the contents of this trait.
26
50
 
File without changes