From cc53f209abb858ceecdcc8e1a56c9730806850a1 Mon Sep 17 00:00:00 2001 From: Egbert Broerse Date: Fri, 18 Oct 2024 18:18:36 +0200 Subject: [PATCH 1/4] ventura scheme --- src/ramses_tx/parsers.py | 54 +++++++++++++++++++++++-------- src/ramses_tx/ramses.py | 18 +++++++++++ tests/tests/parsers/code_22f4.log | 33 +++++++++++++++++++ 3 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 tests/tests/parsers/code_22f4.log diff --git a/src/ramses_tx/parsers.py b/src/ramses_tx/parsers.py index 13b8c7a9..45e8ac8c 100644 --- a/src/ramses_tx/parsers.py +++ b/src/ramses_tx/parsers.py @@ -45,6 +45,7 @@ SZ_DOMAIN_IDX, SZ_DURATION, SZ_FAN_MODE, + SZ_FAN_RATE, SZ_FAULT_STATE, SZ_FAULT_TYPE, SZ_FRAG_LENGTH, @@ -1646,20 +1647,45 @@ def parser_22f3(payload: str, msg: Message) -> dict[str, Any]: # WIP: unknown, HVAC def parser_22f4(payload: str, msg: Message) -> dict[str, Any]: # RP --- 32:155617 18:005904 --:------ 22F4 013 00-60-E6-00000000000000-200000 - # RP --- 32:153258 18:005904 --:------ 22F4 013 00-60-DD-00000000000000-200000 - # RP --- 32:155617 18:005904 --:------ 22F4 013 00-40-B0-00000000000000-200000 - - # RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E4-00000000000000-200000 - # RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E5-00000000000000-200000 - # RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E6-00000000000000-200000 - - assert payload[:2] == "00" - assert payload[6:] == "00000000000000200000" - - return { - "value_02": payload[2:4], - "value_04": payload[4:6], - } + if payload[20:] == "200000": + assert ( + payload[6:] == "00000000000000200000" or payload[14:] == "000000000000" + ) # TODO add an error message + result = { + "value_02": payload[2:4], + "value_04": payload[4:6], + } + else: + # heard from ClimaRad Ventura, see _22F4_MODE_CLIMARAD + from .ramses import _22F4_MODE_CLIMARAD as _22F4_FAN_MODE + + _22f4_scheme = "climarad" + rate = "0" + mode = "N/A" + if payload[2:4] == "40": # auto mode + assert payload[4:6] == "30", f"unknown auto mode: 0x40{payload[4:6]}" + mode = _22F4_FAN_MODE.get("40") + rate = "0" + elif payload[2:4] == "20": # paused mode + assert payload[4:6] == "00", f"unknown paused mode: 0x20{payload[4:6]}" + mode = _22F4_FAN_MODE.get("20") + rate = "0" + _22f4_mode_set = ("", "60") + if payload[10:12] in _22f4_mode_set: # manual mode, with speed rate + mode = _22F4_FAN_MODE.get("60") + try: + assert ( + payload[12:14] in _22F4_FAN_MODE + ), f"unknown fan_mode: {payload[12:14]}" + except AssertionError as err: + _LOGGER.warning( + f"unknown ClimaRad speed rate {msg!r} < {_INFORM_DEV_MSG} ({err})" + ) + + rate = _22F4_FAN_MODE.get(payload[12:14], f"unknown_{payload[12:14]}") + + result = {SZ_FAN_MODE: mode, SZ_FAN_RATE: rate, "_scheme": _22f4_scheme} + return result # bypass_mode, HVAC diff --git a/src/ramses_tx/ramses.py b/src/ramses_tx/ramses.py index 66d18cd4..3e03ba63 100644 --- a/src/ramses_tx/ramses.py +++ b/src/ramses_tx/ramses.py @@ -420,6 +420,7 @@ }, # minutes only? Code._22F4: { # unknown_22f4, HVAC, NB: no I SZ_NAME: "unknown_22f4", + I_: r"^00[0-9A-F]{24}$", RQ: r"^00$", RP: r"^00[0-9A-F]{24}$", }, @@ -1062,6 +1063,7 @@ Code._1FC9: {W_: {}}, Code._22F1: {}, Code._22F3: {}, + Code._22F4: {I_: {}}, Code._22F7: {I_: {}, RP: {}}, Code._2411: {I_: {}, RP: {}}, Code._3120: {I_: {}}, @@ -1234,6 +1236,22 @@ "orcon": _22F1_MODE_ORCON, } +_22F4_MODE_CLIMARAD: dict[str, str] = { + # for ClimaRad Ventura fan/remote + "C9": "1", # * low speed rate, operating mode for C9-CD always 60 - manual + "CA": "2", # ** medium-low + "CB": "3", # *** medium + "CC": "4", # **** medium-high + "CD": "5", # |>|> high aka boost + "20": "paused", + "40": "auto", + "60": "manual", +} + +_22F4_SCHEMES: dict[str, dict[str, str]] = { + "climarad": _22F4_MODE_CLIMARAD, +} + # unclear if true for only Orcon/*all* models _2411_PARAMS_SCHEMA: dict[str, dict[str, Any]] = { "31": { # slot 09 diff --git a/tests/tests/parsers/code_22f4.log b/tests/tests/parsers/code_22f4.log new file mode 100644 index 00000000..024a929d --- /dev/null +++ b/tests/tests/parsers/code_22f4.log @@ -0,0 +1,33 @@ +# RP --- 32:155617 18:005904 --:------ 22F4 013 00-60-E6-00000000000000-200000 # {} +# RP --- 32:153258 18:005904 --:------ 22F4 013 00-60-DD-00000000000000-200000 # {} +# RP --- 32:155617 18:005904 --:------ 22F4 013 00-40-B0-00000000000000-200000 # {} +# +# RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E4-00000000000000-200000 # {} +# RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E5-00000000000000-200000 # {} +# RP --- 32:137185 18:003599 --:------ 22F4 013 00-60-E6-00000000000000-200000 # {} + +# same packets as tests, simulated dates added to packets +2024-01-01T13:12:46.635997 ... RP --- 32:155617 18:005904 --:------ 22F4 013 0060E600000000000000200000 # {'value_02': '60', 'value_04': 'E6'} +2024-01-01T13:12:46.635997 ... RP --- 32:153258 18:005904 --:------ 22F4 013 0060DD00000000000000200000 # {'value_02': '60', 'value_04': 'DD'} +2024-01-01T13:12:46.635997 ... RP --- 32:155617 18:005904 --:------ 22F4 013 0040B000000000000000200000 # {'value_02': '40', 'value_04': 'B0'} + +2024-01-01T13:12:46.635997 ... RP --- 32:137185 18:003599 --:------ 22F4 013 0060E400000000000000200000 # {'value_02': '60', 'value_04': 'E4'} +2024-01-01T13:12:46.635997 ... RP --- 32:137185 18:003599 --:------ 22F4 013 0060E500000000000000200000 # {'value_02': '60', 'value_04': 'E5'} +2024-01-01T13:12:46.635997 ... RP --- 32:137185 18:003599 --:------ 22F4 013 0060E600000000000000200000 # {'value_02': '60', 'value_04': 'E6'} + +# ClimaRad VenturaV1x +# heard from ClimaRad Ventura, see _22F4_MODE_CLIMARAD +# .I --- 37:153226 --:------ 37:153226 22F4 013 004030 0000 0000 000000-000000 # (auto) +# .I --- 37:153226 --:------ 37:153226 22F4 013 000000 0000 60C9 000000-000000 # (speed 1) +# .I --- 37:153226 --:------ 37:153226 22F4 013 000000 0000 60CA 000000-000000 # (speed 2) +# .I --- 37:153226 --:------ 37:153226 22F4 013 000000 0000 60CB 000000-000000 # (speed 3) +# .I --- 37:153226 --:------ 37:153226 22F4 013 002000 0000 2000 000000-000000 # (pause ||) + +2024-10-15T13:12:46.635997 000 RQ --- 18:130140 37:153226 --:------ 22F4 001 00 # {} +2024-10-15T13:12:46.657580 061 RP --- 37:153226 18:130140 --:------ 22F4 013 00403000000000000000000000 # {'_scheme': 'climarad', 'fan_mode': 'auto', 'fan_rate': '0'} # mode Auto + +2024-01-01T13:12:46.635997 ... I --- 37:153226 --:------ 37:153226 22F4 013 00403000000000000000000000 # {'_scheme': 'climarad', 'fan_mode': 'auto', 'fan_rate': '0'} +2024-10-18T15:38:47.301482 065 I --- 37:153226 --:------ 37:153226 22F4 013 000000000060CA000000000000 # {'_scheme': 'climarad', 'fan_mode': 'manual', 'fan_rate': '2'} +2024-01-01T13:12:46.635997 ... I --- 37:153226 --:------ 37:153226 22F4 013 000000000060CA000000000000 # {'_scheme': 'climarad', 'fan_mode': 'manual', 'fan_rate': '2'} +2024-01-01T13:12:46.635997 ... I --- 37:153226 --:------ 37:153226 22F4 013 000000000060CB000000000000 # {'_scheme': 'climarad', 'fan_mode': 'manual', 'fan_rate': '3'} +2024-01-01T13:12:46.635997 ... I --- 37:153226 --:------ 37:153226 22F4 013 00200000002000000000000000 # {'_scheme': 'climarad', 'fan_mode': 'paused', 'fan_rate': '0'} From 6b8617bade9b23bee11bdba15efbe6b28b64fc8c Mon Sep 17 00:00:00 2001 From: Egbert Broerse Date: Fri, 18 Oct 2024 18:52:48 +0200 Subject: [PATCH 2/4] typing (akin to 12a0) --- src/ramses_tx/parsers.py | 13 ++++++++----- src/ramses_tx/typed_dicts.py | 12 ++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ramses_tx/parsers.py b/src/ramses_tx/parsers.py index 81f74c42..ee8c9dd0 100644 --- a/src/ramses_tx/parsers.py +++ b/src/ramses_tx/parsers.py @@ -1645,13 +1645,13 @@ def parser_22f3(payload: str, msg: Message) -> dict[str, Any]: # WIP: unknown, HVAC -def parser_22f4(payload: str, msg: Message) -> dict[str, Any]: +def parser_22f4(payload: str, msg: Message) -> PayDictT._22F4: # RP --- 32:155617 18:005904 --:------ 22F4 013 00-60-E6-00000000000000-200000 if payload[20:] == "200000": assert ( payload[6:] == "00000000000000200000" or payload[14:] == "000000000000" ) # TODO add an error message - result = { + return { "value_02": payload[2:4], "value_04": payload[4:6], } @@ -1661,7 +1661,7 @@ def parser_22f4(payload: str, msg: Message) -> dict[str, Any]: _22f4_scheme = "climarad" rate = "0" - mode = "N/A" + mode = None if payload[2:4] == "40": # auto mode assert payload[4:6] == "30", f"unknown auto mode: 0x40{payload[4:6]}" mode = _22F4_FAN_MODE.get("40") @@ -1684,8 +1684,11 @@ def parser_22f4(payload: str, msg: Message) -> dict[str, Any]: rate = _22F4_FAN_MODE.get(payload[12:14], f"unknown_{payload[12:14]}") - result = {SZ_FAN_MODE: mode, SZ_FAN_RATE: rate, "_scheme": _22f4_scheme} - return result + return { + SZ_FAN_MODE: mode, + SZ_FAN_RATE: rate, + "_scheme": _22f4_scheme, + } # type: ignore[return-value] # bypass_mode, HVAC diff --git a/src/ramses_tx/typed_dicts.py b/src/ramses_tx/typed_dicts.py index a06380b5..23add612 100644 --- a/src/ramses_tx/typed_dicts.py +++ b/src/ramses_tx/typed_dicts.py @@ -159,6 +159,17 @@ class _22b0(TypedDict): enabled: bool +class _22f4(TypedDict): + value_02: str | None + value_04: str | None + + +class _22f4_x(TypedDict): + SZ_FAN_MODE: str | None + SZ_FAN_RATE: str | None + _scheme: str | None + + class _2309(TypedDict): zone_idx: NotRequired[str] setpoint: float | None @@ -420,6 +431,7 @@ class PayDictT: _1FC9: TypeAlias = _1fc9 _1FD4: TypeAlias = _1fd4 _22B0: TypeAlias = _22b0 + _22F4: TypeAlias = _22f4 | _22f4_x _2309: TypeAlias = _2309 _2349: TypeAlias = _2349 _22D9: TypeAlias = _Setpoint From 8e5cbd759ba97f548f03c802cd38cee7f0736758 Mon Sep 17 00:00:00 2001 From: Egbert Broerse Date: Sun, 20 Oct 2024 14:31:23 +0200 Subject: [PATCH 3/4] climarad scheme --- src/ramses_tx/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ramses_tx/schemas.py b/src/ramses_tx/schemas.py index 0c97a6df..9e9b8de2 100644 --- a/src/ramses_tx/schemas.py +++ b/src/ramses_tx/schemas.py @@ -232,7 +232,7 @@ def convert_null_to_dict(node_value: _T | None) -> _T | dict[Never, Never]: SCH_DEVICE_ID_UFC = vol.Match(DEVICE_ID_REGEX.UFC) _SCH_TRAITS_DOMAINS = ("heat", "hvac") -_SCH_TRAITS_HVAC_SCHEMES = ("itho", "nuaire", "orcon") +_SCH_TRAITS_HVAC_SCHEMES = ("itho", "nuaire", "orcon", "climarad") DeviceTraitsT = TypedDict( From 53e3e22ffe3494576b0ec57d828218017cda98d7 Mon Sep 17 00:00:00 2001 From: Egbert Broerse Date: Sun, 3 Nov 2024 22:12:19 +0100 Subject: [PATCH 4/4] tweak ClimaRad payload to correct mode --- src/ramses_tx/parsers.py | 8 +++++++- src/ramses_tx/ramses.py | 16 ---------------- tests/tests/parsers/code_22f4.log | 4 ++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/ramses_tx/parsers.py b/src/ramses_tx/parsers.py index ce78cae5..71e82e7f 100644 --- a/src/ramses_tx/parsers.py +++ b/src/ramses_tx/parsers.py @@ -1637,7 +1637,13 @@ def parser_22f3(payload: str, msg: Message) -> dict[str, Any]: # WIP: unknown, HVAC def parser_22f4(payload: str, msg: Message) -> dict[str, Any]: # HACK: for dev/test: 37:153226 is ClimaRad Ventura fan/remote - payload = payload[8:14] if msg.src.id == "37:153226" else payload[:6] + if msg.src.id == "37:153226": + if payload[10:12] == "60": + payload = payload[8:14] + else: + payload = payload[:4] + payload[12:14] + else: + payload = payload[:6] MODE_LOOKUP = { 0x00: "off?", diff --git a/src/ramses_tx/ramses.py b/src/ramses_tx/ramses.py index 82370206..5909b511 100644 --- a/src/ramses_tx/ramses.py +++ b/src/ramses_tx/ramses.py @@ -1240,22 +1240,6 @@ "orcon": _22F1_MODE_ORCON, } -_22F4_MODE_CLIMARAD: dict[str, str] = { - # for ClimaRad Ventura fan/remote - "C9": "1", # * low speed rate, operating mode for C9-CD always 60 - manual - "CA": "2", # ** medium-low - "CB": "3", # *** medium - "CC": "4", # **** medium-high - "CD": "5", # |>|> high aka boost - "20": "paused", - "40": "auto", - "60": "manual", -} - -_22F4_SCHEMES: dict[str, dict[str, str]] = { - "climarad": _22F4_MODE_CLIMARAD, -} - # unclear if true for only Orcon/*all* models _2411_PARAMS_SCHEMA: dict[str, dict[str, Any]] = { "31": { # slot 09 diff --git a/tests/tests/parsers/code_22f4.log b/tests/tests/parsers/code_22f4.log index 34f9d73d..657b30e5 100644 --- a/tests/tests/parsers/code_22f4.log +++ b/tests/tests/parsers/code_22f4.log @@ -17,11 +17,11 @@ # ClimaRad Ventura V1x, see _22F4_MODE_CLIMARAD 2024-10-15T13:12:46.635997 000 RQ --- 18:130140 37:153226 --:------ 22F4 001 00 # {} -2024-10-15T13:12:46.657580 061 RP --- 37:153226 18:130140 --:------ 22F4 013 00403000000000000000000000 # {'fan_mode': 'off?', 'fan_rate': 'speed 0'} +2024-10-15T13:12:46.657580 061 RP --- 37:153226 18:130140 --:------ 22F4 013 00403000000000000000000000 # {'fan_mode': 'auto', 'fan_rate': 'speed 0'} # (SAME PAYLOAD) appears that payload may be an array? now/next? input/output? other? 2024-10-15T13:12:46.657580 061 RP --- 37:000001 18:130140 --:------ 22F4 013 00403000000000000000000000 # {'fan_mode': 'auto', 'fan_rate': 'speed 0'} -2024-01-01T01:00:00.000000 ... I --- 37:153226 --:------ 37:153226 22F4 013 00403000000000000000000000 # {'fan_mode': 'off?', 'fan_rate': 'speed 0'} +2024-01-01T01:00:00.000000 ... I --- 37:153226 --:------ 37:153226 22F4 013 00403000000000000000000000 # {'fan_mode': 'auto', 'fan_rate': 'speed 0'} 2024-01-01T01:00:00.000000 ... I --- 37:153226 --:------ 37:153226 22F4 013 000000000060C9000000000000 # {'fan_mode': 'manual', 'fan_rate': 'speed 1'} 2024-01-01T01:00:00.000000 ... I --- 37:153226 --:------ 37:153226 22F4 013 000000000060CA000000000000 # {'fan_mode': 'manual', 'fan_rate': 'speed 2'} 2024-01-01T01:00:00.000000 ... I --- 37:153226 --:------ 37:153226 22F4 013 000000000060CB000000000000 # {'fan_mode': 'manual', 'fan_rate': 'speed 3'}