Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
proto_heating_profiles.h
Go to the documentation of this file.
1#pragma once
2
3/// @file proto_heating_profiles.h
4/// @brief Heating profiles: what a climate card offers for each kind of heater, and how.
5/// @ingroup hioc_protocol
6///
7/// A profile is one row per (node type, subtype, model) that a `climate:` entity can drive. It names the
8/// control path (the private register protocol of proto_heating.h, or the standard EXECUTE with a
9/// heating level as the main parameter), the HVAC modes and presets the card shows, how each maps to
10/// a wire value in both directions, which registers a poll reads and which companion entities exist.
11/// The platform asks the profile and never branches on a device type.
12///
13/// The enums here are protocol-side: they carry no ESPHome type. The platform maps HeatingHvacMode
14/// and HeatingPresetId onto ESPHome's climate modes and presets.
15///
16/// \todo Heating-level control of the plain electrical heater (node type 52, subtype 0) has no capture
17/// or hardware report yet. Confirm with one before calling it supported.
18/// \todo Every 52/1 seen is an Atlantic heater. A non-Atlantic 52/1 would need the heating-level
19/// path instead; the profile keys on (type, subtype, model), and the model is the YAML's.
20
21#include "proto_constants.h"
22#include "proto_device_model.h"
23#include "proto_heating.h"
24#include "proto_sizes.h"
25
26#include <cstddef>
27#include <cstdint>
28#include <span>
29
30namespace esphome {
31namespace home_io_control {
32
33/// @brief How a heater is commanded and read.
34enum class HeatingControlPath : uint8_t {
35 PRIVATE_REGISTERS, ///< CMD_WRITE_PRIVATE register reads and writes (proto_heating.h).
36 HEATING_LEVEL, ///< Standard EXECUTE with a heating level as the main parameter; read with 0x03.
37 TEMPERATURE_EXECUTE, ///< Standard EXECUTE with a temperature or an alias as the main parameter; read with 0x03.
38};
39
40/// @brief HVAC modes a profile can offer.
41enum class HeatingHvacMode : uint8_t {
42 OFF, ///< Heater off.
43 HEAT, ///< Heating on.
44 AUTO, ///< The device decides.
45};
46
47/// @brief Presets a profile can offer. CUSTOM entries carry their own name.
48enum class HeatingPresetId : uint8_t {
49 NONE, ///< No preset: selecting it ends the one that runs (a towel dryer's boost or drying).
50 AWAY, ///< Nobody is in the room (the frost-protection level on a level heater).
51 COMFORT, ///< Comfort level.
52 ECO, ///< Economy level.
53 BOOST, ///< Boost level.
54 CUSTOM, ///< Named by HeatingPresetEntry::custom_name.
55};
56
57/// @brief Main-parameter prefix byte of a heating level: the level occupies the low byte.
58static constexpr uint8_t HEATING_LEVEL_MP_PREFIX = 0xFC;
59
60/// @brief Heating levels (low byte of the main parameter, prefix HEATING_LEVEL_MP_PREFIX).
61namespace heating_level {
62static constexpr uint8_t OFF = 0x00; ///< Off.
63static constexpr uint8_t FROST_PROTECTION = 0x01; ///< Frost protection.
64static constexpr uint8_t ECO = 0x02; ///< Economy.
65static constexpr uint8_t COMFORT_MINUS_2 = 0x03; ///< Comfort, two degrees lower.
66static constexpr uint8_t COMFORT_MINUS_1 = 0x04; ///< Comfort, one degree lower.
67static constexpr uint8_t COMFORT = 0x05; ///< Comfort.
68static constexpr uint8_t BOOST = 0x07; ///< Boost.
69static constexpr uint8_t SECURED = 0x3F; ///< Secured; reported by the device, never commanded.
70} // namespace heating_level
71
72/// @brief Main-parameter prefix byte of a setpoint alias: the alias occupies the low byte.
73static constexpr uint8_t HEATING_ALIAS_MP_PREFIX = 0xD8;
74
75/// @brief Setpoint aliases (low byte of the main parameter, prefix HEATING_ALIAS_MP_PREFIX).
76namespace heating_alias {
77static constexpr uint8_t COMFORT = 0x0F; ///< The device's comfort setpoint.
78static constexpr uint8_t THERMOSTAT_ECO = 0x0E; ///< Heating temperature interface: the economy setpoint.
79static constexpr uint8_t SECURED = 0x0A; ///< Heating temperature interface: the secured setpoint.
80static constexpr uint8_t HEAT_PUMP_SETBACK = 0x0E; ///< Heat pump: the setback setpoint.
81static constexpr uint8_t HEAT_PUMP_ECO = 0x12; ///< Heat pump: the economy setpoint.
82static constexpr uint8_t HEAT_PUMP_HALTED = 0x13; ///< Heat pump: halted.
83} // namespace heating_alias
84
85/// @brief Main parameter of a heat pump's off command: MAIN_PARAMETER_KEEP, which the command pairs with the
86/// off value of a functional parameter.
87static constexpr uint16_t HEATING_OFF_MP = MAIN_PARAMETER_KEEP;
88
89/// @brief Sentinel for HeatingModeEntry::main_parameter: send the entity's target temperature, encoded
90/// over the device's range, as the main parameter.
91static constexpr uint16_t HEATING_MP_FROM_TARGET = 0xFFFF;
92
93/// @brief Values of functional parameter 9 on the heating temperature interface: the active mode.
94/// @details The heating / cooling bits (`4`, `8`) belong to a separate operating-mode command (main
95/// parameter `0xD400` with FP9 `4`, `8` or `0xC`); they are never combined into these values and
96/// this component sends no operating-mode command.
98static constexpr uint8_t OFF = 0x00; ///< Off.
99static constexpr uint8_t AUTO = 0x01; ///< The device follows its own schedule.
100static constexpr uint8_t MANUAL = 0x02; ///< The device follows the commanded setpoint.
101} // namespace heating_mode_flags
102
103/// @brief Values of functional parameter 16 on the heat pump: the on/off state.
104/// @details FP16 is the last functional parameter (the last bit of the second bitmap). FP15 reports the
105/// device's capabilities (`1` heating, `2` cooling, `4` away, `8` pool, `0x10` hot water) and
106/// FP16's other bits report its state; both are read-only here: no command selects cooling,
107/// and this component does not read FP15.
108namespace heating_fp16 {
109static constexpr uint16_t ON = 0x4000; ///< On: sent with a setpoint alias to select it.
110static constexpr uint16_t OFF = 0x8000; ///< Off: sent with HEATING_OFF_MP.
111} // namespace heating_fp16
112
113/// @brief Which functional parameter, if any, accompanies a TEMPERATURE_EXECUTE command.
114enum class HeatingFpKind : uint8_t {
115 NONE, ///< A main-parameter-only command.
116 FP9, ///< Functional parameter 9, one byte.
117 FP16, ///< Functional parameter 16, two bytes.
118};
119
120/// @brief A functional parameter and its value.
121struct HeatingFp {
122 HeatingFpKind kind{HeatingFpKind::NONE}; ///< Which parameter; NONE sends none.
123 uint16_t value{0}; ///< Its value (one byte for FP9, two for FP16).
124};
125
126/// @brief Number of main-parameter steps across the encoding range (the full position scale, 0xC800).
127static constexpr uint16_t HEATING_TEMPERATURE_MP_SPAN = 51200;
128
129/// @brief One HVAC mode the card offers and the wire value that selects it.
131 HeatingHvacMode hvac; ///< Mode shown on the card.
132 uint8_t wire; ///< PRIVATE_REGISTERS: mode register value. HEATING_LEVEL: level low byte.
133 ///< TEMPERATURE_EXECUTE: unused.
134 uint16_t main_parameter{0}; ///< TEMPERATURE_EXECUTE: the main parameter the mode sends, or
135 ///< HEATING_MP_FROM_TARGET.
136 HeatingFp fp{}; ///< TEMPERATURE_EXECUTE: the functional parameter the mode sends.
137};
138
139/// @brief One preset the card offers.
141 const char *custom_name; ///< Name of a CUSTOM preset; nullptr otherwise.
142 HeatingPresetId id; ///< Standard preset, or CUSTOM.
143 HeatingFunction write_fn; ///< PRIVATE_REGISTERS: register the preset writes. Unused for levels.
144 uint8_t wire; ///< Value written: register value, or the low byte of a level or alias.
145 bool commandable; ///< False for a preset the device only reports (secured).
146 HeatingFp fp{}; ///< TEMPERATURE_EXECUTE: the functional parameter sent with the alias.
147};
148
149/// @brief What a device-reported wire value shows on the card.
151 uint8_t wire; ///< Mode register value, or level low byte, as the device reports it.
152 HeatingHvacMode hvac; ///< HVAC mode shown.
153 int8_t preset; ///< Index into the profile's presets shown with it, or -1 for none.
154};
155
156/// @brief Where a register heater's "heating" / "idle" comes from.
157enum class HeatingActionSource : uint8_t {
158 REGULATOR, ///< The regulator register (HeatingFunction::REGULATOR_STATE): heating at state 2.
159 WORKING_RATE, ///< The working rate (HeatingFunction::WORKING_RATE): heating above 0 %. A towel dryer's
160 ///< regulator reads 0 during boost and drying, while the element runs at 100 %.
161};
162
163/// @brief Companion entities and traits a profile has.
165 bool target_temperature; ///< The card has a setpoint.
166 bool current_temperature; ///< The card shows a measured temperature.
167 bool action; ///< The card shows heating / idle.
168 bool mode_observed; ///< A device reading decides the card's mode; false when the mode is the
169 ///< last command (nothing reads it back).
170};
171
172/// @brief How a heater's own weekly programme shows which period runs: the registers that tell, and the
173/// presets that name the periods.
174/// @details While the mode register reads `programme_mode` and the preset register reads
175/// `idle_preset_state` (no timed run on top), `in_force_fn` holds the temperature the heater
176/// heats to. It equals the `comfort_fn` temperature in a comfort period and that temperature
177/// minus the `setback_fn` one in an eco period. Outside the programme `in_force_fn` is not a
178/// temperature (it reads 1 in boost and 2 in drying on a towel dryer).
180 uint8_t programme_mode; ///< Value of HeatingProfile::mode_fn while the programme runs.
181 uint8_t idle_preset_state; ///< Value of HeatingProfile::preset_fn with no timed run on top.
182 HeatingFunction in_force_fn; ///< Register of the temperature in force.
183 HeatingFunction comfort_fn; ///< Register of the comfort setpoint.
184 HeatingFunction setback_fn; ///< Register of the eco setback, a distance below the comfort setpoint.
185 int8_t comfort_preset; ///< Index into HeatingProfile::presets shown in a comfort period.
186 int8_t eco_preset; ///< Index into HeatingProfile::presets shown in an eco period.
187};
188
189/// @brief One heater kind.
190/// @details A row is written with designated initializers, in declaration order. The fields before
191/// `setpoint_fp` have no default, so a row that leaves one out does not compile; every other field has
192/// one and is left out where unused. Each list is a span over a `constexpr` array, which carries its
193/// own length.
195 // --- Required: every row states these ---
196 DeviceType type; ///< Node type.
197 uint8_t subtype; ///< Subtype (0 = the type's own row).
198 DeviceModel model; ///< Model (NONE = the (type, subtype) row's own profile).
199 HeatingControlPath path; ///< How the heater is commanded and read.
200 HeatingProfileFeatures features; ///< What the card and its companions offer.
201 std::span<const HeatingModeEntry> modes; ///< HVAC modes offered, with the value each writes.
202
203 // --- Optional: a default stands for "unused". The byte-sized fields come last, so they pack. ---
204 HeatingFp setpoint_fp{}; ///< TEMPERATURE_EXECUTE: the functional parameter sent with a setpoint.
205 float visual_min_c{0.0F}; ///< Lowest target temperature the card offers (0 without a setpoint).
206 float visual_max_c{0.0F}; ///< Highest target temperature the card offers (0 without a setpoint).
207 /// PRIVATE_REGISTERS: how the heater's own programme names the comfort or eco period it is in;
208 /// nullptr for a heater that does not report it.
210 // NOLINTBEGIN(readability-redundant-member-init): a span's own default is empty, but g++'s
211 // -Wmissing-field-initializers still wants the member initializer before a row may leave it out.
212 std::span<const HeatingPresetEntry> presets{}; ///< Presets offered.
213 std::span<const HeatingObservedState> observed{}; ///< Device-reported value -> card state.
214 /// PRIVATE_REGISTERS: registers every poll reads, in order.
215 std::span<const HeatingFunction> poll_registers{};
216 /// PRIVATE_REGISTERS: registers read once until they have been read.
217 std::span<const HeatingFunction> boot_registers{};
218 /// Device-reported value of `preset_fn` -> preset; empty when the mode register names the preset too
219 /// (`observed`). With it, `observed` sets only the mode and this table alone sets the preset, since
220 /// mode and preset live in separate registers.
221 std::span<const HeatingObservedState> preset_observed{};
222 /// PRIVATE_REGISTERS: registers every poll reads after `poll_registers`, for a part the heater may not
223 /// have (a night light). A miss here is not a poll failure, so a model declared on a heater without
224 /// the part costs a read, not the poll.
225 std::span<const HeatingFunction> extra_poll_registers{};
226 // NOLINTEND(readability-redundant-member-init)
227 uint8_t mp_prefix{0}; ///< High byte of a level or alias main parameter (0 for registers).
228 bool fixed_range{false}; ///< TEMPERATURE_EXECUTE: the temperature range is fixed, so the YAML
229 ///< `min_temperature:` / `max_temperature:` do not apply.
230 /// PRIVATE_REGISTERS: the register the HVAC modes write and the card's mode is read from.
232 /// PRIVATE_REGISTERS with `preset_observed`: the register the card's preset is read from. The presets'
233 /// own `write_fn` say what each writes.
235 HeatingActionSource action_source{HeatingActionSource::REGULATOR}; ///< Where `features.action` reads from.
236 bool experimental_writes{false}; ///< PRIVATE_REGISTERS: the mode and preset writes are unconfirmed on a device.
237};
238
239/// @brief What a heater's programme period resolves to, from its readings.
241 bool active{false}; ///< The programme runs (and no timed run is on top of it).
242 int8_t preset_index{-1}; ///< Index into the profile's presets of the period, or -1 when the temperature
243 ///< in force fits neither period or the readings cannot say.
244 float target_c{NAN}; ///< The temperature in force; NaN until it has been read.
245};
246
247/// @brief Look up the heating profile for a (type, subtype, model).
248/// @param type Node type.
249/// @param subtype Subtype; one with no profile of its own falls back to the type's profile (subtype 0),
250/// the same rule as find_device_type_info().
251/// @param model Declared model. A model with a profile of its own gets it; any other falls back to the
252/// (type, subtype) profile. No default: a caller that forgot the model would silently drive a
253/// towel dryer as a radiator.
254/// @return The profile, or nullptr when no climate entity drives this device.
255const HeatingProfile *find_heating_profile(DeviceType type, uint8_t subtype, DeviceModel model);
256
257/// @brief Look up the heating profile of a device record: its type, subtype and declared model.
258/// @param dev The device.
259/// @return The profile, or nullptr when no climate entity drives this device.
260const HeatingProfile *find_heating_profile(const IoDevice &dev);
261
262/// @brief Does a climate entity drive this device over the private register protocol?
263/// @details The gate for every CMD_WRITE_PRIVATE frame the hub sends: a heater that takes the standard
264/// EXECUTE must never be sent a register write. The control path is a fact of the
265/// (type, subtype): a model's profile keeps the path of the profile above it (checked by
266/// heating_profiles_test.cpp), so this and the other path predicates take no model.
267/// @param type Node type.
268/// @param subtype Subtype.
269/// @return true when the profile's control path is HeatingControlPath::PRIVATE_REGISTERS.
270bool device_uses_heating_registers(DeviceType type, uint8_t subtype);
271
272/// @brief May the diagnostic register-read probes (`register_00`, `register_01`) be sent to this device?
273/// @details A read of a register is the request climate support already sends to register-protocol
274/// heaters, so those are allowed, and so is a water heater (device_feature::WATER_HEATER), whose
275/// readings are family-0x00 registers. Every other kind -- covers, lights, switches, locks, the
276/// standard-EXECUTE heaters -- is refused. This gates the probe and the register reads only; a
277/// heater's register writes stay behind device_uses_heating_registers(), a water heater's
278/// behind its WATER_HEATER bit.
279/// @param type Node type.
280/// @param subtype Subtype.
281/// @return true for a register-protocol heater or a water heater.
282bool device_accepts_register_probe(DeviceType type, uint8_t subtype);
283
284/// @brief Does a climate entity drive this device with heating levels?
285/// @param type Node type.
286/// @param subtype Subtype.
287/// @return true when the profile's control path is HeatingControlPath::HEATING_LEVEL.
288bool device_uses_heating_levels(DeviceType type, uint8_t subtype);
289
290/// @brief Does a climate entity drive this device with a temperature or an alias in the main parameter?
291/// @param type Node type.
292/// @param subtype Subtype.
293/// @return true when the profile's control path is HeatingControlPath::TEMPERATURE_EXECUTE.
294bool device_uses_heating_temperature(DeviceType type, uint8_t subtype);
295
296/// @brief Encode a temperature as a main parameter over an encoding range.
297/// @details `round((celsius - min) / (max - min) * HEATING_TEMPERATURE_MP_SPAN)`, clamped to the span.
298/// @param celsius Temperature in degrees Celsius; must be finite.
299/// @param min_c Lower end of the device's encoding range.
300/// @param max_c Upper end of the device's encoding range; must exceed `min_c`.
301/// @param[out] main_parameter The encoded value.
302/// @return false for a non-finite temperature or an empty range; `main_parameter` is then untouched.
303bool encode_temperature_main_parameter(float celsius, float min_c, float max_c, uint16_t &main_parameter);
304
305/// @brief Decode a main parameter as a temperature over an encoding range (the inverse of
306/// encode_temperature_main_parameter()).
307/// @param main_parameter The 16-bit value from a status reply.
308/// @param min_c Lower end of the device's encoding range.
309/// @param max_c Upper end of the device's encoding range; must exceed `min_c`.
310/// @param[out] celsius The temperature.
311/// @return false when the value is above the span (an alias or a marker, not a temperature) or the
312/// range is empty.
313bool decode_temperature_main_parameter(uint16_t main_parameter, float min_c, float max_c, float &celsius);
314
315/// @brief Main parameter of a heating level, as it travels in an EXECUTE and in a status reply.
316/// @param level Level low byte (heating_level::*).
317/// @return HEATING_LEVEL_MP_PREFIX in the high byte, `level` in the low byte.
318constexpr uint16_t heating_level_main_parameter(uint8_t level) {
319 return static_cast<uint16_t>((HEATING_LEVEL_MP_PREFIX << BITS_PER_BYTE) | level);
320}
321
322/// @brief Main parameter of a prefixed value (a level or an alias).
323/// @param prefix High byte (HEATING_LEVEL_MP_PREFIX or HEATING_ALIAS_MP_PREFIX).
324/// @param low Low byte.
325/// @return The 16-bit main parameter.
326constexpr uint16_t heating_prefixed_main_parameter(uint8_t prefix, uint8_t low) {
327 return static_cast<uint16_t>((prefix << BITS_PER_BYTE) | low);
328}
329
330/// @brief Read a heating level out of a main parameter.
331/// @param main_parameter The 16-bit value from a status reply.
332/// @param[out] level Level low byte.
333/// @return true when the value is a heating level (high byte HEATING_LEVEL_MP_PREFIX).
334bool decode_heating_level(uint16_t main_parameter, uint8_t &level);
335
336/// @brief Find what a device-reported wire value shows on the card.
337/// @param profile The device's profile.
338/// @param wire Mode register value or level low byte.
339/// @return The matching entry, or nullptr when the value is not one the profile maps.
340const HeatingObservedState *find_observed_state(const HeatingProfile &profile, uint8_t wire);
341
342/// @brief Find what a device-reported value of the preset register (`preset_fn`) shows on the card.
343/// @param profile The device's profile.
344/// @param wire Value of the profile's preset register.
345/// @return The matching entry, or nullptr when the profile has no preset table or does not map the value.
346const HeatingObservedState *find_observed_preset(const HeatingProfile &profile, uint8_t wire);
347
348/// @brief Does the heater's own programme run right now, with no timed run on top of it?
349/// @details True when the profile has a programme period, its mode register reads the programme value and
350/// its preset register reads the idle value. An unread register is not the programme.
351/// @param profile The device's profile.
352/// @param readings What the hub has read from the heater.
353/// @return false for a profile without a programme period.
354bool programme_period_active(const HeatingProfile &profile, const HeatingReadings &readings);
355
356/// @brief Which period of its programme a heater is in, and the temperature it heats to.
357/// @details Compares in whole tenths of a degree: the temperature in force equals the comfort setpoint
358/// (comfort period) or the comfort setpoint minus the setback (eco period). Anything else, or a
359/// register not read yet, names no period but still reports the temperature in force.
360/// @param profile The device's profile.
361/// @param readings What the hub has read from the heater.
362/// @return `active` false when the programme does not run; otherwise the period's preset index and the
363/// temperature in force.
364ProgrammePeriodState resolve_programme_period(const HeatingProfile &profile, const HeatingReadings &readings);
365
366/// @brief Drop the temperature in force from the readings when the programme does not run.
367/// @details Keeps a value from an earlier run of the programme from being shown when the heater returns to it.
368/// @param profile The device's profile.
369/// @param[in,out] readings What the hub has read from the heater.
370void clear_inactive_programme_reading(const HeatingProfile &profile, HeatingReadings &readings);
371
372} // namespace home_io_control
373} // namespace esphome
Setpoint aliases (low byte of the main parameter, prefix HEATING_ALIAS_MP_PREFIX).
static constexpr uint8_t HEAT_PUMP_HALTED
Heat pump: halted.
static constexpr uint8_t COMFORT
The device's comfort setpoint.
static constexpr uint8_t HEAT_PUMP_ECO
Heat pump: the economy setpoint.
static constexpr uint8_t HEAT_PUMP_SETBACK
Heat pump: the setback setpoint.
static constexpr uint8_t THERMOSTAT_ECO
Heating temperature interface: the economy setpoint.
static constexpr uint8_t SECURED
Heating temperature interface: the secured setpoint.
Values of functional parameter 16 on the heat pump: the on/off state.
static constexpr uint16_t ON
On: sent with a setpoint alias to select it.
static constexpr uint16_t OFF
Off: sent with HEATING_OFF_MP.
Heating levels (low byte of the main parameter, prefix HEATING_LEVEL_MP_PREFIX).
static constexpr uint8_t COMFORT_MINUS_2
Comfort, two degrees lower.
static constexpr uint8_t COMFORT
Comfort.
static constexpr uint8_t FROST_PROTECTION
Frost protection.
static constexpr uint8_t SECURED
Secured; reported by the device, never commanded.
static constexpr uint8_t COMFORT_MINUS_1
Comfort, one degree lower.
Values of functional parameter 9 on the heating temperature interface: the active mode.
static constexpr uint8_t AUTO
The device follows its own schedule.
static constexpr uint8_t MANUAL
The device follows the commanded setpoint.
void clear_inactive_programme_reading(const HeatingProfile &profile, HeatingReadings &readings)
Drop the temperature in force from the readings when the programme does not run.
static constexpr uint8_t HEATING_LEVEL_MP_PREFIX
Main-parameter prefix byte of a heating level: the level occupies the low byte.
HeatingActionSource
Where a register heater's "heating" / "idle" comes from.
@ REGULATOR
The regulator register (HeatingFunction::REGULATOR_STATE): heating at state 2.
const HeatingObservedState * find_observed_state(const HeatingProfile &profile, uint8_t wire)
Find what a device-reported wire value shows on the card.
bool encode_temperature_main_parameter(float celsius, float min_c, float max_c, uint16_t &main_parameter)
Encode a temperature as a main parameter over an encoding range.
HeatingFpKind
Which functional parameter, if any, accompanies a TEMPERATURE_EXECUTE command.
@ FP9
Functional parameter 9, one byte.
@ FP16
Functional parameter 16, two bytes.
const HeatingProfile * find_heating_profile(DeviceType type, uint8_t subtype, DeviceModel model)
Look up the heating profile for a (type, subtype, model).
HeatingFunction
Registers and functions of a 2W heater, one row of the descriptor table each.
@ WORKING_RATE
Register 0x0126, read-only: share of the time the element heats, 0-100 %.
@ SET_MODE
Register 0x0100, read/write: operating mode (HeatingMode).
bool decode_temperature_main_parameter(uint16_t main_parameter, float min_c, float max_c, float &celsius)
Decode a main parameter as a temperature over an encoding range (the inverse of encode_temperature_ma...
HeatingPresetId
Presets a profile can offer. CUSTOM entries carry their own name.
@ CUSTOM
Named by HeatingPresetEntry::custom_name.
DeviceModel
A product model below a (node type, subtype): for products that report the same wire type but need di...
bool programme_period_active(const HeatingProfile &profile, const HeatingReadings &readings)
Does the heater's own programme run right now, with no timed run on top of it?
constexpr uint16_t heating_level_main_parameter(uint8_t level)
Main parameter of a heating level, as it travels in an EXECUTE and in a status reply.
DeviceType
IO-Homecontrol node types.
HeatingControlPath
How a heater is commanded and read.
@ TEMPERATURE_EXECUTE
Standard EXECUTE with a temperature or an alias as the main parameter; read with 0x03.
@ PRIVATE_REGISTERS
CMD_WRITE_PRIVATE register reads and writes (proto_heating.h).
@ HEATING_LEVEL
Standard EXECUTE with a heating level as the main parameter; read with 0x03.
static constexpr uint8_t HEATING_ALIAS_MP_PREFIX
Main-parameter prefix byte of a setpoint alias: the alias occupies the low byte.
const HeatingObservedState * find_observed_preset(const HeatingProfile &profile, uint8_t wire)
Find what a device-reported value of the preset register (preset_fn) shows on the card.
static constexpr uint16_t HEATING_TEMPERATURE_MP_SPAN
Number of main-parameter steps across the encoding range (the full position scale,...
static constexpr uint16_t HEATING_OFF_MP
Main parameter of a heat pump's off command: MAIN_PARAMETER_KEEP, which the command pairs with the of...
bool device_uses_heating_levels(DeviceType type, uint8_t subtype)
Does a climate entity drive this device with heating levels?
static constexpr uint16_t MAIN_PARAMETER_KEEP
16-bit main parameter D400 (POS_UNKNOWN in the high byte): keep the current value.
bool decode_heating_level(uint16_t main_parameter, uint8_t &level)
Read a heating level out of a main parameter.
static constexpr uint16_t HEATING_MP_FROM_TARGET
Sentinel for HeatingModeEntry::main_parameter: send the entity's target temperature,...
bool device_uses_heating_registers(DeviceType type, uint8_t subtype)
Does a climate entity drive this device over the private register protocol?
ProgrammePeriodState resolve_programme_period(const HeatingProfile &profile, const HeatingReadings &readings)
Which period of its programme a heater is in, and the temperature it heats to.
bool device_uses_heating_temperature(DeviceType type, uint8_t subtype)
Does a climate entity drive this device with a temperature or an alias in the main parameter?
bool device_accepts_register_probe(DeviceType type, uint8_t subtype)
May the diagnostic register-read probes (register_00, register_01) be sent to this device?
constexpr uint16_t heating_prefixed_main_parameter(uint8_t prefix, uint8_t low)
Main parameter of a prefixed value (a level or an alias).
HeatingHvacMode
HVAC modes a profile can offer.
IO-Homecontrol command IDs, result codes and protocol enumerations.
IO-Homecontrol device-type model, capabilities and runtime device state.
Pure codec for the private register protocol of 2W heaters (CMD_WRITE_PRIVATE 0x20).
Fundamental IO-Homecontrol frame and crypto size constants.
A functional parameter and its value.
uint16_t value
Its value (one byte for FP9, two for FP16).
HeatingFpKind kind
Which parameter; NONE sends none.
One HVAC mode the card offers and the wire value that selects it.
HeatingFp fp
TEMPERATURE_EXECUTE: the functional parameter the mode sends.
uint16_t main_parameter
TEMPERATURE_EXECUTE: the main parameter the mode sends, or HEATING_MP_FROM_TARGET.
HeatingHvacMode hvac
Mode shown on the card.
uint8_t wire
PRIVATE_REGISTERS: mode register value.
What a device-reported wire value shows on the card.
uint8_t wire
Mode register value, or level low byte, as the device reports it.
int8_t preset
Index into the profile's presets shown with it, or -1 for none.
const char * custom_name
Name of a CUSTOM preset; nullptr otherwise.
HeatingFp fp
TEMPERATURE_EXECUTE: the functional parameter sent with the alias.
uint8_t wire
Value written: register value, or the low byte of a level or alias.
HeatingPresetId id
Standard preset, or CUSTOM.
HeatingFunction write_fn
PRIVATE_REGISTERS: register the preset writes. Unused for levels.
bool commandable
False for a preset the device only reports (secured).
Companion entities and traits a profile has.
bool mode_observed
A device reading decides the card's mode; false when the mode is the last command (nothing reads it b...
bool current_temperature
The card shows a measured temperature.
HeatingProfileFeatures features
What the card and its companions offer.
bool fixed_range
TEMPERATURE_EXECUTE: the temperature range is fixed, so the YAML min_temperature: / max_temperature: ...
uint8_t mp_prefix
High byte of a level or alias main parameter (0 for registers).
std::span< const HeatingPresetEntry > presets
Presets offered.
DeviceModel model
Model (NONE = the (type, subtype) row's own profile).
std::span< const HeatingObservedState > observed
Device-reported value -> card state.
HeatingActionSource action_source
Where features.action reads from.
std::span< const HeatingFunction > boot_registers
PRIVATE_REGISTERS: registers read once until they have been read.
std::span< const HeatingFunction > poll_registers
PRIVATE_REGISTERS: registers every poll reads, in order.
const HeatingProgrammePeriod * programme_period
PRIVATE_REGISTERS: how the heater's own programme names the comfort or eco period it is in; nullptr f...
HeatingControlPath path
How the heater is commanded and read.
float visual_max_c
Highest target temperature the card offers (0 without a setpoint).
bool experimental_writes
PRIVATE_REGISTERS: the mode and preset writes are unconfirmed on a device.
uint8_t subtype
Subtype (0 = the type's own row).
float visual_min_c
Lowest target temperature the card offers (0 without a setpoint).
HeatingFunction preset_fn
PRIVATE_REGISTERS with preset_observed: the register the card's preset is read from.
HeatingFunction mode_fn
PRIVATE_REGISTERS: the register the HVAC modes write and the card's mode is read from.
std::span< const HeatingFunction > extra_poll_registers
PRIVATE_REGISTERS: registers every poll reads after poll_registers, for a part the heater may not hav...
std::span< const HeatingObservedState > preset_observed
Device-reported value of preset_fn -> preset; empty when the mode register names the preset too (obse...
std::span< const HeatingModeEntry > modes
HVAC modes offered, with the value each writes.
HeatingFp setpoint_fp
TEMPERATURE_EXECUTE: the functional parameter sent with a setpoint.
How a heater's own weekly programme shows which period runs: the registers that tell,...
HeatingFunction in_force_fn
Register of the temperature in force.
uint8_t programme_mode
Value of HeatingProfile::mode_fn while the programme runs.
int8_t comfort_preset
Index into HeatingProfile::presets shown in a comfort period.
int8_t eco_preset
Index into HeatingProfile::presets shown in an eco period.
HeatingFunction setback_fn
Register of the eco setback, a distance below the comfort setpoint.
HeatingFunction comfort_fn
Register of the comfort setpoint.
uint8_t idle_preset_state
Value of HeatingProfile::preset_fn with no timed run on top.
What a heater's programme period resolves to, from its readings.
int8_t preset_index
Index into the profile's presets of the period, or -1 when the temperature in force fits neither peri...
bool active
The programme runs (and no timed run is on top of it).
float target_c
The temperature in force; NaN until it has been read.