aiohomematic 2025.8.6__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.

Potentially problematic release.


This version of aiohomematic might be problematic. Click here for more details.

Files changed (77) hide show
  1. aiohomematic/__init__.py +47 -0
  2. aiohomematic/async_support.py +146 -0
  3. aiohomematic/caches/__init__.py +10 -0
  4. aiohomematic/caches/dynamic.py +554 -0
  5. aiohomematic/caches/persistent.py +459 -0
  6. aiohomematic/caches/visibility.py +774 -0
  7. aiohomematic/central/__init__.py +2034 -0
  8. aiohomematic/central/decorators.py +110 -0
  9. aiohomematic/central/xml_rpc_server.py +267 -0
  10. aiohomematic/client/__init__.py +1746 -0
  11. aiohomematic/client/json_rpc.py +1193 -0
  12. aiohomematic/client/xml_rpc.py +222 -0
  13. aiohomematic/const.py +795 -0
  14. aiohomematic/context.py +8 -0
  15. aiohomematic/converter.py +82 -0
  16. aiohomematic/decorators.py +188 -0
  17. aiohomematic/exceptions.py +145 -0
  18. aiohomematic/hmcli.py +159 -0
  19. aiohomematic/model/__init__.py +137 -0
  20. aiohomematic/model/calculated/__init__.py +65 -0
  21. aiohomematic/model/calculated/climate.py +230 -0
  22. aiohomematic/model/calculated/data_point.py +319 -0
  23. aiohomematic/model/calculated/operating_voltage_level.py +311 -0
  24. aiohomematic/model/calculated/support.py +174 -0
  25. aiohomematic/model/custom/__init__.py +175 -0
  26. aiohomematic/model/custom/climate.py +1334 -0
  27. aiohomematic/model/custom/const.py +146 -0
  28. aiohomematic/model/custom/cover.py +741 -0
  29. aiohomematic/model/custom/data_point.py +318 -0
  30. aiohomematic/model/custom/definition.py +861 -0
  31. aiohomematic/model/custom/light.py +1092 -0
  32. aiohomematic/model/custom/lock.py +389 -0
  33. aiohomematic/model/custom/siren.py +268 -0
  34. aiohomematic/model/custom/support.py +40 -0
  35. aiohomematic/model/custom/switch.py +172 -0
  36. aiohomematic/model/custom/valve.py +112 -0
  37. aiohomematic/model/data_point.py +1109 -0
  38. aiohomematic/model/decorators.py +173 -0
  39. aiohomematic/model/device.py +1347 -0
  40. aiohomematic/model/event.py +210 -0
  41. aiohomematic/model/generic/__init__.py +211 -0
  42. aiohomematic/model/generic/action.py +32 -0
  43. aiohomematic/model/generic/binary_sensor.py +28 -0
  44. aiohomematic/model/generic/button.py +25 -0
  45. aiohomematic/model/generic/data_point.py +162 -0
  46. aiohomematic/model/generic/number.py +73 -0
  47. aiohomematic/model/generic/select.py +36 -0
  48. aiohomematic/model/generic/sensor.py +72 -0
  49. aiohomematic/model/generic/switch.py +52 -0
  50. aiohomematic/model/generic/text.py +27 -0
  51. aiohomematic/model/hub/__init__.py +334 -0
  52. aiohomematic/model/hub/binary_sensor.py +22 -0
  53. aiohomematic/model/hub/button.py +26 -0
  54. aiohomematic/model/hub/data_point.py +332 -0
  55. aiohomematic/model/hub/number.py +37 -0
  56. aiohomematic/model/hub/select.py +47 -0
  57. aiohomematic/model/hub/sensor.py +35 -0
  58. aiohomematic/model/hub/switch.py +42 -0
  59. aiohomematic/model/hub/text.py +28 -0
  60. aiohomematic/model/support.py +599 -0
  61. aiohomematic/model/update.py +136 -0
  62. aiohomematic/py.typed +0 -0
  63. aiohomematic/rega_scripts/fetch_all_device_data.fn +75 -0
  64. aiohomematic/rega_scripts/get_program_descriptions.fn +30 -0
  65. aiohomematic/rega_scripts/get_serial.fn +44 -0
  66. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +30 -0
  67. aiohomematic/rega_scripts/set_program_state.fn +12 -0
  68. aiohomematic/rega_scripts/set_system_variable.fn +15 -0
  69. aiohomematic/support.py +482 -0
  70. aiohomematic/validator.py +65 -0
  71. aiohomematic-2025.8.6.dist-info/METADATA +69 -0
  72. aiohomematic-2025.8.6.dist-info/RECORD +77 -0
  73. aiohomematic-2025.8.6.dist-info/WHEEL +5 -0
  74. aiohomematic-2025.8.6.dist-info/licenses/LICENSE +21 -0
  75. aiohomematic-2025.8.6.dist-info/top_level.txt +2 -0
  76. aiohomematic_support/__init__.py +1 -0
  77. aiohomematic_support/client_local.py +349 -0
