ESPHome  2023.11.6
tuya_climate.cpp
Go to the documentation of this file.
1 #include "tuya_climate.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace tuya {
6 
7 static const char *const TAG = "tuya.climate";
8 
10  if (this->switch_id_.has_value()) {
11  this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
12  ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool));
14  if (datapoint.value_bool) {
15  if (this->supports_heat_ && this->supports_cool_) {
17  } else if (this->supports_heat_) {
19  } else if (this->supports_cool_) {
21  }
22  }
23  this->compute_state_();
24  this->publish_state();
25  });
26  }
27  if (this->active_state_id_.has_value()) {
28  this->parent_->register_listener(*this->active_state_id_, [this](const TuyaDatapoint &datapoint) {
29  ESP_LOGV(TAG, "MCU reported active state is: %u", datapoint.value_enum);
30  this->active_state_ = datapoint.value_enum;
31  this->compute_state_();
32  this->publish_state();
33  });
34  } else {
35  if (this->heating_state_pin_ != nullptr) {
36  this->heating_state_pin_->setup();
38  }
39  if (this->cooling_state_pin_ != nullptr) {
40  this->cooling_state_pin_->setup();
42  }
43  }
44  if (this->target_temperature_id_.has_value()) {
45  this->parent_->register_listener(*this->target_temperature_id_, [this](const TuyaDatapoint &datapoint) {
47  if (this->reports_fahrenheit_) {
48  this->manual_temperature_ = (this->manual_temperature_ - 32) * 5 / 9;
49  }
50 
51  ESP_LOGV(TAG, "MCU reported manual target temperature is: %.1f", this->manual_temperature_);
53  this->compute_state_();
54  this->publish_state();
55  });
56  }
57  if (this->current_temperature_id_.has_value()) {
58  this->parent_->register_listener(*this->current_temperature_id_, [this](const TuyaDatapoint &datapoint) {
60  if (this->reports_fahrenheit_) {
61  this->current_temperature = (this->current_temperature - 32) * 5 / 9;
62  }
63 
64  ESP_LOGV(TAG, "MCU reported current temperature is: %.1f", this->current_temperature);
65  this->compute_state_();
66  this->publish_state();
67  });
68  }
69  if (this->eco_id_.has_value()) {
70  this->parent_->register_listener(*this->eco_id_, [this](const TuyaDatapoint &datapoint) {
71  this->eco_ = datapoint.value_bool;
72  ESP_LOGV(TAG, "MCU reported eco is: %s", ONOFF(this->eco_));
73  this->compute_preset_();
75  this->publish_state();
76  });
77  }
78 }
79 
81  if (this->active_state_id_.has_value())
82  return;
83 
84  bool state_changed = false;
85  if (this->heating_state_pin_ != nullptr) {
86  bool heating_state = this->heating_state_pin_->digital_read();
87  if (heating_state != this->heating_state_) {
88  ESP_LOGV(TAG, "Heating state pin changed to: %s", ONOFF(heating_state));
89  this->heating_state_ = heating_state;
90  state_changed = true;
91  }
92  }
93  if (this->cooling_state_pin_ != nullptr) {
94  bool cooling_state = this->cooling_state_pin_->digital_read();
95  if (cooling_state != this->cooling_state_) {
96  ESP_LOGV(TAG, "Cooling state pin changed to: %s", ONOFF(cooling_state));
97  this->cooling_state_ = cooling_state;
98  state_changed = true;
99  }
100  }
101 
102  if (state_changed) {
103  this->compute_state_();
104  this->publish_state();
105  }
106 }
107 
109  if (call.get_mode().has_value()) {
110  const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF;
111  ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state));
112  this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state);
113  }
114 
115  if (call.get_target_temperature().has_value()) {
117  if (this->reports_fahrenheit_)
118  target_temperature = (target_temperature * 9 / 5) + 32;
119 
120  ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temperature);
122  (int) (target_temperature / this->target_temperature_multiplier_));
123  }
124 
125  if (call.get_preset().has_value()) {
126  const climate::ClimatePreset preset = *call.get_preset();
127  if (this->eco_id_.has_value()) {
128  const bool eco = preset == climate::CLIMATE_PRESET_ECO;
129  ESP_LOGV(TAG, "Setting eco: %s", ONOFF(eco));
130  this->parent_->set_boolean_datapoint_value(*this->eco_id_, eco);
131  }
132  }
133 }
134 
139  if (supports_heat_)
141  if (supports_cool_)
143  if (this->eco_id_.has_value()) {
146  }
147  return traits;
148 }
149 
151  LOG_CLIMATE("", "Tuya Climate", this);
152  if (this->switch_id_.has_value()) {
153  ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
154  }
155  if (this->active_state_id_.has_value()) {
156  ESP_LOGCONFIG(TAG, " Active state has datapoint ID %u", *this->active_state_id_);
157  }
158  if (this->target_temperature_id_.has_value()) {
159  ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *this->target_temperature_id_);
160  }
161  if (this->current_temperature_id_.has_value()) {
162  ESP_LOGCONFIG(TAG, " Current Temperature has datapoint ID %u", *this->current_temperature_id_);
163  }
164  LOG_PIN(" Heating State Pin: ", this->heating_state_pin_);
165  LOG_PIN(" Cooling State Pin: ", this->cooling_state_pin_);
166  if (this->eco_id_.has_value()) {
167  ESP_LOGCONFIG(TAG, " Eco has datapoint ID %u", *this->eco_id_);
168  }
169 }
170 
172  if (this->eco_) {
174  } else {
176  }
177 }
178 
180  if (this->eco_ && this->eco_temperature_.has_value()) {
181  this->target_temperature = *this->eco_temperature_;
182  } else {
184  }
185 }
186 
188  if (std::isnan(this->current_temperature) || std::isnan(this->target_temperature)) {
189  // if any control parameters are nan, go to OFF action (not IDLE!)
191  return;
192  }
193 
194  if (this->mode == climate::CLIMATE_MODE_OFF) {
196  return;
197  }
198 
200  if (this->active_state_id_.has_value()) {
201  // Use state from MCU datapoint
204  target_action = climate::CLIMATE_ACTION_HEATING;
205  } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() &&
207  target_action = climate::CLIMATE_ACTION_COOLING;
208  }
209  } else if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) {
210  // Use state from input pins
211  if (this->heating_state_) {
212  target_action = climate::CLIMATE_ACTION_HEATING;
213  } else if (this->cooling_state_) {
214  target_action = climate::CLIMATE_ACTION_COOLING;
215  }
216  } else {
217  // Fallback to active state calc based on temp and hysteresis
218  const float temp_diff = this->target_temperature - this->current_temperature;
219  if (std::abs(temp_diff) > this->hysteresis_) {
220  if (this->supports_heat_ && temp_diff > 0) {
221  target_action = climate::CLIMATE_ACTION_HEATING;
222  } else if (this->supports_cool_ && temp_diff < 0) {
223  target_action = climate::CLIMATE_ACTION_COOLING;
224  }
225  }
226  }
227 
228  this->switch_to_action_(target_action);
229 }
230 
232  // For now this just sets the current action but could include triggers later
233  this->action = action;
234 }
235 
236 } // namespace tuya
237 } // namespace esphome
This class is used to encode all control actions on a climate device.
Definition: climate.h:33
The climate device is off (inactive or no power)
Definition: climate_mode.h:33
ClimatePreset
Enum for all preset modes.
Definition: climate_mode.h:82
float target_temperature
The target temperature of the climate device.
Definition: climate.h:172
void switch_to_action_(climate::ClimateAction action)
Switch the climate device to the given climate mode.
const optional< ClimateMode > & get_mode() const
Definition: climate.cpp:265
This class contains all static data for climate devices.
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:164
float current_temperature
The current temperature of the climate device, as reported from the integration.
Definition: climate.h:168
optional< uint8_t > active_state_cooling_value_
Definition: tuya_climate.h:67
bool has_value() const
Definition: optional.h:87
void register_listener(uint8_t datapoint_id, const std::function< void(TuyaDatapoint)> &func)
Definition: tuya.cpp:671
virtual void setup()=0
optional< uint8_t > switch_id_
Definition: tuya_climate.h:64
void add_supported_preset(ClimatePreset preset)
void compute_target_temperature_()
Re-compute the target temperature of this climate controller.
const char *const TAG
Definition: spi.cpp:8
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
const optional< ClimatePreset > & get_preset() const
Definition: climate.cpp:271
void control(const climate::ClimateCall &call) override
Override control to change settings of the climate device.
optional< ClimatePreset > preset
The active preset of the climate device.
Definition: climate.h:191
optional< uint8_t > active_state_id_
Definition: tuya_climate.h:65
optional< uint8_t > eco_id_
Definition: tuya_climate.h:75
ClimateAction
Enum for the current action of the climate device. Values match those of ClimateMode.
Definition: climate_mode.h:31
optional< float > eco_temperature_
Definition: tuya_climate.h:76
The climate device is set to heat/cool to reach the target temperature.
Definition: climate_mode.h:14
The climate device is actively heating.
Definition: climate_mode.h:37
const optional< float > & get_target_temperature() const
Definition: climate.cpp:266
optional< uint8_t > active_state_heating_value_
Definition: tuya_climate.h:66
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition: climate.cpp:379
virtual bool digital_read()=0
The climate device is off.
Definition: climate_mode.h:12
void set_supports_action(bool supports_action)
climate::ClimateTraits traits() override
Return the traits of this controller.
void set_boolean_datapoint_value(uint8_t datapoint_id, bool value)
Definition: tuya.cpp:543
void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value)
Definition: tuya.cpp:547
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
The climate device is idle (monitoring climate but no action needed)
Definition: climate_mode.h:39
Device is running an energy-saving preset.
Definition: climate_mode.h:94
void set_supports_current_temperature(bool supports_current_temperature)
void compute_state_()
Re-compute the state of this climate controller.
optional< uint8_t > target_temperature_id_
Definition: tuya_climate.h:70
The climate device is actively cooling.
Definition: climate_mode.h:35
void add_supported_mode(ClimateMode mode)
void compute_preset_()
Re-compute the active preset of this climate controller.
optional< uint8_t > current_temperature_id_
Definition: tuya_climate.h:71
ClimateAction action
The active state of the climate device.
Definition: climate.h:166