ESPHome  2024.12.2
smartair2_climate.cpp
Go to the documentation of this file.
1 #include <chrono>
4 #include "smartair2_climate.h"
5 #include "smartair2_packet.h"
6 
7 using namespace esphome::climate;
8 using namespace esphome::uart;
9 
10 namespace esphome {
11 namespace haier {
12 
13 static const char *const TAG = "haier.climate";
14 constexpr size_t SIGNAL_LEVEL_UPDATE_INTERVAL_MS = 10000;
15 constexpr uint8_t CONTROL_MESSAGE_RETRIES = 5;
16 constexpr std::chrono::milliseconds CONTROL_MESSAGE_RETRIES_INTERVAL = std::chrono::milliseconds(500);
17 constexpr uint8_t INIT_REQUESTS_RETRY = 2;
18 constexpr std::chrono::milliseconds INIT_REQUESTS_RETRY_INTERVAL = std::chrono::milliseconds(2000);
19 
20 Smartair2Climate::Smartair2Climate() {
21  last_status_message_ = std::unique_ptr<uint8_t[]>(new uint8_t[sizeof(smartair2_protocol::HaierPacketControl)]);
22 }
23 
24 haier_protocol::HandlerError Smartair2Climate::status_handler_(haier_protocol::FrameType request_type,
25  haier_protocol::FrameType message_type,
26  const uint8_t *data, size_t data_size) {
27  haier_protocol::HandlerError result =
28  this->answer_preprocess_(request_type, haier_protocol::FrameType::CONTROL, message_type,
30  if (result == haier_protocol::HandlerError::HANDLER_OK) {
31  result = this->process_status_message_(data, data_size);
32  if (result != haier_protocol::HandlerError::HANDLER_OK) {
33  ESP_LOGW(TAG, "Error %d while parsing Status packet", (int) result);
34  this->reset_phase_();
35  this->action_request_.reset();
36  this->force_send_control_ = false;
37  } else {
38  if (data_size >= sizeof(smartair2_protocol::HaierPacketControl) + 2) {
39  memcpy(this->last_status_message_.get(), data + 2, sizeof(smartair2_protocol::HaierPacketControl));
40  this->status_message_callback_.call((const char *) data, data_size);
41  } else {
42  ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size,
44  }
45  switch (this->protocol_phase_) {
46  case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST:
47  ESP_LOGI(TAG, "First HVAC status received");
48  this->set_phase(ProtocolPhases::IDLE);
49  break;
50  case ProtocolPhases::SENDING_ACTION_COMMAND:
51  // Do nothing, phase will be changed in process_phase
52  break;
53  case ProtocolPhases::SENDING_STATUS_REQUEST:
54  this->set_phase(ProtocolPhases::IDLE);
55  break;
56  case ProtocolPhases::SENDING_CONTROL:
57  this->set_phase(ProtocolPhases::IDLE);
58  this->force_send_control_ = false;
59  if (this->current_hvac_settings_.valid)
60  this->current_hvac_settings_.reset();
61  break;
62  default:
63  break;
64  }
65  }
66  return result;
67  } else {
68  this->action_request_.reset();
69  this->force_send_control_ = false;
70  this->reset_phase_();
71  return result;
72  }
73 }
74 
75 haier_protocol::HandlerError Smartair2Climate::get_device_version_answer_handler_(
76  haier_protocol::FrameType request_type, haier_protocol::FrameType message_type, const uint8_t *data,
77  size_t data_size) {
78  if (request_type != haier_protocol::FrameType::GET_DEVICE_VERSION)
79  return haier_protocol::HandlerError::UNSUPPORTED_MESSAGE;
80  if (ProtocolPhases::SENDING_INIT_1 != this->protocol_phase_)
81  return haier_protocol::HandlerError::UNEXPECTED_MESSAGE;
82  // Invalid packet is expected answer
83  if ((message_type == haier_protocol::FrameType::GET_DEVICE_VERSION_RESPONSE) && (data_size >= 39) &&
84  ((data[37] & 0x04) != 0)) {
85  ESP_LOGW(TAG, "It looks like your ESPHome Haier climate configuration is wrong. You should use the hOn protocol "
86  "instead of smartAir2");
87  }
88  this->set_phase(ProtocolPhases::SENDING_INIT_2);
89  return haier_protocol::HandlerError::HANDLER_OK;
90 }
91 
92 haier_protocol::HandlerError Smartair2Climate::messages_timeout_handler_with_cycle_for_init_(
93  haier_protocol::FrameType message_type) {
94  if (this->protocol_phase_ >= ProtocolPhases::IDLE)
95  return HaierClimateBase::timeout_default_handler_(message_type);
96  ESP_LOGI(TAG, "Answer timeout for command %02X, phase %s", (uint8_t) message_type,
97  phase_to_string_(this->protocol_phase_));
98  ProtocolPhases new_phase = (ProtocolPhases) ((int) this->protocol_phase_ + 1);
99  if (new_phase >= ProtocolPhases::SENDING_FIRST_ALARM_STATUS_REQUEST)
100  new_phase = ProtocolPhases::SENDING_INIT_1;
101  this->set_phase(new_phase);
102  return haier_protocol::HandlerError::HANDLER_OK;
103 }
104 
105 void Smartair2Climate::set_handlers() {
106  // Set handlers
107  this->haier_protocol_.set_answer_handler(
108  haier_protocol::FrameType::GET_DEVICE_VERSION,
109  std::bind(&Smartair2Climate::get_device_version_answer_handler_, this, std::placeholders::_1,
110  std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
111  this->haier_protocol_.set_answer_handler(
112  haier_protocol::FrameType::CONTROL,
113  std::bind(&Smartair2Climate::status_handler_, this, std::placeholders::_1, std::placeholders::_2,
114  std::placeholders::_3, std::placeholders::_4));
115  this->haier_protocol_.set_answer_handler(
116  haier_protocol::FrameType::REPORT_NETWORK_STATUS,
117  std::bind(&Smartair2Climate::report_network_status_answer_handler_, this, std::placeholders::_1,
118  std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
119  this->haier_protocol_.set_default_timeout_handler(
120  std::bind(&Smartair2Climate::messages_timeout_handler_with_cycle_for_init_, this, std::placeholders::_1));
121 }
122 
123 void Smartair2Climate::dump_config() {
124  HaierClimateBase::dump_config();
125  ESP_LOGCONFIG(TAG, " Protocol version: smartAir2");
126 }
127 
128 void Smartair2Climate::process_phase(std::chrono::steady_clock::time_point now) {
129  switch (this->protocol_phase_) {
130  case ProtocolPhases::SENDING_INIT_1:
131  if (this->can_send_message() && this->is_protocol_initialisation_interval_exceeded_(now)) {
132  // Indicate device capabilities:
133  // bit 0 - if 1 module support interactive mode
134  // bit 1 - if 1 module support controller-device mode
135  // bit 2 - if 1 module support crc
136  // bit 3 - if 1 module support multiple devices
137  // bit 4..bit 15 - not used
138  uint8_t module_capabilities[2] = {0b00000000, 0b00000111};
139  static const haier_protocol::HaierMessage DEVICE_VERSION_REQUEST(
140  haier_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, sizeof(module_capabilities));
141  this->send_message_(DEVICE_VERSION_REQUEST, this->use_crc_, INIT_REQUESTS_RETRY, INIT_REQUESTS_RETRY_INTERVAL);
142  }
143  break;
144  case ProtocolPhases::SENDING_INIT_2:
145  this->set_phase(ProtocolPhases::SENDING_FIRST_STATUS_REQUEST);
146  break;
147  case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST:
148  case ProtocolPhases::SENDING_STATUS_REQUEST:
149  if (this->can_send_message() && this->is_message_interval_exceeded_(now)) {
150  static const haier_protocol::HaierMessage STATUS_REQUEST(haier_protocol::FrameType::CONTROL, 0x4D01);
151  if (this->protocol_phase_ == ProtocolPhases::SENDING_FIRST_STATUS_REQUEST) {
152  this->send_message_(STATUS_REQUEST, this->use_crc_, INIT_REQUESTS_RETRY, INIT_REQUESTS_RETRY_INTERVAL);
153  } else {
154  this->send_message_(STATUS_REQUEST, this->use_crc_);
155  }
156  this->last_status_request_ = now;
157  }
158  break;
159 #ifdef USE_WIFI
160  case ProtocolPhases::SENDING_SIGNAL_LEVEL:
161  if (this->can_send_message() && this->is_message_interval_exceeded_(now)) {
162  this->send_message_(this->get_wifi_signal_message_(), this->use_crc_);
163  this->last_signal_request_ = now;
164  }
165  break;
166 #else
167  case ProtocolPhases::SENDING_SIGNAL_LEVEL:
168  this->set_phase(ProtocolPhases::IDLE);
169  break;
170 #endif
171  case ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST:
172  this->set_phase(ProtocolPhases::SENDING_SIGNAL_LEVEL);
173  break;
174  case ProtocolPhases::SENDING_FIRST_ALARM_STATUS_REQUEST:
175  this->set_phase(ProtocolPhases::SENDING_INIT_1);
176  break;
177  case ProtocolPhases::SENDING_ALARM_STATUS_REQUEST:
178  this->set_phase(ProtocolPhases::IDLE);
179  break;
180  case ProtocolPhases::SENDING_CONTROL:
181  if (this->can_send_message() && this->is_control_message_interval_exceeded_(now)) {
182  ESP_LOGI(TAG, "Sending control packet");
183  this->send_message_(get_control_message(), this->use_crc_, CONTROL_MESSAGE_RETRIES,
184  CONTROL_MESSAGE_RETRIES_INTERVAL);
185  }
186  break;
187  case ProtocolPhases::SENDING_ACTION_COMMAND:
188  if (this->action_request_.has_value()) {
189  if (this->action_request_.value().message.has_value()) {
190  this->send_message_(this->action_request_.value().message.value(), this->use_crc_);
191  this->action_request_.value().message.reset();
192  } else {
193  // Message already sent, reseting request and return to idle
194  this->action_request_.reset();
195  this->set_phase(ProtocolPhases::IDLE);
196  }
197  } else {
198  ESP_LOGW(TAG, "SENDING_ACTION_COMMAND phase without action request!");
199  this->set_phase(ProtocolPhases::IDLE);
200  }
201  break;
202  case ProtocolPhases::IDLE: {
203  if (this->forced_request_status_ || this->is_status_request_interval_exceeded_(now)) {
204  this->set_phase(ProtocolPhases::SENDING_STATUS_REQUEST);
205  this->forced_request_status_ = false;
206  }
207 #ifdef USE_WIFI
208  else if (this->send_wifi_signal_ &&
209  (std::chrono::duration_cast<std::chrono::milliseconds>(now - this->last_signal_request_).count() >
210  SIGNAL_LEVEL_UPDATE_INTERVAL_MS))
211  this->set_phase(ProtocolPhases::SENDING_UPDATE_SIGNAL_REQUEST);
212 #endif
213  } break;
214  default:
215  // Shouldn't get here
216  ESP_LOGE(TAG, "Wrong protocol handler state: %s (%d), resetting communication",
217  phase_to_string_(this->protocol_phase_), (int) this->protocol_phase_);
218  this->set_phase(ProtocolPhases::SENDING_INIT_1);
219  break;
220  }
221 }
222 
223 haier_protocol::HaierMessage Smartair2Climate::get_power_message(bool state) {
224  if (state) {
225  static haier_protocol::HaierMessage power_on_message(haier_protocol::FrameType::CONTROL, 0x4D02);
226  return power_on_message;
227  } else {
228  static haier_protocol::HaierMessage power_off_message(haier_protocol::FrameType::CONTROL, 0x4D03);
229  return power_off_message;
230  }
231 }
232 
233 haier_protocol::HaierMessage Smartair2Climate::get_control_message() {
234  uint8_t control_out_buffer[sizeof(smartair2_protocol::HaierPacketControl)];
235  memcpy(control_out_buffer, this->last_status_message_.get(), sizeof(smartair2_protocol::HaierPacketControl));
237  out_data->cntrl = 0;
238  if (this->current_hvac_settings_.valid) {
239  HvacSettings &climate_control = this->current_hvac_settings_;
240  if (climate_control.mode.has_value()) {
241  switch (climate_control.mode.value()) {
242  case CLIMATE_MODE_OFF:
243  out_data->ac_power = 0;
244  break;
246  out_data->ac_power = 1;
248  out_data->fan_mode = this->other_modes_fan_speed_;
249  break;
250  case CLIMATE_MODE_HEAT:
251  out_data->ac_power = 1;
252  out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::HEAT;
253  out_data->fan_mode = this->other_modes_fan_speed_;
254  break;
255  case CLIMATE_MODE_DRY:
256  out_data->ac_power = 1;
257  out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::DRY;
258  out_data->fan_mode = this->other_modes_fan_speed_;
259  break;
261  out_data->ac_power = 1;
262  out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::FAN;
263  out_data->fan_mode = this->fan_mode_speed_; // Auto doesn't work in fan only mode
264  break;
265  case CLIMATE_MODE_COOL:
266  out_data->ac_power = 1;
267  out_data->ac_mode = (uint8_t) smartair2_protocol::ConditioningMode::COOL;
268  out_data->fan_mode = this->other_modes_fan_speed_;
269  break;
270  default:
271  ESP_LOGE("Control", "Unsupported climate mode");
272  break;
273  }
274  }
275  // Set fan speed, if we are in fan mode, reject auto in fan mode
276  if (climate_control.fan_mode.has_value()) {
277  switch (climate_control.fan_mode.value()) {
278  case CLIMATE_FAN_LOW:
279  out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_LOW;
280  break;
281  case CLIMATE_FAN_MEDIUM:
282  out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_MID;
283  break;
284  case CLIMATE_FAN_HIGH:
285  out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_HIGH;
286  break;
287  case CLIMATE_FAN_AUTO:
288  if (this->mode != CLIMATE_MODE_FAN_ONLY) // if we are not in fan only mode
289  out_data->fan_mode = (uint8_t) smartair2_protocol::FanMode::FAN_AUTO;
290  break;
291  default:
292  ESP_LOGE("Control", "Unsupported fan mode");
293  break;
294  }
295  }
296  // Set swing mode
297  if (climate_control.swing_mode.has_value()) {
298  if (this->use_alternative_swing_control_) {
299  switch (climate_control.swing_mode.value()) {
300  case CLIMATE_SWING_OFF:
301  out_data->swing_mode = 0;
302  break;
304  out_data->swing_mode = 1;
305  break;
307  out_data->swing_mode = 2;
308  break;
309  case CLIMATE_SWING_BOTH:
310  out_data->swing_mode = 3;
311  break;
312  }
313  } else {
314  switch (climate_control.swing_mode.value()) {
315  case CLIMATE_SWING_OFF:
316  out_data->use_swing_bits = 0;
317  out_data->swing_mode = 0;
318  break;
320  out_data->swing_mode = 0;
321  out_data->vertical_swing = 1;
322  out_data->horizontal_swing = 0;
323  break;
325  out_data->swing_mode = 0;
326  out_data->vertical_swing = 0;
327  out_data->horizontal_swing = 1;
328  break;
329  case CLIMATE_SWING_BOTH:
330  out_data->swing_mode = 1;
331  out_data->use_swing_bits = 0;
332  out_data->vertical_swing = 0;
333  out_data->horizontal_swing = 0;
334  break;
335  }
336  }
337  }
338  if (climate_control.target_temperature.has_value()) {
339  float target_temp = climate_control.target_temperature.value();
340  out_data->set_point = ((int) target_temp) - 16; // set the temperature with offset 16
341  out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0;
342  }
343  if (out_data->ac_power == 0) {
344  // If AC is off - no presets allowed
345  out_data->turbo_mode = 0;
346  out_data->quiet_mode = 0;
347  } else if (climate_control.preset.has_value()) {
348  switch (climate_control.preset.value()) {
349  case CLIMATE_PRESET_NONE:
350  out_data->ten_degree = 0;
351  out_data->turbo_mode = 0;
352  out_data->quiet_mode = 0;
353  break;
355  out_data->ten_degree = 0;
356  out_data->turbo_mode = 1;
357  out_data->quiet_mode = 0;
358  break;
360  out_data->ten_degree = 0;
361  out_data->turbo_mode = 0;
362  out_data->quiet_mode = 1;
363  break;
364  case CLIMATE_PRESET_AWAY:
365  // Only allowed in heat mode
366  out_data->ten_degree = (this->mode == CLIMATE_MODE_HEAT) ? 1 : 0;
367  out_data->turbo_mode = 0;
368  out_data->quiet_mode = 0;
369  break;
370  default:
371  ESP_LOGE("Control", "Unsupported preset");
372  out_data->ten_degree = 0;
373  out_data->turbo_mode = 0;
374  out_data->quiet_mode = 0;
375  break;
376  }
377  }
378  }
379  out_data->display_status = this->get_display_state() ? 0 : 1;
380  this->display_status_ = (SwitchState) ((uint8_t) this->display_status_ & 0b01);
381  out_data->health_mode = this->get_health_mode() ? 1 : 0;
382  this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01);
383  return haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, 0x4D5F, control_out_buffer,
385 }
386 
387 haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) {
388  if (size < sizeof(smartair2_protocol::HaierStatus))
389  return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE;
391  memcpy(&packet, packet_buffer, size);
392  bool should_publish = false;
393  {
394  // Extra modes/presets
395  optional<ClimatePreset> old_preset = this->preset;
396  if (packet.control.turbo_mode != 0) {
398  } else if (packet.control.quiet_mode != 0) {
400  } else if (packet.control.ten_degree != 0) {
401  this->preset = CLIMATE_PRESET_AWAY;
402  } else {
403  this->preset = CLIMATE_PRESET_NONE;
404  }
405  should_publish = should_publish || (!old_preset.has_value()) || (old_preset.value() != this->preset.value());
406  }
407  {
408  // Target temperature
409  float old_target_temperature = this->target_temperature;
410  this->target_temperature = packet.control.set_point + 16.0f + ((packet.control.half_degree == 1) ? 0.5f : 0.0f);
411  should_publish = should_publish || (old_target_temperature != this->target_temperature);
412  }
413  {
414  // Current temperature
415  float old_current_temperature = this->current_temperature;
416  this->current_temperature = packet.control.room_temperature;
417  should_publish = should_publish || (old_current_temperature != this->current_temperature);
418  }
419  {
420  // Fan mode
421  optional<ClimateFanMode> old_fan_mode = this->fan_mode;
422  // remember the fan speed we last had for climate vs fan
423  if (packet.control.ac_mode == (uint8_t) smartair2_protocol::ConditioningMode::FAN) {
425  this->fan_mode_speed_ = packet.control.fan_mode;
426  } else {
427  this->other_modes_fan_speed_ = packet.control.fan_mode;
428  }
429  switch (packet.control.fan_mode) {
431  // Sometimes AC reports in fan only mode that fan speed is auto
432  // but never accept this value back
433  if (packet.control.ac_mode != (uint8_t) smartair2_protocol::ConditioningMode::FAN) {
434  this->fan_mode = CLIMATE_FAN_AUTO;
435  } else {
436  should_publish = true;
437  }
438  break;
439  case (uint8_t) smartair2_protocol::FanMode::FAN_MID:
441  break;
443  this->fan_mode = CLIMATE_FAN_LOW;
444  break;
446  this->fan_mode = CLIMATE_FAN_HIGH;
447  break;
448  }
449  should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value());
450  }
451  // Display status
452  // should be before "Climate mode" because it is changing this->mode
453  if (packet.control.ac_power != 0) {
454  // if AC is off display status always ON so process it only when AC is on
455  bool disp_status = packet.control.display_status == 0;
456  if (disp_status != this->get_display_state()) {
457  // Do something only if display status changed
458  if (this->mode == CLIMATE_MODE_OFF) {
459  // AC just turned on from remote need to turn off display
460  this->force_send_control_ = true;
461  } else if ((((uint8_t) this->health_mode_) & 0b10) == 0) {
462  this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF;
463  }
464  }
465  }
466  // Health mode
467  if ((((uint8_t) this->health_mode_) & 0b10) == 0) {
468  bool old_health_mode = this->get_health_mode();
469  this->health_mode_ = packet.control.health_mode == 1 ? SwitchState::ON : SwitchState::OFF;
470  should_publish = should_publish || (old_health_mode != this->get_health_mode());
471  }
472  {
473  // Climate mode
474  ClimateMode old_mode = this->mode;
475  if (packet.control.ac_power == 0) {
476  this->mode = CLIMATE_MODE_OFF;
477  } else {
478  // Check current hvac mode
479  switch (packet.control.ac_mode) {
480  case (uint8_t) smartair2_protocol::ConditioningMode::COOL:
481  this->mode = CLIMATE_MODE_COOL;
482  break;
483  case (uint8_t) smartair2_protocol::ConditioningMode::HEAT:
484  this->mode = CLIMATE_MODE_HEAT;
485  break;
486  case (uint8_t) smartair2_protocol::ConditioningMode::DRY:
487  this->mode = CLIMATE_MODE_DRY;
488  break;
489  case (uint8_t) smartair2_protocol::ConditioningMode::FAN:
490  this->mode = CLIMATE_MODE_FAN_ONLY;
491  break;
494  break;
495  }
496  }
497  should_publish = should_publish || (old_mode != this->mode);
498  }
499  {
500  // Swing mode
501  ClimateSwingMode old_swing_mode = this->swing_mode;
502  if (this->use_alternative_swing_control_) {
503  switch (packet.control.swing_mode) {
504  case 1:
506  break;
507  case 2:
509  break;
510  case 3:
512  break;
513  default:
515  break;
516  }
517  } else {
518  if (packet.control.swing_mode == 0) {
519  if (packet.control.vertical_swing != 0) {
521  } else if (packet.control.horizontal_swing != 0) {
523  } else {
525  }
526  } else {
528  }
529  }
530  should_publish = should_publish || (old_swing_mode != this->swing_mode);
531  }
532  this->last_valid_status_timestamp_ = std::chrono::steady_clock::now();
533  if (should_publish) {
534  this->publish_state();
535  }
536  if (should_publish) {
537  ESP_LOGI(TAG, "HVAC values changed");
538  }
539  int log_level = should_publish ? ESPHOME_LOG_LEVEL_INFO : ESPHOME_LOG_LEVEL_DEBUG;
540  esp_log_printf_(log_level, TAG, __LINE__, "HVAC Mode = 0x%X", packet.control.ac_mode);
541  esp_log_printf_(log_level, TAG, __LINE__, "Fan speed Status = 0x%X", packet.control.fan_mode);
542  esp_log_printf_(log_level, TAG, __LINE__, "Horizontal Swing Status = 0x%X", packet.control.horizontal_swing);
543  esp_log_printf_(log_level, TAG, __LINE__, "Vertical Swing Status = 0x%X", packet.control.vertical_swing);
544  esp_log_printf_(log_level, TAG, __LINE__, "Set Point Status = 0x%X", packet.control.set_point);
545  return haier_protocol::HandlerError::HANDLER_OK;
546 }
547 
548 void Smartair2Climate::set_alternative_swing_control(bool swing_control) {
549  this->use_alternative_swing_control_ = swing_control;
550 }
551 
552 } // namespace haier
553 } // namespace esphome
The fan mode is set to Low.
Definition: climate_mode.h:54
value_type const & value() const
Definition: optional.h:89
esphome::optional< float > target_temperature
Definition: haier_base.h:137
The fan mode is set to Both.
Definition: climate_mode.h:74
esphome::optional< esphome::climate::ClimatePreset > preset
Definition: haier_base.h:138
constexpr std::chrono::milliseconds CONTROL_MESSAGE_RETRIES_INTERVAL
Definition: hon_climate.cpp:19
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
const uint32_t FAN_HIGH
Definition: whynter.cpp:31
bool has_value() const
Definition: optional.h:87
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
const uint32_t FAN_LOW
Definition: whynter.cpp:33
ClimateSwingMode swing_mode
Definition: climate.h:581
ClimateSwingMode
Enum for all modes a climate swing can be in.
Definition: climate_mode.h:70
Device is in away preset.
Definition: climate_mode.h:88
Device is in comfort preset.
Definition: climate_mode.h:92
The fan mode is set to Horizontal.
Definition: climate_mode.h:78
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
constexpr std::chrono::milliseconds INIT_REQUESTS_RETRY_INTERVAL
The fan mode is set to Auto.
Definition: climate_mode.h:52
Automatically detect from MIME type.
Definition: online_image.h:25
constexpr size_t SIGNAL_LEVEL_UPDATE_INTERVAL_MS
Definition: hon_climate.cpp:16
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:183
const uint32_t FAN_AUTO
esphome::optional< esphome::climate::ClimateFanMode > fan_mode
Definition: haier_base.h:135
The climate device is set to heat/cool to reach the target temperature.
Definition: climate_mode.h:14
The fan mode is set to Vertical.
Definition: climate_mode.h:76
The fan mode is set to High.
Definition: climate_mode.h:58
void HOT esp_log_printf_(int level, const char *tag, int line, const char *format,...)
Definition: log.cpp:11
ClimateMode
Enum for all modes a climate device can be in.
Definition: climate_mode.h:10
The swing mode is set to Off.
Definition: climate_mode.h:72
The climate device is off.
Definition: climate_mode.h:12
ClimateFanMode fan_mode
Definition: climate.h:573
Device is in boost preset.
Definition: climate_mode.h:90
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
The fan mode is set to Medium.
Definition: climate_mode.h:56
constexpr uint8_t CONTROL_MESSAGE_RETRIES
Definition: hon_climate.cpp:18
The climate device only has the fan enabled, no heating or cooling is taking place.
Definition: climate_mode.h:20
float target_temperature
Definition: climate.h:138
constexpr uint8_t INIT_REQUESTS_RETRY
ClimatePreset preset
Definition: climate.h:578
esphome::optional< esphome::climate::ClimateSwingMode > swing_mode
Definition: haier_base.h:136
bool state
Definition: fan.h:34
esphome::optional< esphome::climate::ClimateMode > mode
Definition: haier_base.h:134