aiohomematic 2025.11.3__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 +61 -0
  2. aiohomematic/async_support.py +212 -0
  3. aiohomematic/central/__init__.py +2309 -0
  4. aiohomematic/central/decorators.py +155 -0
  5. aiohomematic/central/rpc_server.py +295 -0
  6. aiohomematic/client/__init__.py +1848 -0
  7. aiohomematic/client/_rpc_errors.py +81 -0
  8. aiohomematic/client/json_rpc.py +1326 -0
  9. aiohomematic/client/rpc_proxy.py +311 -0
  10. aiohomematic/const.py +1127 -0
  11. aiohomematic/context.py +18 -0
  12. aiohomematic/converter.py +108 -0
  13. aiohomematic/decorators.py +302 -0
  14. aiohomematic/exceptions.py +164 -0
  15. aiohomematic/hmcli.py +186 -0
  16. aiohomematic/model/__init__.py +140 -0
  17. aiohomematic/model/calculated/__init__.py +84 -0
  18. aiohomematic/model/calculated/climate.py +290 -0
  19. aiohomematic/model/calculated/data_point.py +327 -0
  20. aiohomematic/model/calculated/operating_voltage_level.py +299 -0
  21. aiohomematic/model/calculated/support.py +234 -0
  22. aiohomematic/model/custom/__init__.py +177 -0
  23. aiohomematic/model/custom/climate.py +1532 -0
  24. aiohomematic/model/custom/cover.py +792 -0
  25. aiohomematic/model/custom/data_point.py +334 -0
  26. aiohomematic/model/custom/definition.py +871 -0
  27. aiohomematic/model/custom/light.py +1128 -0
  28. aiohomematic/model/custom/lock.py +394 -0
  29. aiohomematic/model/custom/siren.py +275 -0
  30. aiohomematic/model/custom/support.py +41 -0
  31. aiohomematic/model/custom/switch.py +175 -0
  32. aiohomematic/model/custom/valve.py +114 -0
  33. aiohomematic/model/data_point.py +1123 -0
  34. aiohomematic/model/device.py +1445 -0
  35. aiohomematic/model/event.py +208 -0
  36. aiohomematic/model/generic/__init__.py +217 -0
  37. aiohomematic/model/generic/action.py +34 -0
  38. aiohomematic/model/generic/binary_sensor.py +30 -0
  39. aiohomematic/model/generic/button.py +27 -0
  40. aiohomematic/model/generic/data_point.py +171 -0
  41. aiohomematic/model/generic/dummy.py +147 -0
  42. aiohomematic/model/generic/number.py +76 -0
  43. aiohomematic/model/generic/select.py +39 -0
  44. aiohomematic/model/generic/sensor.py +74 -0
  45. aiohomematic/model/generic/switch.py +54 -0
  46. aiohomematic/model/generic/text.py +29 -0
  47. aiohomematic/model/hub/__init__.py +333 -0
  48. aiohomematic/model/hub/binary_sensor.py +24 -0
  49. aiohomematic/model/hub/button.py +28 -0
  50. aiohomematic/model/hub/data_point.py +340 -0
  51. aiohomematic/model/hub/number.py +39 -0
  52. aiohomematic/model/hub/select.py +49 -0
  53. aiohomematic/model/hub/sensor.py +37 -0
  54. aiohomematic/model/hub/switch.py +44 -0
  55. aiohomematic/model/hub/text.py +30 -0
  56. aiohomematic/model/support.py +586 -0
  57. aiohomematic/model/update.py +143 -0
  58. aiohomematic/property_decorators.py +496 -0
  59. aiohomematic/py.typed +0 -0
  60. aiohomematic/rega_scripts/fetch_all_device_data.fn +92 -0
  61. aiohomematic/rega_scripts/get_program_descriptions.fn +30 -0
  62. aiohomematic/rega_scripts/get_serial.fn +44 -0
  63. aiohomematic/rega_scripts/get_system_variable_descriptions.fn +30 -0
  64. aiohomematic/rega_scripts/set_program_state.fn +12 -0
  65. aiohomematic/rega_scripts/set_system_variable.fn +15 -0
  66. aiohomematic/store/__init__.py +34 -0
  67. aiohomematic/store/dynamic.py +551 -0
  68. aiohomematic/store/persistent.py +988 -0
  69. aiohomematic/store/visibility.py +812 -0
  70. aiohomematic/support.py +664 -0
  71. aiohomematic/validator.py +112 -0
  72. aiohomematic-2025.11.3.dist-info/METADATA +144 -0
  73. aiohomematic-2025.11.3.dist-info/RECORD +77 -0
  74. aiohomematic-2025.11.3.dist-info/WHEEL +5 -0
  75. aiohomematic-2025.11.3.dist-info/entry_points.txt +2 -0
  76. aiohomematic-2025.11.3.dist-info/licenses/LICENSE +21 -0
  77. aiohomematic-2025.11.3.dist-info/top_level.txt +1 -0
