Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_water_heater.h
Go to the documentation of this file.
1#pragma once
2
3/// @file platform_water_heater.h
4/// @brief Water heater entity for a domestic hot water heater, and its opt-in companion sensors.
5/// @ingroup hioc_platforms
6///
7/// Maps a domestic hot water heater (device_feature::WATER_HEATER, proto_dhw.h) onto an ESPHome
8/// `water_heater`: water temperature, target temperature and operating mode. The heater's three modes map
9/// to ESPHome's as follows (ADR 0068):
10///
11/// | Heater (register 0x0006) | ESPHome mode |
12/// |--------------------------|---------------|
13/// | 0 automatic | HEAT_PUMP |
14/// | 1 manual, ECO on | ECO |
15/// | 2 manual, ECO off | PERFORMANCE |
16///
17/// OFF is not offered: no heater has been seen reporting an off state.
18///
19/// In automatic mode the heater chooses its own target, and its display shows none, so the entity publishes
20/// no target while the heater reports automatic mode, and a target set then is not sent.
21///
22/// State is observed, not predicted, as on the climate entity: the hub polls the heater (default every 5
23/// minutes) and this entity publishes from IoDevice::dhw, which only a decoded reply changes. Until a reading
24/// has arrived an accepted write shows the commanded value; after that the read-back decides.
25///
26/// Away mode is part of the entity: Home Assistant's away switch starts and ends the heater's holiday mode
27/// (ADR 0081). The heater reports it, and boost, in the operating-mode word the poll reads, so the entity
28/// shows away only once the heater said so. While away no target is shown (the heater reports a main parameter
29/// of 0, which is no target) and a target set then is logged and dropped.
30///
31/// The companions (energy, heat pump running, electric backup running) show readings the same poll already
32/// stores and add no radio traffic; the boost switch shows the boost state of the operating-mode word the poll
33/// reads and writes it.
34///
35/// The readings, the target EXECUTE and the mode write are confirmed on one Atlantic Calypso Connecte
36/// ([issue #198](https://github.com/laberning/home_io_control/issues/198)): its display follows both writes.
37/// That heater accepts only its own fixed targets (one per shower count, all whole degrees), so a value
38/// between two steps is not taken.
39///
40/// \todo The mode mapping and the target steps rest on that one heater; confirm them on a second one.
41/// \todo Experimental: confirm on a real water heater that away mode starts and ends the holiday mode and that
42/// the state follows the heater's operating-mode word (issue #198).
43
44#include "esphome/components/binary_sensor/binary_sensor.h"
45#include "esphome/components/switch/switch.h"
46#include "esphome/components/water_heater/water_heater.h"
47#include "esphome/core/component.h"
50#include "proto_dhw.h"
51
52namespace esphome {
53namespace home_io_control {
54
55/// @brief ESPHome water heater mode for a heater mode.
56/// @param mode Mode as register 0x0006 holds it.
57/// @return The mapped ESPHome mode (see the file comment).
58water_heater::WaterHeaterMode water_heater_mode_for(DhwMode mode);
59
60/// @brief Heater mode for an ESPHome water heater mode.
61/// @param mode ESPHome mode.
62/// @param[out] out The heater mode; untouched when false is returned.
63/// @return false for a mode the heater does not offer (OFF, ELECTRIC, HIGH_DEMAND, GAS).
64bool dhw_mode_for(water_heater::WaterHeaterMode mode, DhwMode &out);
65
66/// @brief Water heater entity for a domestic hot water heater.
67/// @ingroup hioc_platforms
68///
69/// The device-binding setters and setup() registration ritual come from DeviceBoundEntity.
70class IOHomeWaterHeater : public water_heater::WaterHeater, public Component, public DeviceBoundEntity {
71 public:
72 /// @brief Register the entity with the shared hub and schedule the first poll of the heater.
73 void setup() override;
74 /// @brief Dump configuration to the log.
75 void dump_config() override;
76 /// @brief Get setup priority (DATA).
77 /// @return setup_priority::DATA.
78 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
79
80 /// @brief A call bound to this entity (the pattern of ESPHome's template water heater).
81 /// @return A new call.
82 water_heater::WaterHeaterCallInternal make_call() override { return water_heater::WaterHeaterCallInternal(this); }
83
84 /// @brief Apply a Home Assistant request: a mode is written to register 0x0006, away mode goes through the
85 /// operating-mode word, a target is sent in an EXECUTE. The mode and away go first; a target is then not sent while
86 /// the heater holds automatic mode (it chooses its own), judged on the mode read back after the mode write. A failed
87 /// send leaves its field as it was.
88 /// @param call The requested changes, already checked against traits() by ESPHome.
89 void control(const water_heater::WaterHeaterCall &call) override;
90
91 protected:
92 /// @brief Current and target temperature, the three modes, and the target range
93 /// DHW_TARGET_MIN_C..DHW_TARGET_MAX_C at a 1 C step.
94 water_heater::WaterHeaterTraits traits() override;
95
96 /// @brief Inbound device-update hook: fold IoDevice::dhw into the entity and publish when a shown field
97 /// changed. Ignores updates for other devices.
98 void on_device_update_(const std::string &id, const IoDevice &dev);
99
100 /// @brief Copy the readings into the entity's fields. The target is shown as unknown (NaN) while the
101 /// heater reports automatic mode or away; away follows the heater's report.
102 /// @param readings What the hub has read from the heater.
103 /// @return true when a published field changed.
104 bool sync_from_readings_(const DhwReadings &readings);
105
106 bool observed_{false}; ///< True once a reading has been folded in.
107};
108
109/// @brief Sensor of the heater's energy since installation, in kWh (`total_increasing`).
110/// @ingroup hioc_platforms
111///
112/// Reads IoDevice::dhw.energy_wh (register 0x0004, Wh) and publishes it in kWh, so it fits the Home
113/// Assistant energy dashboard. No state until the first poll has read it.
115 public:
116 /// @brief Subscribe to the device's updates and publish what is already known.
117 void setup() override;
118 /// @brief Dump sensor configuration to the log.
119 void dump_config() override;
120};
121
122/// @brief Binary sensor of one heating state of the heater: heat pump running or electric backup running.
123/// @ingroup hioc_platforms
124///
125/// No state until the first poll has read the register it shows, so "off" always means the heater said so.
126class IOHomeDhwBinarySensor : public binary_sensor::BinarySensor, public Component, public DeviceBoundCompanion {
127 public:
128 /// @brief Which reading the sensor shows.
129 enum class Reading : uint8_t {
130 HEAT_PUMP, ///< Register 0x0021 bytes 3/4: the heat pump runs.
131 ELECTRIC_BACKUP, ///< Register 0x0021 byte 2: the electric element heats.
132 };
133
134 /// @brief Choose the reading (codegen sets it once).
135 /// @param reading Reading to show.
136 void set_reading(Reading reading) { this->reading_ = reading; }
137
138 /// @brief Subscribe to the device's updates and publish what is already known.
139 void setup() override;
140 /// @brief Dump sensor configuration to the log.
141 void dump_config() override;
142 /// @brief Get setup priority so the parent hub is available first.
143 /// @return setup_priority::DATA.
144 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
145
146 protected:
148};
149
150/// @brief Switch that starts and ends the heater's boost.
151/// @ingroup hioc_platforms
152///
153/// A write goes through IOHomeControlComponent::set_water_heater_boost(), which writes the boost duration and
154/// the operating-mode word and reads the status back; the switch shows what the heater reports in that word
155/// (ADR 0081), so it has no state until the first poll and never shows a command the heater did not confirm.
156/// Switching on asks for a boost of duration 1, the only value seen. Switching off sends the word that ends
157/// both boost and away.
158///
159/// It never writes at boot: setup() restores nothing, and the codegen sets restore mode DISABLED, so a
160/// reboot cannot end a boost that is running.
161///
162/// \todo Experimental: confirm on a real water heater that switching on starts a boost and switching off
163/// ends it (issue #198).
164class IOHomeDhwBoostSwitch : public switch_::Switch, public Component, public DeviceBoundCompanion {
165 public:
166 /// @brief Subscribe to the device's updates and publish what is already known.
167 void setup() override;
168 /// @brief Dump switch configuration to the log.
169 void dump_config() override;
170 /// @brief Get setup priority so the parent hub is available first.
171 /// @return setup_priority::DATA.
172 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
173
174 protected:
175 /// @brief Start or end the boost; the read-back publishes the state.
176 /// @param state True to start a boost.
177 void write_state(bool state) override;
178};
179
180} // namespace home_io_control
181} // namespace esphome
Mixin holding the parent + device-id binding shared by per-device entities that are not full entity p...
Mixin holding the hub-device binding shared by all IO-Homecontrol entity platforms.
Shared base for the numeric per-device diagnostic companions.
Binary sensor of one heating state of the heater: heat pump running or electric backup running.
void setup() override
Subscribe to the device's updates and publish what is already known.
@ HEAT_PUMP
Register 0x0021 bytes 3/4: the heat pump runs.
void dump_config() override
Dump sensor configuration to the log.
void set_reading(Reading reading)
Choose the reading (codegen sets it once).
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
Switch that starts and ends the heater's boost.
float get_setup_priority() const override
Get setup priority so the parent hub is available first.
void write_state(bool state) override
Start or end the boost; the read-back publishes the state.
void setup() override
Subscribe to the device's updates and publish what is already known.
void dump_config() override
Dump switch configuration to the log.
Sensor of the heater's energy since installation, in kWh (total_increasing).
void setup() override
Subscribe to the device's updates and publish what is already known.
void dump_config() override
Dump sensor configuration to the log.
Water heater entity for a domestic hot water heater.
void dump_config() override
Dump configuration to the log.
void on_device_update_(const std::string &id, const IoDevice &dev)
Inbound device-update hook: fold IoDevice::dhw into the entity and publish when a shown field changed...
water_heater::WaterHeaterCallInternal make_call() override
A call bound to this entity (the pattern of ESPHome's template water heater).
void setup() override
Register the entity with the shared hub and schedule the first poll of the heater.
bool observed_
True once a reading has been folded in.
water_heater::WaterHeaterTraits traits() override
Current and target temperature, the three modes, and the target range DHW_TARGET_MIN_C....
void control(const water_heater::WaterHeaterCall &call) override
Apply a Home Assistant request: a mode is written to register 0x0006, away mode goes through the oper...
bool sync_from_readings_(const DhwReadings &readings)
Copy the readings into the entity's fields.
float get_setup_priority() const override
Get setup priority (DATA).
DhwMode
Operating mode as register 0x0006 holds it.
Definition proto_dhw.h:145
bool dhw_mode_for(water_heater::WaterHeaterMode mode, DhwMode &out)
Heater mode for an ESPHome water heater mode.
water_heater::WaterHeaterMode water_heater_mode_for(DhwMode mode)
ESPHome water heater mode for a heater mode.
The auto-generated per-device diagnostic companion sensors.
Shared device-binding mixins for IO-Homecontrol entity platforms.
Pure codec for a domestic hot water heater: its family-0x00 registers and its target temperature.
What the hub has read from a domestic hot water heater.
Definition proto_dhw.h:162
Runtime state of a paired IO‑Homecontrol device.