ramses-rf 0.52.5__py3-none-any.whl → 0.53.1__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.
- ramses_cli/__init__.py +1 -1
- ramses_cli/client.py +178 -55
- ramses_cli/discovery.py +12 -28
- ramses_cli/py.typed +0 -0
- ramses_rf/__init__.py +2 -0
- ramses_rf/database.py +6 -3
- ramses_rf/device/heat.py +7 -5
- ramses_rf/entity_base.py +10 -4
- ramses_rf/gateway.py +206 -29
- ramses_rf/schemas.py +1 -0
- ramses_rf/system/zones.py +3 -2
- ramses_rf/version.py +1 -1
- {ramses_rf-0.52.5.dist-info → ramses_rf-0.53.1.dist-info}/METADATA +1 -1
- {ramses_rf-0.52.5.dist-info → ramses_rf-0.53.1.dist-info}/RECORD +28 -27
- {ramses_rf-0.52.5.dist-info → ramses_rf-0.53.1.dist-info}/licenses/LICENSE +1 -1
- ramses_tx/command.py +1 -1
- ramses_tx/const.py +113 -24
- ramses_tx/gateway.py +3 -1
- ramses_tx/helpers.py +1 -1
- ramses_tx/message.py +29 -16
- ramses_tx/parsers.py +2 -2
- ramses_tx/protocol.py +22 -8
- ramses_tx/protocol_fsm.py +28 -10
- ramses_tx/schemas.py +2 -2
- ramses_tx/transport.py +503 -42
- ramses_tx/version.py +1 -1
- {ramses_rf-0.52.5.dist-info → ramses_rf-0.53.1.dist-info}/WHEEL +0 -0
- {ramses_rf-0.52.5.dist-info → ramses_rf-0.53.1.dist-info}/entry_points.txt +0 -0
ramses_rf/gateway.py
CHANGED
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import asyncio
|
|
13
13
|
import logging
|
|
14
|
+
from collections.abc import Awaitable, Callable
|
|
14
15
|
from types import SimpleNamespace
|
|
15
16
|
from typing import TYPE_CHECKING, Any
|
|
16
17
|
|
|
@@ -83,7 +84,12 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
class Gateway(Engine):
|
|
86
|
-
"""The gateway class.
|
|
87
|
+
"""The gateway class.
|
|
88
|
+
|
|
89
|
+
This class serves as the primary interface for the RAMSES RF network. It manages
|
|
90
|
+
the serial connection (via ``Engine``), device discovery, schema maintenance,
|
|
91
|
+
and message dispatching.
|
|
92
|
+
"""
|
|
87
93
|
|
|
88
94
|
def __init__(
|
|
89
95
|
self,
|
|
@@ -94,8 +100,30 @@ class Gateway(Engine):
|
|
|
94
100
|
block_list: DeviceListT | None = None,
|
|
95
101
|
known_list: DeviceListT | None = None,
|
|
96
102
|
loop: asyncio.AbstractEventLoop | None = None,
|
|
103
|
+
transport_constructor: Callable[..., Awaitable[RamsesTransportT]] | None = None,
|
|
97
104
|
**kwargs: Any,
|
|
98
105
|
) -> None:
|
|
106
|
+
"""Initialize the Gateway instance.
|
|
107
|
+
|
|
108
|
+
:param port_name: The serial port name (e.g., '/dev/ttyUSB0') or None if using a file.
|
|
109
|
+
:type port_name: str | None
|
|
110
|
+
:param input_file: Path to a packet log file for playback/parsing, defaults to None.
|
|
111
|
+
:type input_file: str | None, optional
|
|
112
|
+
:param port_config: Configuration dictionary for the serial port, defaults to None.
|
|
113
|
+
:type port_config: PortConfigT | None, optional
|
|
114
|
+
:param packet_log: Configuration for packet logging, defaults to None.
|
|
115
|
+
:type packet_log: PktLogConfigT | None, optional
|
|
116
|
+
:param block_list: A list of device IDs to block/ignore, defaults to None.
|
|
117
|
+
:type block_list: DeviceListT | None, optional
|
|
118
|
+
:param known_list: A list of known device IDs and their traits, defaults to None.
|
|
119
|
+
:type known_list: DeviceListT | None, optional
|
|
120
|
+
:param loop: The asyncio event loop to use, defaults to None.
|
|
121
|
+
:type loop: asyncio.AbstractEventLoop | None, optional
|
|
122
|
+
:param transport_constructor: A factory for creating the transport layer, defaults to None.
|
|
123
|
+
:type transport_constructor: Callable[..., Awaitable[RamsesTransportT]] | None, optional
|
|
124
|
+
:param kwargs: Additional configuration parameters passed to the engine and schema.
|
|
125
|
+
:type kwargs: Any
|
|
126
|
+
"""
|
|
99
127
|
if kwargs.pop("debug_mode", None):
|
|
100
128
|
_LOGGER.setLevel(logging.DEBUG)
|
|
101
129
|
|
|
@@ -110,6 +138,7 @@ class Gateway(Engine):
|
|
|
110
138
|
block_list=block_list,
|
|
111
139
|
known_list=known_list,
|
|
112
140
|
loop=loop,
|
|
141
|
+
transport_constructor=transport_constructor,
|
|
113
142
|
**SCH_ENGINE_CONFIG(config),
|
|
114
143
|
)
|
|
115
144
|
|
|
@@ -132,13 +161,23 @@ class Gateway(Engine):
|
|
|
132
161
|
self.msg_db: MessageIndex | None = None
|
|
133
162
|
|
|
134
163
|
def __repr__(self) -> str:
|
|
164
|
+
"""Return a string representation of the Gateway.
|
|
165
|
+
|
|
166
|
+
:returns: A string describing the gateway's input source (port or file).
|
|
167
|
+
:rtype: str
|
|
168
|
+
"""
|
|
135
169
|
if not self.ser_name:
|
|
136
170
|
return f"Gateway(input_file={self._input_file})"
|
|
137
171
|
return f"Gateway(port_name={self.ser_name}, port_config={self._port_config})"
|
|
138
172
|
|
|
139
173
|
@property
|
|
140
174
|
def hgi(self) -> HgiGateway | None:
|
|
141
|
-
"""Return the active HGI80-compatible gateway device, if known.
|
|
175
|
+
"""Return the active HGI80-compatible gateway device, if known.
|
|
176
|
+
|
|
177
|
+
:returns: The gateway device instance or None if the transport is not set up
|
|
178
|
+
or the HGI ID is not found.
|
|
179
|
+
:rtype: HgiGateway | None
|
|
180
|
+
"""
|
|
142
181
|
if not self._transport:
|
|
143
182
|
return None
|
|
144
183
|
if device_id := self._transport.get_extra_info(SZ_ACTIVE_HGI):
|
|
@@ -152,10 +191,21 @@ class Gateway(Engine):
|
|
|
152
191
|
start_discovery: bool = True,
|
|
153
192
|
cached_packets: dict[str, str] | None = None,
|
|
154
193
|
) -> None:
|
|
155
|
-
"""Start the Gateway and Initiate discovery as required.
|
|
194
|
+
"""Start the Gateway and Initiate discovery as required.
|
|
195
|
+
|
|
196
|
+
This method initializes packet logging, the SQLite index, loads the schema,
|
|
197
|
+
and optionally restores state from cached packets before starting the transport.
|
|
198
|
+
|
|
199
|
+
:param start_discovery: Whether to initiate the discovery process after start, defaults to True.
|
|
200
|
+
:type start_discovery: bool, optional
|
|
201
|
+
:param cached_packets: A dictionary of packet strings used to restore state, defaults to None.
|
|
202
|
+
:type cached_packets: dict[str, str] | None, optional
|
|
203
|
+
:returns: None
|
|
204
|
+
:rtype: None
|
|
205
|
+
"""
|
|
156
206
|
|
|
157
207
|
def initiate_discovery(dev_list: list[Device], sys_list: list[Evohome]) -> None:
|
|
158
|
-
_LOGGER.debug("
|
|
208
|
+
_LOGGER.debug("Engine: Initiating/enabling discovery...")
|
|
159
209
|
|
|
160
210
|
# [d._start_discovery_poller() for d in devs]
|
|
161
211
|
for device in dev_list:
|
|
@@ -174,9 +224,10 @@ class Gateway(Engine):
|
|
|
174
224
|
)
|
|
175
225
|
|
|
176
226
|
# initialize SQLite index, set in _tx/Engine
|
|
177
|
-
if self._sqlite_index: # TODO(eb): default to
|
|
227
|
+
if self._sqlite_index: # TODO(eb): default to True in Q1 2026
|
|
178
228
|
_LOGGER.info("Ramses RF starts SQLite MessageIndex")
|
|
179
|
-
|
|
229
|
+
# if activated in ramses_cc > Engine or set in tests
|
|
230
|
+
self.create_sqlite_message_index()
|
|
180
231
|
|
|
181
232
|
# temporarily turn on discovery, remember original state
|
|
182
233
|
self.config.disable_discovery, disable_discovery = (
|
|
@@ -201,10 +252,21 @@ class Gateway(Engine):
|
|
|
201
252
|
initiate_discovery(self.devices, self.systems)
|
|
202
253
|
|
|
203
254
|
def create_sqlite_message_index(self) -> None:
|
|
255
|
+
"""Initialize the SQLite MessageIndex.
|
|
256
|
+
|
|
257
|
+
:returns: None
|
|
258
|
+
:rtype: None
|
|
259
|
+
"""
|
|
204
260
|
self.msg_db = MessageIndex() # start the index
|
|
205
261
|
|
|
206
262
|
async def stop(self) -> None:
|
|
207
|
-
"""Stop the Gateway and tidy up.
|
|
263
|
+
"""Stop the Gateway and tidy up.
|
|
264
|
+
|
|
265
|
+
Stops the message database and the underlying engine/transport.
|
|
266
|
+
|
|
267
|
+
:returns: None
|
|
268
|
+
:rtype: None
|
|
269
|
+
"""
|
|
208
270
|
|
|
209
271
|
if self.msg_db:
|
|
210
272
|
self.msg_db.stop()
|
|
@@ -214,6 +276,12 @@ class Gateway(Engine):
|
|
|
214
276
|
"""Pause the (unpaused) gateway (disables sending/discovery).
|
|
215
277
|
|
|
216
278
|
There is the option to save other objects, as `args`.
|
|
279
|
+
|
|
280
|
+
:param args: Additional objects/state to save during the pause.
|
|
281
|
+
:type args: Any
|
|
282
|
+
:returns: None
|
|
283
|
+
:rtype: None
|
|
284
|
+
:raises RuntimeError: If the engine fails to pause.
|
|
217
285
|
"""
|
|
218
286
|
_LOGGER.debug("Gateway: Pausing engine...")
|
|
219
287
|
|
|
@@ -229,6 +297,9 @@ class Gateway(Engine):
|
|
|
229
297
|
"""Resume the (paused) gateway (enables sending/discovery, if applicable).
|
|
230
298
|
|
|
231
299
|
Will restore other objects, as `args`.
|
|
300
|
+
|
|
301
|
+
:returns: A tuple of arguments saved during the pause.
|
|
302
|
+
:rtype: tuple[Any]
|
|
232
303
|
"""
|
|
233
304
|
args: tuple[Any]
|
|
234
305
|
|
|
@@ -241,7 +312,13 @@ class Gateway(Engine):
|
|
|
241
312
|
def get_state(
|
|
242
313
|
self, include_expired: bool = False
|
|
243
314
|
) -> tuple[dict[str, Any], dict[str, str]]:
|
|
244
|
-
"""Return the current schema & state (may include expired packets).
|
|
315
|
+
"""Return the current schema & state (may include expired packets).
|
|
316
|
+
|
|
317
|
+
:param include_expired: If True, include expired packets in the state, defaults to False.
|
|
318
|
+
:type include_expired: bool, optional
|
|
319
|
+
:returns: A tuple containing the schema dictionary and the packet log dictionary.
|
|
320
|
+
:rtype: tuple[dict[str, Any], dict[str, str]]
|
|
321
|
+
"""
|
|
245
322
|
|
|
246
323
|
self._pause()
|
|
247
324
|
|
|
@@ -287,10 +364,21 @@ class Gateway(Engine):
|
|
|
287
364
|
async def _restore_cached_packets(
|
|
288
365
|
self, packets: dict[str, str], _clear_state: bool = False
|
|
289
366
|
) -> None:
|
|
290
|
-
"""Restore cached packets (may include expired packets).
|
|
367
|
+
"""Restore cached packets (may include expired packets).
|
|
368
|
+
|
|
369
|
+
This process uses a temporary transport to replay the packet history
|
|
370
|
+
into the message handler.
|
|
371
|
+
|
|
372
|
+
:param packets: A dictionary of packet strings.
|
|
373
|
+
:type packets: dict[str, str]
|
|
374
|
+
:param _clear_state: If True, reset internal state before restoration (for testing), defaults to False.
|
|
375
|
+
:type _clear_state: bool, optional
|
|
376
|
+
:returns: None
|
|
377
|
+
:rtype: None
|
|
378
|
+
"""
|
|
291
379
|
|
|
292
380
|
def clear_state() -> None:
|
|
293
|
-
_LOGGER.info("
|
|
381
|
+
_LOGGER.info("Gateway: Clearing existing schema/state...")
|
|
294
382
|
|
|
295
383
|
# self._schema = {}
|
|
296
384
|
|
|
@@ -303,7 +391,7 @@ class Gateway(Engine):
|
|
|
303
391
|
|
|
304
392
|
tmp_transport: RamsesTransportT # mypy hint
|
|
305
393
|
|
|
306
|
-
_LOGGER.debug("
|
|
394
|
+
_LOGGER.debug("Gateway: Restoring a cached packet log...")
|
|
307
395
|
self._pause()
|
|
308
396
|
|
|
309
397
|
if _clear_state: # only intended for test suite use
|
|
@@ -339,11 +427,18 @@ class Gateway(Engine):
|
|
|
339
427
|
|
|
340
428
|
await tmp_transport.get_extra_info(SZ_READER_TASK)
|
|
341
429
|
|
|
342
|
-
_LOGGER.debug("
|
|
430
|
+
_LOGGER.debug("Gateway: Restored, resuming")
|
|
343
431
|
self._resume()
|
|
344
432
|
|
|
345
433
|
def _add_device(self, dev: Device) -> None: # TODO: also: _add_system()
|
|
346
|
-
"""Add a device to the gateway (called by devices during instantiation).
|
|
434
|
+
"""Add a device to the gateway (called by devices during instantiation).
|
|
435
|
+
|
|
436
|
+
:param dev: The device instance to add.
|
|
437
|
+
:type dev: Device
|
|
438
|
+
:returns: None
|
|
439
|
+
:rtype: None
|
|
440
|
+
:raises LookupError: If the device already exists in the gateway.
|
|
441
|
+
"""
|
|
347
442
|
|
|
348
443
|
if dev.id in self.device_by_id:
|
|
349
444
|
raise LookupError(f"Device already exists: {dev.id}")
|
|
@@ -366,17 +461,17 @@ class Gateway(Engine):
|
|
|
366
461
|
passes a message for it to handle. All devices have traits, but only
|
|
367
462
|
controllers (CTL, UFC) have a schema.
|
|
368
463
|
|
|
369
|
-
:param device_id: The unique identifier for the device (e.g., '01:123456')
|
|
464
|
+
:param device_id: The unique identifier for the device (e.g., '01:123456').
|
|
370
465
|
:type device_id: DeviceIdT
|
|
371
|
-
:param msg: An optional initial message for the device to process, defaults to None
|
|
372
|
-
:type msg: Message | None
|
|
373
|
-
:param parent: The parent entity of this device, if any, defaults to None
|
|
374
|
-
:type parent: Parent | None
|
|
375
|
-
:param child_id: The specific ID of the child component if applicable, defaults to None
|
|
376
|
-
:type child_id: str | None
|
|
377
|
-
:param is_sensor: Indicates if this device should be treated as a sensor, defaults to None
|
|
378
|
-
:type is_sensor: bool | None
|
|
379
|
-
:
|
|
466
|
+
:param msg: An optional initial message for the device to process, defaults to None.
|
|
467
|
+
:type msg: Message | None, optional
|
|
468
|
+
:param parent: The parent entity of this device, if any, defaults to None.
|
|
469
|
+
:type parent: Parent | None, optional
|
|
470
|
+
:param child_id: The specific ID of the child component if applicable, defaults to None.
|
|
471
|
+
:type child_id: str | None, optional
|
|
472
|
+
:param is_sensor: Indicates if this device should be treated as a sensor, defaults to None.
|
|
473
|
+
:type is_sensor: bool | None, optional
|
|
474
|
+
:returns: The existing or newly created device instance.
|
|
380
475
|
:rtype: Device
|
|
381
476
|
:raises LookupError: If the device ID is blocked or not in the allowed known_list.
|
|
382
477
|
"""
|
|
@@ -446,7 +541,21 @@ class Gateway(Engine):
|
|
|
446
541
|
device_id: DeviceIdT,
|
|
447
542
|
create_device: bool = False,
|
|
448
543
|
) -> Device | Fakeable:
|
|
449
|
-
"""Create a faked device.
|
|
544
|
+
"""Create a faked device.
|
|
545
|
+
|
|
546
|
+
Converts an existing device to a fake device, or creates a new fake device
|
|
547
|
+
if it satisfies strict criteria (valid ID, presence in known_list).
|
|
548
|
+
|
|
549
|
+
:param device_id: The ID of the device to fake.
|
|
550
|
+
:type device_id: DeviceIdT
|
|
551
|
+
:param create_device: If True, allow creation of a new device if it doesn't exist, defaults to False.
|
|
552
|
+
:type create_device: bool, optional
|
|
553
|
+
:returns: The faked device instance.
|
|
554
|
+
:rtype: Device | Fakeable
|
|
555
|
+
:raises TypeError: If the device ID is invalid or the device is not fakeable.
|
|
556
|
+
:raises LookupError: If the device does not exist and create_device is False,
|
|
557
|
+
or if create_device is True but the ID is not in known_list.
|
|
558
|
+
"""
|
|
450
559
|
|
|
451
560
|
if not is_valid_dev_id(device_id):
|
|
452
561
|
raise TypeError(f"The device id is not valid: {device_id}")
|
|
@@ -464,7 +573,11 @@ class Gateway(Engine):
|
|
|
464
573
|
|
|
465
574
|
@property
|
|
466
575
|
def tcs(self) -> Evohome | None:
|
|
467
|
-
"""Return the primary TCS, if any.
|
|
576
|
+
"""Return the primary Temperature Control System (TCS), if any.
|
|
577
|
+
|
|
578
|
+
:returns: The primary Evohome system or None.
|
|
579
|
+
:rtype: Evohome | None
|
|
580
|
+
"""
|
|
468
581
|
|
|
469
582
|
if self._tcs is None and self.systems:
|
|
470
583
|
self._tcs = self.systems[0]
|
|
@@ -477,6 +590,9 @@ class Gateway(Engine):
|
|
|
477
590
|
Unlike orphans, which are always instantiated when a schema is loaded, these
|
|
478
591
|
devices may/may not exist. However, if they are ever instantiated, they should
|
|
479
592
|
be given these traits.
|
|
593
|
+
|
|
594
|
+
:returns: A dictionary where keys are device IDs and values are their traits.
|
|
595
|
+
:rtype: DeviceListT
|
|
480
596
|
"""
|
|
481
597
|
|
|
482
598
|
result = self._include # could be devices here, not (yet) in gwy.devices
|
|
@@ -491,6 +607,11 @@ class Gateway(Engine):
|
|
|
491
607
|
|
|
492
608
|
@property
|
|
493
609
|
def system_by_id(self) -> dict[DeviceIdT, Evohome]:
|
|
610
|
+
"""Return a mapping of device IDs to their associated Evohome systems.
|
|
611
|
+
|
|
612
|
+
:returns: A dictionary mapping DeviceId to Evohome instances.
|
|
613
|
+
:rtype: dict[DeviceIdT, Evohome]
|
|
614
|
+
"""
|
|
494
615
|
return {
|
|
495
616
|
d.id: d.tcs
|
|
496
617
|
for d in self.devices
|
|
@@ -499,6 +620,11 @@ class Gateway(Engine):
|
|
|
499
620
|
|
|
500
621
|
@property
|
|
501
622
|
def systems(self) -> list[Evohome]:
|
|
623
|
+
"""Return a list of all identified Evohome systems.
|
|
624
|
+
|
|
625
|
+
:returns: A list of Evohome system instances.
|
|
626
|
+
:rtype: list[Evohome]
|
|
627
|
+
"""
|
|
502
628
|
return list(self.system_by_id.values())
|
|
503
629
|
|
|
504
630
|
@property
|
|
@@ -510,6 +636,9 @@ class Gateway(Engine):
|
|
|
510
636
|
- schema (everything else)
|
|
511
637
|
- known_list
|
|
512
638
|
- block_list
|
|
639
|
+
|
|
640
|
+
:returns: A dictionary representing the current internal configuration state.
|
|
641
|
+
:rtype: dict[str, Any]
|
|
513
642
|
"""
|
|
514
643
|
|
|
515
644
|
return {
|
|
@@ -531,6 +660,9 @@ class Gateway(Engine):
|
|
|
531
660
|
Orphans are devices that 'exist' but don't yet have a place in the schema
|
|
532
661
|
hierarchy (if ever): therefore, they are instantiated when the schema is loaded,
|
|
533
662
|
just like the other devices in the schema.
|
|
663
|
+
|
|
664
|
+
:returns: A dictionary representing the entire system schema structure.
|
|
665
|
+
:rtype: dict[str, Any]
|
|
534
666
|
"""
|
|
535
667
|
|
|
536
668
|
schema: dict[str, Any] = {SZ_MAIN_TCS: self.tcs.ctl.id if self.tcs else None}
|
|
@@ -558,10 +690,20 @@ class Gateway(Engine):
|
|
|
558
690
|
|
|
559
691
|
@property
|
|
560
692
|
def params(self) -> dict[str, Any]:
|
|
693
|
+
"""Return the parameters for all devices.
|
|
694
|
+
|
|
695
|
+
:returns: A dictionary containing parameters for every device in the gateway.
|
|
696
|
+
:rtype: dict[str, Any]
|
|
697
|
+
"""
|
|
561
698
|
return {SZ_DEVICES: {d.id: d.params for d in sorted(self.devices)}}
|
|
562
699
|
|
|
563
700
|
@property
|
|
564
701
|
def status(self) -> dict[str, Any]:
|
|
702
|
+
"""Return the status for all devices and the transport rate.
|
|
703
|
+
|
|
704
|
+
:returns: A dictionary containing device statuses and transmission rate.
|
|
705
|
+
:rtype: dict[str, Any]
|
|
706
|
+
"""
|
|
565
707
|
tx_rate = self._transport.get_extra_info("tx_rate") if self._transport else None
|
|
566
708
|
return {
|
|
567
709
|
SZ_DEVICES: {d.id: d.status for d in sorted(self.devices)},
|
|
@@ -569,7 +711,15 @@ class Gateway(Engine):
|
|
|
569
711
|
}
|
|
570
712
|
|
|
571
713
|
def _msg_handler(self, msg: Message) -> None:
|
|
572
|
-
"""A callback to handle messages from the protocol stack.
|
|
714
|
+
"""A callback to handle messages from the protocol stack.
|
|
715
|
+
|
|
716
|
+
Handles message reassembly (fragmentation) and dispatches the message for processing.
|
|
717
|
+
|
|
718
|
+
:param msg: The incoming message to handle.
|
|
719
|
+
:type msg: Message
|
|
720
|
+
:returns: None
|
|
721
|
+
:rtype: None
|
|
722
|
+
"""
|
|
573
723
|
|
|
574
724
|
super()._msg_handler(msg)
|
|
575
725
|
|
|
@@ -597,9 +747,20 @@ class Gateway(Engine):
|
|
|
597
747
|
) -> asyncio.Task[Packet]:
|
|
598
748
|
"""Wrapper to schedule an async_send_cmd() and return the Task.
|
|
599
749
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
750
|
+
:param cmd: The command object to send.
|
|
751
|
+
:type cmd: Command
|
|
752
|
+
:param gap_duration: The gap between repeats (in seconds), defaults to DEFAULT_GAP_DURATION.
|
|
753
|
+
:type gap_duration: float, optional
|
|
754
|
+
:param num_repeats: Number of times to repeat the command (0 = once, 1 = twice, etc.), defaults to DEFAULT_NUM_REPEATS.
|
|
755
|
+
:type num_repeats: int, optional
|
|
756
|
+
:param priority: The priority of the command, defaults to Priority.DEFAULT.
|
|
757
|
+
:type priority: Priority, optional
|
|
758
|
+
:param timeout: Time to wait for a send to complete, defaults to DEFAULT_SEND_TIMEOUT.
|
|
759
|
+
:type timeout: float, optional
|
|
760
|
+
:param wait_for_reply: Whether to wait for a reply packet, defaults to DEFAULT_WAIT_FOR_REPLY.
|
|
761
|
+
:type wait_for_reply: bool | None, optional
|
|
762
|
+
:returns: The asyncio Task wrapping the send operation.
|
|
763
|
+
:rtype: asyncio.Task[Packet]
|
|
603
764
|
"""
|
|
604
765
|
|
|
605
766
|
coro = self.async_send_cmd(
|
|
@@ -632,6 +793,22 @@ class Gateway(Engine):
|
|
|
632
793
|
If wait_for_reply is True (*and* the Command has a rx_header), return the
|
|
633
794
|
reply Packet. Otherwise, simply return the echo Packet.
|
|
634
795
|
|
|
796
|
+
:param cmd: The command object to send.
|
|
797
|
+
:type cmd: Command
|
|
798
|
+
:param gap_duration: The gap between repeats (in seconds), defaults to DEFAULT_GAP_DURATION.
|
|
799
|
+
:type gap_duration: float, optional
|
|
800
|
+
:param num_repeats: Number of times to repeat the command, defaults to DEFAULT_NUM_REPEATS.
|
|
801
|
+
:type num_repeats: int, optional
|
|
802
|
+
:param priority: The priority of the command, defaults to Priority.DEFAULT.
|
|
803
|
+
:type priority: Priority, optional
|
|
804
|
+
:param max_retries: Maximum number of retries if sending fails, defaults to DEFAULT_MAX_RETRIES.
|
|
805
|
+
:type max_retries: int, optional
|
|
806
|
+
:param timeout: Time to wait for the command to send, defaults to DEFAULT_SEND_TIMEOUT.
|
|
807
|
+
:type timeout: float, optional
|
|
808
|
+
:param wait_for_reply: Whether to wait for a reply packet, defaults to DEFAULT_WAIT_FOR_REPLY.
|
|
809
|
+
:type wait_for_reply: bool | None, optional
|
|
810
|
+
:returns: The echo packet or reply packet depending on wait_for_reply.
|
|
811
|
+
:rtype: Packet
|
|
635
812
|
:raises ProtocolSendFailed: If the command was sent but no reply/echo was received.
|
|
636
813
|
:raises ProtocolError: If the system failed to attempt the transmission.
|
|
637
814
|
"""
|
ramses_rf/schemas.py
CHANGED
|
@@ -237,6 +237,7 @@ SCH_GLOBAL_SCHEMAS_DICT = { # System schemas - can be 0-many Heat/HVAC schemas
|
|
|
237
237
|
vol.Optional(SCH_DEVICE_ID_ANY): SCH_VCS, # must be after SCH_DEVICE_ID_CTL
|
|
238
238
|
vol.Optional(SZ_ORPHANS_HEAT): vol.All([SCH_DEVICE_ID_ANY], vol.Unique()),
|
|
239
239
|
vol.Optional(SZ_ORPHANS_HVAC): vol.All([SCH_DEVICE_ID_ANY], vol.Unique()),
|
|
240
|
+
vol.Optional("transport_constructor"): vol.Any(callable, None),
|
|
240
241
|
}
|
|
241
242
|
SCH_GLOBAL_SCHEMAS = vol.Schema(SCH_GLOBAL_SCHEMAS_DICT, extra=vol.PREVENT_EXTRA)
|
|
242
243
|
|
ramses_rf/system/zones.py
CHANGED
|
@@ -689,7 +689,7 @@ class Zone(ZoneSchedule):
|
|
|
689
689
|
|
|
690
690
|
@property
|
|
691
691
|
def heating_type(self) -> str | None:
|
|
692
|
-
"""
|
|
692
|
+
"""Get the type of the zone/DHW (e.g. electric_zone, stored_dhw)."""
|
|
693
693
|
|
|
694
694
|
if self._SLUG is None: # isinstance(self, ???)
|
|
695
695
|
return None
|
|
@@ -697,12 +697,13 @@ class Zone(ZoneSchedule):
|
|
|
697
697
|
|
|
698
698
|
@property
|
|
699
699
|
def name(self) -> str | None: # 0004
|
|
700
|
-
"""
|
|
700
|
+
"""Get the name of the zone."""
|
|
701
701
|
|
|
702
702
|
if self._gwy.msg_db:
|
|
703
703
|
msgs = self._gwy.msg_db.get(
|
|
704
704
|
code=Code._0004, src=self._z_id, ctx=self._z_idx
|
|
705
705
|
)
|
|
706
|
+
_LOGGER.debug(f"Pick Zone.name from: {msgs}[0])") # DEBUG issue #317
|
|
706
707
|
return msgs[0].payload.get(SZ_NAME) if msgs else None
|
|
707
708
|
|
|
708
709
|
return self._msg_value(Code._0004, key=SZ_NAME) # type: ignore[no-any-return]
|
ramses_rf/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ramses_rf
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.53.1
|
|
4
4
|
Summary: A stateful RAMSES-II protocol decoder & analyser.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ramses-rf/ramses_rf
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ramses-rf/ramses_rf/issues
|
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
ramses_cli/__init__.py,sha256=
|
|
2
|
-
ramses_cli/client.py,sha256=
|
|
1
|
+
ramses_cli/__init__.py,sha256=d_3uIFkK8JnWOxknrBloKCe6-vI9Ouo_KGqR4kfBQW8,417
|
|
2
|
+
ramses_cli/client.py,sha256=Fd6hXGBvI-i89Xu8QbBU9NW-dWlQjSer-_LYAtvJPW4,25055
|
|
3
3
|
ramses_cli/debug.py,sha256=PLcz-3PjUiMVqtD_p6VqTA92eHUM58lOBFXh_qgQ_wA,576
|
|
4
|
-
ramses_cli/discovery.py,sha256=
|
|
4
|
+
ramses_cli/discovery.py,sha256=WTcoFH5hNhQ1AeOZtpdZIVYwdUfmUKlq2iBpa-KcgoI,12512
|
|
5
|
+
ramses_cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
6
|
ramses_cli/utils/cat_slow.py,sha256=AhUpM5gnegCitNKU-JGHn-DrRzSi-49ZR1Qw6lxe_t8,607
|
|
6
7
|
ramses_cli/utils/convert.py,sha256=N3LxGe3_0pclijtmYW-ChqCuPTzbkoJA4XNAnoSnBk0,1806
|
|
7
|
-
ramses_rf/__init__.py,sha256=
|
|
8
|
+
ramses_rf/__init__.py,sha256=AXsCK1Eh9FWeAI9D_zY_2KB0dqrTb9a5TNY1NvyQaDM,1271
|
|
8
9
|
ramses_rf/binding_fsm.py,sha256=fuqvcc9YW-wr8SPH8zadpPqrHAvzl_eeWF-IBtlLppY,26632
|
|
9
10
|
ramses_rf/const.py,sha256=L3z31CZ-xqno6oZp_h-67CB_5tDDqTwSWXsqRtsjMcs,5460
|
|
10
|
-
ramses_rf/database.py,sha256=
|
|
11
|
+
ramses_rf/database.py,sha256=AHXIx5pO0qgiHbBQxLBegnk0e1M4SFwD9Spd4eyW_eQ,21428
|
|
11
12
|
ramses_rf/dispatcher.py,sha256=YjEU-QrBLo9IfoEhJo2ikg_FxOaMYoWvzelr9Vi-JZ8,11398
|
|
12
|
-
ramses_rf/entity_base.py,sha256=
|
|
13
|
+
ramses_rf/entity_base.py,sha256=L47P_6CRz3tLDzOzII9AgmueKDb-Bp7Ot3vVsr8jo10,59121
|
|
13
14
|
ramses_rf/exceptions.py,sha256=mt_T7irqHSDKir6KLaf6oDglUIdrw0S40JbOrWJk5jc,3657
|
|
14
|
-
ramses_rf/gateway.py,sha256=
|
|
15
|
+
ramses_rf/gateway.py,sha256=hHsXbpeZ2Fetpu3jzv8UeUwlNf4rsxOD7eOHuLY83Xk,30101
|
|
15
16
|
ramses_rf/helpers.py,sha256=TNk_QkpIOB3alOp1sqnA9LOzi4fuDCeapNlW3zTzNas,4250
|
|
16
17
|
ramses_rf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
ramses_rf/schemas.py,sha256=
|
|
18
|
-
ramses_rf/version.py,sha256=
|
|
18
|
+
ramses_rf/schemas.py,sha256=X1GAK3kttuLMiSCUDY2s-85fgBxPeU8xiDa6gJ1I5mY,13543
|
|
19
|
+
ramses_rf/version.py,sha256=yMI3sQ8wyLuGx_Hm7ZYNuwbqFZ3Qhr3GJXdkdsGwh7s,125
|
|
19
20
|
ramses_rf/device/__init__.py,sha256=sUbH5dhbYFXSoM_TPFRutpRutBRpup7_cQ9smPtDTy8,4858
|
|
20
21
|
ramses_rf/device/base.py,sha256=Tu5I8Lj7KplfRsIBQAYjilS6YPgTyjpU8qgKugMR2Jk,18281
|
|
21
|
-
ramses_rf/device/heat.py,sha256=
|
|
22
|
+
ramses_rf/device/heat.py,sha256=CU6GlIgjuYD21braJ_RJlS56zP47TGXNxXnZeavfEMY,54654
|
|
22
23
|
ramses_rf/device/hvac.py,sha256=vdgiPiLtCAGr7CVsGhQl6XuAFkyYdQSE_2AEdCmRl2I,48502
|
|
23
24
|
ramses_rf/system/__init__.py,sha256=uZLKio3gLlBzePa2aDQ1nxkcp1YXOGrn6iHTG8LiNIw,711
|
|
24
25
|
ramses_rf/system/faultlog.py,sha256=GdGmVGT3137KsTlV_nhccgIFEmYu6DFsLTn4S-8JSok,12799
|
|
25
26
|
ramses_rf/system/heat.py,sha256=qQmzgmyHy2x87gHAstn0ee7ZVVOq-GJIfDxCrC-6gFU,39254
|
|
26
27
|
ramses_rf/system/schedule.py,sha256=Ts6tdZPTQLV5NkgwA73tPa5QUsnZNIIuYoKC-8VsXDk,18808
|
|
27
|
-
ramses_rf/system/zones.py,sha256=
|
|
28
|
+
ramses_rf/system/zones.py,sha256=6VbPsOuNbGwBUuiRu8w9D1Q18SHKkuZa2YtKTE5nqlo,37110
|
|
28
29
|
ramses_tx/__init__.py,sha256=sqnjM7pUGJDmec6igTtKViSB8FLX49B5gwhAmcY9ERY,3596
|
|
29
30
|
ramses_tx/address.py,sha256=IuwUwZxykn3fP1UCRcv4D-zbTICBe2FJjDAFX5X6VoI,9108
|
|
30
|
-
ramses_tx/command.py,sha256=
|
|
31
|
-
ramses_tx/const.py,sha256=
|
|
31
|
+
ramses_tx/command.py,sha256=drxmpdM4YgyPg4h0QIr1ouxK9QjfeLVgnFpDRox0CCY,125652
|
|
32
|
+
ramses_tx/const.py,sha256=jiE2UaGBJ5agr68EMrcEHWtVz2KMidU7c7rRYCIiaoM,33010
|
|
32
33
|
ramses_tx/exceptions.py,sha256=FJSU9YkvpKjs3yeTqUJX1o3TPFSe_B01gRGIh9b3PNc,2632
|
|
33
34
|
ramses_tx/fingerprints.py,sha256=nfftA1E62HQnb-eLt2EqjEi_la0DAoT0wt-PtTMie0s,11974
|
|
34
35
|
ramses_tx/frame.py,sha256=GzNsXr15YLeidJYGtk_xPqsZQh4ehDDlUCtT6rTDhT8,22046
|
|
35
|
-
ramses_tx/gateway.py,sha256=
|
|
36
|
-
ramses_tx/helpers.py,sha256=
|
|
36
|
+
ramses_tx/gateway.py,sha256=H4JtIkp7JFMyZZ76sij67rTbjc1i3iWaIf6tuxIpHAg,11529
|
|
37
|
+
ramses_tx/helpers.py,sha256=96OvSOWYuMcr89_c-3dRnqHZaMOctCO94uo1hETh3bc,33613
|
|
37
38
|
ramses_tx/logger.py,sha256=1iKRHKUaqHqGd76CkE_6mCVR0sYODtxshRRwfY61fTk,10426
|
|
38
|
-
ramses_tx/message.py,sha256=
|
|
39
|
+
ramses_tx/message.py,sha256=zsyDQztSUYeqj3-P598LSmy9ODQY2BUCzWxSoZds6bM,13953
|
|
39
40
|
ramses_tx/opentherm.py,sha256=58PXz9l5x8Ou6Fm3y-R_UnGHCYahoi2RKIDdYStUMzk,42378
|
|
40
41
|
ramses_tx/packet.py,sha256=_nzuInS_WhdOI26SYvgsdDqIaDvVNguc2YDwdPOVCbU,7661
|
|
41
|
-
ramses_tx/parsers.py,sha256=
|
|
42
|
-
ramses_tx/protocol.py,sha256=
|
|
43
|
-
ramses_tx/protocol_fsm.py,sha256=
|
|
42
|
+
ramses_tx/parsers.py,sha256=vHaVdapzW9TtQhCjR9XuaLLkp5ZMXKmTm05zbu0ekW0,148576
|
|
43
|
+
ramses_tx/protocol.py,sha256=nBPKCD1tcGp_FiX0qhsY0XoGO_h87w5cYywBjSpum4w,33048
|
|
44
|
+
ramses_tx/protocol_fsm.py,sha256=o9vLvlXor3LkPgsY1zii5P1R01GzYLf_PECDdoxtC24,27520
|
|
44
45
|
ramses_tx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
46
|
ramses_tx/ramses.py,sha256=vp748Tf_a-56OMM8CWDA2ZktRfTuj0QVyPRcnsOstSM,53983
|
|
46
|
-
ramses_tx/schemas.py,sha256=
|
|
47
|
-
ramses_tx/transport.py,sha256
|
|
47
|
+
ramses_tx/schemas.py,sha256=Hrmf_q9bAZtkKJzGu6GtUO0QV_-K9i4L99EzGWR13eE,13408
|
|
48
|
+
ramses_tx/transport.py,sha256=hktWSDOzKUME967w58JB4z3MgmCMiQ0QZI0x4-Awaas,76419
|
|
48
49
|
ramses_tx/typed_dicts.py,sha256=w-0V5t2Q3GiNUOrRAWiW9GtSwbta_7luME6GfIb1zhI,10869
|
|
49
50
|
ramses_tx/typing.py,sha256=eF2SlPWhNhEFQj6WX2AhTXiyRQVXYnFutiepllYl2rI,5042
|
|
50
|
-
ramses_tx/version.py,sha256=
|
|
51
|
-
ramses_rf-0.
|
|
52
|
-
ramses_rf-0.
|
|
53
|
-
ramses_rf-0.
|
|
54
|
-
ramses_rf-0.
|
|
55
|
-
ramses_rf-0.
|
|
51
|
+
ramses_tx/version.py,sha256=g3EPkHx--jzBHNq9oau7n6DOcVjdbcDWz5m13ZpzvEQ,123
|
|
52
|
+
ramses_rf-0.53.1.dist-info/METADATA,sha256=OC2EXqy23YPE-jCqrXSdLM4cN5_7a9M3fBWh15r3kqg,4179
|
|
53
|
+
ramses_rf-0.53.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
54
|
+
ramses_rf-0.53.1.dist-info/entry_points.txt,sha256=NnyK29baOCNg8DinPYiZ368h7MTH7bgTW26z2A1NeIE,50
|
|
55
|
+
ramses_rf-0.53.1.dist-info/licenses/LICENSE,sha256=ptVutrtSMr7X-ek6LduiD8Cce4JsNn_8sR8MYlm-fvo,1086
|
|
56
|
+
ramses_rf-0.53.1.dist-info/RECORD,,
|
ramses_tx/command.py
CHANGED
|
@@ -1866,7 +1866,7 @@ class Command(Frame):
|
|
|
1866
1866
|
The actual number of available zones depends on the controller configuration.
|
|
1867
1867
|
Requesting a non-existent zone will typically result in no response.
|
|
1868
1868
|
"""
|
|
1869
|
-
return cls.from_attrs(
|
|
1869
|
+
return cls.from_attrs(RQ, ctl_id, Code._2309, _check_idx(zone_idx))
|
|
1870
1870
|
|
|
1871
1871
|
@classmethod # constructor for W|2309
|
|
1872
1872
|
def set_zone_setpoint(
|