ramses-rf 0.22.2__py3-none-any.whl → 0.51.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 +18 -0
- ramses_cli/client.py +597 -0
- ramses_cli/debug.py +20 -0
- ramses_cli/discovery.py +405 -0
- ramses_cli/utils/cat_slow.py +17 -0
- ramses_cli/utils/convert.py +60 -0
- ramses_rf/__init__.py +31 -10
- ramses_rf/binding_fsm.py +787 -0
- ramses_rf/const.py +124 -105
- ramses_rf/database.py +297 -0
- ramses_rf/device/__init__.py +69 -39
- ramses_rf/device/base.py +187 -376
- ramses_rf/device/heat.py +540 -552
- ramses_rf/device/hvac.py +286 -171
- ramses_rf/dispatcher.py +153 -177
- ramses_rf/entity_base.py +478 -361
- ramses_rf/exceptions.py +82 -0
- ramses_rf/gateway.py +378 -514
- ramses_rf/helpers.py +57 -19
- ramses_rf/py.typed +0 -0
- ramses_rf/schemas.py +148 -194
- ramses_rf/system/__init__.py +16 -23
- ramses_rf/system/faultlog.py +363 -0
- ramses_rf/system/heat.py +295 -302
- ramses_rf/system/schedule.py +312 -198
- ramses_rf/system/zones.py +318 -238
- ramses_rf/version.py +2 -8
- ramses_rf-0.51.1.dist-info/METADATA +72 -0
- ramses_rf-0.51.1.dist-info/RECORD +55 -0
- {ramses_rf-0.22.2.dist-info → ramses_rf-0.51.1.dist-info}/WHEEL +1 -2
- ramses_rf-0.51.1.dist-info/entry_points.txt +2 -0
- {ramses_rf-0.22.2.dist-info → ramses_rf-0.51.1.dist-info/licenses}/LICENSE +1 -1
- ramses_tx/__init__.py +160 -0
- {ramses_rf/protocol → ramses_tx}/address.py +65 -59
- ramses_tx/command.py +1454 -0
- ramses_tx/const.py +903 -0
- ramses_tx/exceptions.py +92 -0
- {ramses_rf/protocol → ramses_tx}/fingerprints.py +56 -15
- {ramses_rf/protocol → ramses_tx}/frame.py +132 -131
- ramses_tx/gateway.py +338 -0
- ramses_tx/helpers.py +883 -0
- {ramses_rf/protocol → ramses_tx}/logger.py +67 -53
- {ramses_rf/protocol → ramses_tx}/message.py +155 -191
- ramses_tx/opentherm.py +1260 -0
- ramses_tx/packet.py +210 -0
- ramses_tx/parsers.py +2957 -0
- ramses_tx/protocol.py +801 -0
- ramses_tx/protocol_fsm.py +672 -0
- ramses_tx/py.typed +0 -0
- {ramses_rf/protocol → ramses_tx}/ramses.py +262 -185
- {ramses_rf/protocol → ramses_tx}/schemas.py +150 -133
- ramses_tx/transport.py +1471 -0
- ramses_tx/typed_dicts.py +492 -0
- ramses_tx/typing.py +181 -0
- ramses_tx/version.py +4 -0
- ramses_rf/discovery.py +0 -398
- ramses_rf/protocol/__init__.py +0 -59
- ramses_rf/protocol/backports.py +0 -42
- ramses_rf/protocol/command.py +0 -1561
- ramses_rf/protocol/const.py +0 -697
- ramses_rf/protocol/exceptions.py +0 -111
- ramses_rf/protocol/helpers.py +0 -390
- ramses_rf/protocol/opentherm.py +0 -1170
- ramses_rf/protocol/packet.py +0 -235
- ramses_rf/protocol/parsers.py +0 -2673
- ramses_rf/protocol/protocol.py +0 -613
- ramses_rf/protocol/transport.py +0 -1011
- ramses_rf/protocol/version.py +0 -10
- ramses_rf/system/hvac.py +0 -82
- ramses_rf-0.22.2.dist-info/METADATA +0 -64
- ramses_rf-0.22.2.dist-info/RECORD +0 -42
- ramses_rf-0.22.2.dist-info/top_level.txt +0 -1
ramses_rf/discovery.py
DELETED
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
#
|
|
4
|
-
"""RAMSES RF - discovery scripts."""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import asyncio
|
|
8
|
-
import json
|
|
9
|
-
import logging
|
|
10
|
-
import re
|
|
11
|
-
|
|
12
|
-
from .const import SZ_SCHEDULE, SZ_ZONE_IDX, __dev_mode__
|
|
13
|
-
from .protocol import CODES_SCHEMA, Command, ExpiredCallbackError, Priority
|
|
14
|
-
from .protocol.command import _mk_cmd
|
|
15
|
-
from .protocol.const import SZ_DISABLE_BACKOFF, SZ_PRIORITY, SZ_RETRIES
|
|
16
|
-
from .protocol.opentherm import OTB_MSG_IDS
|
|
17
|
-
|
|
18
|
-
# Beware, none of this is reliable - it is all subject to random change
|
|
19
|
-
# However, these serve as examples how to us eteh other modules
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# skipcq: PY-W2000
|
|
23
|
-
from .protocol import ( # noqa: F401, isort: skip, pylint: disable=unused-import
|
|
24
|
-
I_,
|
|
25
|
-
RP,
|
|
26
|
-
RQ,
|
|
27
|
-
W_,
|
|
28
|
-
Code,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
EXEC_CMD = "exec_cmd"
|
|
33
|
-
GET_FAULTS = "get_faults"
|
|
34
|
-
GET_SCHED = "get_schedule"
|
|
35
|
-
SET_SCHED = "set_schedule"
|
|
36
|
-
|
|
37
|
-
EXEC_SCR = "exec_scr"
|
|
38
|
-
SCAN_DISC = "scan_disc"
|
|
39
|
-
SCAN_FULL = "scan_full"
|
|
40
|
-
SCAN_HARD = "scan_hard"
|
|
41
|
-
SCAN_XXXX = "scan_xxxx"
|
|
42
|
-
|
|
43
|
-
# DEVICE_ID_REGEX = re.compile(DEVICE_ID_REGEX.ANY)
|
|
44
|
-
|
|
45
|
-
QOS_SCAN = {SZ_PRIORITY: Priority.LOW, SZ_RETRIES: 0}
|
|
46
|
-
QOS_HIGH = {SZ_PRIORITY: Priority.HIGH, SZ_RETRIES: 3}
|
|
47
|
-
|
|
48
|
-
DEV_MODE = __dev_mode__ and False
|
|
49
|
-
|
|
50
|
-
_LOGGER = logging.getLogger(__name__)
|
|
51
|
-
if DEV_MODE:
|
|
52
|
-
_LOGGER.setLevel(logging.DEBUG)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def script_decorator(fnc):
|
|
56
|
-
def wrapper(gwy, *args, **kwargs):
|
|
57
|
-
|
|
58
|
-
highest = {
|
|
59
|
-
SZ_PRIORITY: Priority.HIGHEST,
|
|
60
|
-
SZ_RETRIES: 3,
|
|
61
|
-
SZ_DISABLE_BACKOFF: True,
|
|
62
|
-
}
|
|
63
|
-
gwy.send_cmd(Command._puzzle(message="Script begins:", qos=highest))
|
|
64
|
-
|
|
65
|
-
result = fnc(gwy, *args, **kwargs)
|
|
66
|
-
|
|
67
|
-
lowest = {SZ_PRIORITY: Priority.LOWEST, SZ_RETRIES: 3, SZ_DISABLE_BACKOFF: True}
|
|
68
|
-
gwy.send_cmd(Command._puzzle(message="Script done.", qos=lowest))
|
|
69
|
-
|
|
70
|
-
return result
|
|
71
|
-
|
|
72
|
-
return wrapper
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
async def periodic(gwy, cmd, count=1, interval=None):
|
|
76
|
-
async def _periodic():
|
|
77
|
-
await asyncio.sleep(interval)
|
|
78
|
-
gwy.send_cmd(cmd)
|
|
79
|
-
|
|
80
|
-
if interval is None:
|
|
81
|
-
interval = 0 if count == 1 else 60
|
|
82
|
-
|
|
83
|
-
if count <= 0:
|
|
84
|
-
while True:
|
|
85
|
-
await _periodic()
|
|
86
|
-
else:
|
|
87
|
-
for _ in range(count):
|
|
88
|
-
await _periodic()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def spawn_scripts(gwy, **kwargs) -> list[asyncio.Task]:
|
|
92
|
-
|
|
93
|
-
tasks = []
|
|
94
|
-
|
|
95
|
-
if kwargs.get(EXEC_CMD):
|
|
96
|
-
tasks += [gwy._loop.create_task(exec_cmd(gwy, **kwargs))]
|
|
97
|
-
|
|
98
|
-
if kwargs.get(GET_FAULTS):
|
|
99
|
-
tasks += [gwy._loop.create_task(get_faults(gwy, kwargs[GET_FAULTS]))]
|
|
100
|
-
|
|
101
|
-
elif kwargs.get(GET_SCHED) and kwargs[GET_SCHED][0]:
|
|
102
|
-
tasks += [gwy._loop.create_task(get_schedule(gwy, *kwargs[GET_SCHED]))]
|
|
103
|
-
|
|
104
|
-
elif kwargs.get(SET_SCHED) and kwargs[SET_SCHED][0]:
|
|
105
|
-
tasks += [gwy._loop.create_task(set_schedule(gwy, *kwargs[SET_SCHED]))]
|
|
106
|
-
|
|
107
|
-
elif kwargs.get(EXEC_SCR):
|
|
108
|
-
script = SCRIPTS.get(f"{kwargs[EXEC_SCR][0]}")
|
|
109
|
-
if script is None:
|
|
110
|
-
_LOGGER.warning(f"Script: {kwargs[EXEC_SCR][0]}() - unknown script")
|
|
111
|
-
else:
|
|
112
|
-
_LOGGER.info(f"Script: {kwargs[EXEC_SCR][0]}().- starts...")
|
|
113
|
-
tasks += [gwy._loop.create_task(script(gwy, kwargs[EXEC_SCR][1]))]
|
|
114
|
-
|
|
115
|
-
gwy._tasks.extend(tasks)
|
|
116
|
-
return tasks
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
async def exec_cmd(gwy, **kwargs):
|
|
120
|
-
|
|
121
|
-
await gwy.async_send_cmd(Command.from_cli(kwargs[EXEC_CMD], qos=QOS_HIGH))
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
# @script_decorator
|
|
125
|
-
# async def script_scan_001(gwy, dev_id: str):
|
|
126
|
-
# _LOGGER.warning("scan_001() invoked - expect a lot of nonsense")
|
|
127
|
-
# qos = {SZ_PRIORITY: Priority.LOW, SZ_RETRIES: 3}
|
|
128
|
-
# for idx in range(0x10):
|
|
129
|
-
# gwy.send_cmd(_mk_cmd(W_, Code._000E, f"{idx:02X}0050", dev_id, qos=qos))
|
|
130
|
-
# gwy.send_cmd(_mk_cmd(RQ, Code._000E, f"{idx:02X}00C8", dev_id, qos=qos))
|
|
131
|
-
|
|
132
|
-
# @script_decorator
|
|
133
|
-
# async def script_scan_004(gwy, dev_id: str):
|
|
134
|
-
# _LOGGER.warning("scan_004() invoked - expect a lot of nonsense")
|
|
135
|
-
# cmd = Command.get_dhw_mode(dev_id, **QOS_SCAN)
|
|
136
|
-
# return gwy._loop.create_task(periodic(gwy, cmd, count=0, interval=5))
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
async def get_faults(gwy, ctl_id: str, start=0, limit=0x3F):
|
|
140
|
-
ctl = gwy.get_device(ctl_id)
|
|
141
|
-
|
|
142
|
-
try:
|
|
143
|
-
await ctl.tcs.get_faultlog(start=start, limit=limit) # 0418
|
|
144
|
-
except ExpiredCallbackError as exc:
|
|
145
|
-
_LOGGER.error("get_faults(): Function timed out: %s", exc)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
async def get_schedule(gwy, ctl_id: str, zone_idx: str) -> None:
|
|
149
|
-
zone = gwy.get_device(ctl_id).tcs.get_htg_zone(zone_idx)
|
|
150
|
-
|
|
151
|
-
try:
|
|
152
|
-
await zone.get_schedule()
|
|
153
|
-
except ExpiredCallbackError as exc:
|
|
154
|
-
_LOGGER.error("get_schedule(): Function timed out: %s", exc)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
async def set_schedule(gwy, ctl_id, schedule) -> None:
|
|
158
|
-
schedule = json.load(schedule)
|
|
159
|
-
zone_idx = schedule[SZ_ZONE_IDX]
|
|
160
|
-
|
|
161
|
-
zone = gwy.get_device(ctl_id).tcs.get_htg_zone(zone_idx)
|
|
162
|
-
|
|
163
|
-
try:
|
|
164
|
-
await zone.set_schedule(schedule[SZ_SCHEDULE]) # 0404
|
|
165
|
-
except ExpiredCallbackError as exc:
|
|
166
|
-
_LOGGER.error("set_schedule(): Function timed out: %s", exc)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
async def script_bind_req(gwy, dev_id: str):
|
|
170
|
-
gwy.get_device(dev_id)._make_fake(bind=True)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
async def script_bind_wait(gwy, dev_id: str, code=Code._2309, idx="00"):
|
|
174
|
-
gwy.get_device(dev_id)._make_fake(bind=True, code=code, idx=idx)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def script_poll_device(gwy, dev_id) -> list:
|
|
178
|
-
_LOGGER.warning("poll_device() invoked...")
|
|
179
|
-
|
|
180
|
-
tasks = []
|
|
181
|
-
|
|
182
|
-
for code in (Code._0016, Code._1FC9):
|
|
183
|
-
cmd = _mk_cmd(RQ, code, "00", dev_id, qos=QOS_SCAN)
|
|
184
|
-
tasks.append(gwy._loop.create_task(periodic(gwy, cmd, count=0)))
|
|
185
|
-
|
|
186
|
-
gwy._tasks.extend(tasks)
|
|
187
|
-
return tasks
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
@script_decorator
|
|
191
|
-
async def script_scan_disc(gwy, dev_id: str):
|
|
192
|
-
_LOGGER.warning("scan_disc() invoked...")
|
|
193
|
-
|
|
194
|
-
await gwy.get_device(dev_id).discover() # discover_flag=Discover.DEFAULT)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@script_decorator
|
|
198
|
-
async def script_scan_full(gwy, dev_id: str):
|
|
199
|
-
_LOGGER.warning("scan_full() invoked - expect a lot of Warnings")
|
|
200
|
-
|
|
201
|
-
qos = {SZ_PRIORITY: Priority.DEFAULT, SZ_RETRIES: 5}
|
|
202
|
-
gwy.send_cmd(_mk_cmd(RQ, Code._0016, "0000", dev_id, qos=qos))
|
|
203
|
-
|
|
204
|
-
qos = {SZ_PRIORITY: Priority.DEFAULT, SZ_RETRIES: 1}
|
|
205
|
-
for code in sorted(CODES_SCHEMA):
|
|
206
|
-
if code == Code._0005:
|
|
207
|
-
for zone_type in range(20): # known up to 18
|
|
208
|
-
gwy.send_cmd(_mk_cmd(RQ, code, f"00{zone_type:02X}", dev_id, qos=qos))
|
|
209
|
-
|
|
210
|
-
elif code == Code._000C:
|
|
211
|
-
for zone_idx in range(16): # also: FA-FF?
|
|
212
|
-
gwy.send_cmd(_mk_cmd(RQ, code, f"{zone_idx:02X}00", dev_id, qos=qos))
|
|
213
|
-
|
|
214
|
-
elif code == Code._0016:
|
|
215
|
-
continue
|
|
216
|
-
|
|
217
|
-
elif code in (Code._01D0, Code._01E9):
|
|
218
|
-
for zone_idx in ("00", "01", "FC"): # type: ignore[assignment]
|
|
219
|
-
gwy.send_cmd(_mk_cmd(W_, code, f"{zone_idx}00", dev_id, qos=qos))
|
|
220
|
-
gwy.send_cmd(_mk_cmd(W_, code, f"{zone_idx}03", dev_id, qos=qos))
|
|
221
|
-
|
|
222
|
-
elif code == Code._0404: # FIXME
|
|
223
|
-
gwy.send_cmd(Command.get_schedule_fragment(dev_id, "HW", 1, 0, qos=qos))
|
|
224
|
-
gwy.send_cmd(Command.get_schedule_fragment(dev_id, "00", 1, 0, qos=qos))
|
|
225
|
-
|
|
226
|
-
elif code == Code._0418:
|
|
227
|
-
for log_idx in range(2):
|
|
228
|
-
gwy.send_cmd(Command.get_system_log_entry(dev_id, log_idx, qos=qos))
|
|
229
|
-
|
|
230
|
-
elif code == Code._1100:
|
|
231
|
-
gwy.send_cmd(Command.get_tpi_params(dev_id, qos=qos))
|
|
232
|
-
|
|
233
|
-
elif code == Code._2E04:
|
|
234
|
-
gwy.send_cmd(Command.get_system_mode(dev_id, qos=qos))
|
|
235
|
-
|
|
236
|
-
elif code == Code._3220:
|
|
237
|
-
for data_id in (0, 3): # these are mandatory READ_DATA data_ids
|
|
238
|
-
gwy.send_cmd(Command.get_opentherm_data(dev_id, data_id, qos=qos))
|
|
239
|
-
|
|
240
|
-
elif code == Code._PUZZ:
|
|
241
|
-
continue
|
|
242
|
-
|
|
243
|
-
elif (
|
|
244
|
-
code in CODES_SCHEMA
|
|
245
|
-
and RQ in CODES_SCHEMA[code]
|
|
246
|
-
and re.match(CODES_SCHEMA[code][RQ], "00")
|
|
247
|
-
):
|
|
248
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "00", dev_id, qos=qos))
|
|
249
|
-
|
|
250
|
-
else:
|
|
251
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "0000", dev_id, qos=qos))
|
|
252
|
-
|
|
253
|
-
# these are possible/difficult codes
|
|
254
|
-
qos = {SZ_PRIORITY: Priority.DEFAULT, SZ_RETRIES: 2}
|
|
255
|
-
for code in (Code._0150, Code._2389):
|
|
256
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "0000", dev_id, qos=qos))
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
@script_decorator
|
|
260
|
-
async def script_scan_hard(gwy, dev_id: str, *, start_code: int = None):
|
|
261
|
-
_LOGGER.warning("scan_hard() invoked - expect some Warnings")
|
|
262
|
-
|
|
263
|
-
start_code = start_code or 0
|
|
264
|
-
|
|
265
|
-
for code in range(start_code, 0x5000):
|
|
266
|
-
gwy.send_cmd(_mk_cmd(RQ, f"{code:04X}", "0000", dev_id, qos=QOS_SCAN))
|
|
267
|
-
await asyncio.sleep(0.2)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
@script_decorator
|
|
271
|
-
async def script_scan_fan(gwy, dev_id: str):
|
|
272
|
-
_LOGGER.warning("scan_fan() invoked - expect a lot of nonsense")
|
|
273
|
-
qos = {SZ_PRIORITY: Priority.LOW, SZ_RETRIES: 3}
|
|
274
|
-
|
|
275
|
-
from ramses_rf.protocol.ramses import _DEV_KLASSES_HVAC
|
|
276
|
-
|
|
277
|
-
OUT_CODES = (
|
|
278
|
-
Code._0016,
|
|
279
|
-
Code._1470,
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
OLD_CODES = dict.fromkeys(
|
|
283
|
-
c for k in _DEV_KLASSES_HVAC.values() for c in k if c not in OUT_CODES
|
|
284
|
-
)
|
|
285
|
-
for code in OLD_CODES:
|
|
286
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "00", dev_id, qos=qos))
|
|
287
|
-
|
|
288
|
-
NEW_CODES = (
|
|
289
|
-
Code._0150,
|
|
290
|
-
Code._042F,
|
|
291
|
-
Code._1030,
|
|
292
|
-
Code._10D0,
|
|
293
|
-
Code._10E1,
|
|
294
|
-
Code._2210,
|
|
295
|
-
Code._22B0,
|
|
296
|
-
Code._22E0,
|
|
297
|
-
Code._22E5,
|
|
298
|
-
Code._22E9,
|
|
299
|
-
Code._22F1,
|
|
300
|
-
Code._22F2,
|
|
301
|
-
Code._22F3,
|
|
302
|
-
Code._22F4,
|
|
303
|
-
Code._22F7,
|
|
304
|
-
Code._22F8,
|
|
305
|
-
Code._2400,
|
|
306
|
-
Code._2410,
|
|
307
|
-
Code._2420,
|
|
308
|
-
Code._313E,
|
|
309
|
-
Code._3221,
|
|
310
|
-
Code._3222,
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
for code in NEW_CODES:
|
|
314
|
-
if code not in OLD_CODES and code not in OUT_CODES:
|
|
315
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "00", dev_id, qos=qos))
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
@script_decorator
|
|
319
|
-
async def script_scan_otb(gwy, dev_id: str):
|
|
320
|
-
_LOGGER.warning("script_scan_otb_full invoked - expect a lot of nonsense")
|
|
321
|
-
|
|
322
|
-
qos = {SZ_PRIORITY: Priority.LOW, SZ_RETRIES: 1}
|
|
323
|
-
for msg_id in OTB_MSG_IDS:
|
|
324
|
-
gwy.send_cmd(Command.get_opentherm_data(dev_id, msg_id, qos=qos))
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
@script_decorator
|
|
328
|
-
async def script_scan_otb_hard(gwy, dev_id: str):
|
|
329
|
-
_LOGGER.warning("script_scan_otb_hard invoked - expect a lot of nonsense")
|
|
330
|
-
|
|
331
|
-
for msg_id in range(0x80):
|
|
332
|
-
gwy.send_cmd(Command.get_opentherm_data(dev_id, msg_id, qos=QOS_SCAN))
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
@script_decorator
|
|
336
|
-
async def script_scan_otb_map(gwy, dev_id: str): # Tested only upon a R8820A
|
|
337
|
-
_LOGGER.warning("script_scan_otb_map invoked - expect a lot of nonsense")
|
|
338
|
-
|
|
339
|
-
RAMSES_TO_OPENTHERM = {
|
|
340
|
-
Code._22D9: "01", # boiler setpoint / ControlSetpoint
|
|
341
|
-
Code._3EF1: "11", # rel. modulation level / RelativeModulationLevel
|
|
342
|
-
Code._1300: "12", # cv water pressure / CHWaterPressure
|
|
343
|
-
Code._12F0: "13", # dhw_flow_rate / DHWFlowRate
|
|
344
|
-
Code._3200: "19", # boiler output temp / BoilerWaterTemperature
|
|
345
|
-
Code._1260: "1A", # dhw temp / DHWTemperature
|
|
346
|
-
Code._1290: "1B", # outdoor temp / OutsideTemperature
|
|
347
|
-
Code._3210: "1C", # boiler return temp / ReturnWaterTemperature
|
|
348
|
-
Code._10A0: "38", # dhw params[SZ_SETPOINT] / DHWSetpoint
|
|
349
|
-
Code._1081: "39", # max ch setpoint / MaxCHWaterSetpoint
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
for code, msg_id in RAMSES_TO_OPENTHERM.items():
|
|
353
|
-
gwy.send_cmd(_mk_cmd(RQ, code, "00", dev_id, qos=QOS_SCAN))
|
|
354
|
-
gwy.send_cmd(Command.get_opentherm_data(dev_id, msg_id, qos=QOS_SCAN))
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
@script_decorator
|
|
358
|
-
async def script_scan_otb_ramses(gwy, dev_id: str): # Tested only upon a R8820A
|
|
359
|
-
_LOGGER.warning("script_scan_otb_ramses invoked - expect a lot of nonsense")
|
|
360
|
-
|
|
361
|
-
CODES = (
|
|
362
|
-
Code._042F,
|
|
363
|
-
Code._10E0, # device_info
|
|
364
|
-
Code._10E1, # device_id
|
|
365
|
-
Code._1FD0,
|
|
366
|
-
Code._2400,
|
|
367
|
-
Code._2401,
|
|
368
|
-
Code._2410,
|
|
369
|
-
Code._2420,
|
|
370
|
-
Code._1300, # cv water pressure / CHWaterPressure
|
|
371
|
-
Code._1081, # max ch setpoint / MaxCHWaterSetpoint
|
|
372
|
-
Code._10A0, # dhw params[SZ_SETPOINT] / DHWSetpoint
|
|
373
|
-
Code._22D9, # boiler setpoint / ControlSetpoint
|
|
374
|
-
Code._1260, # dhw temp / DHWTemperature
|
|
375
|
-
Code._1290, # outdoor temp / OutsideTemperature
|
|
376
|
-
Code._3200, # boiler output temp / BoilerWaterTemperature
|
|
377
|
-
Code._3210, # boiler return temp / ReturnWaterTemperature
|
|
378
|
-
Code._0150,
|
|
379
|
-
Code._12F0, # dhw flow rate / DHWFlowRate
|
|
380
|
-
Code._1098,
|
|
381
|
-
Code._10B0,
|
|
382
|
-
Code._3221,
|
|
383
|
-
Code._3223,
|
|
384
|
-
Code._3EF0, # rel. modulation level / RelativeModulationLevel (also, below)
|
|
385
|
-
Code._3EF1, # rel. modulation level / RelativeModulationLevel
|
|
386
|
-
) # excl. 3220
|
|
387
|
-
|
|
388
|
-
# 3EF0 also includes:
|
|
389
|
-
# - boiler status /
|
|
390
|
-
# - ch setpoint /
|
|
391
|
-
# - max. rel. modulation /
|
|
392
|
-
|
|
393
|
-
[gwy.send_cmd(_mk_cmd(RQ, c, "00", dev_id, qos=QOS_SCAN)) for c in CODES]
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
SCRIPTS = {
|
|
397
|
-
k[7:]: v for k, v in locals().items() if callable(v) and k.startswith("script_")
|
|
398
|
-
}
|
ramses_rf/protocol/__init__.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
#
|
|
4
|
-
"""RAMSES RF - a RAMSES-II protocol decoder & analyser."""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from logging import Logger
|
|
8
|
-
|
|
9
|
-
from .address import Address, is_valid_dev_id
|
|
10
|
-
from .command import CODE_API_MAP, Command, FaultLog, Priority
|
|
11
|
-
from .const import (
|
|
12
|
-
SZ_DEVICE_ROLE,
|
|
13
|
-
SZ_DOMAIN_ID,
|
|
14
|
-
SZ_ZONE_CLASS,
|
|
15
|
-
SZ_ZONE_IDX,
|
|
16
|
-
SZ_ZONE_MASK,
|
|
17
|
-
SZ_ZONE_TYPE,
|
|
18
|
-
__dev_mode__,
|
|
19
|
-
)
|
|
20
|
-
from .exceptions import (
|
|
21
|
-
CorruptStateError,
|
|
22
|
-
ExpiredCallbackError,
|
|
23
|
-
InvalidAddrSetError,
|
|
24
|
-
InvalidPacketError,
|
|
25
|
-
)
|
|
26
|
-
from .logger import set_logger_timesource, set_pkt_logging
|
|
27
|
-
from .message import Message
|
|
28
|
-
from .packet import _PKT_LOGGER, Packet
|
|
29
|
-
from .protocol import create_msg_stack
|
|
30
|
-
from .ramses import CODES_BY_DEV_SLUG, CODES_SCHEMA
|
|
31
|
-
from .schemas import SZ_SERIAL_PORT
|
|
32
|
-
from .transport import SZ_POLLER_TASK, create_pkt_stack
|
|
33
|
-
|
|
34
|
-
# noqa: F401, pylint: disable=unused-import
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# skipcq: PY-W2000
|
|
38
|
-
from .const import ( # noqa: F401, isort: skip, pylint: disable=unused-import
|
|
39
|
-
I_,
|
|
40
|
-
RP,
|
|
41
|
-
RQ,
|
|
42
|
-
W_,
|
|
43
|
-
F9,
|
|
44
|
-
FA,
|
|
45
|
-
FC,
|
|
46
|
-
FF,
|
|
47
|
-
DEV_ROLE,
|
|
48
|
-
DEV_ROLE_MAP,
|
|
49
|
-
DEV_TYPE,
|
|
50
|
-
DEV_TYPE_MAP,
|
|
51
|
-
ZON_ROLE,
|
|
52
|
-
ZON_ROLE_MAP,
|
|
53
|
-
Code,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def set_pkt_logging_config(**config) -> Logger:
|
|
58
|
-
set_pkt_logging(_PKT_LOGGER, **config)
|
|
59
|
-
return _PKT_LOGGER
|
ramses_rf/protocol/backports.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
#
|
|
4
|
-
"""RAMSES RF - a RAMSES-II protocol decoder & analyser.
|
|
5
|
-
|
|
6
|
-
Enum backports from standard lib. Taken (with thanks) from
|
|
7
|
-
https://github.com/home-assistant/core/homeassistant/backports
|
|
8
|
-
"""
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from enum import Enum
|
|
12
|
-
from typing import Any, TypeVar
|
|
13
|
-
|
|
14
|
-
_StrEnumT = TypeVar("_StrEnumT", bound="StrEnum")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class StrEnum(str, Enum):
|
|
18
|
-
"""Partial backport of Python 3.11's StrEnum for our basic use cases."""
|
|
19
|
-
|
|
20
|
-
def __new__(
|
|
21
|
-
cls: type[_StrEnumT], value: str, *args: Any, **kwargs: Any
|
|
22
|
-
) -> _StrEnumT:
|
|
23
|
-
"""Create a new StrEnum instance."""
|
|
24
|
-
if not isinstance(value, str):
|
|
25
|
-
raise TypeError(f"{value!r} is not a string")
|
|
26
|
-
return super().__new__(cls, value, *args, **kwargs)
|
|
27
|
-
|
|
28
|
-
def __str__(self) -> str:
|
|
29
|
-
"""Return self.value."""
|
|
30
|
-
return str(self.value)
|
|
31
|
-
|
|
32
|
-
@staticmethod
|
|
33
|
-
def _generate_next_value_(
|
|
34
|
-
name: str, start: int, count: int, last_values: list[Any]
|
|
35
|
-
) -> Any:
|
|
36
|
-
"""
|
|
37
|
-
Make `auto()` explicitly unsupported.
|
|
38
|
-
|
|
39
|
-
We may revisit this when it's very clear that Python 3.11's
|
|
40
|
-
`StrEnum.auto()` behavior will no longer change.
|
|
41
|
-
"""
|
|
42
|
-
raise TypeError("auto() is not supported by this implementation")
|