aiohomematic/const.py ADDED
@@ -0,0 +1,1127 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2021-2025
3
+ """
4
+ Constants used by aiohomematic.
5
+
6
+ Public API of this module is defined by __all__.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections.abc import Callable, Iterable, Mapping
12
+ from dataclasses import dataclass, field
13
+ from datetime import datetime
14
+ from enum import Enum, IntEnum, StrEnum
15
+ import inspect
16
+ import os
17
+ import re
18
+ import sys
19
+ from types import MappingProxyType
20
+ from typing import Any, Final, NamedTuple, Required, TypeAlias, TypedDict
21
+
22
+ VERSION: Final = "2025.11.3"
23
+
24
+ # Detect test speedup mode via environment
25
+ _TEST_SPEEDUP: Final = (
26
+ bool(os.getenv("AIOHOMEMATIC_TEST_SPEEDUP")) or ("PYTEST_CURRENT_TEST" in os.environ) or ("pytest" in sys.modules)
27
+ )
28
+
29
+ # default
30
+ DEFAULT_DELAY_NEW_DEVICE_CREATION: Final = False
31
+ DEFAULT_ENABLE_DEVICE_FIRMWARE_CHECK: Final = False
32
+ DEFAULT_ENABLE_PROGRAM_SCAN: Final = True
33
+ DEFAULT_ENABLE_SYSVAR_SCAN: Final = True
34
+ DEFAULT_HM_MASTER_POLL_AFTER_SEND_INTERVALS: Final = (5,)
35
+ DEFAULT_IGNORE_CUSTOM_DEVICE_DEFINITION_MODELS: Final[frozenset[str]] = frozenset()
36
+ DEFAULT_INCLUDE_INTERNAL_PROGRAMS: Final = False
37
+ DEFAULT_INCLUDE_INTERNAL_SYSVARS: Final = True
38
+ DEFAULT_MAX_READ_WORKERS: Final = 1
39
+ DEFAULT_MAX_WORKERS: Final = 1
40
+ DEFAULT_MULTIPLIER: Final = 1.0
41
+ DEFAULT_OPTIONAL_SETTINGS: Final[tuple[OptionalSettings | str, ...]] = ()
42
+ DEFAULT_PERIODIC_REFRESH_INTERVAL: Final = 15
43
+ DEFAULT_PROGRAM_MARKERS: Final[tuple[DescriptionMarker | str, ...]] = ()
44
+ DEFAULT_SESSION_RECORDER_START_FOR_SECONDS: Final = 180
45
+ DEFAULT_STORAGE_DIRECTORY: Final = "aiohomematic_storage"
46
+ DEFAULT_SYSVAR_MARKERS: Final[tuple[DescriptionMarker | str, ...]] = ()
47
+ DEFAULT_SYS_SCAN_INTERVAL: Final = 30
48
+ DEFAULT_TLS: Final = False
49
+ DEFAULT_UN_IGNORES: Final[frozenset[str]] = frozenset()
50
+ DEFAULT_USE_GROUP_CHANNEL_FOR_COVER_STATE: Final = True
51
+ DEFAULT_VERIFY_TLS: Final = False
52
+
53
+ # Default encoding for json service calls, persistent cache
54
+ UTF_8: Final = "utf-8"
55
+ # Default encoding for xmlrpc service calls and script files
56
+ ISO_8859_1: Final = "iso-8859-1"
57
+
58
+ # Password can be empty.
59
+ # Allowed characters: A-Z, a-z, 0-9, .!$():;#-
60
+ # The CCU WebUI also supports ÄäÖöÜüß, but these characters are not supported by the XmlRPC servers
61
+ CCU_PASSWORD_PATTERN: Final = re.compile(r"[A-Za-z0-9.!$():;#-]{0,}")
62
+ # Pattern is bigger than needed
63
+ CHANNEL_ADDRESS_PATTERN: Final = re.compile(r"^[0-9a-zA-Z-]{5,20}:[0-9]{1,3}$")
64
+ DEVICE_ADDRESS_PATTERN: Final = re.compile(r"^[0-9a-zA-Z-]{5,20}$")
65
+ ALLOWED_HOSTNAME_PATTERN: Final = re.compile(r"(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
66
+ HTMLTAG_PATTERN: Final = re.compile(r"<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});")
67
+ SCHEDULER_PROFILE_PATTERN: Final = re.compile(
68
+ r"^P[1-6]_(ENDTIME|TEMPERATURE)_(MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FRIDAY|SATURDAY|SUNDAY)_([1-9]|1[0-3])$"
69
+ )
70
+ SCHEDULER_TIME_PATTERN: Final = re.compile(r"^(([0-1]{0,1}[0-9])|(2[0-4])):[0-5][0-9]")
71
+
72
+ ALWAYS_ENABLE_SYSVARS_BY_ID: Final[frozenset[str]] = frozenset({"40", "41"})
73
+ RENAME_SYSVAR_BY_NAME: Final[Mapping[str, str]] = MappingProxyType(
74
+ {
75
+ "${sysVarAlarmMessages}": "ALARM_MESSAGES",
76
+ "${sysVarPresence}": "PRESENCE",
77
+ "${sysVarServiceMessages}": "SERVICE_MESSAGES",
78
+ }
79
+ )
80
+
81
+ # Deprecated alias (use ALWAYS_ENABLE_SYSVARS_BY_ID). Kept for backward compatibility.
82
+ SYSVAR_ENABLE_DEFAULT: Final[frozenset[str]] = ALWAYS_ENABLE_SYSVARS_BY_ID
83
+
84
+ ADDRESS_SEPARATOR: Final = ":"
85
+ BLOCK_LOG_TIMEOUT: Final = 60
86
+ CONTENT_PATH: Final = "cache"
87
+ CONF_PASSWORD: Final = "password"
88
+ CONF_USERNAME: Final = "username"
89
+
90
+ CONNECTION_CHECKER_INTERVAL: Final = 1 if _TEST_SPEEDUP else 15 # check if connection is available via rpc ping
91
+ DATETIME_FORMAT: Final = "%d.%m.%Y %H:%M:%S"
92
+ DATETIME_FORMAT_MILLIS: Final = "%d.%m.%Y %H:%M:%S.%f'"
93
+ DEVICE_DESCRIPTIONS_DIR: Final = "export_device_descriptions"
94
+ DEVICE_FIRMWARE_CHECK_INTERVAL: Final = 21600 # 6h
95
+ DEVICE_FIRMWARE_DELIVERING_CHECK_INTERVAL: Final = 3600 # 1h
96
+ DEVICE_FIRMWARE_UPDATING_CHECK_INTERVAL: Final = 300 # 5m
97
+ DUMMY_SERIAL: Final = "SN0815"
98
+ FILE_DEVICES: Final = "homematic_devices"
99
+ FILE_PARAMSETS: Final = "homematic_paramsets"
100
+ FILE_SESSION_RECORDER: Final = "homematic_session_recorder"
101
+ FILE_NAME_TS_PATTERN: Final = "%Y%m%d_%H%M%S"
102
+ SUB_DIRECTORY_CACHE: Final = "cache"
103
+ SUB_DIRECTORY_SESSION: Final = "session"
104
+ HUB_PATH: Final = "hub"
105
+ IDENTIFIER_SEPARATOR: Final = "@"
106
+ INIT_DATETIME: Final = datetime.strptime("01.01.1970 00:00:00", DATETIME_FORMAT)
107
+ IP_ANY_V4: Final = "0.0.0.0"
108
+ JSON_SESSION_AGE: Final = 90
109
+ KWARGS_ARG_CUSTOM_ID: Final = "custom_id"
110
+ KWARGS_ARG_DATA_POINT: Final = "data_point"
111
+ LAST_COMMAND_SEND_STORE_TIMEOUT: Final = 60
112
+ LOCAL_HOST: Final = "127.0.0.1"
113
+ MAX_CACHE_AGE: Final = 10
114
+ MAX_CONCURRENT_HTTP_SESSIONS: Final = 3
115
+ MAX_WAIT_FOR_CALLBACK: Final = 60
116
+ NO_CACHE_ENTRY: Final = "NO_CACHE_ENTRY"
117
+ PARAMSET_DESCRIPTIONS_DIR: Final = "export_paramset_descriptions"
118
+ PATH_JSON_RPC: Final = "/api/homematic.cgi"
119
+ PING_PONG_MISMATCH_COUNT: Final = 15
120
+ PING_PONG_MISMATCH_COUNT_TTL: Final = 300
121
+ PORT_ANY: Final = 0
122
+ PROGRAM_ADDRESS: Final = "program"
123
+ RECONNECT_WAIT: Final = 1 if _TEST_SPEEDUP else 120 # wait with reconnect after a first ping was successful
124
+ REGA_SCRIPT_PATH: Final = "../rega_scripts"
125
+ REPORT_VALUE_USAGE_DATA: Final = "reportValueUsageData"
126
+ REPORT_VALUE_USAGE_VALUE_ID: Final = "PRESS_SHORT"
127
+ SYSVAR_ADDRESS: Final = "sysvar"
128
+ TIMEOUT: Final = 5 if _TEST_SPEEDUP else 60 # default timeout for a connection
129
+ UN_IGNORE_WILDCARD: Final = "all"
130
+ WAIT_FOR_CALLBACK: Final[int | None] = None
131
+
132
+ # Scheduler sleep durations (used by central scheduler loop)
133
+ SCHEDULER_NOT_STARTED_SLEEP: Final = 0.2 if _TEST_SPEEDUP else 10
134
+ SCHEDULER_LOOP_SLEEP: Final = 0.2 if _TEST_SPEEDUP else 5
135
+
136
+ CALLBACK_WARN_INTERVAL: Final = CONNECTION_CHECKER_INTERVAL * 40
137
+
138
+ # Path
139
+ PROGRAM_SET_PATH_ROOT: Final = "program/set"
140
+ PROGRAM_STATE_PATH_ROOT: Final = "program/status"
141
+ SET_PATH_ROOT: Final = "device/set"
142
+ STATE_PATH_ROOT: Final = "device/status"
143
+ SYSVAR_SET_PATH_ROOT: Final = "sysvar/set"
144
+ SYSVAR_STATE_PATH_ROOT: Final = "sysvar/status"
145
+ VIRTDEV_SET_PATH_ROOT: Final = "virtdev/set"
146
+ VIRTDEV_STATE_PATH_ROOT: Final = "virtdev/status"
147
+
148
+ CALLBACK_TYPE: TypeAlias = Callable[[], None] | None
149
+
150
+
151
+ class Backend(StrEnum):
152
+ """Enum with supported aiohomematic backends."""
153
+
154
+ CCU = "CCU"
155
+ HOMEGEAR = "Homegear"
156
+ PYDEVCCU = "PyDevCCU"
157
+
158
+
159
+ class BackendSystemEvent(StrEnum):
160
+ """Enum with aiohomematic system events."""
161
+
162
+ DELETE_DEVICES = "deleteDevices"
163
+ DEVICES_CREATED = "devicesCreated"
164
+ DEVICES_DELAYED = "devicesDelayed"
165
+ ERROR = "error"
166
+ HUB_REFRESHED = "hubDataPointRefreshed"
167
+ LIST_DEVICES = "listDevices"
168
+ NEW_DEVICES = "newDevices"
169
+ REPLACE_DEVICE = "replaceDevice"
170
+ RE_ADDED_DEVICE = "readdedDevice"
171
+ UPDATE_DEVICE = "updateDevice"
172
+
173
+
174
+ class CallSource(StrEnum):
175
+ """Enum with sources for calls."""
176
+
177
+ HA_INIT = "ha_init"
178
+ HM_INIT = "hm_init"
179
+ MANUAL_OR_SCHEDULED = "manual_or_scheduled"
180
+
181
+
182
+ class CalulatedParameter(StrEnum):
183
+ """Enum with calculated Homematic parameters."""
184
+
185
+ APPARENT_TEMPERATURE = "APPARENT_TEMPERATURE"
186
+ DEW_POINT = "DEW_POINT"
187
+ DEW_POINT_SPREAD = "DEW_POINT_SPREAD"
188
+ ENTHALPY = "ENTHALPY"
189
+ FROST_POINT = "FROST_POINT"
190
+ OPERATING_VOLTAGE_LEVEL = "OPERATING_VOLTAGE_LEVEL"
191
+ VAPOR_CONCENTRATION = "VAPOR_CONCENTRATION"
192
+
193
+
194
+ class CDPD(StrEnum):
195
+ """Enum for custom data point definitions."""
196
+
197
+ ADDITIONAL_DPS = "additional_dps"
198
+ ALLOW_UNDEFINED_GENERIC_DPS = "allow_undefined_generic_dps"
199
+ DEFAULT_DPS = "default_dps"
200
+ DEVICE_DEFINITIONS = "device_definitions"
201
+ DEVICE_GROUP = "device_group"
202
+ FIELDS = "fields"
203
+ INCLUDE_DEFAULT_DPS = "include_default_dps"
204
+ PRIMARY_CHANNEL = "primary_channel"
205
+ REPEATABLE_FIELDS = "repeatable_fields"
206
+ SECONDARY_CHANNELS = "secondary_channels"
207
+ STATE_CHANNEL = "state_channel"
208
+ VISIBLE_FIELDS = "visible_fields"
209
+ VISIBLE_REPEATABLE_FIELDS = "visible_repeatable_fields"
210
+
211
+
212
+ class CentralUnitState(StrEnum):
213
+ """Enum with central unit states."""
214
+
215
+ INITIALIZING = "initializing"
216
+ NEW = "new"
217
+ RUNNING = "running"
218
+ STOPPED = "stopped"
219
+ STOPPED_BY_ERROR = "stopped_by_error"
220
+ STOPPING = "stopping"
221
+
222
+
223
+ class CommandRxMode(StrEnum):
224
+ """Enum for Homematic rx modes for commands."""
225
+
226
+ BURST = "BURST"
227
+ WAKEUP = "WAKEUP"
228
+
229
+
230
+ class DataOperationResult(Enum):
231
+ """Enum with data operation results."""
232
+
233
+ LOAD_FAIL = 0
234
+ LOAD_SUCCESS = 1
235
+ SAVE_FAIL = 10
236
+ SAVE_SUCCESS = 11
237
+ NO_LOAD = 20
238
+ NO_SAVE = 21
239
+
240
+
241
+ class DataPointCategory(StrEnum):
242
+ """Enum with data point types."""
243
+
244
+ ACTION = "action"
245
+ BINARY_SENSOR = "binary_sensor"
246
+ BUTTON = "button"
247
+ CLIMATE = "climate"
248
+ COVER = "cover"
249
+ EVENT = "event"
250
+ HUB_BINARY_SENSOR = "hub_binary_sensor"
251
+ HUB_BUTTON = "hub_button"
252
+ HUB_NUMBER = "hub_number"
253
+ HUB_SELECT = "hub_select"
254
+ HUB_SENSOR = "hub_sensor"
255
+ HUB_SWITCH = "hub_switch"
256
+ HUB_TEXT = "hub_text"
257
+ LIGHT = "light"
258
+ LOCK = "lock"
259
+ NUMBER = "number"
260
+ SELECT = "select"
261
+ SENSOR = "sensor"
262
+ SIREN = "siren"
263
+ SWITCH = "switch"
264
+ TEXT = "text"
265
+ UNDEFINED = "undefined"
266
+ UPDATE = "update"
267
+ VALVE = "valve"
268
+
269
+
270
+ class DataPointKey(NamedTuple):
271
+ """Key for data points."""
272
+
273
+ interface_id: str
274
+ channel_address: str
275
+ paramset_key: ParamsetKey
276
+ parameter: str
277
+
278
+
279
+ class DataPointUsage(StrEnum):
280
+ """Enum with usage information."""
281
+
282
+ CDP_PRIMARY = "ce_primary"
283
+ CDP_SECONDARY = "ce_secondary"
284
+ CDP_VISIBLE = "ce_visible"
285
+ DATA_POINT = "data_point"
286
+ EVENT = "event"
287
+ NO_CREATE = "no_create"
288
+
289
+
290
+ class DescriptionMarker(StrEnum):
291
+ """Enum with default description markers."""
292
+
293
+ HAHM = "HAHM"
294
+ HX = "HX"
295
+ INTERNAL = "INTERNAL"
296
+ MQTT = "MQTT"
297
+
298
+
299
+ class DeviceFirmwareState(StrEnum):
300
+ """Enum with Homematic device firmware states."""
301
+
302
+ UNKNOWN = "UNKNOWN"
303
+ UP_TO_DATE = "UP_TO_DATE"
304
+ LIVE_UP_TO_DATE = "LIVE_UP_TO_DATE"
305
+ NEW_FIRMWARE_AVAILABLE = "NEW_FIRMWARE_AVAILABLE"
306
+ LIVE_NEW_FIRMWARE_AVAILABLE = "LIVE_NEW_FIRMWARE_AVAILABLE"
307
+ DELIVER_FIRMWARE_IMAGE = "DELIVER_FIRMWARE_IMAGE"
308
+ LIVE_DELIVER_FIRMWARE_IMAGE = "LIVE_DELIVER_FIRMWARE_IMAGE"
309
+ READY_FOR_UPDATE = "READY_FOR_UPDATE"
310
+ DO_UPDATE_PENDING = "DO_UPDATE_PENDING"
311
+ PERFORMING_UPDATE = "PERFORMING_UPDATE"
312
+ BACKGROUND_UPDATE_NOT_SUPPORTED = "BACKGROUND_UPDATE_NOT_SUPPORTED"
313
+
314
+
315
+ class DeviceProfile(StrEnum):
316
+ """Enum for device profiles."""
317
+
318
+ IP_BUTTON_LOCK = "IPButtonLock"
319
+ IP_COVER = "IPCover"
320
+ IP_DIMMER = "IPDimmer"
321
+ IP_DRG_DALI = "IPDRGDALI"
322
+ IP_FIXED_COLOR_LIGHT = "IPFixedColorLight"
323
+ IP_GARAGE = "IPGarage"
324
+ IP_HDM = "IPHdm"
325
+ IP_IRRIGATION_VALVE = "IPIrrigationValve"
326
+ IP_LOCK = "IPLock"
327
+ IP_RGBW_LIGHT = "IPRGBW"
328
+ IP_SIMPLE_FIXED_COLOR_LIGHT = "IPSimpleFixedColorLight"
329
+ IP_SIMPLE_FIXED_COLOR_LIGHT_WIRED = "IPSimpleFixedColorLightWired"
330
+ IP_SIREN = "IPSiren"
331
+ IP_SIREN_SMOKE = "IPSirenSmoke"
332
+ IP_SWITCH = "IPSwitch"
333
+ IP_THERMOSTAT = "IPThermostat"
334
+ IP_THERMOSTAT_GROUP = "IPThermostatGroup"
335
+ RF_BUTTON_LOCK = "RFButtonLock"
336
+ RF_COVER = "RfCover"
337
+ RF_DIMMER = "RfDimmer"
338
+ RF_DIMMER_COLOR = "RfDimmer_Color"
339
+ RF_DIMMER_COLOR_FIXED = "RfDimmer_Color_Fixed"
340
+ RF_DIMMER_COLOR_TEMP = "RfDimmer_Color_Temp"
341
+ RF_DIMMER_WITH_VIRT_CHANNEL = "RfDimmerWithVirtChannel"
342
+ RF_LOCK = "RfLock"
343
+ RF_SIREN = "RfSiren"
344
+ RF_SWITCH = "RfSwitch"
345
+ RF_THERMOSTAT = "RfThermostat"
346
+ RF_THERMOSTAT_GROUP = "RfThermostatGroup"
347
+ SIMPLE_RF_THERMOSTAT = "SimpleRfThermostat"
348
+
349
+
350
+ class EventKey(StrEnum):
351
+ """Enum with aiohomematic event keys."""
352
+
353
+ ADDRESS = "address"
354
+ AVAILABLE = "available"
355
+ CENTRAL_NAME = "central_name"
356
+ CHANNEL_NO = "channel_no"
357
+ DATA = "data"
358
+ INTERFACE_ID = "interface_id"
359
+ MODEL = "model"
360
+ PARAMETER = "parameter"
361
+ PONG_MISMATCH_ACCEPTABLE = "pong_mismatch_allowed"
362
+ PONG_MISMATCH_COUNT = "pong_mismatch_count"
363
+ SECONDS_SINCE_LAST_EVENT = "seconds_since_last_event"
364
+ TYPE = "type"
365
+ VALUE = "value"
366
+
367
+
368
+ class EventType(StrEnum):
369
+ """Enum with aiohomematic event types."""
370
+
371
+ DEVICE_AVAILABILITY = "homematic.device_availability"
372
+ DEVICE_ERROR = "homematic.device_error"
373
+ IMPULSE = "homematic.impulse"
374
+ INTERFACE = "homematic.interface"
375
+ KEYPRESS = "homematic.keypress"
376
+
377
+
378
+ class Field(Enum):
379
+ """Enum for fields."""
380
+
381
+ ACOUSTIC_ALARM_ACTIVE = "acoustic_alarm_active"
382
+ ACOUSTIC_ALARM_SELECTION = "acoustic_alarm_selection"
383
+ ACTIVE_PROFILE = "active_profile"
384
+ AUTO_MODE = "auto_mode"
385
+ BOOST_MODE = "boost_mode"
386
+ BUTTON_LOCK = "button_lock"
387
+ CHANNEL_COLOR = "channel_color"
388
+ COLOR = "color"
389
+ COLOR_BEHAVIOUR = "color_behaviour"
390
+ COLOR_LEVEL = "color_temp"
391
+ COLOR_TEMPERATURE = "color_temperature"
392
+ COMBINED_PARAMETER = "combined_parameter"
393
+ COMFORT_MODE = "comfort_mode"
394
+ CONCENTRATION = "concentration"
395
+ CONTROL_MODE = "control_mode"
396
+ CURRENT = "current"
397
+ DEVICE_OPERATION_MODE = "device_operation_mode"
398
+ DIRECTION = "direction"
399
+ DOOR_COMMAND = "door_command"
400
+ DOOR_STATE = "door_state"
401
+ DURATION = "duration"
402
+ DURATION_UNIT = "duration_unit"
403
+ DUTYCYCLE = "dutycycle"
404
+ DUTY_CYCLE = "duty_cycle"
405
+ EFFECT = "effect"
406
+ ENERGY_COUNTER = "energy_counter"
407
+ ERROR = "error"
408
+ FREQUENCY = "frequency"
409
+ GROUP_LEVEL = "group_level"
410
+ GROUP_LEVEL_2 = "group_level_2"
411
+ GROUP_STATE = "group_state"
412
+ HEATING_COOLING = "heating_cooling"
413
+ HEATING_VALVE_TYPE = "heating_valve_type"
414
+ HUE = "hue"
415
+ HUMIDITY = "humidity"
416
+ INHIBIT = "inhibit"
417
+ LEVEL = "level"
418
+ LEVEL_2 = "level_2"
419
+ LEVEL_COMBINED = "level_combined"
420
+ LOCK_STATE = "lock_state"
421
+ LOCK_TARGET_LEVEL = "lock_target_level"
422
+ LOWBAT = "lowbat"
423
+ LOWERING_MODE = "lowering_mode"
424
+ LOW_BAT = "low_bat"
425
+ LOW_BAT_LIMIT = "low_bat_limit"
426
+ MANU_MODE = "manu_mode"
427
+ MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE = "min_max_value_not_relevant_for_manu_mode"
428
+ ON_TIME_UNIT = "on_time_unit"
429
+ ON_TIME_VALUE = "on_time_value"
430
+ OPEN = "open"
431
+ OPERATING_VOLTAGE = "operating_voltage"
432
+ OPERATION_MODE = "channel_operation_mode"
433
+ OPTICAL_ALARM_ACTIVE = "optical_alarm_active"
434
+ OPTICAL_ALARM_SELECTION = "optical_alarm_selection"
435
+ OPTIMUM_START_STOP = "optimum_start_stop"
436
+ PARTY_MODE = "party_mode"
437
+ POWER = "power"
438
+ PROGRAM = "program"
439
+ RAMP_TIME_TO_OFF_UNIT = "ramp_time_to_off_unit"
440
+ RAMP_TIME_TO_OFF_VALUE = "ramp_time_to_off_value"
441
+ RAMP_TIME_UNIT = "ramp_time_unit"
442
+ RAMP_TIME_VALUE = "ramp_time_value"
443
+ RSSI_DEVICE = "rssi_device"
444
+ RSSI_PEER = "rssi_peer"
445
+ SABOTAGE = "sabotage"
446
+ SATURATION = "saturation"
447
+ SECTION = "section"
448
+ SETPOINT = "setpoint"
449
+ SET_POINT_MODE = "set_point_mode"
450
+ SMOKE_DETECTOR_ALARM_STATUS = "smoke_detector_alarm_status"
451
+ SMOKE_DETECTOR_COMMAND = "smoke_detector_command"
452
+ STATE = "state"
453
+ STOP = "stop"
454
+ SWITCH_MAIN = "switch_main"
455
+ SWITCH_V1 = "vswitch_1"
456
+ SWITCH_V2 = "vswitch_2"
457
+ TEMPERATURE = "temperature"
458
+ TEMPERATURE_MAXIMUM = "temperature_maximum"
459
+ TEMPERATURE_MINIMUM = "temperature_minimum"
460
+ TEMPERATURE_OFFSET = "temperature_offset"
461
+ VALVE_STATE = "valve_state"
462
+ VOLTAGE = "voltage"
463
+ WEEK_PROGRAM_POINTER = "week_program_pointer"
464
+
465
+
466
+ class Flag(IntEnum):
467
+ """Enum with Homematic flags."""
468
+
469
+ VISIBLE = 1
470
+ INTERNAL = 2
471
+ TRANSFORM = 4 # not used
472
+ SERVICE = 8
473
+ STICKY = 10 # This might be wrong. Documentation says 0x10 # not used
474
+
475
+
476
+ class ForcedDeviceAvailability(StrEnum):
477
+ """Enum with aiohomematic event types."""
478
+
479
+ FORCE_FALSE = "forced_not_available"
480
+ FORCE_TRUE = "forced_available"
481
+ NOT_SET = "not_set"
482
+
483
+
484
+ class InternalCustomID(StrEnum):
485
+ """Enum for Homematic internal custom IDs."""
486
+
487
+ DEFAULT = "cid_default"
488
+ MANU_TEMP = "cid_manu_temp"
489
+
490
+
491
+ class Manufacturer(StrEnum):
492
+ """Enum with aiohomematic system events."""
493
+
494
+ EQ3 = "eQ-3"
495
+ HB = "Homebrew"
496
+ MOEHLENHOFF = "Möhlenhoff"
497
+
498
+
499
+ class Operations(IntEnum):
500
+ """Enum with Homematic operations."""
501
+
502
+ NONE = 0 # not used
503
+ READ = 1
504
+ WRITE = 2
505
+ EVENT = 4
506
+
507
+
508
+ class OptionalSettings(StrEnum):
509
+ """Enum with aiohomematic optional settings."""
510
+
511
+ ENABLE_LINKED_ENTITY_CLIMATE_ACTIVITY = "ENABLE_LINKED_ENTITY_CLIMATE_ACTIVITY"
512
+ SR_DISABLE_RANDOMIZE_OUTPUT = "SR_DISABLE_RANDOMIZED_OUTPUT"
513
+ SR_RECORD_SYSTEM_INIT = "SR_RECORD_SYSTEM_INIT"
514
+
515
+
516
+ class Parameter(StrEnum):
517
+ """Enum with Homematic parameters."""
518
+
519
+ ACOUSTIC_ALARM_ACTIVE = "ACOUSTIC_ALARM_ACTIVE"
520
+ ACOUSTIC_ALARM_SELECTION = "ACOUSTIC_ALARM_SELECTION"
521
+ ACTIVE_PROFILE = "ACTIVE_PROFILE"
522
+ ACTIVITY_STATE = "ACTIVITY_STATE"
523
+ ACTUAL_HUMIDITY = "ACTUAL_HUMIDITY"
524
+ ACTUAL_TEMPERATURE = "ACTUAL_TEMPERATURE"
525
+ AUTO_MODE = "AUTO_MODE"
526
+ BATTERY_STATE = "BATTERY_STATE"
527
+ BOOST_MODE = "BOOST_MODE"
528
+ CHANNEL_OPERATION_MODE = "CHANNEL_OPERATION_MODE"
529
+ COLOR = "COLOR"
530
+ COLOR_BEHAVIOUR = "COLOR_BEHAVIOUR"
531
+ COLOR_TEMPERATURE = "COLOR_TEMPERATURE"
532
+ COMBINED_PARAMETER = "COMBINED_PARAMETER"
533
+ COMFORT_MODE = "COMFORT_MODE"
534
+ CONCENTRATION = "CONCENTRATION"
535
+ CONFIG_PENDING = "CONFIG_PENDING"
536
+ CONTROL_MODE = "CONTROL_MODE"
537
+ CURRENT = "CURRENT"
538
+ CURRENT_ILLUMINATION = "CURRENT_ILLUMINATION"
539
+ DEVICE_OPERATION_MODE = "DEVICE_OPERATION_MODE"
540
+ DIRECTION = "DIRECTION"
541
+ DOOR_COMMAND = "DOOR_COMMAND"
542
+ DOOR_STATE = "DOOR_STATE"
543
+ DURATION_UNIT = "DURATION_UNIT"
544
+ DURATION_VALUE = "DURATION_VALUE"
545
+ DUTYCYCLE = "DUTYCYCLE"
546
+ DUTY_CYCLE = "DUTY_CYCLE"
547
+ EFFECT = "EFFECT"
548
+ ENERGY_COUNTER = "ENERGY_COUNTER"
549
+ ERROR = "ERROR"
550
+ ERROR_JAMMED = "ERROR_JAMMED"
551
+ FREQUENCY = "FREQUENCY"
552
+ GLOBAL_BUTTON_LOCK = "GLOBAL_BUTTON_LOCK"
553
+ HEATING_COOLING = "HEATING_COOLING"
554
+ HEATING_VALVE_TYPE = "HEATING_VALVE_TYPE"
555
+ HUE = "HUE"
556
+ HUMIDITY = "HUMIDITY"
557
+ ILLUMINATION = "ILLUMINATION"
558
+ LED_STATUS = "LED_STATUS"
559
+ LEVEL = "LEVEL"
560
+ LEVEL_2 = "LEVEL_2"
561
+ LEVEL_COMBINED = "LEVEL_COMBINED"
562
+ LEVEL_SLATS = "LEVEL_SLATS"
563
+ LOCK_STATE = "LOCK_STATE"
564
+ LOCK_TARGET_LEVEL = "LOCK_TARGET_LEVEL"
565
+ LOWBAT = "LOWBAT"
566
+ LOWERING_MODE = "LOWERING_MODE"
567
+ LOW_BAT = "LOW_BAT"
568
+ LOW_BAT_LIMIT = "LOW_BAT_LIMIT"
569
+ MANU_MODE = "MANU_MODE"
570
+ MASS_CONCENTRATION_PM_10_24H_AVERAGE = "MASS_CONCENTRATION_PM_10_24H_AVERAGE"
571
+ MASS_CONCENTRATION_PM_1_24H_AVERAGE = "MASS_CONCENTRATION_PM_1_24H_AVERAGE"
572
+ MASS_CONCENTRATION_PM_2_5_24H_AVERAGE = "MASS_CONCENTRATION_PM_2_5_24H_AVERAGE"
573
+ MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE = "MIN_MAX_VALUE_NOT_RELEVANT_FOR_MANU_MODE"
574
+ MOTION = "MOTION"
575
+ MOTION_DETECTION_ACTIVE = "MOTION_DETECTION_ACTIVE"
576
+ ON_TIME = "ON_TIME"
577
+ OPEN = "OPEN"
578
+ OPERATING_VOLTAGE = "OPERATING_VOLTAGE"
579
+ OPTICAL_ALARM_ACTIVE = "OPTICAL_ALARM_ACTIVE"
580
+ OPTICAL_ALARM_SELECTION = "OPTICAL_ALARM_SELECTION"
581
+ OPTIMUM_START_STOP = "OPTIMUM_START_STOP"
582
+ PARTY_MODE = "PARTY_MODE"
583
+ PARTY_MODE_SUBMIT = "PARTY_MODE_SUBMIT"
584
+ PARTY_TIME_END = "PARTY_TIME_END"
585
+ PARTY_TIME_START = "PARTY_TIME_START"
586
+ PONG = "PONG"
587
+ POWER = "POWER"
588
+ PRESS = "PRESS"
589
+ PRESS_CONT = "PRESS_CONT"
590
+ PRESS_LOCK = "PRESS_LOCK"
591
+ PRESS_LONG = "PRESS_LONG"
592
+ PRESS_LONG_RELEASE = "PRESS_LONG_RELEASE"
593
+ PRESS_LONG_START = "PRESS_LONG_START"
594
+ PRESS_SHORT = "PRESS_SHORT"
595
+ PRESS_UNLOCK = "PRESS_UNLOCK"
596
+ PROGRAM = "PROGRAM"
597
+ RAMP_TIME = "RAMP_TIME"
598
+ RAMP_TIME_TO_OFF_UNIT = "RAMP_TIME_TO_OFF_UNIT"
599
+ RAMP_TIME_TO_OFF_VALUE = "RAMP_TIME_TO_OFF_VALUE"
600
+ RAMP_TIME_UNIT = "RAMP_TIME_UNIT"
601
+ RAMP_TIME_VALUE = "RAMP_TIME_VALUE"
602
+ RESET_MOTION = "RESET_MOTION"
603
+ RSSI_DEVICE = "RSSI_DEVICE"
604
+ RSSI_PEER = "RSSI_PEER"
605
+ SABOTAGE = "SABOTAGE"
606
+ SATURATION = "SATURATION"
607
+ SECTION = "SECTION"
608
+ SENSOR = "SENSOR"
609
+ SENSOR_ERROR = "SENSOR_ERROR"
610
+ SEQUENCE_OK = "SEQUENCE_OK"
611
+ SETPOINT = "SETPOINT"
612
+ SET_POINT_MODE = "SET_POINT_MODE"
613
+ SET_POINT_TEMPERATURE = "SET_POINT_TEMPERATURE"
614
+ SET_TEMPERATURE = "SET_TEMPERATURE"
615
+ SMOKE_DETECTOR_ALARM_STATUS = "SMOKE_DETECTOR_ALARM_STATUS"
616
+ SMOKE_DETECTOR_COMMAND = "SMOKE_DETECTOR_COMMAND"
617
+ STATE = "STATE"
618
+ STATUS = "STATUS"
619
+ STICKY_UN_REACH = "STICKY_UNREACH"
620
+ STOP = "STOP"
621
+ SUNSHINE_DURATION = "SUNSHINEDURATION"
622
+ TEMPERATURE = "TEMPERATURE"
623
+ TEMPERATURE_MAXIMUM = "TEMPERATURE_MAXIMUM"
624
+ TEMPERATURE_MINIMUM = "TEMPERATURE_MINIMUM"
625
+ TEMPERATURE_OFFSET = "TEMPERATURE_OFFSET"
626
+ TIME_OF_OPERATION = "TIME_OF_OPERATION"
627
+ UN_REACH = "UNREACH"
628
+ UPDATE_PENDING = "UPDATE_PENDING"
629
+ VALVE_STATE = "VALVE_STATE"
630
+ VOLTAGE = "VOLTAGE"
631
+ WATER_FLOW = "WATER_FLOW"
632
+ WATER_VOLUME = "WATER_VOLUME"
633
+ WATER_VOLUME_SINCE_OPEN = "WATER_VOLUME_SINCE_OPEN"
634
+ WEEK_PROGRAM_POINTER = "WEEK_PROGRAM_POINTER"
635
+ WIND_DIRECTION = "WIND_DIRECTION"
636
+ WIND_DIRECTION_RANGE = "WIND_DIRECTION_RANGE"
637
+ WIND_SPEED = "WIND_SPEED"
638
+ WORKING = "WORKING"
639
+
640
+
641
+ class ParamsetKey(StrEnum):
642
+ """Enum with paramset keys."""
643
+
644
+ CALCULATED = "CALCULATED"
645
+ DUMMY = "DUMMY"
646
+ LINK = "LINK"
647
+ MASTER = "MASTER"
648
+ SERVICE = "SERVICE"
649
+ VALUES = "VALUES"
650
+
651
+
652
+ class ProductGroup(StrEnum):
653
+ """Enum with Homematic product groups."""
654
+
655
+ HM = "BidCos-RF"
656
+ HMIP = "HmIP-RF"
657
+ HMIPW = "HmIP-Wired"
658
+ HMW = "BidCos-Wired"
659
+ UNKNOWN = "unknown"
660
+ VIRTUAL = "VirtualDevices"
661
+
662
+
663
+ class RegaScript(StrEnum):
664
+ """Enum with Homematic rega scripts."""
665
+
666
+ FETCH_ALL_DEVICE_DATA: Final = "fetch_all_device_data.fn"
667
+ GET_PROGRAM_DESCRIPTIONS: Final = "get_program_descriptions.fn"
668
+ GET_SERIAL: Final = "get_serial.fn"
669
+ GET_SYSTEM_VARIABLE_DESCRIPTIONS: Final = "get_system_variable_descriptions.fn"
670
+ SET_PROGRAM_STATE: Final = "set_program_state.fn"
671
+ SET_SYSTEM_VARIABLE: Final = "set_system_variable.fn"
672
+
673
+
674
+ class RPCType(StrEnum):
675
+ """Enum with Homematic rpc types."""
676
+
677
+ XML_RPC = "xmlrpc"
678
+ JSON_RPC = "jsonrpc"
679
+
680
+
681
+ class Interface(StrEnum):
682
+ """Enum with Homematic interfaces."""
683
+
684
+ BIDCOS_RF = "BidCos-RF"
685
+ BIDCOS_WIRED = "BidCos-Wired"
686
+ CCU_JACK = "CCU-Jack"
687
+ CUXD = "CUxD"
688
+ HMIP_RF = "HmIP-RF"
689
+ VIRTUAL_DEVICES = "VirtualDevices"
690
+
691
+
692
+ class InterfaceEventType(StrEnum):
693
+ """Enum with aiohomematic interface event types."""
694
+
695
+ CALLBACK = "callback"
696
+ FETCH_DATA = "fetch_data"
697
+ PENDING_PONG = "pending_pong"
698
+ PROXY = "proxy"
699
+ UNKNOWN_PONG = "unknown_pong"
700
+
701
+
702
+ class ParameterType(StrEnum):
703
+ """Enum for Homematic parameter types."""
704
+
705
+ ACTION = "ACTION" # Usually buttons, send Boolean to trigger
706
+ BOOL = "BOOL"
707
+ DUMMY = "DUMMY"
708
+ ENUM = "ENUM"
709
+ FLOAT = "FLOAT"
710
+ INTEGER = "INTEGER"
711
+ STRING = "STRING"
712
+ EMPTY = ""
713
+
714
+
715
+ class ProxyInitState(Enum):
716
+ """Enum with proxy handling results."""
717
+
718
+ INIT_FAILED = 0
719
+ INIT_SUCCESS = 1
720
+ DE_INIT_FAILED = 4
721
+ DE_INIT_SUCCESS = 8
722
+ DE_INIT_SKIPPED = 16
723
+
724
+
725
+ class RpcServerType(StrEnum):
726
+ """Enum for Homematic rpc server types."""
727
+
728
+ XML_RPC = "xml_rpc"
729
+ NONE = "none"
730
+
731
+
732
+ class RxMode(IntEnum):
733
+ """Enum for Homematic rx modes."""
734
+
735
+ UNDEFINED = 0
736
+ ALWAYS = 1
737
+ BURST = 2
738
+ CONFIG = 4
739
+ WAKEUP = 8
740
+ LAZY_CONFIG = 16
741
+
742
+
743
+ class SourceOfDeviceCreation(StrEnum):
744
+ """Enum with source of device creation."""
745
+
746
+ CACHE = "CACHE"
747
+ INIT = "INIT"
748
+ MANUAL = "MANUAL"
749
+ NEW = "NEW"
750
+ REFRESH = "REFRESH"
751
+
752
+
753
+ class SysvarType(StrEnum):
754
+ """Enum for Homematic sysvar types."""
755
+
756
+ ALARM = "ALARM"
757
+ FLOAT = "FLOAT"
758
+ INTEGER = "INTEGER"
759
+ LIST = "LIST"
760
+ LOGIC = "LOGIC"
761
+ NUMBER = "NUMBER"
762
+ STRING = "STRING"
763
+
764
+
765
+ CLICK_EVENTS: Final[frozenset[Parameter]] = frozenset(
766
+ {
767
+ Parameter.PRESS,
768
+ Parameter.PRESS_CONT,
769
+ Parameter.PRESS_LOCK,
770
+ Parameter.PRESS_LONG,
771
+ Parameter.PRESS_LONG_RELEASE,
772
+ Parameter.PRESS_LONG_START,
773
+ Parameter.PRESS_SHORT,
774
+ Parameter.PRESS_UNLOCK,
775
+ }
776
+ )
777
+
778
+ DEVICE_ERROR_EVENTS: Final[tuple[Parameter, ...]] = (Parameter.ERROR, Parameter.SENSOR_ERROR)
779
+
780
+ DATA_POINT_EVENTS: Final[frozenset[EventType]] = frozenset(
781
+ {
782
+ EventType.IMPULSE,
783
+ EventType.KEYPRESS,
784
+ }
785
+ )
786
+
787
+
788
+ type DP_KEY_VALUE = tuple[DataPointKey, Any]
789
+ type SYSVAR_TYPE = bool | float | int | str | None
790
+
791
+ HMIP_FIRMWARE_UPDATE_IN_PROGRESS_STATES: Final[frozenset[DeviceFirmwareState]] = frozenset(
792
+ {
793
+ DeviceFirmwareState.DO_UPDATE_PENDING,
794
+ DeviceFirmwareState.PERFORMING_UPDATE,
795
+ }
796
+ )
797
+
798
+ HMIP_FIRMWARE_UPDATE_READY_STATES: Final[frozenset[DeviceFirmwareState]] = frozenset(
799
+ {
800
+ DeviceFirmwareState.READY_FOR_UPDATE,
801
+ DeviceFirmwareState.DO_UPDATE_PENDING,
802
+ DeviceFirmwareState.PERFORMING_UPDATE,
803
+ }
804
+ )
805
+
806
+ IMPULSE_EVENTS: Final[frozenset[Parameter]] = frozenset({Parameter.SEQUENCE_OK})
807
+
808
+ KEY_CHANNEL_OPERATION_MODE_VISIBILITY: Final[Mapping[str, frozenset[str]]] = MappingProxyType(
809
+ {
810
+ Parameter.STATE: frozenset({"BINARY_BEHAVIOR"}),
811
+ Parameter.PRESS_LONG: frozenset({"KEY_BEHAVIOR", "SWITCH_BEHAVIOR"}),
812
+ Parameter.PRESS_LONG_RELEASE: frozenset({"KEY_BEHAVIOR", "SWITCH_BEHAVIOR"}),
813
+ Parameter.PRESS_LONG_START: frozenset({"KEY_BEHAVIOR", "SWITCH_BEHAVIOR"}),
814
+ Parameter.PRESS_SHORT: frozenset({"KEY_BEHAVIOR", "SWITCH_BEHAVIOR"}),
815
+ }
816
+ )
817
+
818
+ BLOCKED_CATEGORIES: Final[tuple[DataPointCategory, ...]] = (DataPointCategory.ACTION,)
819
+
820
+ HUB_CATEGORIES: Final[tuple[DataPointCategory, ...]] = (
821
+ DataPointCategory.HUB_BINARY_SENSOR,
822
+ DataPointCategory.HUB_BUTTON,
823
+ DataPointCategory.HUB_NUMBER,
824
+ DataPointCategory.HUB_SELECT,
825
+ DataPointCategory.HUB_SENSOR,
826
+ DataPointCategory.HUB_SWITCH,
827
+ DataPointCategory.HUB_TEXT,
828
+ )
829
+
830
+ CATEGORIES: Final[tuple[DataPointCategory, ...]] = (
831
+ DataPointCategory.BINARY_SENSOR,
832
+ DataPointCategory.BUTTON,
833
+ DataPointCategory.CLIMATE,
834
+ DataPointCategory.COVER,
835
+ DataPointCategory.EVENT,
836
+ DataPointCategory.LIGHT,
837
+ DataPointCategory.LOCK,
838
+ DataPointCategory.NUMBER,
839
+ DataPointCategory.SELECT,
840
+ DataPointCategory.SENSOR,
841
+ DataPointCategory.SIREN,
842
+ DataPointCategory.SWITCH,
843
+ DataPointCategory.TEXT,
844
+ DataPointCategory.UPDATE,
845
+ DataPointCategory.VALVE,
846
+ )
847
+
848
+ PRIMARY_CLIENT_CANDIDATE_INTERFACES: Final[frozenset[Interface]] = frozenset(
849
+ {
850
+ Interface.HMIP_RF,
851
+ Interface.BIDCOS_RF,
852
+ Interface.BIDCOS_WIRED,
853
+ }
854
+ )
855
+
856
+ RELEVANT_INIT_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
857
+ {
858
+ Parameter.CONFIG_PENDING,
859
+ Parameter.STICKY_UN_REACH,
860
+ Parameter.UN_REACH,
861
+ }
862
+ )
863
+
864
+ INTERFACES_SUPPORTING_FIRMWARE_UPDATES: Final[frozenset[Interface]] = frozenset(
865
+ {
866
+ Interface.BIDCOS_RF,
867
+ Interface.BIDCOS_WIRED,
868
+ Interface.HMIP_RF,
869
+ }
870
+ )
871
+
872
+ INTERFACES_REQUIRING_XML_RPC: Final[frozenset[Interface]] = frozenset(
873
+ {
874
+ Interface.BIDCOS_RF,
875
+ Interface.BIDCOS_WIRED,
876
+ Interface.HMIP_RF,
877
+ Interface.VIRTUAL_DEVICES,
878
+ }
879
+ )
880
+
881
+
882
+ INTERFACES_SUPPORTING_RPC_CALLBACK: Final[frozenset[Interface]] = frozenset(INTERFACES_REQUIRING_XML_RPC)
883
+
884
+
885
+ INTERFACES_REQUIRING_JSON_RPC_CLIENT: Final[frozenset[Interface]] = frozenset(
886
+ {
887
+ Interface.CUXD,
888
+ Interface.CCU_JACK,
889
+ }
890
+ )
891
+
892
+ DEFAULT_INTERFACES_REQUIRING_PERIODIC_REFRESH: Final[frozenset[Interface]] = frozenset(
893
+ INTERFACES_REQUIRING_JSON_RPC_CLIENT - INTERFACES_REQUIRING_XML_RPC
894
+ )
895
+
896
+ INTERFACE_RPC_SERVER_TYPE: Final[Mapping[Interface, RpcServerType]] = MappingProxyType(
897
+ {
898
+ Interface.BIDCOS_RF: RpcServerType.XML_RPC,
899
+ Interface.BIDCOS_WIRED: RpcServerType.XML_RPC,
900
+ Interface.HMIP_RF: RpcServerType.XML_RPC,
901
+ Interface.VIRTUAL_DEVICES: RpcServerType.XML_RPC,
902
+ Interface.CUXD: RpcServerType.NONE,
903
+ Interface.CCU_JACK: RpcServerType.NONE,
904
+ }
905
+ )
906
+
907
+
908
+ DEFAULT_USE_PERIODIC_SCAN_FOR_INTERFACES: Final = True
909
+
910
+ IGNORE_FOR_UN_IGNORE_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
911
+ {
912
+ Parameter.CONFIG_PENDING,
913
+ Parameter.STICKY_UN_REACH,
914
+ Parameter.UN_REACH,
915
+ }
916
+ )
917
+
918
+
919
+ # Ignore Parameter on initial load that end with
920
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS_END_RE: Final = re.compile(r".*(_ERROR)$")
921
+ # Ignore Parameter on initial load that start with
922
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS_START_RE: Final = re.compile(r"^(ERROR_|RSSI_)")
923
+ _IGNORE_ON_INITIAL_LOAD_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
924
+ {
925
+ Parameter.DUTY_CYCLE,
926
+ Parameter.DUTYCYCLE,
927
+ Parameter.LOW_BAT,
928
+ Parameter.LOWBAT,
929
+ Parameter.OPERATING_VOLTAGE,
930
+ }
931
+ )
932
+
933
+ _CLIMATE_SOURCE_ROLES: Final[tuple[str, ...]] = ("CLIMATE",)
934
+ _CLIMATE_TARGET_ROLES: Final[tuple[str, ...]] = ("CLIMATE", "SWITCH", "LEVEL")
935
+ _CLIMATE_TRANSMITTER_RE: Final = re.compile(r"(?:CLIMATE|HEATING).*(?:TRANSMITTER|TRANSCEIVER)")
936
+ _CLIMATE_RECEIVER_RE: Final = re.compile(r"(?:CLIMATE|HEATING).*(?:TRANSCEIVER|RECEIVER)")
937
+
938
+
939
+ def get_link_source_categories(
940
+ *, source_roles: tuple[str, ...], channel_type_name: str
941
+ ) -> tuple[DataPointCategory, ...]:
942
+ """Return the channel sender roles."""
943
+ result: set[DataPointCategory] = set()
944
+ has_climate = False
945
+ if _CLIMATE_TRANSMITTER_RE.search(channel_type_name):
946
+ result.add(DataPointCategory.CLIMATE)
947
+ has_climate = True
948
+
949
+ if not has_climate and source_roles and any("CLIMATE" in role for role in source_roles):
950
+ result.add(DataPointCategory.CLIMATE)
951
+
952
+ return tuple(result)
953
+
954
+
955
+ def get_link_target_categories(
956
+ *, target_roles: tuple[str, ...], channel_type_name: str
957
+ ) -> tuple[DataPointCategory, ...]:
958
+ """Return the channel receiver roles."""
959
+ result: set[DataPointCategory] = set()
960
+ has_climate = False
961
+ if _CLIMATE_RECEIVER_RE.search(channel_type_name):
962
+ result.add(DataPointCategory.CLIMATE)
963
+ has_climate = True
964
+
965
+ if (
966
+ not has_climate
967
+ and target_roles
968
+ and any(cl_role in role for role in target_roles for cl_role in _CLIMATE_TARGET_ROLES)
969
+ ):
970
+ result.add(DataPointCategory.CLIMATE)
971
+
972
+ return tuple(result)
973
+
974
+
975
+ RECEIVER_PARAMETERS: Final[frozenset[Parameter]] = frozenset(
976
+ {
977
+ Parameter.LEVEL,
978
+ Parameter.STATE,
979
+ }
980
+ )
981
+
982
+
983
+ def check_ignore_parameter_on_initial_load(parameter: str) -> bool:
984
+ """Check if a parameter matches common wildcard patterns."""
985
+ return (
986
+ bool(_IGNORE_ON_INITIAL_LOAD_PARAMETERS_START_RE.match(parameter))
987
+ or bool(_IGNORE_ON_INITIAL_LOAD_PARAMETERS_END_RE.match(parameter))
988
+ or parameter in _IGNORE_ON_INITIAL_LOAD_PARAMETERS
989
+ )
990
+
991
+
992
+ # Ignore Parameter on initial load that start with
993
+ _IGNORE_ON_INITIAL_LOAD_MODEL_START_RE: Final = re.compile(r"^(HmIP-SWSD)")
994
+ _IGNORE_ON_INITIAL_LOAD_MODEL: Final = ("HmIP-SWD",)
995
+ _IGNORE_ON_INITIAL_LOAD_MODEL_LOWER: Final = tuple(model.lower() for model in _IGNORE_ON_INITIAL_LOAD_MODEL)
996
+
997
+
998
+ def check_ignore_model_on_initial_load(model: str) -> bool:
999
+ """Check if a model matches common wildcard patterns."""
1000
+ return (
1001
+ bool(_IGNORE_ON_INITIAL_LOAD_MODEL_START_RE.match(model))
1002
+ or model.lower() in _IGNORE_ON_INITIAL_LOAD_MODEL_LOWER
1003
+ )
1004
+
1005
+
1006
+ # virtual remotes s
1007
+ VIRTUAL_REMOTE_MODELS: Final[tuple[str, ...]] = (
1008
+ "HM-RCV-50",
1009
+ "HMW-RCV-50",
1010
+ "HmIP-RCV-50",
1011
+ )
1012
+
1013
+ VIRTUAL_REMOTE_ADDRESSES: Final[tuple[str, ...]] = (
1014
+ "BidCoS-RF",
1015
+ "BidCoS-Wir",
1016
+ "HmIP-RCV-1",
1017
+ )
1018
+
1019
+
1020
+ @dataclass(frozen=True, kw_only=True, slots=True)
1021
+ class HubData:
1022
+ """Dataclass for hub data points."""
1023
+
1024
+ legacy_name: str
1025
+ enabled_default: bool = False
1026
+ description: str | None = None
1027
+
1028
+
1029
+ @dataclass(frozen=True, kw_only=True, slots=True)
1030
+ class ProgramData(HubData):
1031
+ """Dataclass for programs."""
1032
+
1033
+ pid: str
1034
+ is_active: bool
1035
+ is_internal: bool
1036
+ last_execute_time: str
1037
+
1038
+
1039
+ @dataclass(frozen=True, kw_only=True, slots=True)
1040
+ class SystemVariableData(HubData):
1041
+ """Dataclass for system variables."""
1042
+
1043
+ vid: str
1044
+ value: SYSVAR_TYPE
1045
+ data_type: SysvarType | None = None
1046
+ extended_sysvar: bool = False
1047
+ max_value: float | int | None = None
1048
+ min_value: float | int | None = None
1049
+ unit: str | None = None
1050
+ values: tuple[str, ...] | None = None
1051
+
1052
+
1053
+ @dataclass(frozen=True, kw_only=True, slots=True)
1054
+ class SystemInformation:
1055
+ """System information of the backend."""
1056
+
1057
+ available_interfaces: tuple[str, ...] = field(default_factory=tuple)
1058
+ auth_enabled: bool | None = None
1059
+ https_redirect_enabled: bool | None = None
1060
+ serial: str | None = None
1061
+
1062
+
1063
+ class ParameterData(TypedDict, total=False):
1064
+ """Typed dict for parameter data."""
1065
+
1066
+ DEFAULT: Any
1067
+ FLAGS: int
1068
+ ID: str
1069
+ MAX: Any
1070
+ MIN: Any
1071
+ OPERATIONS: int
1072
+ SPECIAL: Mapping[str, Any]
1073
+ TYPE: ParameterType
1074
+ UNIT: str
1075
+ VALUE_LIST: Iterable[Any]
1076
+
1077
+
1078
+ class DeviceDescription(TypedDict, total=False):
1079
+ """Typed dict for device descriptions."""
1080
+
1081
+ TYPE: Required[str]
1082
+ ADDRESS: Required[str]
1083
+ PARAMSETS: Required[list[str]]
1084
+ SUBTYPE: str | None
1085
+ CHILDREN: list[str]
1086
+ PARENT: str | None
1087
+ FIRMWARE: str | None
1088
+ AVAILABLE_FIRMWARE: str | None
1089
+ UPDATABLE: bool
1090
+ FIRMWARE_UPDATE_STATE: str | None
1091
+ FIRMWARE_UPDATABLE: bool | None
1092
+ INTERFACE: str | None
1093
+ RX_MODE: int | None
1094
+ LINK_SOURCE_ROLES: str | None
1095
+ LINK_TARGET_ROLES: str | None
1096
+ # RF_ADDRESS: int | None
1097
+ # PARENT_TYPE: str | None
1098
+ # INDEX: int | None
1099
+ # AES_ACTIVE: int | None
1100
+ # VERSION: Required[int]
1101
+ # FLAGS: Required[int]
1102
+ # DIRECTION: int | None
1103
+ # GROUP: str | None
1104
+ # TEAM: str | None
1105
+ # TEAM_TAG: str | None
1106
+ # TEAM_CHANNELS: list
1107
+ # ROAMING: int | None
1108
+
1109
+
1110
+ # Define public API for this module
1111
+ __all__ = tuple(
1112
+ sorted(
1113
+ name
1114
+ for name, obj in globals().items()
1115
+ if not name.startswith("_")
1116
+ and (
1117
+ name.isupper() # constants like VERSION, patterns, defaults
1118
+ or inspect.isclass(obj) # Enums, dataclasses, TypedDicts, NamedTuple classes
1119
+ or inspect.isfunction(obj) # module functions
1120
+ )
1121
+ and (
1122
+ getattr(obj, "__module__", __name__) == __name__
1123
+ if not isinstance(obj, int | float | str | bytes | tuple | frozenset | dict)
1124
+ else True
1125
+ )
1126
+ )
1127
+ )