aiohomematic 2026.1.29__py3-none-any.whl

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 (188) hide show
  1. aiohomematic/__init__.py +110 -0
  2. aiohomematic/_log_context_protocol.py +29 -0
  3. aiohomematic/api.py +410 -0
  4. aiohomematic/async_support.py +250 -0
  5. aiohomematic/backend_detection.py +462 -0
  6. aiohomematic/central/__init__.py +103 -0
  7. aiohomematic/central/async_rpc_server.py +760 -0
  8. aiohomematic/central/central_unit.py +1152 -0
  9. aiohomematic/central/config.py +463 -0
  10. aiohomematic/central/config_builder.py +772 -0
  11. aiohomematic/central/connection_state.py +160 -0
  12. aiohomematic/central/coordinators/__init__.py +38 -0
  13. aiohomematic/central/coordinators/cache.py +414 -0
  14. aiohomematic/central/coordinators/client.py +480 -0
  15. aiohomematic/central/coordinators/connection_recovery.py +1141 -0
  16. aiohomematic/central/coordinators/device.py +1166 -0
  17. aiohomematic/central/coordinators/event.py +514 -0
  18. aiohomematic/central/coordinators/hub.py +532 -0
  19. aiohomematic/central/decorators.py +184 -0
  20. aiohomematic/central/device_registry.py +229 -0
  21. aiohomematic/central/events/__init__.py +104 -0
  22. aiohomematic/central/events/bus.py +1392 -0
  23. aiohomematic/central/events/integration.py +424 -0
  24. aiohomematic/central/events/types.py +194 -0
  25. aiohomematic/central/health.py +762 -0
  26. aiohomematic/central/rpc_server.py +353 -0
  27. aiohomematic/central/scheduler.py +794 -0
  28. aiohomematic/central/state_machine.py +391 -0
  29. aiohomematic/client/__init__.py +203 -0
  30. aiohomematic/client/_rpc_errors.py +187 -0
  31. aiohomematic/client/backends/__init__.py +48 -0
  32. aiohomematic/client/backends/base.py +335 -0
  33. aiohomematic/client/backends/capabilities.py +138 -0
  34. aiohomematic/client/backends/ccu.py +487 -0
  35. aiohomematic/client/backends/factory.py +116 -0
  36. aiohomematic/client/backends/homegear.py +294 -0
  37. aiohomematic/client/backends/json_ccu.py +252 -0
  38. aiohomematic/client/backends/protocol.py +316 -0
  39. aiohomematic/client/ccu.py +1857 -0
  40. aiohomematic/client/circuit_breaker.py +459 -0
  41. aiohomematic/client/config.py +64 -0
  42. aiohomematic/client/handlers/__init__.py +40 -0
  43. aiohomematic/client/handlers/backup.py +157 -0
  44. aiohomematic/client/handlers/base.py +79 -0
  45. aiohomematic/client/handlers/device_ops.py +1085 -0
  46. aiohomematic/client/handlers/firmware.py +144 -0
  47. aiohomematic/client/handlers/link_mgmt.py +199 -0
  48. aiohomematic/client/handlers/metadata.py +436 -0
  49. aiohomematic/client/handlers/programs.py +144 -0
  50. aiohomematic/client/handlers/sysvars.py +100 -0
  51. aiohomematic/client/interface_client.py +1304 -0
  52. aiohomematic/client/json_rpc.py +2068 -0
  53. aiohomematic/client/request_coalescer.py +282 -0
  54. aiohomematic/client/rpc_proxy.py +629 -0
  55. aiohomematic/client/state_machine.py +324 -0
  56. aiohomematic/const.py +2207 -0
  57. aiohomematic/context.py +275 -0
  58. aiohomematic/converter.py +270 -0
  59. aiohomematic/decorators.py +390 -0
  60. aiohomematic/exceptions.py +185 -0
  61. aiohomematic/hmcli.py +997 -0
  62. aiohomematic/i18n.py +193 -0
  63. aiohomematic/interfaces/__init__.py +407 -0
  64. aiohomematic/interfaces/central.py +1067 -0
  65. aiohomematic/interfaces/client.py +1096 -0
  66. aiohomematic/interfaces/coordinators.py +63 -0
  67. aiohomematic/interfaces/model.py +1921 -0
  68. aiohomematic/interfaces/operations.py +217 -0
  69. aiohomematic/logging_context.py +134 -0
  70. aiohomematic/metrics/__init__.py +125 -0
  71. aiohomematic/metrics/_protocols.py +140 -0
  72. aiohomematic/metrics/aggregator.py +534 -0
  73. aiohomematic/metrics/dataclasses.py +489 -0
  74. aiohomematic/metrics/emitter.py +292 -0
  75. aiohomematic/metrics/events.py +183 -0
  76. aiohomematic/metrics/keys.py +300 -0
  77. aiohomematic/metrics/observer.py +563 -0
  78. aiohomematic/metrics/stats.py +172 -0
  79. aiohomematic/model/__init__.py +189 -0
  80. aiohomematic/model/availability.py +65 -0
  81. aiohomematic/model/calculated/__init__.py +89 -0
  82. aiohomematic/model/calculated/climate.py +276 -0
  83. aiohomematic/model/calculated/data_point.py +315 -0
  84. aiohomematic/model/calculated/field.py +147 -0
  85. aiohomematic/model/calculated/operating_voltage_level.py +286 -0
  86. aiohomematic/model/calculated/support.py +232 -0
  87. aiohomematic/model/custom/__init__.py +214 -0
  88. aiohomematic/model/custom/capabilities/__init__.py +67 -0
  89. aiohomematic/model/custom/capabilities/climate.py +41 -0
  90. aiohomematic/model/custom/capabilities/light.py +87 -0
  91. aiohomematic/model/custom/capabilities/lock.py +44 -0
  92. aiohomematic/model/custom/capabilities/siren.py +63 -0
  93. aiohomematic/model/custom/climate.py +1130 -0
  94. aiohomematic/model/custom/cover.py +722 -0
  95. aiohomematic/model/custom/data_point.py +360 -0
  96. aiohomematic/model/custom/definition.py +300 -0
  97. aiohomematic/model/custom/field.py +89 -0
  98. aiohomematic/model/custom/light.py +1174 -0
  99. aiohomematic/model/custom/lock.py +322 -0
  100. aiohomematic/model/custom/mixins.py +445 -0
  101. aiohomematic/model/custom/profile.py +945 -0
  102. aiohomematic/model/custom/registry.py +251 -0
  103. aiohomematic/model/custom/siren.py +462 -0
  104. aiohomematic/model/custom/switch.py +195 -0
  105. aiohomematic/model/custom/text_display.py +289 -0
  106. aiohomematic/model/custom/valve.py +78 -0
  107. aiohomematic/model/data_point.py +1416 -0
  108. aiohomematic/model/device.py +1840 -0
  109. aiohomematic/model/event.py +216 -0
  110. aiohomematic/model/generic/__init__.py +327 -0
  111. aiohomematic/model/generic/action.py +40 -0
  112. aiohomematic/model/generic/action_select.py +62 -0
  113. aiohomematic/model/generic/binary_sensor.py +30 -0
  114. aiohomematic/model/generic/button.py +31 -0
  115. aiohomematic/model/generic/data_point.py +177 -0
  116. aiohomematic/model/generic/dummy.py +150 -0
  117. aiohomematic/model/generic/number.py +76 -0
  118. aiohomematic/model/generic/select.py +56 -0
  119. aiohomematic/model/generic/sensor.py +76 -0
  120. aiohomematic/model/generic/switch.py +54 -0
  121. aiohomematic/model/generic/text.py +33 -0
  122. aiohomematic/model/hub/__init__.py +100 -0
  123. aiohomematic/model/hub/binary_sensor.py +24 -0
  124. aiohomematic/model/hub/button.py +28 -0
  125. aiohomematic/model/hub/connectivity.py +190 -0
  126. aiohomematic/model/hub/data_point.py +342 -0
  127. aiohomematic/model/hub/hub.py +864 -0
  128. aiohomematic/model/hub/inbox.py +135 -0
  129. aiohomematic/model/hub/install_mode.py +393 -0
  130. aiohomematic/model/hub/metrics.py +208 -0
  131. aiohomematic/model/hub/number.py +42 -0
  132. aiohomematic/model/hub/select.py +52 -0
  133. aiohomematic/model/hub/sensor.py +37 -0
  134. aiohomematic/model/hub/switch.py +43 -0
  135. aiohomematic/model/hub/text.py +30 -0
  136. aiohomematic/model/hub/update.py +221 -0
  137. aiohomematic/model/support.py +592 -0
  138. aiohomematic/model/update.py +140 -0
  139. aiohomematic/model/week_profile.py +1827 -0
  140. aiohomematic/property_decorators.py +719 -0
  141. aiohomematic/py.typed +0 -0
  142. aiohomematic/rega_scripts/accept_device_in_inbox.fn +51 -0
  143. aiohomematic/rega_scripts/create_backup_start.fn +28 -0
  144. aiohomematic/rega_scripts/create_backup_status.fn +89 -0
  145. aiohomematic/rega_scripts/fetch_all_device_data.fn +97 -0
  146. aiohomematic/rega_scripts/get_backend_info.fn +25 -0
  147. aiohomematic/rega_scripts/get_inbox_devices.fn +61 -0
  148. aiohomematic/rega_scripts/get_program_descriptions.fn +31 -0
  149. aiohomematic/rega_scripts/get_serial.fn +44 -0
  150. aiohomematic/rega_scripts/get_service_messages.fn +83 -0
  151. aiohomematic/rega_scripts/get_system_update_info.fn +39 -0
  152. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +31 -0
  153. aiohomematic/rega_scripts/set_program_state.fn +17 -0
  154. aiohomematic/rega_scripts/set_system_variable.fn +19 -0
  155. aiohomematic/rega_scripts/trigger_firmware_update.fn +67 -0
  156. aiohomematic/schemas.py +256 -0
  157. aiohomematic/store/__init__.py +55 -0
  158. aiohomematic/store/dynamic/__init__.py +43 -0
  159. aiohomematic/store/dynamic/command.py +250 -0
  160. aiohomematic/store/dynamic/data.py +175 -0
  161. aiohomematic/store/dynamic/details.py +187 -0
  162. aiohomematic/store/dynamic/ping_pong.py +416 -0
  163. aiohomematic/store/persistent/__init__.py +71 -0
  164. aiohomematic/store/persistent/base.py +285 -0
  165. aiohomematic/store/persistent/device.py +233 -0
  166. aiohomematic/store/persistent/incident.py +380 -0
  167. aiohomematic/store/persistent/paramset.py +241 -0
  168. aiohomematic/store/persistent/session.py +556 -0
  169. aiohomematic/store/serialization.py +150 -0
  170. aiohomematic/store/storage.py +689 -0
  171. aiohomematic/store/types.py +526 -0
  172. aiohomematic/store/visibility/__init__.py +40 -0
  173. aiohomematic/store/visibility/parser.py +141 -0
  174. aiohomematic/store/visibility/registry.py +722 -0
  175. aiohomematic/store/visibility/rules.py +307 -0
  176. aiohomematic/strings.json +237 -0
  177. aiohomematic/support.py +706 -0
  178. aiohomematic/tracing.py +236 -0
  179. aiohomematic/translations/de.json +237 -0
  180. aiohomematic/translations/en.json +237 -0
  181. aiohomematic/type_aliases.py +51 -0
  182. aiohomematic/validator.py +128 -0
  183. aiohomematic-2026.1.29.dist-info/METADATA +296 -0
  184. aiohomematic-2026.1.29.dist-info/RECORD +188 -0
  185. aiohomematic-2026.1.29.dist-info/WHEEL +5 -0
  186. aiohomematic-2026.1.29.dist-info/entry_points.txt +2 -0
  187. aiohomematic-2026.1.29.dist-info/licenses/LICENSE +21 -0
  188. aiohomematic-2026.1.29.dist-info/top_level.txt +1 -0
