ESPHome 2026.9.0-dev
Loading...
Searching...
No Matches
tuya_water_heater.cpp
Go to the documentation of this file.
1#include "tuya_water_heater.h"
2#include "esphome/core/log.h"
3
4namespace esphome::tuya {
5
6static const char *const TAG = "tuya.water_heater";
7
9 if (this->switch_id_.has_value()) {
10 this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
11 ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool));
12 this->is_on_ = datapoint.value_bool;
14 if (!this->is_on_) {
16 } else {
17 // Turned on: use the last mode reported by the mode datapoint if we have one, otherwise
18 // fall back to a supported mode. Datapoints can arrive in any order, so the mode enum may
19 // have been reported before this switch update.
20 this->set_mode_(this->last_reported_mode_.value_or(this->default_on_mode_()));
21 }
22 this->publish_state();
23 });
24 }
25
26 if (this->mode_id_.has_value()) {
27 this->parent_->register_listener(*this->mode_id_, [this](const TuyaDatapoint &datapoint) {
28 ESP_LOGV(TAG, "MCU reported mode value is: %u", datapoint.value_enum);
30 if (!this->mode_from_value_(datapoint.value_enum, mode)) {
31 return;
32 }
33 // Always remember the reported mode; only surface it while the heater is on (OFF is driven
34 // by the switch datapoint, not the mode enum).
36 if (this->is_on_ && this->mode_ != mode) {
37 this->set_mode_(mode);
38 this->publish_state();
39 }
40 });
41 }
42
43 if (this->target_temperature_id_.has_value()) {
44 this->parent_->register_listener(*this->target_temperature_id_, [this](const TuyaDatapoint &datapoint) {
45 float value = datapoint.value_int * this->target_temperature_multiplier_;
46 ESP_LOGV(TAG, "MCU reported target temperature is: %.1f", value);
47 this->set_target_temperature_(value);
48 this->publish_state();
49 });
50 }
51
52 if (this->current_temperature_id_.has_value()) {
53 this->parent_->register_listener(*this->current_temperature_id_, [this](const TuyaDatapoint &datapoint) {
54 float value = datapoint.value_int * this->current_temperature_multiplier_;
55 ESP_LOGV(TAG, "MCU reported current temperature is: %.1f", value);
56 this->set_current_temperature(value);
57 this->publish_state();
58 });
59 }
60}
61
65
67 auto mode_val = call.get_mode();
68 auto on_val = call.get_on();
69
70 // Determine the desired on/off state. An explicit on/off request wins; otherwise a mode of
71 // OFF means off and any other mode means on.
72 optional<bool> want_on = on_val;
73 if (mode_val.has_value() && !want_on.has_value()) {
74 want_on = *mode_val != water_heater::WATER_HEATER_MODE_OFF;
75 }
76
77 if (want_on.has_value() && this->switch_id_.has_value()) {
78 ESP_LOGV(TAG, "Setting switch: %s", ONOFF(*want_on));
79 this->parent_->set_boolean_datapoint_value(*this->switch_id_, *want_on);
80 }
81
82 if (mode_val.has_value() && *mode_val != water_heater::WATER_HEATER_MODE_OFF && this->mode_id_.has_value()) {
83 uint8_t value;
84 if (this->value_from_mode_(*mode_val, value)) {
85 ESP_LOGV(TAG, "Setting mode value: %u", value);
86 this->parent_->set_enum_datapoint_value(*this->mode_id_, value);
87 } else {
88 ESP_LOGW(TAG, "No mode value configured for requested mode");
89 }
90 }
91
92 auto target_temp = call.get_target_temperature();
93 if (!std::isnan(target_temp) && this->target_temperature_id_.has_value()) {
94 ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temp);
96 (int) (target_temp / this->target_temperature_multiplier_));
97 }
98}
99
116
118 if (this->eco_value_ == value) {
120 } else if (this->electric_value_ == value) {
122 } else if (this->performance_value_ == value) {
124 } else if (this->high_demand_value_ == value) {
126 } else if (this->heat_pump_value_ == value) {
128 } else if (this->gas_value_ == value) {
130 } else {
131 return false;
132 }
133 return true;
134}
135
137 optional<uint8_t> mapped;
138 switch (mode) {
140 mapped = this->eco_value_;
141 break;
143 mapped = this->electric_value_;
144 break;
146 mapped = this->performance_value_;
147 break;
149 mapped = this->high_demand_value_;
150 break;
152 mapped = this->heat_pump_value_;
153 break;
155 mapped = this->gas_value_;
156 break;
157 default:
158 break;
159 }
160 if (mapped.has_value()) {
161 value = *mapped;
162 return true;
163 }
164 return false;
165}
166
168 // Prefer the first configured supported non-OFF mode so we never surface a mode the user
169 // cannot control. Fall back to ELECTRIC when no supported modes are configured.
172 return mode;
173 }
174 }
176}
177
179 LOG_WATER_HEATER("", "Tuya Water Heater", this);
180 if (this->switch_id_.has_value()) {
181 ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
182 }
183 if (this->mode_id_.has_value()) {
184 ESP_LOGCONFIG(TAG, " Mode has datapoint ID %u", *this->mode_id_);
185 }
186 if (this->target_temperature_id_.has_value()) {
187 ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *this->target_temperature_id_);
188 }
189 if (this->current_temperature_id_.has_value()) {
190 ESP_LOGCONFIG(TAG, " Current Temperature has datapoint ID %u", *this->current_temperature_id_);
191 }
192}
193
194} // namespace esphome::tuya
BedjetMode mode
BedJet operating mode.
constexpr bool empty() const
Check if the set is empty.
void set_boolean_datapoint_value(uint8_t datapoint_id, bool value)
Definition tuya.cpp:653
void set_enum_datapoint_value(uint8_t datapoint_id, uint8_t value)
Definition tuya.cpp:665
void register_listener(uint8_t datapoint_id, const std::function< void(TuyaDatapoint)> &func)
Definition tuya.cpp:784
void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value)
Definition tuya.cpp:657
water_heater::WaterHeaterTraits traits() override
optional< uint8_t > target_temperature_id_
optional< uint8_t > electric_value_
optional< uint8_t > performance_value_
optional< water_heater::WaterHeaterMode > last_reported_mode_
Last non-OFF mode reported by the mode datapoint, applied when the heater turns on.
void control(const water_heater::WaterHeaterCall &call) override
optional< uint8_t > high_demand_value_
water_heater::WaterHeaterModeMask supported_modes_
bool value_from_mode_(water_heater::WaterHeaterMode mode, uint8_t &value) const
Map a WaterHeaterMode to its configured Tuya enum value. Returns true when a mapping exists.
water_heater::WaterHeaterMode default_on_mode_() const
The mode to show when the heater is on but no mode datapoint value is known yet: the last reported mo...
water_heater::WaterHeaterCallInternal make_call() override
bool mode_from_value_(uint8_t value, water_heater::WaterHeaterMode &mode) const
Map a Tuya mode datapoint enum value to a WaterHeaterMode.
optional< uint8_t > heat_pump_value_
optional< uint8_t > current_temperature_id_
void set_mode_(WaterHeaterMode mode)
Set the mode of the water heater. Should only be called from control().
void set_state_flag_(uint32_t flag, bool value)
Set or clear a state flag. Should only be called from control().
void set_target_temperature_(float target_temperature)
Set the target temperature of the water heater. Should only be called from control().
void set_current_temperature(float current_temperature)
void set_supported_modes(WaterHeaterModeMask modes)
void add_feature_flags(uint32_t flags)
Get/set feature flags (see WaterHeaterFeature enum)
const char *const TAG
Definition spi.cpp:7
@ WATER_HEATER_STATE_ON
Water heater is on (not in standby)
@ WATER_HEATER_SUPPORTS_TARGET_TEMPERATURE
The water heater supports a target temperature.
@ WATER_HEATER_SUPPORTS_OPERATION_MODE
The water heater supports operation mode selection.
@ WATER_HEATER_SUPPORTS_ON_OFF
The water heater can be turned on/off.
@ WATER_HEATER_SUPPORTS_CURRENT_TEMPERATURE
The water heater supports reporting the current temperature.