aiohomematic 2025.10.20a0__py3-none-any.whl → 2025.10.21__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.

@@ -110,6 +110,7 @@ from aiohomematic.const import (
110
110
  DEVICE_FIRMWARE_CHECK_INTERVAL,
111
111
  DEVICE_FIRMWARE_DELIVERING_CHECK_INTERVAL,
112
112
  DEVICE_FIRMWARE_UPDATING_CHECK_INTERVAL,
113
+ IDENTIFIER_SEPARATOR,
113
114
  IGNORE_FOR_UN_IGNORE_PARAMETERS,
114
115
  IP_ANY_V4,
115
116
  LOCAL_HOST,
@@ -173,12 +174,16 @@ from aiohomematic.store import (
173
174
  from aiohomematic.support import (
174
175
  LogContextMixin,
175
176
  PayloadMixin,
176
- check_config,
177
+ check_or_create_directory,
178
+ check_password,
177
179
  extract_device_addresses_from_device_descriptions,
178
180
  extract_exc_args,
179
181
  get_channel_no,
180
182
  get_device_address,
181
183
  get_ip_addr,
184
+ is_hostname,
185
+ is_ipv4_address,
186
+ is_port,
182
187
  )
183
188
 
184
189
  __all__ = ["CentralConfig", "CentralUnit", "INTERFACE_EVENT_SCHEMA"]
@@ -2219,6 +2224,55 @@ class CentralConnectionState:
2219
2224
  )
2220
2225
 
2221
2226
 
2227
+ def check_config(
2228
+ *,
2229
+ central_name: str,
2230
+ host: str,
2231
+ username: str,
2232
+ password: str,
2233
+ storage_directory: str,
2234
+ callback_host: str | None,
2235
+ callback_port_xml_rpc: int | None,
2236
+ json_port: int | None,
2237
+ interface_configs: AbstractSet[hmcl.InterfaceConfig] | None = None,
2238
+ ) -> list[str]:
2239
+ """Check config. Throws BaseHomematicException on failure."""
2240
+ config_failures: list[str] = []
2241
+ if central_name and IDENTIFIER_SEPARATOR in central_name:
2242
+ config_failures.append(f"Instance name must not contain {IDENTIFIER_SEPARATOR}")
2243
+
2244
+ if not (is_hostname(hostname=host) or is_ipv4_address(address=host)):
2245
+ config_failures.append("Invalid hostname or ipv4 address")
2246
+ if not username:
2247
+ config_failures.append("Username must not be empty")
2248
+ if not password:
2249
+ config_failures.append("Password is required")
2250
+ if not check_password(password=password):
2251
+ config_failures.append("Password is not valid")
2252
+ try:
2253
+ check_or_create_directory(directory=storage_directory)
2254
+ except BaseHomematicException as bhexc:
2255
+ config_failures.append(extract_exc_args(exc=bhexc)[0])
2256
+ if callback_host and not (is_hostname(hostname=callback_host) or is_ipv4_address(address=callback_host)):
2257
+ config_failures.append("Invalid callback hostname or ipv4 address")
2258
+ if callback_port_xml_rpc and not is_port(port=callback_port_xml_rpc):
2259
+ config_failures.append("Invalid xml rpc callback port")
2260
+ if json_port and not is_port(port=json_port):
2261
+ config_failures.append("Invalid json port")
2262
+ if interface_configs and not _has_primary_client(interface_configs=interface_configs):
2263
+ config_failures.append(f"No primary interface ({', '.join(PRIMARY_CLIENT_CANDIDATE_INTERFACES)}) defined")
2264
+
2265
+ return config_failures
2266
+
2267
+
2268
+ def _has_primary_client(*, interface_configs: AbstractSet[hmcl.InterfaceConfig]) -> bool:
2269
+ """Check if all configured clients exists in central."""
2270
+ for interface_config in interface_configs:
2271
+ if interface_config.interface in PRIMARY_CLIENT_CANDIDATE_INTERFACES:
2272
+ return True
2273
+ return False
2274
+
2275
+
2222
2276
  def _get_new_data_points(
2223
2277
  *,
2224
2278
  new_devices: set[Device],
@@ -58,8 +58,7 @@ from aiohomematic import central as hmcu
58
58
  from aiohomematic.client.json_rpc import AioJsonRpcAioHttpClient
59
59
  from aiohomematic.client.rpc_proxy import AioXmlRpcProxy, BaseRpcProxy
60
60
  from aiohomematic.const import (
61
- CALLBACK_WARN_ARM_INTERVAL,
62
- CALLBACK_WARN_DISARM_INTERVAL,
61
+ CALLBACK_WARN_INTERVAL,
63
62
  DATETIME_FORMAT_MILLIS,
64
63
  DEFAULT_MAX_WORKERS,
65
64
  DP_KEY_VALUE,
@@ -146,6 +145,7 @@ class Client(ABC, LogContextMixin):
146
145
  self._last_value_send_cache = CommandCache(interface_id=client_config.interface_id)
147
146
  self._available: bool = True
148
147
  self._connection_error_count: int = 0
148
+ self._is_callback_alive: bool = True
149
149
  self._is_initialized: bool = False
150
150
  self._ping_pong_cache: Final = PingPongCache(
151
151
  central=client_config.central, interface_id=client_config.interface_id
@@ -395,7 +395,7 @@ class Client(ABC, LogContextMixin):
395
395
  return False
396
396
  if not self.supports_push_updates:
397
397
  return True
398
- return (datetime.now() - self.modified_at).total_seconds() < CALLBACK_WARN_ARM_INTERVAL
398
+ return (datetime.now() - self.modified_at).total_seconds() < CALLBACK_WARN_INTERVAL
399
399
 
400
400
  def is_callback_alive(self) -> bool:
401
401
  """Return if XmlRPC-Server is alive based on received events for this client."""
@@ -404,29 +404,31 @@ class Client(ABC, LogContextMixin):
404
404
  if (
405
405
  last_events_dt := self.central.get_last_event_seen_for_interface(interface_id=self.interface_id)
406
406
  ) is not None:
407
- if (
408
- seconds_since_last_event := (datetime.now() - last_events_dt).total_seconds()
409
- ) > CALLBACK_WARN_ARM_INTERVAL:
410
- self.central.fire_interface_event(
411
- interface_id=self.interface_id,
412
- interface_event_type=InterfaceEventType.CALLBACK,
413
- data={
414
- EventKey.AVAILABLE: False,
415
- EventKey.SECONDS_SINCE_LAST_EVENT: int(seconds_since_last_event),
416
- },
417
- )
407
+ if (seconds_since_last_event := (datetime.now() - last_events_dt).total_seconds()) > CALLBACK_WARN_INTERVAL:
408
+ if self._is_callback_alive:
409
+ self.central.fire_interface_event(
410
+ interface_id=self.interface_id,
411
+ interface_event_type=InterfaceEventType.CALLBACK,
412
+ data={
413
+ EventKey.AVAILABLE: False,
414
+ EventKey.SECONDS_SINCE_LAST_EVENT: int(seconds_since_last_event),
415
+ },
416
+ )
417
+ self._is_callback_alive = False
418
418
  _LOGGER.warning(
419
419
  "IS_CALLBACK_ALIVE: Callback for %s has not received events for %is",
420
420
  self.interface_id,
421
421
  seconds_since_last_event,
422
422
  )
423
423
  return False
424
- if ((datetime.now() - last_events_dt).total_seconds()) < CALLBACK_WARN_DISARM_INTERVAL:
424
+
425
+ if not self._is_callback_alive:
425
426
  self.central.fire_interface_event(
426
427
  interface_id=self.interface_id,
427
428
  interface_event_type=InterfaceEventType.CALLBACK,
428
429
  data={EventKey.AVAILABLE: True},
429
430
  )
431
+ self._is_callback_alive = True
430
432
  return True
431
433
 
432
434
  @abstractmethod
aiohomematic/const.py CHANGED
@@ -19,7 +19,7 @@ import sys
19
19
  from types import MappingProxyType
20
20
  from typing import Any, Final, NamedTuple, Required, TypeAlias, TypedDict
21
21
 
22
- VERSION: Final = "2025.10.20a"
22
+ VERSION: Final = "2025.10.21"
23
23
 
24
24
  # Detect test speedup mode via environment
25
25
  _TEST_SPEEDUP: Final = (
@@ -133,8 +133,7 @@ WAIT_FOR_CALLBACK: Final[int | None] = None
133
133
  SCHEDULER_NOT_STARTED_SLEEP: Final = 0.2 if _TEST_SPEEDUP else 10
134
134
  SCHEDULER_LOOP_SLEEP: Final = 0.2 if _TEST_SPEEDUP else 5
135
135
 
136
- CALLBACK_WARN_ARM_INTERVAL: Final = CONNECTION_CHECKER_INTERVAL * 40
137
- CALLBACK_WARN_DISARM_INTERVAL: Final = CONNECTION_CHECKER_INTERVAL * 20
136
+ CALLBACK_WARN_INTERVAL: Final = CONNECTION_CHECKER_INTERVAL * 40
138
137
 
139
138
  # Path
140
139
  PROGRAM_SET_PATH_ROOT: Final = "program/set"
@@ -304,6 +303,7 @@ class EventKey(StrEnum):
304
303
  INTERFACE_ID = "interface_id"
305
304
  MODEL = "model"
306
305
  PARAMETER = "parameter"
306
+ PONG_MISMATCH_ALLOWED = "pong_mismatch_allowed"
307
307
  PONG_MISMATCH_COUNT = "pong_mismatch_count"
308
308
  SECONDS_SINCE_LAST_EVENT = "seconds_since_last_event"
309
309
  TYPE = "type"
@@ -204,12 +204,12 @@ class CustomDataPoint(BaseDataPoint):
204
204
  def _init_data_points(self) -> None:
205
205
  """Init data point collection."""
206
206
  # Add repeating fields
207
- for field_name, parameter in self._device_def.get(hmed.CDPD.REPEATABLE_FIELDS, {}).items():
207
+ for field_name, parameter in self._device_def.get(CDPD.REPEATABLE_FIELDS, {}).items():
208
208
  if dp := self._device.get_generic_data_point(channel_address=self._channel.address, parameter=parameter):
209
209
  self._add_data_point(field=field_name, data_point=dp, is_visible=False)
210
210
 
211
211
  # Add visible repeating fields
212
- for field_name, parameter in self._device_def.get(hmed.CDPD.VISIBLE_REPEATABLE_FIELDS, {}).items():
212
+ for field_name, parameter in self._device_def.get(CDPD.VISIBLE_REPEATABLE_FIELDS, {}).items():
213
213
  if dp := self._device.get_generic_data_point(channel_address=self._channel.address, parameter=parameter):
214
214
  self._add_data_point(field=field_name, data_point=dp, is_visible=True)
215
215
 
@@ -229,11 +229,11 @@ class CustomDataPoint(BaseDataPoint):
229
229
 
230
230
  # Add device fields
231
231
  self._add_data_points(
232
- field_dict_name=hmed.CDPD.FIELDS,
232
+ field_dict_name=CDPD.FIELDS,
233
233
  )
234
234
  # Add visible device fields
235
235
  self._add_data_points(
236
- field_dict_name=hmed.CDPD.VISIBLE_FIELDS,
236
+ field_dict_name=CDPD.VISIBLE_FIELDS,
237
237
  is_visible=True,
238
238
  )
239
239
 
@@ -243,7 +243,7 @@ class CustomDataPoint(BaseDataPoint):
243
243
  if hmed.get_include_default_data_points(device_profile=self._device_profile):
244
244
  self._mark_data_points(custom_data_point_def=hmed.get_default_data_points())
245
245
 
246
- def _add_data_points(self, *, field_dict_name: hmed.CDPD, is_visible: bool | None = None) -> None:
246
+ def _add_data_points(self, *, field_dict_name: CDPD, is_visible: bool | None = None) -> None:
247
247
  """Add data points to custom data point."""
248
248
  fields = self._device_def.get(field_dict_name, {})
249
249
  for channel_no, channel in fields.items():
@@ -32,7 +32,7 @@ from aiohomematic.const import (
32
32
  ParameterType,
33
33
  )
34
34
  from aiohomematic.model import device as hmd
35
- from aiohomematic.model.custom import definition as hmed
35
+ from aiohomematic.model.custom.const import CDPD
36
36
  from aiohomematic.support import to_bool
37
37
 
38
38
  __all__ = [
@@ -565,7 +565,7 @@ def check_channel_is_the_only_primary_channel(
565
565
  device_has_multiple_channels: bool,
566
566
  ) -> bool:
567
567
  """Check if this channel is the only primary channel."""
568
- primary_channel: int = device_def[hmed.CDPD.PRIMARY_CHANNEL]
568
+ primary_channel: int = device_def[CDPD.PRIMARY_CHANNEL]
569
569
  return bool(primary_channel == current_channel_no and device_has_multiple_channels is False)
570
570
 
571
571
 
@@ -386,6 +386,11 @@ class PingPongCache:
386
386
  self._pending_pong_logged: bool = False
387
387
  self._unknown_pong_logged: bool = False
388
388
 
389
+ @property
390
+ def allowed_delta(self) -> int:
391
+ """Return the allowed delta."""
392
+ return self._allowed_delta
393
+
389
394
  @property
390
395
  def high_pending_pongs(self) -> bool:
391
396
  """Check, if store contains too many pending pongs."""
@@ -515,6 +520,7 @@ class PingPongCache:
515
520
  EventKey.TYPE: event_type,
516
521
  EventKey.DATA: {
517
522
  EventKey.CENTRAL_NAME: self._central.name,
523
+ EventKey.PONG_MISMATCH_ALLOWED: mismatch_count <= self._allowed_delta,
518
524
  EventKey.PONG_MISMATCH_COUNT: mismatch_count,
519
525
  },
520
526
  }
aiohomematic/support.py CHANGED
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import base64
12
12
  from collections import defaultdict
13
- from collections.abc import Callable, Collection, Mapping, Set as AbstractSet
13
+ from collections.abc import Callable, Collection, Mapping
14
14
  import contextlib
15
15
  from dataclasses import dataclass
16
16
  from datetime import datetime
@@ -30,7 +30,6 @@ from typing import Any, Final, cast
30
30
 
31
31
  import orjson
32
32
 
33
- from aiohomematic import client as hmcl
34
33
  from aiohomematic.const import (
35
34
  ADDRESS_SEPARATOR,
36
35
  ALLOWED_HOSTNAME_PATTERN,
@@ -38,12 +37,10 @@ from aiohomematic.const import (
38
37
  CHANNEL_ADDRESS_PATTERN,
39
38
  DEVICE_ADDRESS_PATTERN,
40
39
  HTMLTAG_PATTERN,
41
- IDENTIFIER_SEPARATOR,
42
40
  INIT_DATETIME,
43
41
  ISO_8859_1,
44
42
  MAX_CACHE_AGE,
45
43
  NO_CACHE_ENTRY,
46
- PRIMARY_CLIENT_CANDIDATE_INTERFACES,
47
44
  TIMEOUT,
48
45
  UTF_8,
49
46
  CommandRxMode,
@@ -95,55 +92,6 @@ def build_xml_rpc_headers(
95
92
  return [("Authorization", f"Basic {base64_message}")]
96
93
 
97
94
 
98
- def check_config(
99
- *,
100
- central_name: str,
101
- host: str,
102
- username: str,
103
- password: str,
104
- storage_directory: str,
105
- callback_host: str | None,
106
- callback_port_xml_rpc: int | None,
107
- json_port: int | None,
108
- interface_configs: AbstractSet[hmcl.InterfaceConfig] | None = None,
109
- ) -> list[str]:
110
- """Check config. Throws BaseHomematicException on failure."""
111
- config_failures: list[str] = []
112
- if central_name and IDENTIFIER_SEPARATOR in central_name:
113
- config_failures.append(f"Instance name must not contain {IDENTIFIER_SEPARATOR}")
114
-
115
- if not (is_hostname(hostname=host) or is_ipv4_address(address=host)):
116
- config_failures.append("Invalid hostname or ipv4 address")
117
- if not username:
118
- config_failures.append("Username must not be empty")
119
- if not password:
120
- config_failures.append("Password is required")
121
- if not check_password(password=password):
122
- config_failures.append("Password is not valid")
123
- try:
124
- check_or_create_directory(directory=storage_directory)
125
- except BaseHomematicException as bhexc:
126
- config_failures.append(extract_exc_args(exc=bhexc)[0])
127
- if callback_host and not (is_hostname(hostname=callback_host) or is_ipv4_address(address=callback_host)):
128
- config_failures.append("Invalid callback hostname or ipv4 address")
129
- if callback_port_xml_rpc and not is_port(port=callback_port_xml_rpc):
130
- config_failures.append("Invalid xml rpc callback port")
131
- if json_port and not is_port(port=json_port):
132
- config_failures.append("Invalid json port")
133
- if interface_configs and not has_primary_client(interface_configs=interface_configs):
134
- config_failures.append(f"No primary interface ({', '.join(PRIMARY_CLIENT_CANDIDATE_INTERFACES)}) defined")
135
-
136
- return config_failures
137
-
138
-
139
- def has_primary_client(*, interface_configs: AbstractSet[hmcl.InterfaceConfig]) -> bool:
140
- """Check if all configured clients exists in central."""
141
- for interface_config in interface_configs:
142
- if interface_config.interface in PRIMARY_CLIENT_CANDIDATE_INTERFACES:
143
- return True
144
- return False
145
-
146
-
147
95
  def delete_file(directory: str, file_name: str) -> None: # kwonly: disable
148
96
  """Delete the file. File can contain a wildcard."""
149
97
  if os.path.exists(directory):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiohomematic
3
- Version: 2025.10.20a0
3
+ Version: 2025.10.21
4
4
  Summary: Homematic interface for Home Assistant running on Python 3.
5
5
  Home-page: https://github.com/sukramj/aiohomematic
6
6
  Author-email: SukramJ <sukramj@icloud.com>, Daniel Perna <danielperna84@gmail.com>
@@ -21,10 +21,10 @@ Classifier: Topic :: Home Automation
21
21
  Requires-Python: >=3.13.0
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
- Requires-Dist: aiohttp>=3.13.1
25
- Requires-Dist: orjson>=3.11.4
26
- Requires-Dist: python-slugify>=8.0.4
27
- Requires-Dist: voluptuous>=0.15.2
24
+ Requires-Dist: aiohttp>=3.12.0
25
+ Requires-Dist: orjson>=3.11.0
26
+ Requires-Dist: python-slugify>=8.0.0
27
+ Requires-Dist: voluptuous>=0.15.0
28
28
  Dynamic: license-file
29
29
 
30
30
  [![releasebadge]][release]
@@ -1,6 +1,6 @@
1
1
  aiohomematic/__init__.py,sha256=Uo9CIoil0Arl3GwtgMZAwM8jhcgoBKcZEgj8cXYlswY,2258
2
2
  aiohomematic/async_support.py,sha256=Fg6RLD7Irt1mTwXbLkfphJbfd7oU_Svhp23i3Bb4Q7k,8762
3
- aiohomematic/const.py,sha256=j7hv5C0qcpEArQ6cwWg6zxYbYE3Z3mQtnSXBh5wgTfs,27504
3
+ aiohomematic/const.py,sha256=YOCIFXt3xTY7GT29XqKpHi8Ir9eYYtY6Ur2bzWwtCIs,27479
4
4
  aiohomematic/context.py,sha256=hGE-iPcPt21dY-1MZar-Hyh9YaKL-VS42xjrulIVyRQ,429
5
5
  aiohomematic/converter.py,sha256=FiHU71M5RZ7N5FXJYh2CN14s63-PM-SHdb0cJ_CLx54,3602
6
6
  aiohomematic/decorators.py,sha256=cSW0aF3PzrW_qW6H0sjRNH9eqO8ysqhXZDgJ2OJTZM4,11038
@@ -8,12 +8,12 @@ aiohomematic/exceptions.py,sha256=RLldRD4XY8iYuNYVdspCbbphGcKsximB7R5OL7cYKw0,50
8
8
  aiohomematic/hmcli.py,sha256=_QZFKcfr_KJrdiyBRbhz0f8LZ95glD7LgJBmQc8cwog,4911
9
9
  aiohomematic/property_decorators.py,sha256=3Id1_rWIYnwyN_oSMgbh7XNKz9HPkGTC1CeS5ei04ZQ,17139
10
10
  aiohomematic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- aiohomematic/support.py,sha256=eUbtdnrkq99o2DxJzyai5LHqrkpXC_gWQtrkI4zIgzg,23310
11
+ aiohomematic/support.py,sha256=F8jiuRgw3Dn7v2kPBvFTHFGI4nJzybd3eQIQEK4Y6XI,21056
12
12
  aiohomematic/validator.py,sha256=qX5janicu4jLrAVzKoyWgXe1XU4EOjk5-QhNFL4awTQ,3541
13
- aiohomematic/central/__init__.py,sha256=xqlWOAKbnLzYTteVHIdxFpLCBcrTzgub8ZztJd43HTw,94122
13
+ aiohomematic/central/__init__.py,sha256=f4IXc_-d8JZC77kAdIOBUuAwMrimTRDMC3akfwlzZ2M,96361
14
14
  aiohomematic/central/decorators.py,sha256=vrujdw2QMXva-7DGXMQyittujx0q7cPuGD-SCeQlD30,6886
15
15
  aiohomematic/central/rpc_server.py,sha256=EhvBy8oMjBTR8MvH5QXo3lvlsCNJrvu6B85_CAg6sG8,10742
16
- aiohomematic/client/__init__.py,sha256=45Pzvuzf-Ne8iZqhvj2X_1ZsWL0w42Xpr6DEovV7qsY,74043
16
+ aiohomematic/client/__init__.py,sha256=dMCDQIDyPc01Z4BvPsWIe688Bqtq81l51YRis22iKok,74131
17
17
  aiohomematic/client/_rpc_errors.py,sha256=IaYjX60mpBJ43gDCJjuUSVraamy5jXHTRjOnutK4azs,2962
18
18
  aiohomematic/client/json_rpc.py,sha256=DtK4xdnZPVw-drWZ4HW-t0zp8Q0p3oYSn6RNfd01YYU,51331
19
19
  aiohomematic/client/rpc_proxy.py,sha256=T6tmfBAJJSFxzBLrhKJc6_KiHyTs5EVnStQsVJA5YkY,11604
@@ -21,7 +21,7 @@ aiohomematic/model/__init__.py,sha256=gUYa8ROWSbXjZTWUTmINZ1bbYAxGkVpA-onxaJN2Is
21
21
  aiohomematic/model/data_point.py,sha256=VdwzjRrBDaYhWyIQL4JVC9wYTFMSwvwymYSEAPxjms8,41573
22
22
  aiohomematic/model/device.py,sha256=K_xIRA5Jc2xC8iQcmdKUkR8O4BCoxK7MOfy1s4YQY8Q,52896
23
23
  aiohomematic/model/event.py,sha256=uO6Z2pCZEU_8MR8uRIIZjX8IL0rFh7sNhhTNT8yFoVU,6852
24
- aiohomematic/model/support.py,sha256=ITyxBIJ2Bv69fcwuUD2HyMKlburOnLo9NFs5VKg34ZY,19635
24
+ aiohomematic/model/support.py,sha256=MQJVuE1C043VRs7t7Ld7kZ1quMmIDNXjzwNKW1LQtEs,19622
25
25
  aiohomematic/model/update.py,sha256=R3uUA61m-UQNNGkRod3vES66AgkPKay_CPyyrd-nqVI,5140
26
26
  aiohomematic/model/calculated/__init__.py,sha256=JNtxK4-XZeyR6MxfKVPdcF6ezQliQYTWEDoeOChumaE,2966
27
27
  aiohomematic/model/calculated/climate.py,sha256=rm9b4rCrmsZAA5_dzP6YRtahdveI97581_EnC4utqpg,10499
@@ -32,7 +32,7 @@ aiohomematic/model/custom/__init__.py,sha256=JxJXyr2CgKlj-jc1xQ14lbMT76vvswfLUec
32
32
  aiohomematic/model/custom/climate.py,sha256=OnkZKxJKInrP52Tqu_hPcDDZbyL0wTMaIjWuBJ3th_k,57292
33
33
  aiohomematic/model/custom/const.py,sha256=s4iqhwvt8x41h4-CtMCyXwryGHuBNbhBrcJ5zGVRFJU,4939
34
34
  aiohomematic/model/custom/cover.py,sha256=KQzLEoPkKgZ2oi2oblUrGReQnT_0WAuseWAxu_xH5_Y,29035
35
- aiohomematic/model/custom/data_point.py,sha256=WLKygP3SQwtG35BpOH3HNt_o-z9dfSUmuSyPDIEWF8A,14133
35
+ aiohomematic/model/custom/data_point.py,sha256=D36sRWsPdh6s-WSR1CxsnJCyp7PpROV2wVyExTXEAKA,14108
36
36
  aiohomematic/model/custom/definition.py,sha256=miZssuy1u5EcQ4opOWo9n0Eko-2aIK9f3MAKYiMmJb8,35640
37
37
  aiohomematic/model/custom/light.py,sha256=JC7GeU87gObBN0b1fCjm0VzgCtoytWsmq2Sd-fQqBGM,44426
38
38
  aiohomematic/model/custom/lock.py,sha256=iJY8jiJA_HRynpbeACEQ_kzwiXOfAaT2IcF1FbXc0xY,11974
@@ -66,11 +66,11 @@ aiohomematic/rega_scripts/get_system_variable_descriptions.fn,sha256=UKXvC0_5lSA
66
66
  aiohomematic/rega_scripts/set_program_state.fn,sha256=0bnv7lUj8FMjDZBz325tDVP61m04cHjVj4kIOnUUgpY,279
67
67
  aiohomematic/rega_scripts/set_system_variable.fn,sha256=sTmr7vkPTPnPkor5cnLKlDvfsYRbGO1iq2z_2pMXq5E,383
68
68
  aiohomematic/store/__init__.py,sha256=PHwF_tw_zL20ODwLywHgpOLWrghQo_BMZzeiQSXN1Fc,1081
69
- aiohomematic/store/dynamic.py,sha256=kgZs5gJ4i8bHZKkJ883xuLecSKdjj6UwlLRJAvQcNGI,22528
69
+ aiohomematic/store/dynamic.py,sha256=K1nTal_bYTxOXF8Brmyv3yl7A4cy9ZZm0SQ9ANbUKi4,22757
70
70
  aiohomematic/store/persistent.py,sha256=SBL8AhqUzpoPtJ50GkLYHwvRJS52fBWqNPjgvykxbY8,40233
71
71
  aiohomematic/store/visibility.py,sha256=0y93kPTugqQsrh6kKamfgwBkbIdBPEZpQVv_1NaLz3A,31662
72
- aiohomematic-2025.10.20a0.dist-info/licenses/LICENSE,sha256=q-B0xpREuZuvKsmk3_iyVZqvZ-vJcWmzMZpeAd0RqtQ,1083
73
- aiohomematic-2025.10.20a0.dist-info/METADATA,sha256=0UbFLL35SL6MnJ10hB-QV0jbGgEGuy4KRemQqIpL82g,7674
74
- aiohomematic-2025.10.20a0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- aiohomematic-2025.10.20a0.dist-info/top_level.txt,sha256=iGUvt1N-E72vKRq7Anpp62HwkQngStrUK0JfL1zj1TE,13
76
- aiohomematic-2025.10.20a0.dist-info/RECORD,,
72
+ aiohomematic-2025.10.21.dist-info/licenses/LICENSE,sha256=q-B0xpREuZuvKsmk3_iyVZqvZ-vJcWmzMZpeAd0RqtQ,1083
73
+ aiohomematic-2025.10.21.dist-info/METADATA,sha256=l1aVOPRrDGn6JSPcroaoRuZkFlmja6f-lv35NUnU-oI,7672
74
+ aiohomematic-2025.10.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ aiohomematic-2025.10.21.dist-info/top_level.txt,sha256=iGUvt1N-E72vKRq7Anpp62HwkQngStrUK0JfL1zj1TE,13
76
+ aiohomematic-2025.10.21.dist-info/RECORD,,