@@ -0,0 +1,322 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2021-2026
3
+ """
4
+ Custom lock data points for door locks and access control.
5
+
6
+ Public API of this module is defined by __all__.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from abc import abstractmethod
12
+ from enum import StrEnum
13
+ from typing import Final
14
+
15
+ from aiohomematic.const import DataPointCategory, DeviceProfile, Field, Parameter
16
+ from aiohomematic.model.custom.capabilities.lock import BUTTON_LOCK_CAPABILITIES, IP_LOCK_CAPABILITIES, LockCapabilities
17
+ from aiohomematic.model.custom.data_point import CustomDataPoint
18
+ from aiohomematic.model.custom.field import DataPointField
19
+ from aiohomematic.model.custom.registry import DeviceConfig, DeviceProfileRegistry, ExtendedDeviceConfig
20
+ from aiohomematic.model.data_point import CallParameterCollector, bind_collector
21
+ from aiohomematic.model.generic import DpAction, DpActionSelect, DpSensor, DpSwitch
22
+ from aiohomematic.property_decorators import state_property
23
+
24
+
25
+ class _LockActivity(StrEnum):
26
+ """Enum with lock activities."""
27
+
28
+ LOCKING = "DOWN"
29
+ UNLOCKING = "UP"
30
+
31
+
32
+ class _LockError(StrEnum):
33
+ """Enum with lock errors."""
34
+
35
+ NO_ERROR = "NO_ERROR"
36
+ CLUTCH_FAILURE = "CLUTCH_FAILURE"
37
+ MOTOR_ABORTED = "MOTOR_ABORTED"
38
+
39
+
40
+ class _LockTargetLevel(StrEnum):
41
+ """Enum with lock target levels."""
42
+
43
+ LOCKED = "LOCKED"
44
+ OPEN = "OPEN"
45
+ UNLOCKED = "UNLOCKED"
46
+
47
+
48
+ class LockState(StrEnum):
49
+ """Enum with lock states."""
50
+
51
+ LOCKED = "LOCKED"
52
+ UNKNOWN = "UNKNOWN"
53
+ UNLOCKED = "UNLOCKED"
54
+
55
+
56
+ class BaseCustomDpLock(CustomDataPoint):
57
+ """Class for HomematicIP lock data point."""
58
+
59
+ __slots__ = ("_capabilities",)
60
+
61
+ _category = DataPointCategory.LOCK
62
+ _ignore_multiple_channels_for_name = True
63
+
64
+ @property
65
+ def capabilities(self) -> LockCapabilities:
66
+ """Return the lock capabilities."""
67
+ if (caps := getattr(self, "_capabilities", None)) is None:
68
+ caps = self._compute_capabilities()
69
+ object.__setattr__(self, "_capabilities", caps)
70
+ return caps
71
+
72
+ @state_property
73
+ def is_jammed(self) -> bool:
74
+ """Return true if lock is jammed."""
75
+ return False
76
+
77
+ @state_property
78
+ @abstractmethod
79
+ def is_locked(self) -> bool:
80
+ """Return true if lock is on."""
81
+
82
+ @state_property
83
+ def is_locking(self) -> bool | None:
84
+ """Return true if the lock is locking."""
85
+ return None
86
+
87
+ @state_property
88
+ def is_unlocking(self) -> bool | None:
89
+ """Return true if the lock is unlocking."""
90
+ return None
91
+
92
+ @abstractmethod
93
+ @bind_collector
94
+ async def lock(self, *, collector: CallParameterCollector | None = None) -> None:
95
+ """Lock the lock."""
96
+
97
+ @abstractmethod
98
+ @bind_collector
99
+ async def open(self, *, collector: CallParameterCollector | None = None) -> None:
100
+ """Open the lock."""
101
+
102
+ @abstractmethod
103
+ @bind_collector
104
+ async def unlock(self, *, collector: CallParameterCollector | None = None) -> None:
105
+ """Unlock the lock."""
106
+
107
+ @abstractmethod
108
+ def _compute_capabilities(self) -> LockCapabilities:
109
+ """Compute static capabilities. Implemented by subclasses."""
110
+
111
+
112
+ class CustomDpIpLock(BaseCustomDpLock):
113
+ """Class for HomematicIP lock data point."""
114
+
115
+ __slots__ = () # Required to prevent __dict__ creation (descriptors are class-level)
116
+
117
+ # Declarative data point field definitions
118
+ _dp_direction: Final = DataPointField(field=Field.DIRECTION, dpt=DpSensor[str | None])
119
+ _dp_lock_state: Final = DataPointField(field=Field.LOCK_STATE, dpt=DpSensor[str | None])
120
+ _dp_lock_target_level: Final = DataPointField(field=Field.LOCK_TARGET_LEVEL, dpt=DpActionSelect)
121
+
122
+ @state_property
123
+ def is_locked(self) -> bool:
124
+ """Return true if lock is on."""
125
+ return self._dp_lock_state.value == LockState.LOCKED
126
+
127
+ @state_property
128
+ def is_locking(self) -> bool | None:
129
+ """Return true if the lock is locking."""
130
+ if self._dp_direction.value is not None:
131
+ return str(self._dp_direction.value) == _LockActivity.LOCKING
132
+ return None
133
+
134
+ @state_property
135
+ def is_unlocking(self) -> bool | None:
136
+ """Return true if the lock is unlocking."""
137
+ if self._dp_direction.value is not None:
138
+ return str(self._dp_direction.value) == _LockActivity.UNLOCKING
139
+ return None
140
+
141
+ @bind_collector
142
+ async def lock(self, *, collector: CallParameterCollector | None = None) -> None:
143
+ """Lock the lock."""
144
+ await self._dp_lock_target_level.send_value(value=_LockTargetLevel.LOCKED, collector=collector)
145
+
146
+ @bind_collector
147
+ async def open(self, *, collector: CallParameterCollector | None = None) -> None:
148
+ """Open the lock."""
149
+ await self._dp_lock_target_level.send_value(value=_LockTargetLevel.OPEN, collector=collector)
150
+
151
+ @bind_collector
152
+ async def unlock(self, *, collector: CallParameterCollector | None = None) -> None:
153
+ """Unlock the lock."""
154
+ await self._dp_lock_target_level.send_value(value=_LockTargetLevel.UNLOCKED, collector=collector)
155
+
156
+ def _compute_capabilities(self) -> LockCapabilities:
157
+ """Compute static capabilities. IP locks support open."""
158
+ return IP_LOCK_CAPABILITIES
159
+
160
+
161
+ class CustomDpButtonLock(BaseCustomDpLock):
162
+ """Class for HomematicIP button lock data point."""
163
+
164
+ __slots__ = () # Required to prevent __dict__ creation (descriptors are class-level)
165
+
166
+ # Declarative data point field definitions
167
+ _dp_button_lock: Final = DataPointField(field=Field.BUTTON_LOCK, dpt=DpSwitch)
168
+
169
+ @property
170
+ def data_point_name_postfix(self) -> str:
171
+ """Return the data_point name postfix."""
172
+ return "BUTTON_LOCK"
173
+
174
+ @state_property
175
+ def is_locked(self) -> bool:
176
+ """Return true if lock is on."""
177
+ return self._dp_button_lock.value is True
178
+
179
+ @bind_collector
180
+ async def lock(self, *, collector: CallParameterCollector | None = None) -> None:
181
+ """Lock the lock."""
182
+ await self._dp_button_lock.turn_on(collector=collector)
183
+
184
+ @bind_collector
185
+ async def open(self, *, collector: CallParameterCollector | None = None) -> None:
186
+ """Open the lock."""
187
+ return
188
+
189
+ @bind_collector
190
+ async def unlock(self, *, collector: CallParameterCollector | None = None) -> None:
191
+ """Unlock the lock."""
192
+ await self._dp_button_lock.turn_off(collector=collector)
193
+
194
+ def _compute_capabilities(self) -> LockCapabilities:
195
+ """Compute static capabilities. Button locks do not support open."""
196
+ return BUTTON_LOCK_CAPABILITIES
197
+
198
+
199
+ class CustomDpRfLock(BaseCustomDpLock):
200
+ """Class for classic Homematic lock data point."""
201
+
202
+ __slots__ = () # Required to prevent __dict__ creation (descriptors are class-level)
203
+
204
+ # Declarative data point field definitions
205
+ _dp_direction: Final = DataPointField(field=Field.DIRECTION, dpt=DpSensor[str | None])
206
+ _dp_error: Final = DataPointField(field=Field.ERROR, dpt=DpSensor[str | None])
207
+ _dp_open: Final = DataPointField(field=Field.OPEN, dpt=DpAction)
208
+ _dp_state: Final = DataPointField(field=Field.STATE, dpt=DpSwitch)
209
+
210
+ @state_property
211
+ def is_jammed(self) -> bool:
212
+ """Return true if lock is jammed."""
213
+ return self._dp_error.value is not None and self._dp_error.value != _LockError.NO_ERROR
214
+
215
+ @state_property
216
+ def is_locked(self) -> bool:
217
+ """Return true if lock is on."""
218
+ return self._dp_state.value is not True
219
+
220
+ @state_property
221
+ def is_locking(self) -> bool | None:
222
+ """Return true if the lock is locking."""
223
+ if self._dp_direction.value is not None:
224
+ return str(self._dp_direction.value) == _LockActivity.LOCKING
225
+ return None
226
+
227
+ @state_property
228
+ def is_unlocking(self) -> bool | None:
229
+ """Return true if the lock is unlocking."""
230
+ if self._dp_direction.value is not None:
231
+ return str(self._dp_direction.value) == _LockActivity.UNLOCKING
232
+ return None
233
+
234
+ @bind_collector
235
+ async def lock(self, *, collector: CallParameterCollector | None = None) -> None:
236
+ """Lock the lock."""
237
+ await self._dp_state.send_value(value=False, collector=collector)
238
+
239
+ @bind_collector
240
+ async def open(self, *, collector: CallParameterCollector | None = None) -> None:
241
+ """Open the lock."""
242
+ await self._dp_open.send_value(value=True, collector=collector)
243
+
244
+ @bind_collector
245
+ async def unlock(self, *, collector: CallParameterCollector | None = None) -> None:
246
+ """Unlock the lock."""
247
+ await self._dp_state.send_value(value=True, collector=collector)
248
+
249
+ def _compute_capabilities(self) -> LockCapabilities:
250
+ """Compute static capabilities. RF locks support open."""
251
+ return IP_LOCK_CAPABILITIES
252
+
253
+
254
+ # =============================================================================
255
+ # DeviceProfileRegistry Registration
256
+ # =============================================================================
257
+
258
+ # RF Lock (HM-Sec-Key)
259
+ DeviceProfileRegistry.register(
260
+ category=DataPointCategory.LOCK,
261
+ models="HM-Sec-Key",
262
+ data_point_class=CustomDpRfLock,
263
+ profile_type=DeviceProfile.RF_LOCK,
264
+ channels=(1,),
265
+ extended=ExtendedDeviceConfig(
266
+ additional_data_points={
267
+ 1: (
268
+ Parameter.DIRECTION,
269
+ Parameter.ERROR,
270
+ ),
271
+ }
272
+ ),
273
+ )
274
+
275
+ # IP Lock with Button Lock (HmIP-DLD - multiple configs)
276
+ DeviceProfileRegistry.register_multiple(
277
+ category=DataPointCategory.LOCK,
278
+ models="HmIP-DLD",
279
+ configs=(
280
+ DeviceConfig(
281
+ data_point_class=CustomDpIpLock,
282
+ profile_type=DeviceProfile.IP_LOCK,
283
+ extended=ExtendedDeviceConfig(
284
+ additional_data_points={
285
+ 0: (Parameter.ERROR_JAMMED,),
286
+ }
287
+ ),
288
+ ),
289
+ DeviceConfig(
290
+ data_point_class=CustomDpButtonLock,
291
+ profile_type=DeviceProfile.IP_BUTTON_LOCK,
292
+ channels=(0,),
293
+ ),
294
+ ),
295
+ )
296
+
297
+ # RF Button Lock
298
+ DeviceProfileRegistry.register(
299
+ category=DataPointCategory.LOCK,
300
+ models="HM-TC-IT-WM-W-EU",
301
+ data_point_class=CustomDpButtonLock,
302
+ profile_type=DeviceProfile.RF_BUTTON_LOCK,
303
+ channels=(None,),
304
+ )
305
+
306
+ # IP Button Lock (various thermostats and controls)
307
+ DeviceProfileRegistry.register(
308
+ category=DataPointCategory.LOCK,
309
+ models=(
310
+ "ALPHA-IP-RBG",
311
+ "HmIP-BWTH",
312
+ "HmIP-FAL",
313
+ "HmIP-WGT",
314
+ "HmIP-WTH",
315
+ "HmIP-eTRV",
316
+ "HmIPW-FAL",
317
+ "HmIPW-WTH",
318
+ ),
319
+ data_point_class=CustomDpButtonLock,
320
+ profile_type=DeviceProfile.IP_BUTTON_LOCK,
321
+ channels=(0,),
322
+ )