Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
proto_heating.h
Go to the documentation of this file.
1#pragma once
2
3/// @file proto_heating.h
4/// @brief Pure codec for IO-Homecontrol 2W heating/climate functions (CMD_WRITE_PRIVATE 0x20).
5/// @ingroup hioc_protocol
6///
7/// Encodes the six "Cozytouch" radiator functions (Sauter / Atlantic / Thermor) into
8/// CMD_WRITE_PRIVATE (0x20) payloads. This module is pure: it does not touch a frame, a device
9/// record or the radio — proto_commands.h's create_write_private() frames the result.
10///
11/// Byte-layout sources: the iohomecontrol reference implementation's Cozy 2W device code —
12/// `forgePacket()` and the DeviceButton payload builders in its `cmd()` — cross-checked against
13/// the iown-homecontrol project's Atlantic/Thermor register map, which names the
14/// opcodes ("Set 0c61 01xx" / "Get 0c60 01xx") and shows the setpoint registers as 16-bit
15/// little-endian tenths of a degree. Every payload byte below is cited. No hardware is available
16/// for this family; the experimental banner lives in docs/home_io_control.md.
17
18#include <cstddef>
19#include <cstdint>
20
21namespace esphome {
22namespace home_io_control {
23
24/// @brief Heating functions, one per user-pressable radiator button in the reference.
25enum class HeatingFunction : uint8_t {
26 POWER_ON, ///< Wake / retrieve paired devices (iohcCozyDevice2W.cpp:105).
27 SET_TEMPERATURE, ///< Setpoint in degrees Celsius (iohcCozyDevice2W.cpp:125).
28 SET_MODE, ///< Operating mode (iohcCozyDevice2W.cpp:155).
29 SET_PRESENCE, ///< Presence / absence (iohcCozyDevice2W.cpp:195).
30 SET_WINDOW, ///< Open-window / frost-protection (iohcCozyDevice2W.cpp:218).
31 MIDNIGHT_SYNC, ///< Reads register 0x0130 — the comfort/eco/auto setpoint block
32 ///< (iohcCozyDevice2W.cpp:248; AtlanticThermor/README.md's 0x0130 rows). Named
33 ///< "midnight" in the reference, but the payload is a 0x60 *read*, not a
34 ///< clock-set: the device's clock register is 0x010F and this component never
35 ///< writes it. Provided for protocol exploration; the 0x21 ACK payload is
36 ///< logged at DEBUG (see IOHomeControlComponent::send_heating_command()).
37};
38
39/// @brief Operating modes for HeatingFunction::SET_MODE.
40///
41/// Values from iohcCozyDevice2W.cpp:158-162. The 0x03 "special" mode is commented out at :161 in
42/// the reference and is deliberately not exposed here.
43enum class HeatingMode : uint8_t {
44 AUTO = 0x00, ///< Automatic mode; device manages the setpoint itself (iohcCozyDevice2W.cpp:158).
45 MANUAL = 0x01, ///< Manual mode; follows the last SET_TEMPERATURE setpoint (iohcCozyDevice2W.cpp:159).
46 PROG = 0x02, ///< Program mode; device runs its own stored weekly schedule (iohcCozyDevice2W.cpp:160).
47 OFF = 0x04, ///< Off / standby; note the value is 0x04, not 0x03 (that is the reference's
48 ///< commented-out "special" mode) (iohcCozyDevice2W.cpp:162).
49};
50
51/// @brief Lowest setpoint this codec will encode.
52///
53/// The conventional frost-protection setpoint. No reference evidence pins a hard lower bound;
54/// 7.0 is safely representable as wire byte 0x46.
55constexpr float HEATING_TEMP_MIN_C = 7.0F;
56
57/// @brief Highest setpoint this codec will encode.
58///
59/// iohcCozyDevice2W.cpp:125-128 only writes the low byte of the setpoint field, so *that*
60/// implementation tops out at 0xFF = 25.5 C — a latent bug, not the wire limit. The vendored
61/// Atlantic register map (AtlanticThermor/README.md) shows the setpoint field is a 16-bit
62/// little-endian value in tenths of a degree: its 0x0130 block carries `18 01` = 0x0118 = 280 =
63/// 28.0 C as a live setpoint. This codec writes both bytes and allows up to 28.0 C, the ceiling
64/// Atlantic radiator manuals document. The encoding above 25.5 C is corroborated by the vendored
65/// register map but still unverified on hardware — see docs/home_io_control.md.
66constexpr float HEATING_TEMP_MAX_C = 28.0F;
67
68/// @brief Largest payload any function produces — SET_TEMPERATURE's 6-byte form
69/// (iohcCozyDevice2W.cpp:125).
70constexpr size_t HEATING_PAYLOAD_MAX_SIZE = 6;
71
72/// @brief Leading payload byte, common to every function (iohcCozyDevice2W.cpp:105 et al.).
73///
74/// The reference gives it no name and no explanation; its meaning is unconfirmed. Do not read a
75/// semantic (e.g. "device class") into it.
76constexpr uint8_t HEATING_PAYLOAD_PREFIX = 0x0C;
77
78/// @brief Payload byte at index 2 — the high byte of the 16-bit register number, constant `0x01`
79/// (registers are `0x01xx`) per AtlanticThermor/README.md ("Set 0c61 01xx" / "Get 0c60 01xx").
80/// The low byte (register selector) is per-function; see HeatingFunctionDescriptor::register_low.
81constexpr uint8_t HEATING_REGISTER_HIGH_BYTE = 0x01;
82
83/// @brief Stable lowercase name for a heating function ("power_on", "set_temperature", ...).
84/// @param fn Function.
85/// @return Null-terminated string; "unknown" for an out-of-range value.
87
88/// @brief Encode one heating function into a CMD_WRITE_PRIVATE (0x20) payload.
89///
90/// Table-driven: a single constexpr descriptor table supplies the direction byte, register-low
91/// byte and value kind per function, so there is no copy-pasted per-function builder. `value` is
92/// interpreted by function:
93/// - SET_TEMPERATURE: degrees Celsius, must lie within
94/// [HEATING_TEMP_MIN_C, HEATING_TEMP_MAX_C]; encoded as a 16-bit little-endian value in tenths
95/// of a degree, round-half-away-from-zero(10 * value) (AtlanticThermor/README.md's 0x0103 /
96/// 0x0130 rows). iohcCozyDevice2W.cpp:125-128 only writes the low byte and truncates; this
97/// codec writes both bytes and rounds, deliberately.
98/// - SET_MODE: a HeatingMode value widened to float (e.g. `float(HeatingMode::MANUAL)`); must
99/// be exactly one of AUTO / MANUAL / PROG / OFF.
100/// - SET_PRESENCE: 0 (absent) or 1 (present) (iohcCozyDevice2W.cpp:198-199).
101/// - SET_WINDOW: 0 (closed) or 1 (open / frost protection) (iohcCozyDevice2W.cpp:221-222).
102/// - POWER_ON / MIDNIGHT_SYNC: `value` is ignored.
103/// Out-of-range, non-integral (for enum/binary kinds) or non-finite input is rejected with a 0
104/// return — a byte derived from a truncating or wrapping cast is never emitted.
105/// @param fn Function to encode.
106/// @param value Function-specific value (see above).
107/// @param out Output buffer of HEATING_PAYLOAD_MAX_SIZE bytes.
108/// @return Number of payload bytes written (4, 5 or 6), or 0 on invalid input.
109size_t encode_heating_payload(HeatingFunction fn, float value, uint8_t out[HEATING_PAYLOAD_MAX_SIZE]);
110
111} // namespace home_io_control
112} // namespace esphome
constexpr size_t HEATING_PAYLOAD_MAX_SIZE
Largest payload any function produces — SET_TEMPERATURE's 6-byte form (iohcCozyDevice2W....
size_t encode_heating_payload(HeatingFunction fn, float value, uint8_t out[HEATING_PAYLOAD_MAX_SIZE])
Encode one heating function into a CMD_WRITE_PRIVATE (0x20) payload.
HeatingFunction
Heating functions, one per user-pressable radiator button in the reference.
@ MIDNIGHT_SYNC
Reads register 0x0130 — the comfort/eco/auto setpoint block (iohcCozyDevice2W.cpp:248; AtlanticThermo...
@ POWER_ON
Wake / retrieve paired devices (iohcCozyDevice2W.cpp:105).
@ SET_PRESENCE
Presence / absence (iohcCozyDevice2W.cpp:195).
@ SET_TEMPERATURE
Setpoint in degrees Celsius (iohcCozyDevice2W.cpp:125).
@ SET_MODE
Operating mode (iohcCozyDevice2W.cpp:155).
@ SET_WINDOW
Open-window / frost-protection (iohcCozyDevice2W.cpp:218).
constexpr uint8_t HEATING_REGISTER_HIGH_BYTE
Payload byte at index 2 — the high byte of the 16-bit register number, constant 0x01 (registers are 0...
constexpr float HEATING_TEMP_MAX_C
Highest setpoint this codec will encode.
const char * heating_function_name(HeatingFunction fn)
Stable lowercase name for a heating function ("power_on", "set_temperature", ...).
constexpr float HEATING_TEMP_MIN_C
Lowest setpoint this codec will encode.
HeatingMode
Operating modes for HeatingFunction::SET_MODE.
@ OFF
Off / standby; note the value is 0x04, not 0x03 (that is the reference's commented-out "special" mode...
@ PROG
Program mode; device runs its own stored weekly schedule (iohcCozyDevice2W.cpp:160).
@ MANUAL
Manual mode; follows the last SET_TEMPERATURE setpoint (iohcCozyDevice2W.cpp:159).
@ AUTO
Automatic mode; device manages the setpoint itself (iohcCozyDevice2W.cpp:158).
constexpr uint8_t HEATING_PAYLOAD_PREFIX
Leading payload byte, common to every function (iohcCozyDevice2W.cpp:105 et al.).