ramses-rf 0.22.40__py3-none-any.whl → 0.51.2__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 +279 -171
- ramses_rf/dispatcher.py +153 -177
- ramses_rf/entity_base.py +478 -361
- ramses_rf/exceptions.py +82 -0
- ramses_rf/gateway.py +377 -513
- 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.2.dist-info/METADATA +72 -0
- ramses_rf-0.51.2.dist-info/RECORD +55 -0
- {ramses_rf-0.22.40.dist-info → ramses_rf-0.51.2.dist-info}/WHEEL +1 -2
- ramses_rf-0.51.2.dist-info/entry_points.txt +2 -0
- {ramses_rf-0.22.40.dist-info → ramses_rf-0.51.2.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_rf/protocol → ramses_tx}/parsers.py +1266 -1003
- 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 -1576
- 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/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.40.dist-info/METADATA +0 -64
- ramses_rf-0.22.40.dist-info/RECORD +0 -42
- ramses_rf-0.22.40.dist-info/top_level.txt +0 -1
|
@@ -1,42 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
#
|
|
4
2
|
"""RAMSES RF - a RAMSES-II protocol decoder & analyser."""
|
|
3
|
+
|
|
4
|
+
# TODO: code a lifespan for most packets
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
7
|
-
import logging
|
|
8
8
|
from datetime import timedelta as td
|
|
9
|
+
from typing import Any, Final
|
|
9
10
|
|
|
10
|
-
from .const import
|
|
11
|
+
from .const import SZ_NAME, DevType
|
|
11
12
|
|
|
12
|
-
# skipcq: PY-W2000
|
|
13
13
|
from .const import ( # noqa: F401, isort: skip, pylint: disable=unused-import
|
|
14
14
|
I_,
|
|
15
15
|
RP,
|
|
16
16
|
RQ,
|
|
17
17
|
W_,
|
|
18
18
|
Code,
|
|
19
|
+
VerbT,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
DEV_MODE = __dev_mode__ and False
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
if DEV_MODE:
|
|
25
|
-
_LOGGER.setLevel(logging.DEBUG)
|
|
23
|
+
SZ_LIFESPAN: Final = "lifespan" # WIP
|
|
26
24
|
|
|
27
|
-
RQ_NULL = "rq_null"
|
|
28
|
-
EXPIRES = "expires"
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
#
|
|
27
|
+
########################################################################################
|
|
28
|
+
# CODES_SCHEMA - HEAT (CH/DHW, Honeywell/Resideo) vs HVAC (ventilation, Itho/Orcon/etc.)
|
|
31
29
|
|
|
32
30
|
# The master list - all known codes are here, even if there's no corresponding parser
|
|
33
31
|
# Anything with a zone-idx should start: ^0[0-9A-F], ^(0[0-9A-F], or ^((0[0-9A-F]
|
|
34
32
|
|
|
35
33
|
#
|
|
36
|
-
|
|
37
|
-
# CODES_SCHEMA - HEAT (CH/DHW, Honeywell/Resideo) vs HVAC (ventilation, Itho/Orcon/etc.)
|
|
38
|
-
#
|
|
39
|
-
CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
34
|
+
CODES_SCHEMA: dict[Code, dict[str, Any]] = { # rf_unknown
|
|
40
35
|
Code._0001: {
|
|
41
36
|
SZ_NAME: "rf_unknown",
|
|
42
37
|
I_: r"^00FFFF02(00|FF)$", # loopback
|
|
@@ -45,6 +40,9 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
45
40
|
W_: r"^(0[0-9A-F]|FC|FF)000005(01|05)$",
|
|
46
41
|
}, # TODO: there appears to be a dodgy? RQ/RP for UFC
|
|
47
42
|
Code._0002: { # WIP: outdoor_sensor - CODE_IDX_COMPLEX?
|
|
43
|
+
# is it CODE_IDX_COMPLEX:
|
|
44
|
+
# - 02...... for outside temp?
|
|
45
|
+
# - 03...... for other stuff?
|
|
48
46
|
SZ_NAME: "outdoor_sensor",
|
|
49
47
|
I_: r"^0[0-4][0-9A-F]{4}(00|01|02|05)$", # Domoticz sends ^02!!
|
|
50
48
|
RQ: r"^00$", # NOTE: sent by an RFG100
|
|
@@ -53,15 +51,16 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
53
51
|
SZ_NAME: "zone_name",
|
|
54
52
|
I_: r"^0[0-9A-F]00([0-9A-F]){40}$", # RP is same, null_rp: xxxx,7F*20
|
|
55
53
|
RQ: r"^0[0-9A-F]00$",
|
|
56
|
-
|
|
54
|
+
W_: r"^0[0-9A-F]00([0-9A-F]){40}$", # contrived
|
|
55
|
+
SZ_LIFESPAN: td(days=1),
|
|
57
56
|
},
|
|
58
57
|
Code._0005: { # system_zones
|
|
59
58
|
SZ_NAME: "system_zones",
|
|
60
59
|
# .I --- 34:092243 --:------ 34:092243 0005 012 000A0000-000F0000-00100000
|
|
61
60
|
I_: r"^(00[01][0-9A-F]{5}){1,3}$",
|
|
62
|
-
RQ: r"^00[01][0-9A-F]$", # f"00{zone_type}", evohome
|
|
61
|
+
RQ: r"^00[01][0-9A-F]$", # f"00{zone_type}", evohome won't respond to 00
|
|
63
62
|
RP: r"^00[01][0-9A-F]{3,5}$",
|
|
64
|
-
|
|
63
|
+
SZ_LIFESPAN: False,
|
|
65
64
|
},
|
|
66
65
|
Code._0006: { # schedule_version # TODO: what for DHW schedule?
|
|
67
66
|
SZ_NAME: "schedule_version",
|
|
@@ -93,7 +92,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
93
92
|
# 17:54:13.141 045 RP --- 01:145038 34:064023 --:------ 000A 006 031002260B86
|
|
94
93
|
# 19:20:49.460 062 RQ --- 12:010740 01:145038 --:------ 000A 006 080001F40DAC
|
|
95
94
|
# 19:20:49.476 045 RP --- 01:145038 12:010740 --:------ 000A 006 081001F40DAC
|
|
96
|
-
|
|
95
|
+
SZ_LIFESPAN: td(days=1),
|
|
97
96
|
},
|
|
98
97
|
Code._000C: { # zone_devices
|
|
99
98
|
SZ_NAME: "zone_devices",
|
|
@@ -101,11 +100,11 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
101
100
|
# RP --- 01:145038 18:013393 --:------ 000C 016 05-08-00-109901 08-00-109902 08-00-109903
|
|
102
101
|
I_: r"^0[0-9A-F][01][0-9A-F]|7F[0-9A-F]{6}([0-9A-F]{10}|[0-9A-F]{12}){1,7}$",
|
|
103
102
|
RQ: r"^0[0-9A-F][01][0-9A-F]$", # TODO: f"{zone_idx}{device_type}"
|
|
104
|
-
|
|
103
|
+
SZ_LIFESPAN: False,
|
|
105
104
|
},
|
|
106
105
|
Code._000E: { # unknown_000e
|
|
107
106
|
SZ_NAME: "message_000e",
|
|
108
|
-
I_: r"^
|
|
107
|
+
I_: r"^0000(14|28)$",
|
|
109
108
|
},
|
|
110
109
|
Code._0016: { # rf_check
|
|
111
110
|
SZ_NAME: "rf_check",
|
|
@@ -116,7 +115,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
116
115
|
SZ_NAME: "language",
|
|
117
116
|
RQ: r"^00([0-9A-F]{4}F{4})?$", # NOTE: RQ/04/0100 has a payload
|
|
118
117
|
RP: r"^00[0-9A-F]{4}F{4}$",
|
|
119
|
-
|
|
118
|
+
SZ_LIFESPAN: td(days=1), # TODO: make longer?
|
|
120
119
|
},
|
|
121
120
|
Code._0150: { # unknown_0150
|
|
122
121
|
SZ_NAME: "message_0150",
|
|
@@ -137,13 +136,19 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
137
136
|
# .W --- 04:000722 01:158182 --:------ 01E9 002 0003 # is a guess, the
|
|
138
137
|
# .I --- 01:158182 04:000722 --:------ 01E9 002 0000 # TRV was in zone 00
|
|
139
138
|
},
|
|
139
|
+
Code._01FF: { # unknown_01ff, TODO: definitely a real code, Itho Spider
|
|
140
|
+
SZ_NAME: "message_01ff",
|
|
141
|
+
I_: r"^(00|01)[0-9A-F]{50}$",
|
|
142
|
+
RQ: r"^(00|01)[0-9A-F]{50}$",
|
|
143
|
+
W_: r"^00[0-9A-F]{50}$",
|
|
144
|
+
},
|
|
140
145
|
Code._0404: { # zone_schedule
|
|
141
146
|
SZ_NAME: "zone_schedule",
|
|
142
147
|
I_: r"^0[0-9A-F](20|23)[0-9A-F]{2}08[0-9A-F]{6}$",
|
|
143
148
|
RQ: r"^0[0-9A-F](20|23)000800[0-9A-F]{4}$",
|
|
144
149
|
RP: r"^0[0-9A-F](20|23)0008[0-9A-F]{6}[0-9A-F]{2,82}$",
|
|
145
150
|
W_: r"^0[0-9A-F](20|23)[0-9A-F]{2}08[0-9A-F]{6}[0-9A-F]{2,82}$", # as per RP
|
|
146
|
-
|
|
151
|
+
SZ_LIFESPAN: None,
|
|
147
152
|
},
|
|
148
153
|
Code._0418: { # system_fault
|
|
149
154
|
SZ_NAME: "system_fault",
|
|
@@ -167,11 +172,13 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
167
172
|
SZ_NAME: "mixvalve_params",
|
|
168
173
|
# .I --- --:------ --:------ 12:138834 1030 016 01C80137C9010FCA0196CB010FCC0101
|
|
169
174
|
I_: r"^0[0-9A-F](C[89A-C]01[0-9A-F]{2}){5}$",
|
|
175
|
+
RP: r"^00((20|21)01[0-9A-F]{2}){2}$", # rarely seen, HVAC
|
|
176
|
+
W_: r"^0[0-9A-F](C[89A-C]01[0-9A-F]{2}){5}$", # contrived
|
|
170
177
|
},
|
|
171
178
|
Code._1060: { # device_battery
|
|
172
179
|
SZ_NAME: "device_battery",
|
|
173
180
|
I_: r"^0[0-9A-F](FF|[0-9A-F]{2})0[01]$", # HCW: r"^(FF|0[0-9A-F]...
|
|
174
|
-
|
|
181
|
+
SZ_LIFESPAN: td(days=1),
|
|
175
182
|
},
|
|
176
183
|
Code._1081: { # max_ch_setpoint
|
|
177
184
|
SZ_NAME: "max_ch_setpoint",
|
|
@@ -196,34 +203,34 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
196
203
|
# NOTE: RFG100 uses a domain id! (00|01)
|
|
197
204
|
# 19:14:24.662 051 RQ --- 30:185469 01:037519 --:------ 10A0 001 00
|
|
198
205
|
# 19:14:31.463 053 RQ --- 30:185469 01:037519 --:------ 10A0 001 01
|
|
199
|
-
I_: r"^
|
|
200
|
-
RQ: r"^
|
|
201
|
-
W_: r"^
|
|
202
|
-
|
|
206
|
+
I_: r"^(00|01)[0-9A-F]{4}([0-9A-F]{6})?$", # NOTE: RQ/07/10A0 has a payload
|
|
207
|
+
RQ: r"^(00|01)([0-9A-F]{10})?$", # NOTE: RQ/07/10A0 has a payload
|
|
208
|
+
W_: r"^(00|01)[0-9A-F]{4}([0-9A-F]{6})?$", # TODO: needs checking
|
|
209
|
+
SZ_LIFESPAN: td(hours=4),
|
|
203
210
|
},
|
|
204
211
|
Code._10B0: { # unknown_10b0
|
|
205
212
|
SZ_NAME: "message_10b0",
|
|
206
213
|
RQ: r"^00$",
|
|
207
214
|
RP: r"^00[0-9A-F]{8}$",
|
|
208
215
|
},
|
|
209
|
-
Code._10D0: { # filter_change
|
|
216
|
+
Code._10D0: { # filter_change - polling interval should be 1/day
|
|
210
217
|
SZ_NAME: "filter_change",
|
|
211
|
-
I_: r"^00[0-9A-F]{6}(0000)?$",
|
|
218
|
+
I_: r"^00[0-9A-F]{6}(0000|FFFF)?$",
|
|
212
219
|
RQ: r"^00(00)?$",
|
|
213
220
|
W_: r"^00FF$",
|
|
214
221
|
},
|
|
215
222
|
Code._10E0: { # device_info
|
|
216
223
|
SZ_NAME: "device_info",
|
|
217
|
-
I_: r"^00[0-9A-F]{30,}
|
|
218
|
-
RQ: r"^00$", # NOTE: will accept [0-9A-F]{2}
|
|
224
|
+
I_: r"^(00|FF)([0-9A-F]{30,})?$", # r"^[0-9A-F]{32,}$" might be OK
|
|
225
|
+
RQ: r"^00$", # NOTE: 63 seen (no RP), some devices will accept [0-9A-F]{2}
|
|
219
226
|
# RP: r"^[0-9A-F]{2}([0-9A-F]){30,}$", # NOTE: indx same as RQ
|
|
220
|
-
|
|
227
|
+
SZ_LIFESPAN: False,
|
|
221
228
|
},
|
|
222
229
|
Code._10E1: { # device_id
|
|
223
230
|
SZ_NAME: "device_id",
|
|
224
231
|
RP: r"^00[0-9A-F]{6}$",
|
|
225
232
|
RQ: r"^00$",
|
|
226
|
-
|
|
233
|
+
SZ_LIFESPAN: False,
|
|
227
234
|
},
|
|
228
235
|
Code._10E2: { # unknown_10e2, HVAC?
|
|
229
236
|
SZ_NAME: "unknown_10e2",
|
|
@@ -231,14 +238,16 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
231
238
|
},
|
|
232
239
|
Code._1100: { # tpi_params
|
|
233
240
|
SZ_NAME: "tpi_params",
|
|
241
|
+
# I --- 01:172368 --:------ 01:172368 1100 008 FC180400007FFF00
|
|
242
|
+
# I --- 01:172368 13:040439 --:------ 1100 008 FC042814007FFF00
|
|
234
243
|
# RQ --- 01:145038 13:163733 --:------ 1100 008 00180400007FFF01 # boiler relay
|
|
235
244
|
# RP --- 13:163733 01:145038 --:------ 1100 008 00180400FF7FFF01
|
|
236
245
|
# RQ --- 01:145038 13:035462 --:------ 1100 008 FC240428007FFF01 # not bolier relay
|
|
237
246
|
# RP --- 13:035462 01:145038 --:------ 1100 008 00240428007FFF01
|
|
238
|
-
I_: r"^(00|FC)[0-9A-F]{6}(00|FF)([0-9A-F]{4}01)?$",
|
|
239
|
-
W_: r"^(00|FC)[0-9A-F]{6}(00|FF)([0-9A-F]{4}01)?$", # TODO: is there no I?
|
|
240
|
-
RQ: r"^(00|FC)([0-9A-F]{6}(00|FF)([0-9A-F]{4}01)?)?$", # RQ/13:/00, or RQ/01:/FC:
|
|
241
|
-
|
|
247
|
+
I_: r"^(00|FC)[0-9A-F]{6}(00|FF)([0-9A-F]{4}0[01])?$",
|
|
248
|
+
W_: r"^(00|FC)[0-9A-F]{6}(00|FF)([0-9A-F]{4}0[01])?$", # TODO: is there no I?
|
|
249
|
+
RQ: r"^(00|FC)([0-9A-F]{6}(00|FF)([0-9A-F]{4}0[01])?)?$", # RQ/13:/00, or RQ/01:/FC:
|
|
250
|
+
SZ_LIFESPAN: td(days=1),
|
|
242
251
|
},
|
|
243
252
|
Code._11F0: { # unknown_11f0, from heatpump relay
|
|
244
253
|
SZ_NAME: "message_11f0",
|
|
@@ -251,9 +260,9 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
251
260
|
# RQ --- 18:200202 10:067219 --:------ 1260 002 0000
|
|
252
261
|
# RP --- 10:067219 18:200202 --:------ 1260 003 007FFF
|
|
253
262
|
# .I --- 07:045960 --:------ 07:045960 1260 003 0007A9
|
|
254
|
-
I_: r"^
|
|
255
|
-
RQ: r"^
|
|
256
|
-
|
|
263
|
+
I_: r"^(00|01)[0-9A-F]{4}$", # NOTE: RP is same
|
|
264
|
+
RQ: r"^(00|01)(00)?$", # TODO: officially: r"^(00|01)$"
|
|
265
|
+
SZ_LIFESPAN: td(hours=1),
|
|
257
266
|
},
|
|
258
267
|
Code._1280: { # outdoor_humidity
|
|
259
268
|
SZ_NAME: "outdoor_humidity",
|
|
@@ -266,21 +275,20 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
266
275
|
},
|
|
267
276
|
Code._1298: { # co2_level
|
|
268
277
|
SZ_NAME: "co2_level",
|
|
269
|
-
I_: r"^00[0-9A-F]{4}$",
|
|
278
|
+
I_: r"^00[0-9A-F]{4}$", # NOTE: RP is same
|
|
279
|
+
RQ: r"^00$",
|
|
270
280
|
},
|
|
271
281
|
Code._12A0: { # indoor_humidity
|
|
272
|
-
# .I --- 32:168090 --:------ 32:168090 12A0 006 0030093504A8
|
|
273
|
-
# .I --- 32:132125 --:------ 32:132125 12A0 007 003107B67FFF00 # only dev_id with 007
|
|
274
|
-
# RP --- 20:008749 18:142609 --:------ 12A0 002 00EF
|
|
275
282
|
SZ_NAME: "indoor_humidity",
|
|
276
|
-
I_: r"^
|
|
277
|
-
|
|
283
|
+
I_: r"^(0[0-9A-F]{3}([0-9A-F]{8}(00)?)?)+$",
|
|
284
|
+
RP: r"^0[0-9A-F]{3}([0-9A-F]{8}(00)?)?$",
|
|
285
|
+
SZ_LIFESPAN: td(hours=1),
|
|
278
286
|
},
|
|
279
287
|
Code._12B0: { # window_state (HVAC % window open)
|
|
280
288
|
SZ_NAME: "window_state",
|
|
281
289
|
I_: r"^0[0-9A-F](0000|C800|FFFF)$", # NOTE: RP is same
|
|
282
290
|
RQ: r"^0[0-9A-F](00)?$",
|
|
283
|
-
|
|
291
|
+
SZ_LIFESPAN: td(hours=1),
|
|
284
292
|
},
|
|
285
293
|
Code._12C0: { # displayed_temp (HVAC room temp)
|
|
286
294
|
SZ_NAME: "displayed_temp", # displayed room temp
|
|
@@ -321,10 +329,10 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
321
329
|
},
|
|
322
330
|
Code._1F41: { # dhw_mode
|
|
323
331
|
SZ_NAME: "dhw_mode",
|
|
324
|
-
I_: r"^
|
|
325
|
-
RQ: r"^
|
|
326
|
-
W_: r"^
|
|
327
|
-
|
|
332
|
+
I_: r"^(00|01)(00|01|FF)0[0-5]F{6}(([0-9A-F]){12})?$",
|
|
333
|
+
RQ: r"^(00|01)$", # will accept: r"^(00|01)(00)$"
|
|
334
|
+
W_: r"^(00|01)(00|01|FF)0[0-5]F{6}(([0-9A-F]){12})?$",
|
|
335
|
+
SZ_LIFESPAN: td(hours=4),
|
|
328
336
|
},
|
|
329
337
|
Code._1F70: { # programme_config, HVAC (1470, 1F70, 22B0)
|
|
330
338
|
SZ_NAME: "programme_config",
|
|
@@ -333,14 +341,11 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
333
341
|
W_: r"^00[0-9A-F]{30}$",
|
|
334
342
|
},
|
|
335
343
|
Code._1FC9: { # rf_bind
|
|
336
|
-
# RP --- 13:035462 18:013393 --:------ 1FC9 018 00-3EF0-348A86 00-11F0-348A86 90-3FF1-956ABD # noqa: E501
|
|
337
|
-
# RP --- 13:035462 18:013393 --:------ 1FC9 018 00-3EF0-348A86 00-11F0-348A86 90-7FE1-DD6ABD # noqa: E501
|
|
338
|
-
# RP --- 01:145038 18:013393 --:------ 1FC9 012 FF-10E0-06368E FF-1FC9-06368E
|
|
339
344
|
SZ_NAME: "rf_bind", # idx-code-dev_id
|
|
340
345
|
RQ: r"^00$",
|
|
341
|
-
RP: r"^((0[0-9A-F]|F[69ABCF]|
|
|
342
|
-
I_: r"^((0[0-9A-F]|F[69ABCF]|
|
|
343
|
-
W_: r"^((0[0-9A-F]|F[69ABCF])([0-9A-F]{10}))+$",
|
|
346
|
+
RP: r"^((0[0-9A-F]|F[69ABCF]|[0-9A-F]{2})([0-9A-F]{10}))+$",
|
|
347
|
+
I_: r"^((0[0-9A-F]|F[69ABCF]|[0-9A-F]{2})([0-9A-F]{10}))+|00|21$", # NOTE: payload can be 00
|
|
348
|
+
W_: r"^((0[0-9A-F]|F[69ABCF]|[0-9A-F]{2})([0-9A-F]{10}))+$",
|
|
344
349
|
},
|
|
345
350
|
Code._1FCA: { # unknown_1fca
|
|
346
351
|
SZ_NAME: "message_1fca",
|
|
@@ -358,20 +363,19 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
358
363
|
SZ_NAME: "opentherm_sync",
|
|
359
364
|
I_: r"^00([0-9A-F]{4})$",
|
|
360
365
|
},
|
|
361
|
-
Code._2210: { # unknown_2210, HVAC,
|
|
366
|
+
Code._2210: { # unknown_2210, HVAC,
|
|
362
367
|
SZ_NAME: "unknown_2210",
|
|
368
|
+
I_: r"^00[0-9A-F]{82}$",
|
|
363
369
|
RQ: r"^00$",
|
|
364
|
-
RP: r"^00[0-9A-F]{82}$",
|
|
365
370
|
},
|
|
366
371
|
Code._2249: { # setpoint_now?
|
|
367
372
|
SZ_NAME: "setpoint_now", # setpt_now_next
|
|
368
373
|
I_: r"^(0[0-9A-F]{13}){1,2}$",
|
|
369
374
|
}, # TODO: This could be an array
|
|
370
|
-
Code._22C9: { # ufh_setpoint
|
|
371
|
-
SZ_NAME: "
|
|
372
|
-
I_: r"^(0[0-9A-F][0-9A-F]{8}0[12]){1,4}(
|
|
373
|
-
W_: r"^(0[0-9A-F][0-9A-F]{8}0[12])$", #
|
|
374
|
-
# RP: Appear wont get any?,
|
|
375
|
+
Code._22C9: { # setpoint_bounds (was: ufh_setpoint)
|
|
376
|
+
SZ_NAME: "setpoint_bounds",
|
|
377
|
+
I_: r"^(0[0-9A-F][0-9A-F]{8}0[12]){1,4}(0[12]03)?$", # (0[12]03)? only if len(array) == 1
|
|
378
|
+
W_: r"^(0[0-9A-F][0-9A-F]{8}0[12])$", # never an array
|
|
375
379
|
},
|
|
376
380
|
Code._22D0: { # unknown_22d0, HVAC system switch?
|
|
377
381
|
SZ_NAME: "message_22d0",
|
|
@@ -401,6 +405,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
401
405
|
Code._22F1: { # fan_mode, HVAC
|
|
402
406
|
SZ_NAME: "fan_mode",
|
|
403
407
|
RQ: r"^00$",
|
|
408
|
+
RP: r"^00[0-9A-F]{4}$",
|
|
404
409
|
I_: r"^(00|63)(0[0-9A-F]){1,2}$",
|
|
405
410
|
},
|
|
406
411
|
Code._22F2: { # unknown_22f2, HVAC, NB: no I
|
|
@@ -410,12 +415,12 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
410
415
|
},
|
|
411
416
|
Code._22F3: { # fan_boost, HVAC
|
|
412
417
|
SZ_NAME: "fan_boost",
|
|
413
|
-
I_: r"^(00|63)[0-9A-F]{4}([0-9A-F]{8})?$",
|
|
414
|
-
}, # minutes
|
|
415
|
-
Code._22F4: { # unknown_22f4, HVAC
|
|
418
|
+
I_: r"^(00|63)(021E)?[0-9A-F]{4}([0-9A-F]{8})?$",
|
|
419
|
+
}, # minutes only?
|
|
420
|
+
Code._22F4: { # unknown_22f4, HVAC
|
|
416
421
|
SZ_NAME: "unknown_22f4",
|
|
422
|
+
I_: r"^00[0-9A-F]{24}$",
|
|
417
423
|
RQ: r"^00$",
|
|
418
|
-
RP: r"^00[0-9A-F]{24}$",
|
|
419
424
|
},
|
|
420
425
|
Code._22F7: { # fan_bypass_mode (% open), HVAC
|
|
421
426
|
SZ_NAME: "fan_bypass_mode",
|
|
@@ -439,7 +444,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
439
444
|
W_: r"^0[0-9A-F]{5}$",
|
|
440
445
|
# RQ --- 12:010740 01:145038 --:------ 2309 003 03073A # No RPs
|
|
441
446
|
RQ: r"^0[0-9A-F]([0-9A-F]{4})?$", # NOTE: 12 uses: r"^0[0-9A-F]$"
|
|
442
|
-
|
|
447
|
+
SZ_LIFESPAN: td(minutes=30),
|
|
443
448
|
},
|
|
444
449
|
Code._2349: { # zone_mode
|
|
445
450
|
SZ_NAME: "zone_mode",
|
|
@@ -449,7 +454,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
449
454
|
# .W --- 18:141846 01:050858 --:------ 2349 007 02-08FC-01-FFFFFF
|
|
450
455
|
RQ: r"^0[0-9A-F](00|[0-9A-F]{12})?$",
|
|
451
456
|
# RQ --- 22:070483 01:063844 --:------ 2349 007 06-0708-03-000027
|
|
452
|
-
|
|
457
|
+
SZ_LIFESPAN: td(hours=4),
|
|
453
458
|
},
|
|
454
459
|
Code._2389: { # unknown_2389 - CODE_IDX_COMPLEX?
|
|
455
460
|
# .I 024 03:052382 --:------ 03:052382 2389 003 02001B
|
|
@@ -473,9 +478,9 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
473
478
|
},
|
|
474
479
|
Code._2411: { # fan_params, HVAC
|
|
475
480
|
SZ_NAME: "fan_params",
|
|
476
|
-
I_: r"^
|
|
477
|
-
RQ: r"^
|
|
478
|
-
W_: r"^
|
|
481
|
+
I_: r"^(00|01|15|16|17|21)00[0-9A-F]{6}([0-9A-F]{8}){4}[0-9A-F]{4}$",
|
|
482
|
+
RQ: r"^(00|01|15|16|17|21)00[0-9A-F]{2}((00){19})?$",
|
|
483
|
+
W_: r"^(00|01|15|16|17|21)00[0-9A-F]{6}[0-9A-F]{8}(([0-9A-F]{8}){3}[0-9A-F]{4})?$",
|
|
479
484
|
},
|
|
480
485
|
Code._2420: { # unknown_2420, from OTB
|
|
481
486
|
SZ_NAME: "message_2420",
|
|
@@ -496,7 +501,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
496
501
|
I_: r"^0[0-7][0-9A-F]{12}0[01]$",
|
|
497
502
|
RQ: r"^FF$",
|
|
498
503
|
W_: r"^0[0-7][0-9A-F]{12}0[01]$",
|
|
499
|
-
|
|
504
|
+
SZ_LIFESPAN: td(hours=4),
|
|
500
505
|
},
|
|
501
506
|
Code._2E10: { # presence_detect - HVAC
|
|
502
507
|
SZ_NAME: "presence_detect",
|
|
@@ -507,11 +512,11 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
507
512
|
I_: r"^(0[0-9A-F][0-9A-F]{4})+$",
|
|
508
513
|
RQ: r"^0[0-9A-F](00)?$", # TODO: officially: r"^0[0-9A-F]$"
|
|
509
514
|
RP: r"^0[0-9A-F][0-9A-F]{4}$", # Null: r"^0[0-9A-F]7FFF$"
|
|
510
|
-
|
|
515
|
+
SZ_LIFESPAN: td(hours=1),
|
|
511
516
|
},
|
|
512
|
-
Code._3110: { #
|
|
513
|
-
SZ_NAME: "
|
|
514
|
-
I_: r"^00",
|
|
517
|
+
Code._3110: { # ufc_demand - HVAC
|
|
518
|
+
SZ_NAME: "ufc_demand",
|
|
519
|
+
I_: r"^(00|01)00[0-9A-F]{2}(00|10|20)", # (00|10|20|FF)???
|
|
515
520
|
},
|
|
516
521
|
Code._3120: { # unknown_3120 - Error Report?
|
|
517
522
|
SZ_NAME: "message_3120",
|
|
@@ -529,24 +534,24 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
529
534
|
I_: r"^00[0-9A-F]{16}$", # NOTE: RP is same
|
|
530
535
|
RQ: r"^00$",
|
|
531
536
|
W_: r"^00[0-9A-F]{16}$",
|
|
532
|
-
|
|
537
|
+
SZ_LIFESPAN: td(seconds=3),
|
|
533
538
|
},
|
|
534
|
-
Code._3150: { # heat_demand
|
|
539
|
+
Code._3150: { # heat_demand, also fans with preheat
|
|
535
540
|
SZ_NAME: "heat_demand",
|
|
536
541
|
I_: r"^((0[0-9A-F])[0-9A-F]{2}|FC[0-9A-F]{2})+$",
|
|
537
|
-
|
|
542
|
+
SZ_LIFESPAN: td(minutes=20),
|
|
538
543
|
},
|
|
539
544
|
Code._31D9: { # fan_state
|
|
540
545
|
SZ_NAME: "fan_state",
|
|
541
546
|
# I_: r"^(00|21)[0-9A-F]{32}$",
|
|
542
547
|
# I_: r"^(00|01|21)[0-9A-F]{4}((00|FE)(00|20){12}(00|08))?$",
|
|
543
|
-
I_: r"^(00|01|21)[0-9A-F]{4}(([0-9A-F]{2})(00|20){0,12}(00|01|04|08)?)?$", # 00-0004-FE
|
|
544
|
-
RQ: r"^(00|01|21)$",
|
|
548
|
+
I_: r"^(00|01|15|16|17|21)[0-9A-F]{4}(([0-9A-F]{2})(00|20){0,12}(00|01|04|08)?)?$", # 00-0004-FE
|
|
549
|
+
RQ: r"^(00|01|15|16|17|21)$",
|
|
545
550
|
},
|
|
546
551
|
Code._31DA: { # hvac_state (fan_state_extended)
|
|
547
552
|
SZ_NAME: "hvac_state",
|
|
548
|
-
I_: r"^(00|01|21)[0-9A-F]{56}(00|20)?$",
|
|
549
|
-
RQ: r"^(00|01|21)$"
|
|
553
|
+
I_: r"^(00|01|15|16|17|21)[0-9A-F]{56}(00|20)?$",
|
|
554
|
+
RQ: r"^(00|01|15|16|17|21)$",
|
|
550
555
|
# RQ --- 32:168090 30:082155 --:------ 31DA 001 21
|
|
551
556
|
},
|
|
552
557
|
Code._31E0: { # fan_demand
|
|
@@ -556,12 +561,12 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
556
561
|
SZ_NAME: "fan_demand",
|
|
557
562
|
I_: r"^00([0-9A-F]{4}){1,3}(00|FF)?$",
|
|
558
563
|
},
|
|
559
|
-
Code._3200: { # boiler output temp
|
|
564
|
+
Code._3200: { # boiler (or CV?) output temp
|
|
560
565
|
SZ_NAME: "boiler_output",
|
|
566
|
+
I_: r"^00[0-9A-F]{4}$",
|
|
561
567
|
RQ: r"^00$",
|
|
562
|
-
RP: r"^00[0-9A-F]{4}$",
|
|
563
568
|
},
|
|
564
|
-
Code._3210: { # boiler return temp
|
|
569
|
+
Code._3210: { # boiler (or CV?) return temp
|
|
565
570
|
SZ_NAME: "boiler_return",
|
|
566
571
|
RQ: r"^00$",
|
|
567
572
|
RP: r"^00[0-9A-F]{4}$",
|
|
@@ -579,7 +584,7 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
579
584
|
Code._3222: { # unknown_3222, HVAC, NB: no I
|
|
580
585
|
SZ_NAME: "unknown_3222",
|
|
581
586
|
RQ: r"^00$",
|
|
582
|
-
RP: r"^00[0-9A-F]{4,
|
|
587
|
+
RP: r"^00[0-9A-F]{4,24}$",
|
|
583
588
|
},
|
|
584
589
|
Code._3223: { # unknown_3223, from OTB
|
|
585
590
|
SZ_NAME: "message_3223",
|
|
@@ -618,30 +623,45 @@ CODES_SCHEMA: dict[Code, dict] = { # rf_unknown
|
|
|
618
623
|
RQ: r"^[0-9A-F]{40}$",
|
|
619
624
|
W_: r"^[0-9A-F]{40}$",
|
|
620
625
|
},
|
|
621
|
-
Code._4E01: { #
|
|
626
|
+
Code._4E01: { # xxx (HVAC) - Itho Spider
|
|
622
627
|
SZ_NAME: "hvac_4e01",
|
|
623
|
-
I_: r"^00([0-9A-F]{4}){
|
|
628
|
+
I_: r"^00([0-9A-F]{4}){3,12}00$",
|
|
624
629
|
},
|
|
625
|
-
Code._4E02: { #
|
|
630
|
+
Code._4E02: { # xxx (HVAC) - Itho Spider
|
|
626
631
|
SZ_NAME: "hvac_4e02",
|
|
627
|
-
I_: r"^00([0-9A-F]{4}){
|
|
632
|
+
I_: r"^00([0-9A-F]{4}){3,12}(02|03|04|05)([0-9A-F]{4}){3,12}$",
|
|
628
633
|
},
|
|
629
|
-
Code._4E04: { #
|
|
634
|
+
Code._4E04: { # xxx (HVAC) - Itho Spider
|
|
630
635
|
SZ_NAME: "hvac_4e04",
|
|
631
|
-
I_: r"^00(
|
|
632
|
-
W_: r"^00(
|
|
636
|
+
I_: r"^00(00|01|02)[0-9A-F]{2}$",
|
|
637
|
+
W_: r"^00(00|01|02)[0-9A-F]{2}$",
|
|
638
|
+
},
|
|
639
|
+
Code._4E0D: { # xxx (HVAC) - Itho Spider
|
|
640
|
+
SZ_NAME: "hvac_4e0d",
|
|
641
|
+
I_: r"^(01|02)(00|01)$",
|
|
642
|
+
},
|
|
643
|
+
Code._4E15: { # xxx (HVAC) - Itho Spider
|
|
644
|
+
SZ_NAME: "hvac_4e15",
|
|
645
|
+
I_: r"^000[0-7]$",
|
|
646
|
+
},
|
|
647
|
+
Code._4E16: { # xxx (HVAC) - Itho Spider
|
|
648
|
+
SZ_NAME: "hvac_4e16",
|
|
649
|
+
I_: r"^00(00){6}$",
|
|
633
650
|
},
|
|
634
651
|
Code._PUZZ: {
|
|
635
652
|
SZ_NAME: "puzzle_packet",
|
|
636
653
|
I_: r"^00(([0-9A-F]){2})+$",
|
|
637
654
|
},
|
|
638
655
|
}
|
|
639
|
-
|
|
656
|
+
CODE_NAME_LOOKUP = {k: v["name"] for k, v in CODES_SCHEMA.items()}
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
for code in CODES_SCHEMA.values(): # map any (missing) RPs to I_s
|
|
640
660
|
if RQ in code and RP not in code and I_ in code:
|
|
641
661
|
code[RP] = code[I_]
|
|
642
662
|
#
|
|
643
663
|
# .I --- 01:210309 --:------ 01:210309 0009 006 FC00FFF900FF
|
|
644
|
-
CODES_WITH_ARRAYS: dict[Code, list] = { # 000C/1FC9 are special
|
|
664
|
+
CODES_WITH_ARRAYS: dict[Code, list[int | tuple[str, ...]]] = { # 000C/1FC9 are special
|
|
645
665
|
Code._0005: [4, ("34",)],
|
|
646
666
|
Code._0009: [3, ("01", "12", "22")],
|
|
647
667
|
Code._000A: [6, ("01", "12", "22")], # single element I after a W
|
|
@@ -659,6 +679,7 @@ RQ_IDX_COMPLEX: list[Code] = [
|
|
|
659
679
|
Code._0016, # optional payload
|
|
660
680
|
Code._0100, # optional payload
|
|
661
681
|
Code._0404, # context: index, fragment_idx (fragment_header)
|
|
682
|
+
Code._0418, # context: index
|
|
662
683
|
Code._10A0, # optional payload
|
|
663
684
|
Code._1100, # optional payload
|
|
664
685
|
Code._2309, # optional payload
|
|
@@ -673,44 +694,50 @@ RQ_NO_PAYLOAD: list[Code] = [
|
|
|
673
694
|
]
|
|
674
695
|
RQ_NO_PAYLOAD.extend((Code._0418,))
|
|
675
696
|
|
|
676
|
-
|
|
697
|
+
|
|
698
|
+
########################################################################################
|
|
699
|
+
# IDX:_xxxxxx: index (and context)
|
|
700
|
+
|
|
677
701
|
# all known codes should be in only one of IDX_COMPLEX, IDX_NONE, IDX_SIMPLE
|
|
678
|
-
|
|
702
|
+
|
|
703
|
+
# IDX_COMPLEX - *usually has* a context, but doesn't satisfy criteria for IDX_SIMPLE:
|
|
704
|
+
CODE_IDX_ARE_COMPLEX: set[Code] = {
|
|
679
705
|
Code._0005,
|
|
680
|
-
Code._000C,
|
|
706
|
+
Code._000C, # idx = fx(payload[0:4])
|
|
707
|
+
# Code._0404, # use "HW" for idx if payload[4:6] == "23" # TODO: should be used
|
|
708
|
+
Code._0418, # log_idx (payload[4:6]) # null RPs are missing an idx
|
|
681
709
|
Code._1100,
|
|
682
|
-
Code._3220,
|
|
683
|
-
|
|
684
|
-
# CODE_IDX_COMPLEX.sort()
|
|
710
|
+
Code._3220, # data_id (payload[4:6])
|
|
711
|
+
} # TODO: 0005 to ..._NONE?
|
|
685
712
|
|
|
686
713
|
# IDX_SIMPLE - *can have* a context, but sometimes not (usu. 00): only ever payload[:2],
|
|
687
714
|
# either a zone_idx, domain_id or (UFC) circuit_idx (or array of such, i.e. seqx[:2])
|
|
688
|
-
|
|
715
|
+
|
|
716
|
+
_SIMPLE_IDX = ("^0[0-9A-F]", "^(0[0-9A-F]", "^((0[0-9A-F]", "^(00|01)")
|
|
717
|
+
CODE_IDX_ARE_SIMPLE: set[Code] = {
|
|
689
718
|
k
|
|
690
719
|
for k, v in CODES_SCHEMA.items()
|
|
691
|
-
|
|
692
|
-
and (
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
720
|
+
for verb in (RQ, I_)
|
|
721
|
+
if k not in CODE_IDX_ARE_COMPLEX and v.get(verb, "").startswith(_SIMPLE_IDX)
|
|
722
|
+
}
|
|
723
|
+
CODE_IDX_ARE_SIMPLE |= {
|
|
724
|
+
Code._22D0,
|
|
725
|
+
Code._2411,
|
|
726
|
+
Code._31D9,
|
|
727
|
+
Code._31DA,
|
|
728
|
+
Code._3B00,
|
|
729
|
+
Code._4E0D,
|
|
730
|
+
}
|
|
701
731
|
|
|
702
732
|
# IDX_NONE - *never has* a context: most payloads start 00, but no context even if the
|
|
703
733
|
# payload starts with something else (e.g. 2E04)
|
|
704
|
-
|
|
734
|
+
CODE_IDX_ARE_NONE: set[Code] = {
|
|
705
735
|
k
|
|
706
736
|
for k, v in CODES_SCHEMA.items()
|
|
707
|
-
if k not in
|
|
737
|
+
if k not in CODE_IDX_ARE_COMPLEX | CODE_IDX_ARE_SIMPLE
|
|
708
738
|
and ((RQ in v and v[RQ][:3] == "^00") or (I_ in v and v[I_][:3] == "^00"))
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
(Code._0002, Code._22F1, Code._22F3, Code._2389, Code._2E04, Code._31DA, Code._4401)
|
|
712
|
-
) # 31DA does appear to have an idx?
|
|
713
|
-
# CODE_IDX_NONE.sort()
|
|
739
|
+
}
|
|
740
|
+
CODE_IDX_ARE_NONE |= {Code._22F3, Code._2389, Code._2E04, Code._4401}
|
|
714
741
|
|
|
715
742
|
# CODE_IDX_DOMAIN - NOTE: not necc. mutex with other 3
|
|
716
743
|
CODE_IDX_DOMAIN: dict[Code, str] = {
|
|
@@ -723,13 +750,13 @@ CODE_IDX_DOMAIN: dict[Code, str] = {
|
|
|
723
750
|
Code._3B00: "^FC",
|
|
724
751
|
}
|
|
725
752
|
|
|
753
|
+
|
|
726
754
|
#
|
|
727
755
|
########################################################################################
|
|
728
756
|
# CODES_BY_DEV_SLUG - HEAT (CH/DHW) vs HVAC (ventilation)
|
|
729
|
-
#
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
DEV_TYPE.RFG: { # RFG100: RF to Internet gateway (and others)
|
|
757
|
+
# TODO: 34: can 3220 - split out RND from THM/STA
|
|
758
|
+
_DEV_KLASSES_HEAT: dict[str, dict[Code, dict[VerbT, Any]]] = {
|
|
759
|
+
DevType.RFG: { # RFG100: RF to Internet gateway (and others)
|
|
733
760
|
Code._0002: {RQ: {}},
|
|
734
761
|
Code._0004: {I_: {}, RQ: {}},
|
|
735
762
|
Code._0005: {RQ: {}},
|
|
@@ -755,7 +782,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
755
782
|
Code._3220: {RQ: {}},
|
|
756
783
|
Code._3EF0: {RQ: {}},
|
|
757
784
|
},
|
|
758
|
-
|
|
785
|
+
DevType.CTL: { # e.g. ATC928: Evohome Colour Controller
|
|
759
786
|
Code._0001: {W_: {}},
|
|
760
787
|
Code._0002: {I_: {}, RP: {}},
|
|
761
788
|
Code._0004: {I_: {}, RP: {}},
|
|
@@ -794,7 +821,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
794
821
|
Code._3B00: {I_: {}},
|
|
795
822
|
Code._3EF0: {RQ: {}},
|
|
796
823
|
},
|
|
797
|
-
|
|
824
|
+
DevType.PRG: { # e.g. HCF82/HCW82: Room Temperature Sensor
|
|
798
825
|
Code._0009: {I_: {}},
|
|
799
826
|
Code._1090: {RP: {}},
|
|
800
827
|
Code._10A0: {RP: {}},
|
|
@@ -806,7 +833,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
806
833
|
Code._3B00: {I_: {}},
|
|
807
834
|
Code._3EF1: {RP: {}},
|
|
808
835
|
},
|
|
809
|
-
|
|
836
|
+
DevType.THM: { # e.g. Generic Thermostat
|
|
810
837
|
Code._0001: {W_: {}},
|
|
811
838
|
Code._0005: {I_: {}},
|
|
812
839
|
Code._0008: {I_: {}},
|
|
@@ -824,6 +851,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
824
851
|
Code._12C0: {I_: {}},
|
|
825
852
|
Code._1F09: {I_: {}},
|
|
826
853
|
Code._1FC9: {I_: {}},
|
|
854
|
+
Code._22C9: {W_: {}}, # DT4R
|
|
827
855
|
Code._2309: {I_: {}, RQ: {}, W_: {}},
|
|
828
856
|
Code._2349: {RQ: {}, W_: {}},
|
|
829
857
|
Code._30C9: {I_: {}},
|
|
@@ -831,11 +859,12 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
831
859
|
Code._313F: {
|
|
832
860
|
I_: {}
|
|
833
861
|
}, # .W --- 30:253184 34:010943 --:------ 313F 009 006000070E0...
|
|
862
|
+
Code._3220: {RP: {}}, # RND (using OT)
|
|
834
863
|
Code._3B00: {I_: {}},
|
|
835
864
|
Code._3EF0: {RQ: {}}, # when bound direct to a 13:
|
|
836
865
|
Code._3EF1: {RQ: {}}, # when bound direct to a 13:
|
|
837
866
|
},
|
|
838
|
-
|
|
867
|
+
DevType.UFC: { # e.g. HCE80/HCC80: Underfloor Heating Controller
|
|
839
868
|
Code._0001: {RP: {}, W_: {}}, # TODO: Ix RP
|
|
840
869
|
Code._0005: {RP: {}},
|
|
841
870
|
Code._0008: {I_: {}},
|
|
@@ -848,7 +877,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
848
877
|
Code._2309: {RP: {}},
|
|
849
878
|
Code._3150: {I_: {}},
|
|
850
879
|
},
|
|
851
|
-
|
|
880
|
+
DevType.TRV: { # e.g. HR92/HR91: Radiator Controller
|
|
852
881
|
Code._0001: {W_: {r"^0[0-9A-F]"}},
|
|
853
882
|
Code._0004: {RQ: {r"^0[0-9A-F]00$"}},
|
|
854
883
|
Code._0016: {RQ: {}, RP: {}},
|
|
@@ -865,14 +894,14 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
865
894
|
Code._313F: {RQ: {r"^00$"}},
|
|
866
895
|
Code._3150: {I_: {r"^0[0-9A-F]{3}$"}},
|
|
867
896
|
},
|
|
868
|
-
|
|
897
|
+
DevType.DHW: { # e.g. CS92: (DHW) Cylinder Thermostat
|
|
869
898
|
Code._0016: {RQ: {}},
|
|
870
899
|
Code._1060: {I_: {}},
|
|
871
900
|
Code._10A0: {RQ: {}}, # This RQ/07/10A0 includes a payload
|
|
872
901
|
Code._1260: {I_: {}},
|
|
873
902
|
Code._1FC9: {I_: {}},
|
|
874
903
|
},
|
|
875
|
-
|
|
904
|
+
DevType.OTB: { # e.g. R8810/R8820: OpenTherm Bridge
|
|
876
905
|
Code._0009: {I_: {}}, # 1/24h for a R8820 (not an R8810)
|
|
877
906
|
Code._0150: {RP: {}}, # R8820A only?
|
|
878
907
|
Code._042F: {I_: {}, RP: {}},
|
|
@@ -903,7 +932,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
903
932
|
Code._3EF0: {I_: {}, RP: {}},
|
|
904
933
|
Code._3EF1: {RP: {}},
|
|
905
934
|
}, # see: https://www.opentherm.eu/request-details/?post_ids=2944
|
|
906
|
-
|
|
935
|
+
DevType.BDR: { # e.g. BDR91A/BDR91T: Wireless Relay Box
|
|
907
936
|
Code._0008: {RP: {}}, # doesn't RP/0009
|
|
908
937
|
Code._0016: {RP: {}},
|
|
909
938
|
# Code._10E0: {}, # 13: will not RP/10E0 # TODO: how to indicate that fact here
|
|
@@ -916,24 +945,24 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
916
945
|
# RP: {}, # RQ --- 01:145038 13:237335 --:------ 3EF0 001 00
|
|
917
946
|
Code._3EF1: {RP: {}},
|
|
918
947
|
},
|
|
919
|
-
|
|
948
|
+
DevType.OUT: {
|
|
920
949
|
Code._0002: {I_: {}},
|
|
921
950
|
Code._1FC9: {I_: {}},
|
|
922
951
|
}, # i.e. HB85 (ext. temperature/luminosity(lux)), HB95 (+ wind speed)
|
|
923
952
|
#
|
|
924
|
-
|
|
953
|
+
DevType.JIM: { # Jasper Interface Module, 08
|
|
925
954
|
Code._0008: {RQ: {}},
|
|
926
955
|
Code._10E0: {I_: {}},
|
|
927
956
|
Code._1100: {I_: {}},
|
|
928
957
|
Code._3EF0: {I_: {}},
|
|
929
958
|
Code._3EF1: {RP: {}},
|
|
930
959
|
},
|
|
931
|
-
|
|
960
|
+
DevType.JST: { # Jasper Stat, 31
|
|
932
961
|
Code._0008: {I_: {}},
|
|
933
962
|
Code._10E0: {I_: {}},
|
|
934
963
|
Code._3EF1: {RQ: {}, RP: {}},
|
|
935
964
|
},
|
|
936
|
-
#
|
|
965
|
+
# DevType.RND: { # e.g. TR87RF: Single (round) Zone Thermostat
|
|
937
966
|
# Code._0005: {I_: {}},
|
|
938
967
|
# Code._0008: {I_: {}},
|
|
939
968
|
# Code._000A: {I_: {}, RQ: {}},
|
|
@@ -953,7 +982,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
953
982
|
# Code._3EF0: {I_: {}, RQ: {}}, # when bound direct to a 13:
|
|
954
983
|
# Code._3EF1: {RQ: {}}, # when bound direct to a 13:
|
|
955
984
|
# },
|
|
956
|
-
#
|
|
985
|
+
# DevType.DTS: { # e.g. DTS92(E)
|
|
957
986
|
# Code._0001: {W_: {}},
|
|
958
987
|
# Code._0008: {I_: {}},
|
|
959
988
|
# Code._0009: {I_: {}},
|
|
@@ -973,7 +1002,7 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
973
1002
|
# Code._3B00: {I_: {}},
|
|
974
1003
|
# Code._3EF1: {RQ: {}},
|
|
975
1004
|
# },
|
|
976
|
-
#
|
|
1005
|
+
# DevType.HCW: { # e.g. HCF82/HCW82: Room Temperature Sensor
|
|
977
1006
|
# Code._0001: {W_: {}},
|
|
978
1007
|
# Code._0002: {I_: {}},
|
|
979
1008
|
# Code._0008: {I_: {}},
|
|
@@ -988,8 +1017,8 @@ _DEV_KLASSES_HEAT: dict[str, dict] = {
|
|
|
988
1017
|
# },
|
|
989
1018
|
}
|
|
990
1019
|
# TODO: add 1FC9 everywhere?
|
|
991
|
-
_DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
992
|
-
|
|
1020
|
+
_DEV_KLASSES_HVAC: dict[str, dict[Code, dict[VerbT, Any]]] = {
|
|
1021
|
+
DevType.DIS: { # Orcon RF15 Display: ?a superset of a REM
|
|
993
1022
|
Code._0001: {RQ: {}},
|
|
994
1023
|
Code._042F: {I_: {}},
|
|
995
1024
|
Code._10E0: {I_: {}, RQ: {}},
|
|
@@ -1004,7 +1033,7 @@ _DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
|
1004
1033
|
Code._313F: {RQ: {}},
|
|
1005
1034
|
Code._31DA: {RQ: {}},
|
|
1006
1035
|
},
|
|
1007
|
-
|
|
1036
|
+
DevType.RFS: { # Itho spIDer: RF to Internet gateway (like a RFG100)
|
|
1008
1037
|
Code._1060: {I_: {}},
|
|
1009
1038
|
Code._10E0: {I_: {}, RP: {}},
|
|
1010
1039
|
Code._12C0: {I_: {}},
|
|
@@ -1019,8 +1048,9 @@ _DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
|
1019
1048
|
Code._31DA: {RQ: {}},
|
|
1020
1049
|
Code._3EF0: {I_: {}},
|
|
1021
1050
|
},
|
|
1022
|
-
|
|
1051
|
+
DevType.FAN: {
|
|
1023
1052
|
Code._0001: {RP: {}},
|
|
1053
|
+
Code._0002: {I_: {}},
|
|
1024
1054
|
Code._042F: {I_: {}},
|
|
1025
1055
|
Code._10D0: {I_: {}, RP: {}},
|
|
1026
1056
|
Code._10E0: {I_: {}, RP: {}},
|
|
@@ -1030,26 +1060,40 @@ _DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
|
1030
1060
|
Code._1470: {RP: {}},
|
|
1031
1061
|
Code._1F09: {I_: {}, RP: {}},
|
|
1032
1062
|
Code._1FC9: {W_: {}},
|
|
1063
|
+
Code._2210: {I_: {}, RP: {}},
|
|
1064
|
+
Code._22E0: {RP: {}},
|
|
1065
|
+
Code._22E5: {RP: {}},
|
|
1066
|
+
Code._22E9: {RP: {}},
|
|
1067
|
+
Code._22F1: {RP: {}},
|
|
1068
|
+
Code._22F2: {I_: {}, RP: {}},
|
|
1069
|
+
Code._22F3: {},
|
|
1070
|
+
Code._22F4: {I_: {}, RP: {}},
|
|
1033
1071
|
Code._22F7: {I_: {}, RP: {}},
|
|
1034
1072
|
Code._2411: {I_: {}, RP: {}},
|
|
1073
|
+
Code._2E10: {I_: {}},
|
|
1035
1074
|
Code._3120: {I_: {}},
|
|
1075
|
+
Code._3150: {I_: {}},
|
|
1076
|
+
Code._313E: {RP: {}},
|
|
1036
1077
|
Code._313F: {I_: {}, RP: {}},
|
|
1037
1078
|
Code._31D9: {I_: {}, RP: {}},
|
|
1038
1079
|
Code._31DA: {I_: {}, RP: {}},
|
|
1039
1080
|
# Code._31E0: {I_: {}},
|
|
1081
|
+
Code._3200: {I_: {}},
|
|
1082
|
+
Code._3222: {RP: {}},
|
|
1040
1083
|
},
|
|
1041
|
-
|
|
1084
|
+
DevType.CO2: {
|
|
1042
1085
|
Code._042F: {I_: {}},
|
|
1043
1086
|
Code._10E0: {I_: {}, RP: {}},
|
|
1044
|
-
Code._1298: {I_: {}},
|
|
1087
|
+
Code._1298: {I_: {}, RP: {}},
|
|
1045
1088
|
Code._1FC9: {I_: {}},
|
|
1089
|
+
Code._22F1: {RQ: {}},
|
|
1046
1090
|
Code._2411: {RQ: {}},
|
|
1047
1091
|
Code._2E10: {I_: {}},
|
|
1048
1092
|
Code._3120: {I_: {}},
|
|
1049
1093
|
Code._31DA: {RQ: {}},
|
|
1050
1094
|
Code._31E0: {I_: {}},
|
|
1051
1095
|
},
|
|
1052
|
-
|
|
1096
|
+
DevType.HUM: {
|
|
1053
1097
|
Code._042F: {I_: {}},
|
|
1054
1098
|
Code._1060: {I_: {}},
|
|
1055
1099
|
Code._10E0: {I_: {}},
|
|
@@ -1058,10 +1102,15 @@ _DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
|
1058
1102
|
Code._31DA: {RQ: {}},
|
|
1059
1103
|
Code._31E0: {I_: {}},
|
|
1060
1104
|
},
|
|
1061
|
-
|
|
1105
|
+
DevType.REM: { # HVAC: two-way switch; also an "06/22F1"?
|
|
1062
1106
|
Code._0001: {RQ: {}}, # from a VMI (only?)
|
|
1063
1107
|
Code._042F: {I_: {}}, # from a VMI (only?)
|
|
1064
1108
|
Code._1060: {I_: {}},
|
|
1109
|
+
Code._10D0: {
|
|
1110
|
+
RP: {},
|
|
1111
|
+
RQ: {},
|
|
1112
|
+
W_: {},
|
|
1113
|
+
}, # RQ/RP Orcon HRC, W=reset filter count from REM
|
|
1065
1114
|
Code._10E0: {I_: {}, RQ: {}}, # RQ from a VMI (only?)
|
|
1066
1115
|
Code._1470: {RQ: {}}, # from a VMI (only?)
|
|
1067
1116
|
Code._1FC9: {I_: {}},
|
|
@@ -1078,8 +1127,8 @@ _DEV_KLASSES_HVAC: dict[str, dict] = {
|
|
|
1078
1127
|
# },
|
|
1079
1128
|
}
|
|
1080
1129
|
|
|
1081
|
-
CODES_BY_DEV_SLUG: dict[str, dict] = {
|
|
1082
|
-
|
|
1130
|
+
CODES_BY_DEV_SLUG: dict[str, dict[Code, dict[VerbT, Any]]] = {
|
|
1131
|
+
DevType.HGI: { # HGI80: RF to (USB) serial gateway interface
|
|
1083
1132
|
Code._PUZZ: {I_: {}, RQ: {}, W_: {}},
|
|
1084
1133
|
}, # HGI80s can do what they like
|
|
1085
1134
|
**{k: v for k, v in _DEV_KLASSES_HVAC.items() if k is not None},
|
|
@@ -1087,11 +1136,10 @@ CODES_BY_DEV_SLUG: dict[str, dict] = {
|
|
|
1087
1136
|
}
|
|
1088
1137
|
|
|
1089
1138
|
CODES_OF_HEAT_DOMAIN: tuple[Code] = sorted( # type: ignore[assignment]
|
|
1090
|
-
tuple(
|
|
1091
|
-
+ (Code._0B04, Code._2389)
|
|
1139
|
+
tuple({c for k in _DEV_KLASSES_HEAT.values() for c in k}) + (Code._0B04, Code._2389)
|
|
1092
1140
|
)
|
|
1093
1141
|
CODES_OF_HVAC_DOMAIN: tuple[Code] = sorted( # type: ignore[assignment]
|
|
1094
|
-
tuple(
|
|
1142
|
+
tuple({c for k in _DEV_KLASSES_HVAC.values() for c in k})
|
|
1095
1143
|
+ (Code._22F8, Code._4401, Code._4E01, Code._4E02, Code._4E04)
|
|
1096
1144
|
)
|
|
1097
1145
|
CODES_OF_HEAT_DOMAIN_ONLY: tuple[Code, ...] = tuple(
|
|
@@ -1100,27 +1148,27 @@ CODES_OF_HEAT_DOMAIN_ONLY: tuple[Code, ...] = tuple(
|
|
|
1100
1148
|
CODES_OF_HVAC_DOMAIN_ONLY: tuple[Code, ...] = tuple(
|
|
1101
1149
|
c for c in sorted(CODES_OF_HVAC_DOMAIN) if c not in CODES_OF_HEAT_DOMAIN
|
|
1102
1150
|
)
|
|
1103
|
-
_CODES_OF_BOTH_DOMAINS: tuple[Code, ...] =
|
|
1104
|
-
|
|
1151
|
+
_CODES_OF_BOTH_DOMAINS: tuple[Code, ...] = tuple(
|
|
1152
|
+
sorted(set(CODES_OF_HEAT_DOMAIN) & set(CODES_OF_HVAC_DOMAIN))
|
|
1105
1153
|
)
|
|
1106
|
-
_CODES_OF_EITHER_DOMAIN: tuple[Code, ...] =
|
|
1107
|
-
|
|
1154
|
+
_CODES_OF_EITHER_DOMAIN: tuple[Code, ...] = tuple(
|
|
1155
|
+
sorted(set(CODES_OF_HEAT_DOMAIN) | set(CODES_OF_HVAC_DOMAIN))
|
|
1108
1156
|
)
|
|
1109
1157
|
_CODES_OF_NO_DOMAIN: tuple[Code, ...] = tuple(
|
|
1110
1158
|
c for c in CODES_SCHEMA if c not in _CODES_OF_EITHER_DOMAIN
|
|
1111
1159
|
)
|
|
1112
1160
|
|
|
1113
|
-
_CODE_FROM_NON_CTL: tuple[Code] = tuple(
|
|
1161
|
+
_CODE_FROM_NON_CTL: tuple[Code, ...] = tuple(
|
|
1114
1162
|
dict.fromkeys(
|
|
1115
1163
|
c
|
|
1116
1164
|
for k, v1 in CODES_BY_DEV_SLUG.items()
|
|
1117
1165
|
for c, v2 in v1.items()
|
|
1118
|
-
if k !=
|
|
1166
|
+
if k != DevType.CTL and (I_ in v2 or RP in v2)
|
|
1119
1167
|
)
|
|
1120
1168
|
)
|
|
1121
|
-
_CODE_FROM_CTL = _DEV_KLASSES_HEAT[
|
|
1169
|
+
_CODE_FROM_CTL = _DEV_KLASSES_HEAT[DevType.CTL].keys()
|
|
1122
1170
|
|
|
1123
|
-
_CODE_ONLY_FROM_CTL: tuple[Code] = tuple(
|
|
1171
|
+
_CODE_ONLY_FROM_CTL: tuple[Code, ...] = tuple(
|
|
1124
1172
|
c for c in _CODE_FROM_CTL if c not in _CODE_FROM_NON_CTL
|
|
1125
1173
|
)
|
|
1126
1174
|
CODES_ONLY_FROM_CTL: tuple[Code, ...] = (
|
|
@@ -1130,6 +1178,10 @@ CODES_ONLY_FROM_CTL: tuple[Code, ...] = (
|
|
|
1130
1178
|
Code._313F,
|
|
1131
1179
|
) # I packets, TODO: 31Dx too?
|
|
1132
1180
|
|
|
1181
|
+
#
|
|
1182
|
+
########################################################################################
|
|
1183
|
+
# Other Stuff
|
|
1184
|
+
|
|
1133
1185
|
# ### WIP:
|
|
1134
1186
|
# _result = {}
|
|
1135
1187
|
# for domain in (_DEV_KLASSES_HVAC, ):
|
|
@@ -1149,22 +1201,22 @@ CODES_ONLY_FROM_CTL: tuple[Code, ...] = (
|
|
|
1149
1201
|
# }
|
|
1150
1202
|
|
|
1151
1203
|
|
|
1152
|
-
_HVAC_VC_PAIR_BY_CLASS: dict[
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1204
|
+
_HVAC_VC_PAIR_BY_CLASS: dict[DevType, tuple[tuple[VerbT, Code], ...]] = {
|
|
1205
|
+
DevType.CO2: ((I_, Code._1298),),
|
|
1206
|
+
DevType.FAN: ((I_, Code._31D9), (I_, Code._31DA), (RP, Code._31DA)),
|
|
1207
|
+
DevType.HUM: ((I_, Code._12A0),),
|
|
1208
|
+
DevType.REM: ((I_, Code._22F1), (I_, Code._22F3)),
|
|
1157
1209
|
}
|
|
1158
|
-
HVAC_KLASS_BY_VC_PAIR: dict[tuple,
|
|
1210
|
+
HVAC_KLASS_BY_VC_PAIR: dict[tuple[VerbT, Code], DevType] = {
|
|
1159
1211
|
t: k for k, v in _HVAC_VC_PAIR_BY_CLASS.items() for t in v
|
|
1160
1212
|
}
|
|
1161
1213
|
|
|
1162
1214
|
|
|
1163
|
-
SZ_DESCRIPTION = "description"
|
|
1164
|
-
SZ_MIN_VALUE = "min_value"
|
|
1165
|
-
SZ_MAX_VALUE = "max_value"
|
|
1166
|
-
SZ_PRECISION = "precision"
|
|
1167
|
-
SZ_DATA_TYPE = "data_type"
|
|
1215
|
+
SZ_DESCRIPTION: Final = "description"
|
|
1216
|
+
SZ_MIN_VALUE: Final = "min_value"
|
|
1217
|
+
SZ_MAX_VALUE: Final = "max_value"
|
|
1218
|
+
SZ_PRECISION: Final = "precision"
|
|
1219
|
+
SZ_DATA_TYPE: Final = "data_type"
|
|
1168
1220
|
|
|
1169
1221
|
_22F1_MODE_ITHO: dict[str, str] = {
|
|
1170
1222
|
"00": "off", # not seen
|
|
@@ -1192,13 +1244,24 @@ _22F1_MODE_ORCON: dict[str, str] = {
|
|
|
1192
1244
|
"07": "off",
|
|
1193
1245
|
}
|
|
1194
1246
|
|
|
1195
|
-
|
|
1247
|
+
_22F1_MODE_VASCO: dict[str, str] = { # for VASCO D60 and ClimaRad Minibox remotes
|
|
1248
|
+
"00": "off",
|
|
1249
|
+
"01": "away", # 000106 minimum
|
|
1250
|
+
"02": "low", # 000206
|
|
1251
|
+
"03": "medium", # 000306
|
|
1252
|
+
"04": "high", # 000406, aka boost with 22F3
|
|
1253
|
+
"05": "auto",
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
_22F1_SCHEMES: dict[str, dict[str, str]] = {
|
|
1196
1257
|
"itho": _22F1_MODE_ITHO,
|
|
1197
1258
|
"nuaire": _22F1_MODE_NUAIRE,
|
|
1198
1259
|
"orcon": _22F1_MODE_ORCON,
|
|
1260
|
+
"vasco": _22F1_MODE_VASCO,
|
|
1199
1261
|
}
|
|
1200
1262
|
|
|
1201
|
-
|
|
1263
|
+
# unclear if true for only Orcon/*all* models
|
|
1264
|
+
_2411_PARAMS_SCHEMA: dict[str, dict[str, Any]] = {
|
|
1202
1265
|
"31": { # slot 09
|
|
1203
1266
|
SZ_DESCRIPTION: "Time to change filter (days)",
|
|
1204
1267
|
SZ_MIN_VALUE: 0,
|
|
@@ -1299,11 +1362,25 @@ _2411_PARAMS_SCHEMA: dict[str, dict] = { # unclear if true for only Orcon/*all*
|
|
|
1299
1362
|
},
|
|
1300
1363
|
}
|
|
1301
1364
|
|
|
1365
|
+
# ventilation speed description
|
|
1366
|
+
_31D9_FAN_INFO_VASCO: dict[int, str] = {
|
|
1367
|
+
0x00: "off",
|
|
1368
|
+
0x01: "1 (trickle)", # aka low
|
|
1369
|
+
0x02: "2 (low)", # aka medium
|
|
1370
|
+
0x03: "3 (medium)", # aka high
|
|
1371
|
+
0x04: "4 (boost)",
|
|
1372
|
+
0x05: "auto",
|
|
1373
|
+
0xC8: "III (boost)", # same code sent for speed II and III, mode manual
|
|
1374
|
+
0x50: "I (low)",
|
|
1375
|
+
0x1E: "0 (very low)",
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
# ventilation speed
|
|
1302
1379
|
_31DA_FAN_INFO: dict[int, str] = {
|
|
1303
1380
|
0x00: "off",
|
|
1304
|
-
0x01: "speed 1", # low
|
|
1305
|
-
0x02: "speed 2", # medium
|
|
1306
|
-
0x03: "speed 3", # high
|
|
1381
|
+
0x01: "speed 1, low", # aka low
|
|
1382
|
+
0x02: "speed 2, medium", # aka medium
|
|
1383
|
+
0x03: "speed 3, high", # aka high
|
|
1307
1384
|
0x04: "speed 4",
|
|
1308
1385
|
0x05: "speed 5",
|
|
1309
1386
|
0x06: "speed 6",
|
|
@@ -1311,8 +1388,8 @@ _31DA_FAN_INFO: dict[int, str] = {
|
|
|
1311
1388
|
0x08: "speed 8",
|
|
1312
1389
|
0x09: "speed 9",
|
|
1313
1390
|
0x0A: "speed 10",
|
|
1314
|
-
0x0B: "speed 1 temporary override",
|
|
1315
|
-
0x0C: "speed 2 temporary override",
|
|
1391
|
+
0x0B: "speed 1 temporary override", # timer
|
|
1392
|
+
0x0C: "speed 2 temporary override", # timer
|
|
1316
1393
|
0x0D: "speed 3 temporary override", # timer/boost? (timer 1, 2, 3)
|
|
1317
1394
|
0x0E: "speed 4 temporary override",
|
|
1318
1395
|
0x0F: "speed 5 temporary override",
|
|
@@ -1321,17 +1398,17 @@ _31DA_FAN_INFO: dict[int, str] = {
|
|
|
1321
1398
|
0x12: "speed 8 temporary override",
|
|
1322
1399
|
0x13: "speed 9 temporary override",
|
|
1323
1400
|
0x14: "speed 10 temporary override",
|
|
1324
|
-
0x15: "away",
|
|
1401
|
+
0x15: "away", # absolute minimum speed
|
|
1325
1402
|
0x16: "absolute minimum", # trickle?
|
|
1326
|
-
0x17: "absolute maximum", # boost?
|
|
1403
|
+
0x17: "boost", # absolute maximum", # boost?
|
|
1327
1404
|
0x18: "auto",
|
|
1328
|
-
0x19: "
|
|
1405
|
+
0x19: "auto_night",
|
|
1329
1406
|
0x1A: "-unknown 0x1A-",
|
|
1330
1407
|
0x1B: "-unknown 0x1B-",
|
|
1331
1408
|
0x1C: "-unknown 0x1C-",
|
|
1332
1409
|
0x1D: "-unknown 0x1D-",
|
|
1333
1410
|
0x1E: "-unknown 0x1E-",
|
|
1334
|
-
0x1F: "-unknown 0x1F-",
|
|
1411
|
+
0x1F: "-unknown 0x1F-", # static field, used as filter in parser_31da so keep same
|
|
1335
1412
|
}
|
|
1336
1413
|
|
|
1337
1414
|
|