ramses-rf 0.52.1__py3-none-any.whl → 0.52.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.
- ramses_rf/__init__.py +1 -0
- ramses_rf/binding_fsm.py +18 -4
- ramses_rf/database.py +57 -39
- ramses_rf/device/heat.py +4 -6
- ramses_rf/device/hvac.py +116 -56
- ramses_rf/dispatcher.py +9 -4
- ramses_rf/entity_base.py +133 -66
- ramses_rf/gateway.py +2 -2
- ramses_rf/schemas.py +1 -1
- ramses_rf/system/zones.py +1 -1
- ramses_rf/version.py +1 -1
- {ramses_rf-0.52.1.dist-info → ramses_rf-0.52.3.dist-info}/METADATA +1 -1
- {ramses_rf-0.52.1.dist-info → ramses_rf-0.52.3.dist-info}/RECORD +24 -24
- ramses_tx/__init__.py +3 -1
- ramses_tx/command.py +6 -5
- ramses_tx/gateway.py +3 -0
- ramses_tx/logger.py +8 -0
- ramses_tx/parsers.py +41 -37
- ramses_tx/schemas.py +28 -15
- ramses_tx/transport.py +45 -25
- ramses_tx/version.py +1 -1
- {ramses_rf-0.52.1.dist-info → ramses_rf-0.52.3.dist-info}/WHEEL +0 -0
- {ramses_rf-0.52.1.dist-info → ramses_rf-0.52.3.dist-info}/entry_points.txt +0 -0
- {ramses_rf-0.52.1.dist-info → ramses_rf-0.52.3.dist-info}/licenses/LICENSE +0 -0
ramses_tx/parsers.py
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
NOTES: aspirations on a consistent Schema, going forward:
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
mode (
|
|
8
|
-
|
|
6
|
+
============== ======== =================================== ========================
|
|
7
|
+
:mode/state: :bool: :mutex (infinitive. vs -ing): :flags:
|
|
8
|
+
mode (config.) enabled disabled, heat, cool, heat_cool... ch_enabled, dhw_enabled
|
|
9
|
+
state (action) active idle, heating, cooling... is_heating, is_cooling
|
|
10
|
+
============== ======== =================================== ========================
|
|
9
11
|
|
|
10
12
|
- prefer: enabled: True over xx_enabled: True (if only ever 1 flag)
|
|
11
13
|
- prefer: active: True over is_heating: True (if only ever 1 flag)
|
|
@@ -362,8 +364,9 @@ def parser_0009(payload: str, msg: Message) -> dict | list[dict]: # TODO: only
|
|
|
362
364
|
|
|
363
365
|
The failsafe mode defines the relay behaviour if the RF communication is lost (e.g.
|
|
364
366
|
when a room thermostat stops communicating due to discharged batteries):
|
|
365
|
-
|
|
366
|
-
|
|
367
|
+
|
|
368
|
+
- False (disabled) - if RF comms are lost, relay will be held in OFF position
|
|
369
|
+
- True (enabled) - if RF comms are lost, relay will cycle at 20% ON, 80% OFF
|
|
367
370
|
|
|
368
371
|
This setting may need to be enabled to ensure frost protect mode.
|
|
369
372
|
"""
|
|
@@ -2289,45 +2292,46 @@ def parser_31da(payload: str, msg: Message) -> PayDictT._31DA:
|
|
|
2289
2292
|
def parser_31e0(payload: str, msg: Message) -> dict | list[dict]: # TODO: only dict
|
|
2290
2293
|
"""Notes are.
|
|
2291
2294
|
|
|
2292
|
-
van means
|
|
2295
|
+
"van" means "of".
|
|
2293
2296
|
- 0 = min. van min. potm would be:
|
|
2294
2297
|
- 0 = minimum of minimum potentiometer
|
|
2295
2298
|
|
|
2296
2299
|
See: https://www.industrialcontrolsonline.com/honeywell-t991a
|
|
2297
2300
|
- modulates air temperatures in ducts
|
|
2298
|
-
|
|
2299
|
-
case 0x31E0: ' 12768:
|
|
2300
|
-
{
|
|
2301
|
-
string str4;
|
|
2302
|
-
unchecked
|
|
2303
|
-
{
|
|
2304
|
-
result.Fan = Conversions.ToString((double)(int)data[checked(start + 1)] / 2.0);
|
|
2305
|
-
str4 = "";
|
|
2306
|
-
}
|
|
2307
|
-
str4 = (data[start + 2] & 0xF) switch
|
|
2308
|
-
{
|
|
2309
|
-
0 => str4 + "0 = min. potm. ",
|
|
2310
|
-
1 => str4 + "0 = min. van min. potm ",
|
|
2311
|
-
2 => str4 + "0 = min. fan ",
|
|
2312
|
-
_ => "",
|
|
2313
|
-
};
|
|
2314
|
-
switch (data[start + 2] & 0xF0)
|
|
2315
|
-
{
|
|
2316
|
-
case 16:
|
|
2317
|
-
str4 += "100 = max. potm";
|
|
2318
|
-
break;
|
|
2319
|
-
case 32:
|
|
2320
|
-
str4 += "100 = max. van max. potm ";
|
|
2321
|
-
break;
|
|
2322
|
-
case 48:
|
|
2323
|
-
str4 += "100 = max. fan ";
|
|
2324
|
-
break;
|
|
2325
|
-
}
|
|
2326
|
-
result.Data = str4;
|
|
2327
|
-
break;
|
|
2328
|
-
}
|
|
2329
2301
|
"""
|
|
2330
2302
|
|
|
2303
|
+
# coding note:
|
|
2304
|
+
# case 0x31E0: ' 12768:
|
|
2305
|
+
# {
|
|
2306
|
+
# string str4;
|
|
2307
|
+
# unchecked
|
|
2308
|
+
# {
|
|
2309
|
+
# result.Fan = Conversions.ToString((double)(int)data[checked(start + 1)] / 2.0);
|
|
2310
|
+
# str4 = "";
|
|
2311
|
+
# }
|
|
2312
|
+
# str4 = (data[start + 2] & 0xF) switch
|
|
2313
|
+
# {
|
|
2314
|
+
# 0 => str4 + "0 = min. potm. ",
|
|
2315
|
+
# 1 => str4 + "0 = min. van min. potm ",
|
|
2316
|
+
# 2 => str4 + "0 = min. fan ",
|
|
2317
|
+
# _ => "",
|
|
2318
|
+
# };
|
|
2319
|
+
# switch (data[start + 2] & 0xF0)
|
|
2320
|
+
# {
|
|
2321
|
+
# case 16:
|
|
2322
|
+
# str4 += "100 = max. potm";
|
|
2323
|
+
# break;
|
|
2324
|
+
# case 32:
|
|
2325
|
+
# str4 += "100 = max. van max. potm ";
|
|
2326
|
+
# break;
|
|
2327
|
+
# case 48:
|
|
2328
|
+
# str4 += "100 = max. fan ";
|
|
2329
|
+
# break;
|
|
2330
|
+
# }
|
|
2331
|
+
# result.Data = str4;
|
|
2332
|
+
# break;
|
|
2333
|
+
# }
|
|
2334
|
+
|
|
2331
2335
|
# .I --- 37:005302 32:132403 --:------ 31E0 008 00-0000-00 01-0064-00 # RF15 CO2 to Orcon HRC400 series SmartComfort Valve
|
|
2332
2336
|
|
|
2333
2337
|
# .I --- 29:146052 32:023459 --:------ 31E0 003 00-0000
|
ramses_tx/schemas.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""RAMSES RF - a RAMSES-II protocol decoder & analyser.
|
|
3
3
|
|
|
4
|
-
Schema processor for protocol (lower) layer.
|
|
4
|
+
:term:`Schema` processor for protocol (lower) layer.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
@@ -73,13 +73,17 @@ class PktLogConfigT(TypedDict):
|
|
|
73
73
|
def sch_packet_log_dict_factory(
|
|
74
74
|
default_backups: int = 0,
|
|
75
75
|
) -> dict[vol.Required, vol.Any]:
|
|
76
|
-
"""
|
|
76
|
+
"""
|
|
77
|
+
:return: a packet log dict with a configurable default rotation policy.
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Usage:
|
|
80
|
+
|
|
81
|
+
.. code-block::
|
|
82
|
+
|
|
83
|
+
SCH_PACKET_LOG_7 = vol.Schema(
|
|
84
|
+
packet_log_dict_factory(default_backups=7), extra=vol.PREVENT_EXTRA
|
|
85
|
+
)
|
|
79
86
|
|
|
80
|
-
SCH_PACKET_LOG_7 = vol.Schema(
|
|
81
|
-
packet_log_dict_factory(default_backups=7), extra=vol.PREVENT_EXTRA
|
|
82
|
-
)
|
|
83
87
|
"""
|
|
84
88
|
|
|
85
89
|
SCH_PACKET_LOG_CONFIG = vol.Schema(
|
|
@@ -162,11 +166,13 @@ class PortConfigT(TypedDict):
|
|
|
162
166
|
def sch_serial_port_dict_factory() -> dict[vol.Required, vol.Any]:
|
|
163
167
|
"""Return a serial port dict.
|
|
164
168
|
|
|
165
|
-
|
|
169
|
+
Usage:
|
|
166
170
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
171
|
+
.. code-block::
|
|
172
|
+
|
|
173
|
+
SCH_SERIAL_PORT = vol.Schema(
|
|
174
|
+
sch_serial_port_dict_factory(), extra=vol.PREVENT_EXTRA
|
|
175
|
+
)
|
|
170
176
|
"""
|
|
171
177
|
|
|
172
178
|
SCH_SERIAL_PORT_NAME = str
|
|
@@ -252,11 +258,13 @@ def sch_global_traits_dict_factory(
|
|
|
252
258
|
) -> tuple[dict[vol.Optional, vol.Any], vol.Any]:
|
|
253
259
|
"""Return a global traits dict with a configurable extra traits.
|
|
254
260
|
|
|
255
|
-
|
|
261
|
+
Usage:
|
|
256
262
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
263
|
+
.. code-block::
|
|
264
|
+
|
|
265
|
+
SCH_GLOBAL_TRAITS = vol.Schema(
|
|
266
|
+
sch_global_traits_dict(heat=traits), extra=vol.PREVENT_EXTRA
|
|
267
|
+
)
|
|
260
268
|
"""
|
|
261
269
|
|
|
262
270
|
heat_traits = heat_traits or {}
|
|
@@ -348,7 +356,8 @@ def select_device_filter_mode(
|
|
|
348
356
|
known_list: DeviceListT,
|
|
349
357
|
block_list: DeviceListT,
|
|
350
358
|
) -> bool:
|
|
351
|
-
"""
|
|
359
|
+
"""
|
|
360
|
+
Determine which device filter to use, if any.
|
|
352
361
|
|
|
353
362
|
Either:
|
|
354
363
|
- block if device_id in block_list (could be empty), otherwise
|
|
@@ -404,6 +413,7 @@ SZ_EVOFW_FLAG: Final = "evofw_flag"
|
|
|
404
413
|
SZ_SQLITE_INDEX: Final = (
|
|
405
414
|
"sqlite_index" # temporary 0.52.x SQLite dev config option in ramses_cc
|
|
406
415
|
)
|
|
416
|
+
SZ_LOG_ALL_MQTT: Final = "log_all_mqtt"
|
|
407
417
|
SZ_USE_REGEX: Final = "use_regex"
|
|
408
418
|
|
|
409
419
|
SCH_ENGINE_DICT = {
|
|
@@ -418,6 +428,9 @@ SCH_ENGINE_DICT = {
|
|
|
418
428
|
vol.Optional(
|
|
419
429
|
SZ_SQLITE_INDEX, default=False
|
|
420
430
|
): bool, # temporary 0.52.x dev config option
|
|
431
|
+
vol.Optional(
|
|
432
|
+
SZ_LOG_ALL_MQTT, default=False
|
|
433
|
+
): bool, # log all incoming MQTT traffic config option
|
|
421
434
|
vol.Optional(SZ_USE_REGEX): dict, # vol.All(ConvertNullToDict(), dict),
|
|
422
435
|
vol.Optional(SZ_COMMS_PARAMS): SCH_COMMS_PARAMS,
|
|
423
436
|
}
|
ramses_tx/transport.py
CHANGED
|
@@ -3,30 +3,38 @@
|
|
|
3
3
|
|
|
4
4
|
Operates at the pkt layer of: app - msg - pkt - h/w
|
|
5
5
|
|
|
6
|
-
For ser2net, use the following YAML with: ser2net -c misc/ser2net.yaml
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
For ser2net, use the following YAML with: ``ser2net -c misc/ser2net.yaml``
|
|
7
|
+
|
|
8
|
+
.. code-block::
|
|
9
|
+
|
|
10
|
+
connection: &con00
|
|
11
|
+
accepter: telnet(rfc2217),tcp,5001
|
|
12
|
+
timeout: 0
|
|
13
|
+
connector: serialdev,/dev/ttyUSB0,115200n81,local
|
|
14
|
+
options:
|
|
15
|
+
max-connections: 3
|
|
16
|
+
|
|
17
|
+
For ``socat``, see:
|
|
18
|
+
|
|
19
|
+
.. code-block::
|
|
20
|
+
|
|
21
|
+
socat -dd pty,raw,echo=0 pty,raw,echo=0
|
|
22
|
+
python client.py monitor /dev/pts/0
|
|
23
|
+
cat packet.log | cut -d ' ' -f 2- | unix2dos > /dev/pts/1
|
|
18
24
|
|
|
19
25
|
For re-flashing evofw3 via Arduino IDE on *my* atmega328p (YMMV):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
|
|
27
|
+
- Board: atmega328p (SW UART)
|
|
28
|
+
- Bootloader: Old Bootloader
|
|
29
|
+
- Processor: atmega328p (5V, 16 MHz)
|
|
30
|
+
- Host: 57600 (or 115200, YMMV)
|
|
31
|
+
- Pinout: Nano
|
|
25
32
|
|
|
26
33
|
For re-flashing evofw3 via Arduino IDE on *my* atmega32u4 (YMMV):
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
|
|
35
|
+
- Board: atmega32u4 (HW UART)
|
|
36
|
+
- Processor: atmega32u4 (5V, 16 MHz)
|
|
37
|
+
- Pinout: Pro Micro
|
|
30
38
|
"""
|
|
31
39
|
|
|
32
40
|
from __future__ import annotations
|
|
@@ -250,11 +258,12 @@ async def is_hgi80(serial_port: SerPortNameT) -> bool | None:
|
|
|
250
258
|
|
|
251
259
|
|
|
252
260
|
def _normalise(pkt_line: str) -> str:
|
|
253
|
-
"""
|
|
261
|
+
"""
|
|
262
|
+
Perform any (transparent) frame-level hacks, as required at (near-)RF layer.
|
|
254
263
|
|
|
255
264
|
Goals:
|
|
256
265
|
- ensure an evofw3 provides the same output as a HGI80 (none, presently)
|
|
257
|
-
- handle 'strange' packets (e.g. I|08:|0008)
|
|
266
|
+
- handle 'strange' packets (e.g. ``I|08:|0008``)
|
|
258
267
|
"""
|
|
259
268
|
|
|
260
269
|
# TODO: deprecate as only for ramses_esp <0.4.0
|
|
@@ -1015,6 +1024,7 @@ class PortTransport(_RegHackMixin, _FullTransport, _PortTransportAbstractor): #
|
|
|
1015
1024
|
|
|
1016
1025
|
class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
1017
1026
|
"""Send/receive packets to/from ramses_esp via MQTT.
|
|
1027
|
+
For full RX logging, turn on debug logging.
|
|
1018
1028
|
|
|
1019
1029
|
See: https://github.com/IndaloTech/ramses_esp
|
|
1020
1030
|
"""
|
|
@@ -1057,6 +1067,9 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1057
1067
|
self._max_tokens: float = self._MAX_TOKENS * 2 # allow for the initial burst
|
|
1058
1068
|
self._num_tokens: float = self._MAX_TOKENS * 2
|
|
1059
1069
|
|
|
1070
|
+
# set log MQTT flag
|
|
1071
|
+
self._log_all = kwargs.pop("log_all", False)
|
|
1072
|
+
|
|
1060
1073
|
# instantiate a paho mqtt client
|
|
1061
1074
|
self.client = mqtt.Client(
|
|
1062
1075
|
protocol=mqtt.MQTTv5, callback_api_version=CallbackAPIVersion.VERSION2
|
|
@@ -1274,8 +1287,9 @@ class MqttTransport(_FullTransport, _MqttTransportAbstractor):
|
|
|
1274
1287
|
|
|
1275
1288
|
if _DBG_FORCE_FRAME_LOGGING:
|
|
1276
1289
|
_LOGGER.warning("Rx: %s", msg.payload)
|
|
1277
|
-
elif _LOGGER.getEffectiveLevel() == logging.INFO:
|
|
1278
|
-
|
|
1290
|
+
elif self._log_all and _LOGGER.getEffectiveLevel() == logging.INFO:
|
|
1291
|
+
# log for INFO not DEBUG
|
|
1292
|
+
_LOGGER.info("mq Rx: %s", msg.payload) # TODO remove mq marker?
|
|
1279
1293
|
|
|
1280
1294
|
if msg.topic[-3:] != "/rx": # then, e.g. 'RAMSES/GATEWAY/18:017804'
|
|
1281
1295
|
if msg.payload == b"offline":
|
|
@@ -1498,6 +1512,7 @@ async def transport_factory(
|
|
|
1498
1512
|
disable_sending: bool | None = False,
|
|
1499
1513
|
extra: dict[str, Any] | None = None,
|
|
1500
1514
|
loop: asyncio.AbstractEventLoop | None = None,
|
|
1515
|
+
log_all: bool = False,
|
|
1501
1516
|
**kwargs: Any, # HACK: odd/misc params
|
|
1502
1517
|
) -> RamsesTransportT:
|
|
1503
1518
|
"""Create and return a Ramses-specific async packet Transport."""
|
|
@@ -1549,19 +1564,24 @@ async def transport_factory(
|
|
|
1549
1564
|
"Packet source must be exactly one of: packet_dict, packet_log, port_name"
|
|
1550
1565
|
)
|
|
1551
1566
|
|
|
1567
|
+
# File
|
|
1552
1568
|
if (pkt_source := packet_log or packet_dict) is not None:
|
|
1553
1569
|
return FileTransport(pkt_source, protocol, extra=extra, loop=loop, **kwargs)
|
|
1554
1570
|
|
|
1555
1571
|
assert port_name is not None # mypy check
|
|
1556
1572
|
assert port_config is not None # mypy check
|
|
1557
1573
|
|
|
1574
|
+
# MQTT
|
|
1558
1575
|
if port_name[:4] == "mqtt": # TODO: handle disable_sending
|
|
1559
|
-
transport = MqttTransport(
|
|
1576
|
+
transport = MqttTransport(
|
|
1577
|
+
port_name, protocol, extra=extra, loop=loop, log_all=log_all, **kwargs
|
|
1578
|
+
)
|
|
1560
1579
|
|
|
1561
1580
|
# TODO: remove this? better to invoke timeout after factory returns?
|
|
1562
1581
|
await protocol.wait_for_connection_made(timeout=_DEFAULT_TIMEOUT_MQTT)
|
|
1563
1582
|
return transport
|
|
1564
1583
|
|
|
1584
|
+
# Serial
|
|
1565
1585
|
ser_instance = get_serial_instance(port_name, port_config)
|
|
1566
1586
|
|
|
1567
1587
|
if os.name == "nt" or ser_instance.portstr[:7] in ("rfc2217", "socket:"):
|
ramses_tx/version.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|