ESPHome 2026.1.0b1
Loading...
Searching...
No Matches
water_heater.cpp
Go to the documentation of this file.
1#include "water_heater.h"
2#include "esphome/core/log.h"
5
6#include <cmath>
7
9
10static const char *const TAG = "water_heater";
11
12void log_water_heater(const char *tag, const char *prefix, const char *type, WaterHeater *obj) {
13 if (obj != nullptr) {
14 ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
15 }
16}
17
18WaterHeaterCall::WaterHeaterCall(WaterHeater *parent) : parent_(parent) {}
19
24
28 } else if (str_equals_case_insensitive(mode, "ECO")) {
30 } else if (str_equals_case_insensitive(mode, "ELECTRIC")) {
32 } else if (str_equals_case_insensitive(mode, "PERFORMANCE")) {
34 } else if (str_equals_case_insensitive(mode, "HIGH_DEMAND")) {
36 } else if (str_equals_case_insensitive(mode, "HEAT_PUMP")) {
38 } else if (str_equals_case_insensitive(mode, "GAS")) {
40 } else {
41 ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str());
42 }
43 return *this;
44}
45
50
55
60
62 if (away) {
64 } else {
65 this->state_ &= ~WATER_HEATER_STATE_AWAY;
66 }
67 return *this;
68}
69
71 if (on) {
73 } else {
74 this->state_ &= ~WATER_HEATER_STATE_ON;
75 }
76 return *this;
77}
78
80 ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
81 this->validate_();
82 if (this->mode_.has_value()) {
83 ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(water_heater_mode_to_string(*this->mode_)));
84 }
85 if (!std::isnan(this->target_temperature_)) {
86 ESP_LOGD(TAG, " Target Temperature: %.2f", this->target_temperature_);
87 }
88 if (!std::isnan(this->target_temperature_low_)) {
89 ESP_LOGD(TAG, " Target Temperature Low: %.2f", this->target_temperature_low_);
90 }
91 if (!std::isnan(this->target_temperature_high_)) {
92 ESP_LOGD(TAG, " Target Temperature High: %.2f", this->target_temperature_high_);
93 }
94 if (this->state_ & WATER_HEATER_STATE_AWAY) {
95 ESP_LOGD(TAG, " Away: YES");
96 }
97 if (this->state_ & WATER_HEATER_STATE_ON) {
98 ESP_LOGD(TAG, " On: YES");
99 }
100 this->parent_->control(*this);
101}
102
104 auto traits = this->parent_->get_traits();
105 if (this->mode_.has_value()) {
106 if (!traits.supports_mode(*this->mode_)) {
107 ESP_LOGW(TAG, "'%s' - Mode %d not supported", this->parent_->get_name().c_str(), *this->mode_);
108 this->mode_.reset();
109 }
110 }
111 if (!std::isnan(this->target_temperature_)) {
112 if (traits.get_supports_two_point_target_temperature()) {
113 ESP_LOGW(TAG, "'%s' - Cannot set target temperature for device with two-point target temperature",
114 this->parent_->get_name().c_str());
115 this->target_temperature_ = NAN;
116 } else if (this->target_temperature_ < traits.get_min_temperature() ||
117 this->target_temperature_ > traits.get_max_temperature()) {
118 ESP_LOGW(TAG, "'%s' - Target temperature %.1f is out of range [%.1f - %.1f]", this->parent_->get_name().c_str(),
119 this->target_temperature_, traits.get_min_temperature(), traits.get_max_temperature());
120 this->target_temperature_ =
121 std::max(traits.get_min_temperature(), std::min(this->target_temperature_, traits.get_max_temperature()));
122 }
123 }
124 if (!std::isnan(this->target_temperature_low_) || !std::isnan(this->target_temperature_high_)) {
125 if (!traits.get_supports_two_point_target_temperature()) {
126 ESP_LOGW(TAG, "'%s' - Cannot set low/high target temperature", this->parent_->get_name().c_str());
127 this->target_temperature_low_ = NAN;
128 this->target_temperature_high_ = NAN;
129 }
130 }
131 if (!std::isnan(this->target_temperature_low_) && !std::isnan(this->target_temperature_high_)) {
133 ESP_LOGW(TAG, "'%s' - Target temperature low %.2f must be less than high %.2f", this->parent_->get_name().c_str(),
134 this->target_temperature_low_, this->target_temperature_high_);
135 this->target_temperature_low_ = NAN;
136 this->target_temperature_high_ = NAN;
137 }
138 }
139 if ((this->state_ & WATER_HEATER_STATE_AWAY) && !traits.get_supports_away_mode()) {
140 ESP_LOGW(TAG, "'%s' - Away mode not supported", this->parent_->get_name().c_str());
141 this->state_ &= ~WATER_HEATER_STATE_AWAY;
142 }
143 // If ON/OFF not supported, device is always on - clear the flag silently
144 if (!traits.has_feature_flags(WATER_HEATER_SUPPORTS_ON_OFF)) {
145 this->state_ &= ~WATER_HEATER_STATE_ON;
146 }
147}
148
152
154 auto traits = this->get_traits();
155 ESP_LOGD(TAG,
156 "'%s' - Sending state:\n"
157 " Mode: %s",
158 this->name_.c_str(), LOG_STR_ARG(water_heater_mode_to_string(this->mode_)));
159 if (!std::isnan(this->current_temperature_)) {
160 ESP_LOGD(TAG, " Current Temperature: %.2f°C", this->current_temperature_);
161 }
163 ESP_LOGD(TAG, " Target Temperature: Low: %.2f°C High: %.2f°C", this->target_temperature_low_,
165 } else if (!std::isnan(this->target_temperature_)) {
166 ESP_LOGD(TAG, " Target Temperature: %.2f°C", this->target_temperature_);
167 }
168 if (this->state_ & WATER_HEATER_STATE_AWAY) {
169 ESP_LOGD(TAG, " Away: YES");
170 }
172 ESP_LOGD(TAG, " On: %s", (this->state_ & WATER_HEATER_STATE_ON) ? "YES" : "NO");
173 }
174
175#if defined(USE_WATER_HEATER) && defined(USE_CONTROLLER_REGISTRY)
177#endif
178
179 SavedWaterHeaterState saved{};
180 saved.mode = this->mode_;
182 saved.target_temperature_low = this->target_temperature_low_;
183 saved.target_temperature_high = this->target_temperature_high_;
184 } else {
185 saved.target_temperature = this->target_temperature_;
186 }
187 saved.state = this->state_;
188 this->pref_.save(&saved);
189}
190
192 SavedWaterHeaterState recovered{};
193 if (!this->pref_.load(&recovered))
194 return {};
195
196 auto traits = this->get_traits();
197 auto call = this->make_call();
198 call.set_mode(recovered.mode);
200 call.set_target_temperature_low(recovered.target_temperature_low);
201 call.set_target_temperature_high(recovered.target_temperature_high);
202 } else {
203 call.set_target_temperature(recovered.target_temperature);
204 }
205 call.set_away((recovered.state & WATER_HEATER_STATE_AWAY) != 0);
206 call.set_on((recovered.state & WATER_HEATER_STATE_ON) != 0);
207 return call;
208}
209
211 auto traits = this->traits();
212#ifdef USE_WATER_HEATER_VISUAL_OVERRIDES
213 if (!std::isnan(this->visual_min_temperature_override_)) {
215 }
216 if (!std::isnan(this->visual_max_temperature_override_)) {
218 }
219 if (!std::isnan(this->visual_target_temperature_step_override_)) {
221 }
222#endif
223 return traits;
224}
225
226#ifdef USE_WATER_HEATER_VISUAL_OVERRIDES
227void WaterHeater::set_visual_min_temperature_override(float min_temperature_override) {
228 this->visual_min_temperature_override_ = min_temperature_override;
229}
230void WaterHeater::set_visual_max_temperature_override(float max_temperature_override) {
231 this->visual_max_temperature_override_ = max_temperature_override;
232}
233void WaterHeater::set_visual_target_temperature_step_override(float visual_target_temperature_step_override) {
234 this->visual_target_temperature_step_override_ = visual_target_temperature_step_override;
235}
236#endif
237
239 switch (mode) {
241 return LOG_STR("OFF");
243 return LOG_STR("ECO");
245 return LOG_STR("ELECTRIC");
247 return LOG_STR("PERFORMANCE");
249 return LOG_STR("HIGH_DEMAND");
251 return LOG_STR("HEAT_PUMP");
253 return LOG_STR("GAS");
254 default:
255 return LOG_STR("UNKNOWN");
256 }
257}
258
259void WaterHeater::dump_traits_(const char *tag) {
260 auto traits = this->get_traits();
261 ESP_LOGCONFIG(tag,
262 " Min Temperature: %.1f°C\n"
263 " Max Temperature: %.1f°C\n"
264 " Temperature Step: %.1f",
267 ESP_LOGCONFIG(tag, " Supports Two-Point Target Temperature: YES");
268 }
270 ESP_LOGCONFIG(tag, " Supports Away Mode: YES");
271 }
273 ESP_LOGCONFIG(tag, " Supports On/Off: YES");
274 }
276 ESP_LOGCONFIG(tag, " Supported Modes:");
278 ESP_LOGCONFIG(tag, " - %s", LOG_STR_ARG(water_heater_mode_to_string(m)));
279 }
280 }
281}
282
283} // namespace esphome::water_heater
BedjetMode mode
BedJet operating mode.
uint8_t m
Definition bl0906.h:1
static void notify_water_heater_update(water_heater::WaterHeater *obj)
bool save(const T *src)
Definition preferences.h:21
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
const StringRef & get_name() const
uint32_t get_preference_hash()
Get a unique hash for storing preferences/settings for this entity.
constexpr bool empty() const
Check if the set is empty.
constexpr const char * c_str() const
Definition string_ref.h:73
bool has_value() const
Definition optional.h:92
WaterHeaterCall & set_away(bool away)
WaterHeaterCall & set_target_temperature_high(float temperature)
WaterHeaterCall & set_mode(WaterHeaterMode mode)
WaterHeaterCall & set_target_temperature_low(float temperature)
WaterHeaterCall & set_on(bool on)
optional< WaterHeaterMode > mode_
WaterHeaterCall & set_target_temperature(float temperature)
void set_visual_min_temperature_override(float min_temperature_override)
virtual void control(const WaterHeaterCall &call)=0
void set_visual_target_temperature_step_override(float visual_target_temperature_step_override)
void set_visual_max_temperature_override(float max_temperature_override)
virtual WaterHeaterCallInternal make_call()=0
void dump_traits_(const char *tag)
Log the traits of this water heater for dump_config().
virtual WaterHeaterTraits get_traits()
virtual WaterHeaterTraits traits()=0
optional< WaterHeaterCall > restore_state()
const WaterHeaterModeMask & get_supported_modes() const
void set_min_temperature(float min_temperature)
bool has_feature_flags(uint32_t flags) const
void set_target_temperature_step(float target_temperature_step)
void set_max_temperature(float max_temperature)
uint16_t type
void log_water_heater(const char *tag, const char *prefix, const char *type, WaterHeater *obj)
@ WATER_HEATER_STATE_ON
Water heater is on (not in standby)
@ WATER_HEATER_STATE_AWAY
Away/vacation mode is currently active.
@ WATER_HEATER_SUPPORTS_ON_OFF
The water heater can be turned on/off.
const LogString * water_heater_mode_to_string(WaterHeaterMode mode)
Convert the given WaterHeaterMode to a human-readable string for logging.
ESPPreferences * global_preferences
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare strings for equality in case-insensitive manner.
Definition helpers.cpp:162
uint16_t temperature
Definition sun_gtil2.cpp:12