aiohomematic/const.py ADDED
@@ -0,0 +1,795 @@
1
+ """Constants used by aiohomematic."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Iterable, Mapping
6
+ from dataclasses import dataclass, field
7
+ from datetime import datetime
8
+ from enum import Enum, IntEnum, StrEnum
9
+ import os
10
+ import re
11
+ import sys
12
+ from typing import Any, Final, NamedTuple, Required, TypedDict
13
+
14
+ VERSION: Final = "2025.8.6"
15
+
16
+ # Detect test speedup mode via environment
17
+ _TEST_SPEEDUP: Final = (
18
+ bool(os.getenv("AIOHOMEMATIC_TEST_SPEEDUP")) or ("PYTEST_CURRENT_TEST" in os.environ) or ("pytest" in sys.modules)
19
+ )
20
+
21
+ # default
22
+ DEFAULT_CUSTOM_ID: Final = "custom_id"
23
+ DEFAULT_ENABLE_DEVICE_FIRMWARE_CHECK: Final = False
24
+ DEFAULT_ENABLE_PROGRAM_SCAN: Final = True
25
+ DEFAULT_ENABLE_SYSVAR_SCAN: Final = True
26
+ DEFAULT_HM_MASTER_POLL_AFTER_SEND_INTERVALS: Final = (5,)
27
+ DEFAULT_IGNORE_CUSTOM_DEVICE_DEFINITION_MODELS: Final[tuple[str, ...]] = ()
28
+ DEFAULT_INCLUDE_INTERNAL_PROGRAMS: Final = False
29
+ DEFAULT_INCLUDE_INTERNAL_SYSVARS: Final = True
30
+ DEFAULT_MAX_READ_WORKERS: Final = 1
31
+ DEFAULT_MAX_WORKERS: Final = 1
32
+ DEFAULT_MULTIPLIER: Final = 1.0
33
+ DEFAULT_PERIODIC_REFRESH_INTERVAL: Final = 15
34
+ DEFAULT_PROGRAM_MARKERS: Final[tuple[DescriptionMarker | str, ...]] = ()
35
+ DEFAULT_SYSVAR_MARKERS: Final[tuple[DescriptionMarker | str, ...]] = ()
36
+ DEFAULT_SYS_SCAN_INTERVAL: Final = 30
37
+ DEFAULT_TLS: Final = False
38
+ DEFAULT_UN_IGNORES: Final[tuple[str, ...]] = ()
39
+ DEFAULT_VERIFY_TLS: Final = False
40
+
41
+ # Default encoding for json service calls, persistent cache
42
+ UTF_8: Final = "utf-8"
43
+ # Default encoding for xmlrpc service calls and script files
44
+ ISO_8859_1: Final = "iso-8859-1"
45
+
46
+ # Password can be empty.
47
+ # Allowed characters: A-Z, a-z, 0-9, .!$():;#-
48
+ # The CCU WebUI also supports ÄäÖöÜüß, but these characters are not supported by the XmlRPC servers
49
+ CCU_PASSWORD_PATTERN: Final = re.compile(r"[A-Za-z0-9.!$():;#-]{0,}")
50
+ # Pattern is bigger than needed
51
+ CHANNEL_ADDRESS_PATTERN: Final = re.compile(r"^[0-9a-zA-Z-]{5,20}:[0-9]{1,3}$")
52
+ DEVICE_ADDRESS_PATTERN: Final = re.compile(r"^[0-9a-zA-Z-]{5,20}$")
53
+ ALLOWED_HOSTNAME_PATTERN: Final = re.compile(r"(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
54
+ HTMLTAG_PATTERN: Final = re.compile(r"<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});")
55
+ SCHEDULER_PROFILE_PATTERN = re.compile(
56
+ r"^P[1-6]_(ENDTIME|TEMPERATURE)_(MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FRIDAY|SATURDAY|SUNDAY)_([1-9]|1[0-3])$"
57
+ )
58
+ SCHEDULER_TIME_PATTERN = re.compile(r"^(([0-1]{0,1}[0-9])|(2[0-4])):[0-5][0-9]")
59
+
60
+ ALWAYS_ENABLE_SYSVARS_BY_ID: Final = "40", "41"
61
+ RENAME_SYSVAR_BY_NAME: Final = {
62
+ "${sysVarAlarmMessages}": "ALARM_MESSAGES",
63
+ "${sysVarPresence}": "PRESENCE",
64
+ "${sysVarServiceMessages}": "SERVICE_MESSAGES",
65
+ }
66
+
67
+ SYSVAR_ENABLE_DEFAULT: Final = "40", "41"
68
+
69
+ ADDRESS_SEPARATOR: Final = ":"
70
+ BLOCK_LOG_TIMEOUT = 60
71
+ CACHE_PATH: Final = "cache"
72
+ CONF_PASSWORD: Final = "password"
73
+ CONF_USERNAME: Final = "username"
74
+
75
+ CONNECTION_CHECKER_INTERVAL: Final = 1 if _TEST_SPEEDUP else 15 # check if connection is available via rpc ping
76
+ DATETIME_FORMAT: Final = "%d.%m.%Y %H:%M:%S"
77
+ DATETIME_FORMAT_MILLIS: Final = "%d.%m.%Y %H:%M:%S.%f'"
78
+ DEVICE_DESCRIPTIONS_DIR: Final = "export_device_descriptions"
79
+ DEVICE_FIRMWARE_CHECK_INTERVAL: Final = 21600 # 6h
80
+ DEVICE_FIRMWARE_DELIVERING_CHECK_INTERVAL: Final = 3600 # 1h
81
+ DEVICE_FIRMWARE_UPDATING_CHECK_INTERVAL: Final = 300 # 5m
82
+ DUMMY_SERIAL = "SN0815"
83
+ FILE_DEVICES: Final = "homematic_devices.json"
84
+ FILE_PARAMSETS: Final = "homematic_paramsets.json"
85
+ HUB_PATH: Final = "hub"
86
+ IDENTIFIER_SEPARATOR: Final = "@"
87
+ INIT_DATETIME: Final = datetime.strptime("01.01.1970 00:00:00", DATETIME_FORMAT)
88
+ IP_ANY_V4: Final = "0.0.0.0"
89
+ JSON_SESSION_AGE: Final = 90
90
+ KWARGS_ARG_DATA_POINT = "data_point"
91
+ LAST_COMMAND_SEND_STORE_TIMEOUT: Final = 60
92
+ LOCAL_HOST: Final = "127.0.0.1"
93
+ MAX_CACHE_AGE: Final = 10
94
+ MAX_CONCURRENT_HTTP_SESSIONS: Final = 3
95
+ MAX_WAIT_FOR_CALLBACK: Final = 60
96
+ NO_CACHE_ENTRY: Final = "NO_CACHE_ENTRY"
97
+ PARAMSET_DESCRIPTIONS_DIR: Final = "export_paramset_descriptions"
98
+ PATH_JSON_RPC: Final = "/api/homematic.cgi"
99
+ PING_PONG_MISMATCH_COUNT: Final = 15
100
+ PING_PONG_MISMATCH_COUNT_TTL: Final = 300
101
+ PORT_ANY: Final = 0
102
+ PROGRAM_ADDRESS: Final = "program"
103
+ RECONNECT_WAIT: Final = 1 if _TEST_SPEEDUP else 120 # wait with reconnect after a first ping was successful
104
+ REGA_SCRIPT_PATH: Final = "../rega_scripts"
105
+ REPORT_VALUE_USAGE_DATA: Final = "reportValueUsageData"
106
+ REPORT_VALUE_USAGE_VALUE_ID: Final = "PRESS_SHORT"
107
+ SYSVAR_ADDRESS: Final = "sysvar"
108
+ TIMEOUT: Final = 5 if _TEST_SPEEDUP else 60 # default timeout for a connection
109
+ UN_IGNORE_WILDCARD: Final = "all"
110
+ WAIT_FOR_CALLBACK: Final[int | None] = None
111
+
112
+ # Scheduler sleep durations (used by central scheduler loop)
113
+ SCHEDULER_NOT_STARTED_SLEEP: Final = 0.05 if _TEST_SPEEDUP else 10
114
+ SCHEDULER_LOOP_SLEEP: Final = 0.05 if _TEST_SPEEDUP else 5
115
+
116
+ CALLBACK_WARN_INTERVAL = CONNECTION_CHECKER_INTERVAL * 40
117
+
118
+ # Path
119
+ PROGRAM_SET_PATH_ROOT: Final = "program/set"
120
+ PROGRAM_STATE_PATH_ROOT: Final = "program/status"
121
+ SET_PATH_ROOT: Final = "device/set"
122
+ STATE_PATH_ROOT: Final = "device/status"
123
+ SYSVAR_SET_PATH_ROOT: Final = "sysvar/set"
124
+ SYSVAR_STATE_PATH_ROOT: Final = "sysvar/status"
125
+ VIRTDEV_SET_PATH_ROOT: Final = "virtdev/set"
126
+ VIRTDEV_STATE_PATH_ROOT: Final = "virtdev/status"
127
+
128
+ CALLBACK_TYPE = Callable[[], None] | None
129
+
130
+
131
+ class Backend(StrEnum):
132
+ """Enum with supported aiohomematic backends."""
133
+
134
+ CCU = "CCU"
135
+ HOMEGEAR = "Homegear"
136
+ PYDEVCCU = "PyDevCCU"
137
+
138
+
139
+ class BackendSystemEvent(StrEnum):
140
+ """Enum with aiohomematic system events."""
141
+
142
+ DELETE_DEVICES = "deleteDevices"
143
+ DEVICES_CREATED = "devicesCreated"
144
+ ERROR = "error"
145
+ HUB_REFRESHED = "hubDataPointRefreshed"
146
+ LIST_DEVICES = "listDevices"
147
+ NEW_DEVICES = "newDevices"
148
+ REPLACE_DEVICE = "replaceDevice"
149
+ RE_ADDED_DEVICE = "readdedDevice"
150
+ UPDATE_DEVICE = "updateDevice"
151
+
152
+
153
+ class CallSource(StrEnum):
154
+ """Enum with sources for calls."""
155
+
156
+ HA_INIT = "ha_init"
157
+ HM_INIT = "hm_init"
158
+ MANUAL_OR_SCHEDULED = "manual_or_scheduled"
159
+
160
+
161
+ class DataOperationResult(Enum):
162
+ """Enum with data operation results."""
163
+
164
+ LOAD_FAIL = 0
165
+ LOAD_SUCCESS = 1
166
+ SAVE_FAIL = 10
167
+ SAVE_SUCCESS = 11
168
+ NO_LOAD = 20
169
+ NO_SAVE = 21
170
+
171
+
172
+ class DataPointCategory(StrEnum):
173
+ """Enum with data point types."""
174
+
175
+ ACTION = "action"
176
+ BINARY_SENSOR = "binary_sensor"
177
+ BUTTON = "button"
178
+ CLIMATE = "climate"
179
+ COVER = "cover"
180
+ EVENT = "event"
181
+ HUB_BINARY_SENSOR = "hub_binary_sensor"
182
+ HUB_BUTTON = "hub_button"
183
+ HUB_NUMBER = "hub_number"
184
+ HUB_SELECT = "hub_select"
185
+ HUB_SENSOR = "hub_sensor"
186
+ HUB_SWITCH = "hub_switch"
187
+ HUB_TEXT = "hub_text"
188
+ LIGHT = "light"
189
+ LOCK = "lock"
190
+ NUMBER = "number"
191
+ SELECT = "select"
192
+ SENSOR = "sensor"
193
+ SIREN = "siren"
194
+ SWITCH = "switch"
195
+ TEXT = "text"
196
+ UNDEFINED = "undefined"
197
+ UPDATE = "update"
198
+ VALVE = "valve"
199
+
200
+
201
+ class DataPointUsage(StrEnum):
202
+ """Enum with usage information."""
203
+
204
+ CDP_PRIMARY = "ce_primary"
205
+ CDP_SECONDARY = "ce_secondary"
206
+ CDP_VISIBLE = "ce_visible"
207
+ DATA_POINT = "data_point"
208
+ EVENT = "event"
209
+ NO_CREATE = "no_create"
210
+
211
+
212
+ class DescriptionMarker(StrEnum):
213
+ """Enum with default description markers."""
214
+
215
+ HAHM = "HAHM"
216
+ HX = "HX"
217
+ INTERNAL = "INTERNAL"
218
+ MQTT = "MQTT"
219
+
220
+
221
+ class DeviceFirmwareState(StrEnum):
222
+ """Enum with homematic device firmware states."""
223
+
224
+ UNKNOWN = "UNKNOWN"
225
+ UP_TO_DATE = "UP_TO_DATE"
226
+ LIVE_UP_TO_DATE = "LIVE_UP_TO_DATE"
227
+ NEW_FIRMWARE_AVAILABLE = "NEW_FIRMWARE_AVAILABLE"
228
+ LIVE_NEW_FIRMWARE_AVAILABLE = "LIVE_NEW_FIRMWARE_AVAILABLE"
229
+ DELIVER_FIRMWARE_IMAGE = "DELIVER_FIRMWARE_IMAGE"
230
+ LIVE_DELIVER_FIRMWARE_IMAGE = "LIVE_DELIVER_FIRMWARE_IMAGE"
231
+ READY_FOR_UPDATE = "READY_FOR_UPDATE"
232
+ DO_UPDATE_PENDING = "DO_UPDATE_PENDING"
233
+ PERFORMING_UPDATE = "PERFORMING_UPDATE"
234
+ BACKGROUND_UPDATE_NOT_SUPPORTED = "BACKGROUND_UPDATE_NOT_SUPPORTED"
235
+
236
+
237
+ class EventKey(StrEnum):
238
+ """Enum with aiohomematic event keys."""
239
+
240
+ ADDRESS = "address"
241
+ AVAILABLE = "available"
242
+ CENTRAL_NAME = "central_name"
243
+ CHANNEL_NO = "channel_no"
244
+ DATA = "data"
245
+ INTERFACE_ID = "interface_id"
246
+ MODEL = "model"
247
+ PARAMETER = "parameter"
248
+ PONG_MISMATCH_COUNT = "pong_mismatch_count"
249
+ SECONDS_SINCE_LAST_EVENT = "seconds_since_last_event"
250
+ TYPE = "type"
251
+ VALUE = "value"
252
+
253
+
254
+ class EventType(StrEnum):
255
+ """Enum with aiohomematic event types."""
256
+
257
+ DEVICE_AVAILABILITY = "homematic.device_availability"
258
+ DEVICE_ERROR = "homematic.device_error"
259
+ IMPULSE = "homematic.impulse"
260
+ INTERFACE = "homematic.interface"
261
+ KEYPRESS = "homematic.keypress"
262
+
263
+
264
+ class Flag(IntEnum):
265
+ """Enum with homematic flags."""
266
+
267
+ VISIBLE = 1
268
+ INTERNAL = 2
269
+ TRANSFORM = 4 # not used
270
+ SERVICE = 8
271
+ STICKY = 10 # This might be wrong. Documentation says 0x10 # not used
272
+
273
+
274
+ class ForcedDeviceAvailability(StrEnum):
275
+ """Enum with aiohomematic event types."""
276
+
277
+ FORCE_FALSE = "forced_not_available"
278
+ FORCE_TRUE = "forced_available"
279
+ NOT_SET = "not_set"
280
+
281
+
282
+ class Manufacturer(StrEnum):
283
+ """Enum with aiohomematic system events."""
284
+
285
+ EQ3 = "eQ-3"
286
+ HB = "Homebrew"
287
+ MOEHLENHOFF = "Möhlenhoff"
288
+
289
+
290
+ class Operations(IntEnum):
291
+ """Enum with homematic operations."""
292
+
293
+ NONE = 0 # not used
294
+ READ = 1
295
+ WRITE = 2
296
+ EVENT = 4
297
+
298
+
299
+ class CalulatedParameter(StrEnum):
300
+ """Enum with calculated homematic parameters."""
301
+
302
+ APPARENT_TEMPERATURE = "APPARENT_TEMPERATURE"
303
+ DEW_POINT = "DEW_POINT"
304
+ FROST_POINT = "FROST_POINT"
305
+ OPERATING_VOLTAGE_LEVEL = "OPERATING_VOLTAGE_LEVEL"
306
+ VAPOR_CONCENTRATION = "VAPOR_CONCENTRATION"
307
+
308
+
309
+ class Parameter(StrEnum):
310
+ """Enum with homematic parameters."""
311
+
312
+ ACOUSTIC_ALARM_ACTIVE = "ACOUSTIC_ALARM_ACTIVE"
313
+ ACOUSTIC_ALARM_SELECTION = "ACOUSTIC_ALARM_SELECTION"
314
+ ACTIVE_PROFILE = "ACTIVE_PROFILE"
315
+ ACTIVITY_STATE = "ACTIVITY_STATE"
316
+ ACTUAL_HUMIDITY = "ACTUAL_HUMIDITY"
317
+ ACTUAL_TEMPERATURE = "ACTUAL_TEMPERATURE"
318
+ AUTO_MODE = "AUTO_MODE"
319
+ BATTERY_STATE = "BATTERY_STATE"
320
+ BOOST_MODE = "BOOST_MODE"
321
+ CHANNEL_OPERATION_MODE = "CHANNEL_OPERATION_MODE"
322
+ COLOR = "COLOR"
323
+ COLOR_BEHAVIOUR = "COLOR_BEHAVIOUR"
324
+ COLOR_TEMPERATURE = "COLOR_TEMPERATURE"
325
+ COMBINED_PARAMETER = "COMBINED_PARAMETER"
326
+ COMFORT_MODE = "COMFORT_MODE"
327
+ CONCENTRATION = "CONCENTRATION"
328
+ CONFIG_PENDING = "CONFIG_PENDING"
329
+ CONTROL_MODE = "CONTROL_MODE"
330
+ CURRENT = "CURRENT"
331
+ CURRENT_ILLUMINATION = "CURRENT_ILLUMINATION"
332
+ DEVICE_OPERATION_MODE = "DEVICE_OPERATION_MODE"
333
+ DIRECTION = "DIRECTION"
334
+ DOOR_COMMAND = "DOOR_COMMAND"
335
+ DOOR_STATE = "DOOR_STATE"
336
+ DURATION_UNIT = "DURATION_UNIT"
337
+ DURATION_VALUE = "DURATION_VALUE"
338
+ DUTYCYCLE = "DUTYCYCLE"
339
+ DUTY_CYCLE = "DUTY_CYCLE"
340
+ EFFECT = "EFFECT"
341
+ ENERGY_COUNTER = "ENERGY_COUNTER"
342
+ ERROR = "ERROR"
343
+ ERROR_JAMMED = "ERROR_JAMMED"
344
+ FREQUENCY = "FREQUENCY"
345
+ GLOBAL_BUTTON_LOCK = "GLOBAL_BUTTON_LOCK"
346
+ HEATING_COOLING = "HEATING_COOLING"
347
+ HEATING_VALVE_TYPE = "HEATING_VALVE_TYPE"
348
+ HUE = "HUE"
349
+ HUMIDITY = "HUMIDITY"
350
+ ILLUMINATION = "ILLUMINATION"
351
+ LED_STATUS = "LED_STATUS"
352
+ LEVEL = "LEVEL"
353
+ LEVEL_2 = "LEVEL_2"
354
+ LEVEL_COMBINED = "LEVEL_COMBINED"
355
+ LEVEL_SLATS = "LEVEL_SLATS"
356
+ LOCK_STATE = "LOCK_STATE"
357
+ LOCK_TARGET_LEVEL = "LOCK_TARGET_LEVEL"
358
+ LOWBAT = "LOWBAT"
359
+ LOWERING_MODE = "LOWERING_MODE"
360
+ LOW_BAT = "LOW_BAT"
361
+ LOW_BAT_LIMIT = "LOW_BAT_LIMIT"
362
+ MANU_MODE = "MANU_MODE"
363
+ MASS_CONCENTRATION_PM_10_24H_AVERAGE = "MASS_CONCENTRATION_PM_10_24H_AVERAGE"
364
+ MASS_CONCENTRATION_PM_1_24H_AVERAGE = "MASS_CONCENTRATION_PM_1_24H_AVERAGE"
365
+ MASS_CONCENTRATION_PM_2_5_24H_AVERAGE = "MASS_CONCENTRATION_PM_2_5_24H_AVERAGE"
366
+ MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE = "MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE"
367
+ MOTION = "MOTION"
368
+ MOTION_DETECTION_ACTIVE = "MOTION_DETECTION_ACTIVE"
369
+ ON_TIME = "ON_TIME"
370
+ OPEN = "OPEN"
371
+ OPERATING_VOLTAGE = "OPERATING_VOLTAGE"
372
+ OPTICAL_ALARM_ACTIVE = "OPTICAL_ALARM_ACTIVE"
373
+ OPTICAL_ALARM_SELECTION = "OPTICAL_ALARM_SELECTION"
374
+ OPTIMUM_START_STOP = "OPTIMUM_START_STOP"
375
+ PARTY_MODE = "PARTY_MODE"
376
+ PARTY_MODE_SUBMIT = "PARTY_MODE_SUBMIT"
377
+ PARTY_TIME_END = "PARTY_TIME_END"
378
+ PARTY_TIME_START = "PARTY_TIME_START"
379
+ PONG = "PONG"
380
+ POWER = "POWER"
381
+ PRESS = "PRESS"
382
+ PRESS_CONT = "PRESS_CONT"
383
+ PRESS_LOCK = "PRESS_LOCK"
384
+ PRESS_LONG = "PRESS_LONG"
385
+ PRESS_LONG_RELEASE = "PRESS_LONG_RELEASE"
386
+ PRESS_LONG_START = "PRESS_LONG_START"
387
+ PRESS_SHORT = "PRESS_SHORT"
388
+ PRESS_UNLOCK = "PRESS_UNLOCK"
389
+ PROGRAM = "PROGRAM"
390
+ RAMP_TIME = "RAMP_TIME"
391
+ RAMP_TIME_TO_OFF_UNIT = "RAMP_TIME_TO_OFF_UNIT"
392
+ RAMP_TIME_TO_OFF_VALUE = "RAMP_TIME_TO_OFF_VALUE"
393
+ RAMP_TIME_UNIT = "RAMP_TIME_UNIT"
394
+ RAMP_TIME_VALUE = "RAMP_TIME_VALUE"
395
+ RESET_MOTION = "RESET_MOTION"
396
+ RSSI_DEVICE = "RSSI_DEVICE"
397
+ RSSI_PEER = "RSSI_PEER"
398
+ SABOTAGE = "SABOTAGE"
399
+ SATURATION = "SATURATION"
400
+ SECTION = "SECTION"
401
+ SENSOR = "SENSOR"
402
+ SENSOR_ERROR = "SENSOR_ERROR"
403
+ SEQUENCE_OK = "SEQUENCE_OK"
404
+ SETPOINT = "SETPOINT"
405
+ SET_POINT_MODE = "SET_POINT_MODE"
406
+ SET_POINT_TEMPERATURE = "SET_POINT_TEMPERATURE"
407
+ SET_TEMPERATURE = "SET_TEMPERATURE"
408
+ SMOKE_DETECTOR_ALARM_STATUS = "SMOKE_DETECTOR_ALARM_STATUS"
409
+ SMOKE_DETECTOR_COMMAND = "SMOKE_DETECTOR_COMMAND"
410
+ STATE = "STATE"
411
+ STATUS = "STATUS"
412
+ STICKY_UN_REACH = "STICKY_UNREACH"
413
+ STOP = "STOP"
414
+ SUNSHINE_DURATION = "SUNSHINEDURATION"
415
+ TEMPERATURE = "TEMPERATURE"
416
+ TEMPERATURE_MAXIMUM = "TEMPERATURE_MAXIMUM"
417
+ TEMPERATURE_MINIMUM = "TEMPERATURE_MINIMUM"
418
+ TEMPERATURE_OFFSET = "TEMPERATURE_OFFSET"
419
+ TIME_OF_OPERATION = "TIME_OF_OPERATION"
420
+ UN_REACH = "UNREACH"
421
+ UPDATE_PENDING = "UPDATE_PENDING"
422
+ VALVE_STATE = "VALVE_STATE"
423
+ VOLTAGE = "VOLTAGE"
424
+ WATER_FLOW = "WATER_FLOW"
425
+ WATER_VOLUME = "WATER_VOLUME"
426
+ WATER_VOLUME_SINCE_OPEN = "WATER_VOLUME_SINCE_OPEN"
427
+ WEEK_PROGRAM_POINTER = "WEEK_PROGRAM_POINTER"
428
+ WIND_DIRECTION = "WIND_DIRECTION"
429
+ WIND_DIRECTION_RANGE = "WIND_DIRECTION_RANGE"
430
+ WIND_SPEED = "WIND_SPEED"
431
+ WORKING = "WORKING"
432
+
433
+
434
+ class ParamsetKey(StrEnum):
435
+ """Enum with paramset keys."""
436
+
437
+ CALCULATED = "CALCULATED"
438
+ LINK = "LINK"
439
+ MASTER = "MASTER"
440
+ SERVICE = "SERVICE"
441
+ VALUES = "VALUES"
442
+
443
+
444
+ class ProductGroup(StrEnum):
445
+ """Enum with homematic product groups."""
446
+
447
+ HM = "BidCos-RF"
448
+ HMIP = "HmIP-RF"
449
+ HMIPW = "HmIP-Wired"
450
+ HMW = "BidCos-Wired"
451
+ UNKNOWN = "unknown"
452
+ VIRTUAL = "VirtualDevices"
453
+
454
+
455
+ class RegaScript(StrEnum):
456
+ """Enum with homematic rega scripts."""
457
+
458
+ FETCH_ALL_DEVICE_DATA: Final = "fetch_all_device_data.fn"
459
+ GET_PROGRAM_DESCRIPTIONS: Final = "get_program_descriptions.fn"
460
+ GET_SERIAL: Final = "get_serial.fn"
461
+ GET_SYSTEM_VARIABLE_DESCRIPTIONS: Final = "get_system_variable_descriptions.fn"
462
+ SET_PROGRAM_STATE: Final = "set_program_state.fn"
463
+ SET_SYSTEM_VARIABLE: Final = "set_system_variable.fn"
464
+
465
+
466
+ class Interface(StrEnum):
467
+ """Enum with homematic interfaces."""
468
+
469
+ BIDCOS_RF = "BidCos-RF"
470
+ BIDCOS_WIRED = "BidCos-Wired"
471
+ CCU_JACK = "CCU-Jack"
472
+ CUXD = "CUxD"
473
+ HMIP_RF = "HmIP-RF"
474
+ VIRTUAL_DEVICES = "VirtualDevices"
475
+
476
+
477
+ class InterfaceEventType(StrEnum):
478
+ """Enum with aiohomematic interface event types."""
479
+
480
+ CALLBACK = "callback"
481
+ FETCH_DATA = "fetch_data"
482
+ PENDING_PONG = "pending_pong"
483
+ PROXY = "proxy"
484
+ UNKNOWN_PONG = "unknown_pong"
485
+
486
+
487
+ class ProxyInitState(Enum):
488
+ """Enum with proxy handling results."""
489
+
490
+ INIT_FAILED = 0
491
+ INIT_SUCCESS = 1
492
+ DE_INIT_FAILED = 4
493
+ DE_INIT_SUCCESS = 8
494
+ DE_INIT_SKIPPED = 16
495
+
496
+
497
+ class RxMode(IntEnum):
498
+ """Enum for homematic rx modes."""
499
+
500
+ UNDEFINED = 0
501
+ ALWAYS = 1
502
+ BURST = 2
503
+ CONFIG = 4
504
+ WAKEUP = 8
505
+ LAZY_CONFIG = 16
506
+
507
+
508
+ class CommandRxMode(StrEnum):
509
+ """Enum for homematic rx modes for commands."""
510
+
511
+ BURST = "BURST"
512
+ WAKEUP = "WAKEUP"
513
+
514
+
515
+ class SysvarType(StrEnum):
516
+ """Enum for homematic sysvar types."""
517
+
518
+ ALARM = "ALARM"
519
+ FLOAT = "FLOAT"
520
+ INTEGER = "INTEGER"
521
+ LIST = "LIST"
522
+ LOGIC = "LOGIC"
523
+ NUMBER = "NUMBER"
524
+ STRING = "STRING"
525
+
526
+
527
+ class ParameterType(StrEnum):
528
+ """Enum for homematic parameter types."""
529
+
530
+ ACTION = "ACTION" # Usually buttons, send Boolean to trigger
531
+ BOOL = "BOOL"
532
+ ENUM = "ENUM"
533
+ FLOAT = "FLOAT"
534
+ INTEGER = "INTEGER"
535
+ STRING = "STRING"
536
+ EMPTY = ""
537
+
538
+
539
+ CLICK_EVENTS: Final[tuple[Parameter, ...]] = (
540
+ Parameter.PRESS,
541
+ Parameter.PRESS_CONT,
542
+ Parameter.PRESS_LOCK,
543
+ Parameter.PRESS_LONG,
544
+ Parameter.PRESS_LONG_RELEASE,
545
+ Parameter.PRESS_LONG_START,
546
+ Parameter.PRESS_SHORT,
547
+ Parameter.PRESS_UNLOCK,
548
+ )
549
+
550
+ DEVICE_ERROR_EVENTS: Final[tuple[Parameter, ...]] = (Parameter.ERROR, Parameter.SENSOR_ERROR)
551
+
552
+ DATA_POINT_EVENTS: Final[tuple[EventType, ...]] = (
553
+ EventType.IMPULSE,
554
+ EventType.KEYPRESS,
555
+ )
556
+
557
+
558
+ class DataPointKey(NamedTuple):
559
+ """Key for data points."""
560
+
561
+ interface_id: str
562
+ channel_address: str
563
+ paramset_key: ParamsetKey
564
+ parameter: str
565
+
566
+
567
+ type DP_KEY_VALUE = tuple[DataPointKey, Any]
568
+ type SYSVAR_TYPE = bool | float | int | str | None
569
+
570
+ HMIP_FIRMWARE_UPDATE_IN_PROGRESS_STATES: Final[tuple[DeviceFirmwareState, ...]] = (
571
+ DeviceFirmwareState.DO_UPDATE_PENDING,
572
+ DeviceFirmwareState.PERFORMING_UPDATE,
573
+ )
574
+
575
+ HMIP_FIRMWARE_UPDATE_READY_STATES: Final[tuple[DeviceFirmwareState, ...]] = (
576
+ DeviceFirmwareState.READY_FOR_UPDATE,
577
+ DeviceFirmwareState.DO_UPDATE_PENDING,
578
+ DeviceFirmwareState.PERFORMING_UPDATE,
579
+ )
580
+
581
+ IMPULSE_EVENTS: Final[tuple[Parameter, ...]] = (Parameter.SEQUENCE_OK,)
582
+
583
+ KEY_CHANNEL_OPERATION_MODE_VISIBILITY: Final[Mapping[str, tuple[str, ...]]] = {
584
+ Parameter.STATE: ("BINARY_BEHAVIOR",),
585
+ Parameter.PRESS_LONG: ("KEY_BEHAVIOR", "SWITCH_BEHAVIOR"),
586
+ Parameter.PRESS_LONG_RELEASE: ("KEY_BEHAVIOR", "SWITCH_BEHAVIOR"),
587
+ Parameter.PRESS_LONG_START: ("KEY_BEHAVIOR", "SWITCH_BEHAVIOR"),
588
+ Parameter.PRESS_SHORT: ("KEY_BEHAVIOR", "SWITCH_BEHAVIOR"),
589
+ }
590
+
591
+ HUB_CATEGORIES: Final[tuple[DataPointCategory, ...]] = (
592
+ DataPointCategory.HUB_BINARY_SENSOR,
593
+ DataPointCategory.HUB_BUTTON,
594
+ DataPointCategory.HUB_NUMBER,
595
+ DataPointCategory.HUB_SELECT,
596
+ DataPointCategory.HUB_SENSOR,
597
+ DataPointCategory.HUB_SWITCH,
598
+ DataPointCategory.HUB_TEXT,
599
+ )
600
+
601
+ CATEGORIES: Final[tuple[DataPointCategory, ...]] = (
602
+ DataPointCategory.BINARY_SENSOR,
603
+ DataPointCategory.BUTTON,
604
+ DataPointCategory.CLIMATE,
605
+ DataPointCategory.COVER,
606
+ DataPointCategory.EVENT,
607
+ DataPointCategory.LIGHT,
608
+ DataPointCategory.LOCK,
609
+ DataPointCategory.NUMBER,
610
+ DataPointCategory.SELECT,
611
+ DataPointCategory.SENSOR,
612
+ DataPointCategory.SIREN,
613
+ DataPointCategory.SWITCH,
614
+ DataPointCategory.TEXT,
615
+ DataPointCategory.UPDATE,
616
+ DataPointCategory.VALVE,
617
+ )
618
+
619
+ PRIMARY_CLIENT_CANDIDATE_INTERFACES: Final = (
620
+ Interface.HMIP_RF,
621
+ Interface.BIDCOS_RF,
622
+ Interface.BIDCOS_WIRED,
623
+ )
624
+
625
+ RELEVANT_INIT_PARAMETERS: Final[tuple[Parameter, ...]] = (
626
+ Parameter.CONFIG_PENDING,
627
+ Parameter.STICKY_UN_REACH,
628
+ Parameter.UN_REACH,
629
+ )
630
+
631
+ INTERFACES_SUPPORTING_FIRMWARE_UPDATES: Final[tuple[Interface, ...]] = (
632
+ Interface.BIDCOS_RF,
633
+ Interface.BIDCOS_WIRED,
634
+ Interface.HMIP_RF,
635
+ )
636
+
637
+ INTERFACES_SUPPORTING_XML_RPC: Final[tuple[Interface, ...]] = (
638
+ Interface.BIDCOS_RF,
639
+ Interface.BIDCOS_WIRED,
640
+ Interface.HMIP_RF,
641
+ Interface.VIRTUAL_DEVICES,
642
+ )
643
+
644
+ INTERFACES_REQUIRING_PERIODIC_REFRESH: Final[tuple[Interface, ...]] = (
645
+ Interface.CCU_JACK,
646
+ Interface.CUXD,
647
+ )
648
+
649
+ DEFAULT_USE_PERIODIC_SCAN_FOR_INTERFACES: Final = True
650
+
651
+ IGNORE_FOR_UN_IGNORE_PARAMETERS: Final[tuple[Parameter, ...]] = (
652
+ Parameter.CONFIG_PENDING,
653
+ Parameter.STICKY_UN_REACH,
654
+ Parameter.UN_REACH,
655
+ )
656
+
657
+
658
+ # Ignore Parameter on initial load that end with
659
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS_END_RE: Final = re.compile(r".*(_ERROR)$")
660
+ # Ignore Parameter on initial load that start with
661
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS_START_RE: Final = re.compile(r"^(ERROR_|RSSI_)")
662
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS: Final = (
663
+ Parameter.DUTY_CYCLE,
664
+ Parameter.DUTYCYCLE,
665
+ Parameter.LOW_BAT,
666
+ Parameter.LOWBAT,
667
+ Parameter.OPERATING_VOLTAGE,
668
+ )
669
+
670
+
671
+ def check_ignore_parameter_on_initial_load(parameter: str) -> bool:
672
+ """Check if a parameter matches common wildcard patterns."""
673
+ return (
674
+ bool(_IGNORE_ON_INITIAL_LOAD_PARAMETERS_START_RE.match(parameter))
675
+ or bool(_IGNORE_ON_INITIAL_LOAD_PARAMETERS_END_RE.match(parameter))
676
+ or parameter in _IGNORE_ON_INITIAL_LOAD_PARAMETERS
677
+ )
678
+
679
+
680
+ # Ignore Parameter on initial load that start with
681
+ _IGNORE_ON_INITIAL_LOAD_MODEL_START_RE: Final = re.compile(r"^(HmIP-SWSD)")
682
+ _IGNORE_ON_INITIAL_LOAD_MODEL: Final = ("HmIP-SWD",)
683
+ _IGNORE_ON_INITIAL_LOAD_MODEL_LOWER: Final = tuple(model.lower() for model in _IGNORE_ON_INITIAL_LOAD_MODEL)
684
+
685
+
686
+ def check_ignore_model_on_initial_load(model: str) -> bool:
687
+ """Check if a model matches common wildcard patterns."""
688
+ return (
689
+ bool(_IGNORE_ON_INITIAL_LOAD_MODEL_START_RE.match(model))
690
+ or model.lower() in _IGNORE_ON_INITIAL_LOAD_MODEL_LOWER
691
+ )
692
+
693
+
694
+ # virtual remotes s
695
+ VIRTUAL_REMOTE_MODELS: Final[tuple[str, ...]] = (
696
+ "HM-RCV-50",
697
+ "HMW-RCV-50",
698
+ "HmIP-RCV-50",
699
+ )
700
+
701
+ VIRTUAL_REMOTE_ADDRESSES: Final[tuple[str, ...]] = (
702
+ "BidCoS-RF",
703
+ "BidCoS-Wir",
704
+ "HmIP-RCV-1",
705
+ )
706
+
707
+
708
+ @dataclass(frozen=True, kw_only=True, slots=True)
709
+ class HubData:
710
+ """Dataclass for hub data points."""
711
+
712
+ legacy_name: str
713
+ enabled_default: bool = False
714
+ description: str | None = None
715
+
716
+
717
+ @dataclass(frozen=True, kw_only=True, slots=True)
718
+ class ProgramData(HubData):
719
+ """Dataclass for programs."""
720
+
721
+ pid: str
722
+ is_active: bool
723
+ is_internal: bool
724
+ last_execute_time: str
725
+
726
+
727
+ @dataclass(frozen=True, kw_only=True, slots=True)
728
+ class SystemVariableData(HubData):
729
+ """Dataclass for system variables."""
730
+
731
+ vid: str
732
+ value: SYSVAR_TYPE
733
+ data_type: SysvarType | None = None
734
+ extended_sysvar: bool = False
735
+ max_value: float | int | None = None
736
+ min_value: float | int | None = None
737
+ unit: str | None = None
738
+ values: tuple[str, ...] | None = None
739
+
740
+
741
+ @dataclass(frozen=True, kw_only=True, slots=True)
742
+ class SystemInformation:
743
+ """System information of the backend."""
744
+
745
+ available_interfaces: tuple[str, ...] = field(default_factory=tuple)
746
+ auth_enabled: bool | None = None
747
+ https_redirect_enabled: bool | None = None
748
+ serial: str | None = None
749
+
750
+
751
+ class ParameterData(TypedDict, total=False):
752
+ """Typed dict for parameter data."""
753
+
754
+ DEFAULT: Any
755
+ FLAGS: int
756
+ ID: str
757
+ MAX: Any
758
+ MIN: Any
759
+ OPERATIONS: int
760
+ SPECIAL: Mapping[str, Any]
761
+ TYPE: ParameterType
762
+ UNIT: str
763
+ VALUE_LIST: Iterable[Any]
764
+
765
+
766
+ class DeviceDescription(TypedDict, total=False):
767
+ """Typed dict for device descriptions."""
768
+
769
+ TYPE: Required[str]
770
+ SUBTYPE: str | None
771
+ ADDRESS: Required[str]
772
+ # RF_ADDRESS: int | None
773
+ CHILDREN: list[str]
774
+ PARENT: str | None
775
+ # PARENT_TYPE: str | None
776
+ # INDEX: int | None
777
+ # AES_ACTIVE: int | None
778
+ PARAMSETS: list[str]
779
+ FIRMWARE: str
780
+ AVAILABLE_FIRMWARE: str | None
781
+ UPDATABLE: bool
782
+ FIRMWARE_UPDATE_STATE: str | None
783
+ FIRMWARE_UPDATABLE: bool | None
784
+ # VERSION: Required[int]
785
+ # FLAGS: Required[int]
786
+ # LINK_SOURCE_ROLES: str | None
787
+ # LINK_TARGET_ROLES: str | None
788
+ # DIRECTION: int | None
789
+ # GROUP: str | None
790
+ # TEAM: str | None
791
+ # TEAM_TAG: str | None
792
+ # TEAM_CHANNELS: list
793
+ INTERFACE: str | None
794
+ # ROAMING: int | None
795
+ RX_MODE: int