ESPHome  2022.12.8
thermostat_climate.cpp
Go to the documentation of this file.
1 #include "thermostat_climate.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace thermostat {
6 
7 static const char *const TAG = "thermostat.climate";
8 
10  if (this->use_startup_delay_) {
11  // start timers so that no actions are called for a moment
17  }
18  // add a callback so that whenever the sensor state changes we can take action
19  this->sensor_->add_on_state_callback([this](float state) {
20  this->current_temperature = state;
21  // required action may have changed, recompute, refresh, we'll publish_state() later
22  this->switch_to_action_(this->compute_action_(), false);
24  // current temperature and possibly action changed, so publish the new state
25  this->publish_state();
26  });
27  this->current_temperature = this->sensor_->state;
28 
29  auto use_default_preset = true;
30 
32  // restore all climate data, if possible
33  auto restore = this->restore_state_();
34  if (restore.has_value()) {
35  use_default_preset = false;
36  restore->to_call(this).perform();
37  }
38  }
39 
40  // Either we failed to restore state or the user has requested we always apply the default preset
41  if (use_default_preset) {
43  this->change_preset_(this->default_preset_);
44  } else if (!this->default_custom_preset_.empty()) {
46  }
47  }
48 
49  // refresh the climate action based on the restored settings, we'll publish_state() later
50  this->switch_to_action_(this->compute_action_(), false);
52  this->setup_complete_ = true;
53  this->publish_state();
54 }
55 
60 
62  this->switch_to_mode_(this->mode, false);
63  this->switch_to_action_(this->compute_action_(), false);
65  this->switch_to_fan_mode_(this->fan_mode.value(), false);
66  this->switch_to_swing_mode_(this->swing_mode, false);
68  this->publish_state();
69 }
70 
72  bool state_mismatch = this->action != this->compute_action_(true);
73 
74  switch (this->compute_action_(true)) {
77  return state_mismatch && (!this->idle_action_ready_());
79  return state_mismatch && (!this->cooling_action_ready_());
81  return state_mismatch && (!this->heating_action_ready_());
83  return state_mismatch && (!this->fanning_action_ready_());
85  return state_mismatch && (!this->drying_action_ready_());
86  default:
87  break;
88  }
89  return false;
90 }
91 
93  bool state_mismatch = this->fan_mode.value_or(climate::CLIMATE_FAN_ON) != this->prev_fan_mode_;
94  return state_mismatch && (!this->fan_mode_ready_());
95 }
96 
98 
100 
102  if ((this->supports_cool_ || (this->supports_fan_only_ && this->supports_fan_only_cooling_)) &&
103  (std::isnan(this->cooling_deadband_) || std::isnan(this->cooling_overrun_)))
104  return false;
105 
106  if (this->supports_heat_ && (std::isnan(this->heating_deadband_) || std::isnan(this->heating_overrun_)))
107  return false;
108 
109  return true;
110 }
111 
113  if (std::isnan(this->target_temperature)) {
114  this->target_temperature =
117  } else {
118  // target_temperature must be between the visual minimum and the visual maximum
119  if (this->target_temperature < this->get_traits().get_visual_min_temperature())
121  if (this->target_temperature > this->get_traits().get_visual_max_temperature())
123  }
124 }
125 
127  if (this->supports_two_points_) {
130  } else {
132  }
133 }
134 
136  if (std::isnan(this->target_temperature_low)) {
138  } else {
139  // target_temperature_low must not be lower than the visual minimum
140  if (this->target_temperature_low < this->get_traits().get_visual_min_temperature())
142  // target_temperature_low must not be greater than the visual maximum minus set_point_minimum_differential_
143  if (this->target_temperature_low >
144  this->get_traits().get_visual_max_temperature() - this->set_point_minimum_differential_) {
145  this->target_temperature_low =
147  }
148  // if target_temperature_low is set greater than target_temperature_high, move up target_temperature_high
151  }
152 }
153 
155  if (std::isnan(this->target_temperature_high)) {
157  } else {
158  // target_temperature_high must not be lower than the visual maximum
159  if (this->target_temperature_high > this->get_traits().get_visual_max_temperature())
161  // target_temperature_high must not be lower than the visual minimum plus set_point_minimum_differential_
162  if (this->target_temperature_high <
163  this->get_traits().get_visual_min_temperature() + this->set_point_minimum_differential_) {
166  }
167  // if target_temperature_high is set less than target_temperature_low, move down target_temperature_low
168  if (this->target_temperature_high < this->target_temperature_low + this->set_point_minimum_differential_)
170  }
171 }
172 
174  if (call.get_preset().has_value()) {
175  // setup_complete_ blocks modifying/resetting the temps immediately after boot
176  if (this->setup_complete_) {
177  this->change_preset_(*call.get_preset());
178  } else {
179  this->preset = *call.get_preset();
180  }
181  }
182  if (call.get_custom_preset().has_value()) {
183  // setup_complete_ blocks modifying/resetting the temps immediately after boot
184  if (this->setup_complete_) {
186  } else {
187  this->custom_preset = *call.get_custom_preset();
188  }
189  }
190 
191  if (call.get_mode().has_value())
192  this->mode = *call.get_mode();
193  if (call.get_fan_mode().has_value())
194  this->fan_mode = *call.get_fan_mode();
195  if (call.get_swing_mode().has_value())
196  this->swing_mode = *call.get_swing_mode();
197  if (this->supports_two_points_) {
198  if (call.get_target_temperature_low().has_value()) {
201  }
202  if (call.get_target_temperature_high().has_value()) {
205  }
206  } else {
207  if (call.get_target_temperature().has_value()) {
210  }
211  }
212  // make any changes happen
213  refresh();
214 }
215 
219  if (supports_auto_)
223  if (supports_cool_)
225  if (supports_dry_)
227  if (supports_fan_only_)
229  if (supports_heat_)
231 
250 
259 
260  for (auto &it : this->preset_config_) {
261  traits.add_supported_preset(it.first);
262  }
263  for (auto &it : this->custom_preset_config_) {
265  }
266 
269  return traits;
270 }
271 
273  auto target_action = climate::CLIMATE_ACTION_IDLE;
274  // if any hysteresis values or current_temperature is not valid, we go to OFF;
275  if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
277  }
278  // do not change the action if an "ON" timer is running
279  if ((!ignore_timers) &&
282  return this->action;
283  }
284 
285  // ensure set point(s) is/are valid before computing the action
287  // everything has been validated so we can now safely compute the action
288  switch (this->mode) {
289  // if the climate mode is OFF then the climate action must be OFF
291  target_action = climate::CLIMATE_ACTION_OFF;
292  break;
294  if (this->fanning_required_())
295  target_action = climate::CLIMATE_ACTION_FAN;
296  break;
298  target_action = climate::CLIMATE_ACTION_DRYING;
299  break;
301  if (this->cooling_required_() && this->heating_required_()) {
302  // this is bad and should never happen, so just stop.
303  // target_action = climate::CLIMATE_ACTION_IDLE;
304  } else if (this->cooling_required_()) {
305  target_action = climate::CLIMATE_ACTION_COOLING;
306  } else if (this->heating_required_()) {
307  target_action = climate::CLIMATE_ACTION_HEATING;
308  }
309  break;
311  if (this->cooling_required_()) {
312  target_action = climate::CLIMATE_ACTION_COOLING;
313  }
314  break;
316  if (this->heating_required_()) {
317  target_action = climate::CLIMATE_ACTION_HEATING;
318  }
319  break;
320  default:
321  break;
322  }
323  // do not abruptly switch actions. cycle through IDLE, first. we'll catch this at the next update.
325  (target_action == climate::CLIMATE_ACTION_HEATING)) ||
327  ((target_action == climate::CLIMATE_ACTION_COOLING) || (target_action == climate::CLIMATE_ACTION_DRYING)))) {
329  }
330 
331  return target_action;
332 }
333 
335  auto target_action = climate::CLIMATE_ACTION_IDLE;
336  // if any hysteresis values or current_temperature is not valid, we go to OFF;
337  if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
339  }
340 
341  // ensure set point(s) is/are valid before computing the action
343  // everything has been validated so we can now safely compute the action
344  switch (this->mode) {
345  // if the climate mode is OFF then the climate action must be OFF
347  target_action = climate::CLIMATE_ACTION_OFF;
348  break;
351  // this is bad and should never happen, so just stop.
352  // target_action = climate::CLIMATE_ACTION_IDLE;
353  } else if (this->supplemental_cooling_required_()) {
354  target_action = climate::CLIMATE_ACTION_COOLING;
355  } else if (this->supplemental_heating_required_()) {
356  target_action = climate::CLIMATE_ACTION_HEATING;
357  }
358  break;
360  if (this->supplemental_cooling_required_()) {
361  target_action = climate::CLIMATE_ACTION_COOLING;
362  }
363  break;
365  if (this->supplemental_heating_required_()) {
366  target_action = climate::CLIMATE_ACTION_HEATING;
367  }
368  break;
369  default:
370  break;
371  }
372 
373  return target_action;
374 }
375 
377  // setup_complete_ helps us ensure an action is called immediately after boot
378  if ((action == this->action) && this->setup_complete_) {
379  // already in target mode
380  return;
381  }
382 
383  if (((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) ||
384  (action == climate::CLIMATE_ACTION_IDLE && this->action == climate::CLIMATE_ACTION_OFF)) &&
385  this->setup_complete_) {
386  // switching from OFF to IDLE or vice-versa -- this is only a visual difference.
387  // OFF means user manually disabled, IDLE means the temperature is in target range.
388  this->action = action;
389  if (publish_state)
390  this->publish_state();
391  return;
392  }
393 
394  bool action_ready = false;
395  Trigger<> *trig = this->idle_action_trigger_, *trig_fan = nullptr;
396  switch (action) {
399  if (this->idle_action_ready_()) {
401  if (this->action == climate::CLIMATE_ACTION_COOLING)
403  if (this->action == climate::CLIMATE_ACTION_FAN) {
406  } else {
408  }
409  }
410  if (this->action == climate::CLIMATE_ACTION_HEATING)
412  // trig = this->idle_action_trigger_;
413  ESP_LOGVV(TAG, "Switching to IDLE/OFF action");
414  this->cooling_max_runtime_exceeded_ = false;
415  this->heating_max_runtime_exceeded_ = false;
416  action_ready = true;
417  }
418  break;
420  if (this->cooling_action_ready_()) {
423  if (this->supports_fan_with_cooling_) {
425  trig_fan = this->fan_only_action_trigger_;
426  }
427  trig = this->cool_action_trigger_;
428  ESP_LOGVV(TAG, "Switching to COOLING action");
429  action_ready = true;
430  }
431  break;
433  if (this->heating_action_ready_()) {
436  if (this->supports_fan_with_heating_) {
438  trig_fan = this->fan_only_action_trigger_;
439  }
440  trig = this->heat_action_trigger_;
441  ESP_LOGVV(TAG, "Switching to HEATING action");
442  action_ready = true;
443  }
444  break;
446  if (this->fanning_action_ready_()) {
449  } else {
451  }
452  trig = this->fan_only_action_trigger_;
453  ESP_LOGVV(TAG, "Switching to FAN_ONLY action");
454  action_ready = true;
455  }
456  break;
458  if (this->drying_action_ready_()) {
461  trig = this->dry_action_trigger_;
462  ESP_LOGVV(TAG, "Switching to DRYING action");
463  action_ready = true;
464  }
465  break;
466  default:
467  // we cannot report an invalid mode back to HA (even if it asked for one)
468  // and must assume some valid value
470  // trig = this->idle_action_trigger_;
471  }
472 
473  if (action_ready) {
474  if (this->prev_action_trigger_ != nullptr) {
476  this->prev_action_trigger_ = nullptr;
477  }
478  this->action = action;
479  this->prev_action_trigger_ = trig;
480  assert(trig != nullptr);
481  trig->trigger();
482  // if enabled, call the fan_only action with cooling/heating actions
483  if (trig_fan != nullptr) {
484  ESP_LOGVV(TAG, "Calling FAN_ONLY action with HEATING/COOLING action");
485  trig_fan->trigger();
486  }
487  if (publish_state)
488  this->publish_state();
489  }
490 }
491 
493  // setup_complete_ helps us ensure an action is called immediately after boot
494  if ((action == this->supplemental_action_) && this->setup_complete_) {
495  // already in target mode
496  return;
497  }
498 
499  switch (action) {
504  break;
507  break;
510  break;
511  default:
512  return;
513  }
514  ESP_LOGVV(TAG, "Updating supplemental action...");
517 }
518 
520  Trigger<> *trig = nullptr;
521 
522  switch (this->supplemental_action_) {
526  }
528  ESP_LOGVV(TAG, "Calling supplemental COOLING action");
529  break;
533  }
535  ESP_LOGVV(TAG, "Calling supplemental HEATING action");
536  break;
537  default:
538  break;
539  }
540 
541  if (trig != nullptr) {
542  assert(trig != nullptr);
543  trig->trigger();
544  }
545 }
546 
548  // setup_complete_ helps us ensure an action is called immediately after boot
549  if ((fan_mode == this->prev_fan_mode_) && this->setup_complete_) {
550  // already in target mode
551  return;
552  }
553 
554  this->fan_mode = fan_mode;
555  if (publish_state)
556  this->publish_state();
557 
558  if (this->fan_mode_ready_()) {
559  Trigger<> *trig = this->fan_mode_auto_trigger_;
560  switch (fan_mode) {
562  trig = this->fan_mode_on_trigger_;
563  ESP_LOGVV(TAG, "Switching to FAN_ON mode");
564  break;
566  trig = this->fan_mode_off_trigger_;
567  ESP_LOGVV(TAG, "Switching to FAN_OFF mode");
568  break;
570  // trig = this->fan_mode_auto_trigger_;
571  ESP_LOGVV(TAG, "Switching to FAN_AUTO mode");
572  break;
574  trig = this->fan_mode_low_trigger_;
575  ESP_LOGVV(TAG, "Switching to FAN_LOW mode");
576  break;
578  trig = this->fan_mode_medium_trigger_;
579  ESP_LOGVV(TAG, "Switching to FAN_MEDIUM mode");
580  break;
582  trig = this->fan_mode_high_trigger_;
583  ESP_LOGVV(TAG, "Switching to FAN_HIGH mode");
584  break;
586  trig = this->fan_mode_middle_trigger_;
587  ESP_LOGVV(TAG, "Switching to FAN_MIDDLE mode");
588  break;
590  trig = this->fan_mode_focus_trigger_;
591  ESP_LOGVV(TAG, "Switching to FAN_FOCUS mode");
592  break;
594  trig = this->fan_mode_diffuse_trigger_;
595  ESP_LOGVV(TAG, "Switching to FAN_DIFFUSE mode");
596  break;
597  default:
598  // we cannot report an invalid mode back to HA (even if it asked for one)
599  // and must assume some valid value
600  fan_mode = climate::CLIMATE_FAN_AUTO;
601  // trig = this->fan_mode_auto_trigger_;
602  }
603  if (this->prev_fan_mode_trigger_ != nullptr) {
605  this->prev_fan_mode_trigger_ = nullptr;
606  }
608  assert(trig != nullptr);
609  trig->trigger();
610  this->prev_fan_mode_ = fan_mode;
611  this->prev_fan_mode_trigger_ = trig;
612  }
613 }
614 
616  // setup_complete_ helps us ensure an action is called immediately after boot
617  if ((mode == this->prev_mode_) && this->setup_complete_) {
618  // already in target mode
619  return;
620  }
621 
622  if (this->prev_mode_trigger_ != nullptr) {
624  this->prev_mode_trigger_ = nullptr;
625  }
626  Trigger<> *trig = this->auto_mode_trigger_;
627  switch (mode) {
629  trig = this->off_mode_trigger_;
630  break;
632  // trig = this->auto_mode_trigger_;
633  break;
635  trig = this->cool_mode_trigger_;
636  break;
638  trig = this->heat_mode_trigger_;
639  break;
641  trig = this->fan_only_mode_trigger_;
642  break;
644  trig = this->dry_mode_trigger_;
645  break;
646  default:
647  // we cannot report an invalid mode back to HA (even if it asked for one)
648  // and must assume some valid value
650  // trig = this->auto_mode_trigger_;
651  }
652  assert(trig != nullptr);
653  trig->trigger();
654  this->mode = mode;
655  this->prev_mode_ = mode;
656  this->prev_mode_trigger_ = trig;
657  if (publish_state)
658  this->publish_state();
659 }
660 
662  // setup_complete_ helps us ensure an action is called immediately after boot
663  if ((swing_mode == this->prev_swing_mode_) && this->setup_complete_) {
664  // already in target mode
665  return;
666  }
667 
668  if (this->prev_swing_mode_trigger_ != nullptr) {
670  this->prev_swing_mode_trigger_ = nullptr;
671  }
672  Trigger<> *trig = this->swing_mode_off_trigger_;
673  switch (swing_mode) {
675  trig = this->swing_mode_both_trigger_;
676  break;
678  trig = this->swing_mode_horizontal_trigger_;
679  break;
681  // trig = this->swing_mode_off_trigger_;
682  break;
684  trig = this->swing_mode_vertical_trigger_;
685  break;
686  default:
687  // we cannot report an invalid mode back to HA (even if it asked for one)
688  // and must assume some valid value
689  swing_mode = climate::CLIMATE_SWING_OFF;
690  // trig = this->swing_mode_off_trigger_;
691  }
692  assert(trig != nullptr);
693  trig->trigger();
694  this->swing_mode = swing_mode;
696  this->prev_swing_mode_trigger_ = trig;
697  if (publish_state)
698  this->publish_state();
699 }
700 
705  }
708 }
709 
713 }
714 
718 }
719 
721 
724  return !(this->timer_active_(thermostat::TIMER_FAN_MODE));
725  }
727 }
728 
732 }
733 
735  if (this->timer_duration_(timer_index) > 0) {
736  this->set_timeout(this->timer_[timer_index].name, this->timer_duration_(timer_index),
737  this->timer_cbf_(timer_index));
738  this->timer_[timer_index].active = true;
739  }
740 }
741 
743  this->timer_[timer_index].active = false;
744  return this->cancel_timeout(this->timer_[timer_index].name);
745 }
746 
748  return this->timer_[timer_index].active;
749 }
750 
752  return this->timer_[timer_index].time;
753 }
754 
755 std::function<void()> ThermostatClimate::timer_cbf_(ThermostatClimateTimerIndex timer_index) {
756  return this->timer_[timer_index].func;
757 }
758 
760  ESP_LOGVV(TAG, "cooling_max_run_time timer expired");
761  this->timer_[thermostat::TIMER_COOLING_MAX_RUN_TIME].active = false;
762  this->cooling_max_runtime_exceeded_ = true;
765 }
766 
768  ESP_LOGVV(TAG, "cooling_off timer expired");
769  this->timer_[thermostat::TIMER_COOLING_OFF].active = false;
770  this->switch_to_action_(this->compute_action_());
772 }
773 
775  ESP_LOGVV(TAG, "cooling_on timer expired");
776  this->timer_[thermostat::TIMER_COOLING_ON].active = false;
777  this->switch_to_action_(this->compute_action_());
779 }
780 
782  ESP_LOGVV(TAG, "fan_mode timer expired");
783  this->timer_[thermostat::TIMER_FAN_MODE].active = false;
786  this->switch_to_action_(this->compute_action_());
787 }
788 
790  ESP_LOGVV(TAG, "fanning_off timer expired");
791  this->timer_[thermostat::TIMER_FANNING_OFF].active = false;
792  this->switch_to_action_(this->compute_action_());
793 }
794 
796  ESP_LOGVV(TAG, "fanning_on timer expired");
797  this->timer_[thermostat::TIMER_FANNING_ON].active = false;
798  this->switch_to_action_(this->compute_action_());
799 }
800 
802  ESP_LOGVV(TAG, "heating_max_run_time timer expired");
803  this->timer_[thermostat::TIMER_HEATING_MAX_RUN_TIME].active = false;
804  this->heating_max_runtime_exceeded_ = true;
807 }
808 
810  ESP_LOGVV(TAG, "heating_off timer expired");
811  this->timer_[thermostat::TIMER_HEATING_OFF].active = false;
812  this->switch_to_action_(this->compute_action_());
814 }
815 
817  ESP_LOGVV(TAG, "heating_on timer expired");
818  this->timer_[thermostat::TIMER_HEATING_ON].active = false;
819  this->switch_to_action_(this->compute_action_());
821 }
822 
824  ESP_LOGVV(TAG, "idle_on timer expired");
825  this->timer_[thermostat::TIMER_IDLE_ON].active = false;
826  this->switch_to_action_(this->compute_action_());
828 }
829 
831  if (this->supports_two_points_) {
832  // setup_complete_ helps us ensure an action is called immediately after boot
835  return; // nothing changed, no reason to trigger
836  } else {
837  // save the new temperatures so we can check them again later; the trigger will fire below
840  }
841  } else {
842  if ((this->prev_target_temperature_ == this->target_temperature) && this->setup_complete_) {
843  return; // nothing changed, no reason to trigger
844  } else {
845  // save the new temperature so we can check it again later; the trigger will fire below
847  }
848  }
849  // trigger the action
851  assert(trig != nullptr);
852  trig->trigger();
853 }
854 
857 
858  if (this->supports_cool_) {
859  if (this->current_temperature > temperature + this->cooling_deadband_) {
860  // if the current temperature exceeds the target + deadband, cooling is required
861  return true;
862  } else if (this->current_temperature < temperature - this->cooling_overrun_) {
863  // if the current temperature is less than the target - overrun, cooling should stop
864  return false;
865  } else {
866  // if we get here, the current temperature is between target + deadband and target - overrun,
867  // so the action should not change unless it conflicts with the current mode
868  return (this->action == climate::CLIMATE_ACTION_COOLING) &&
870  }
871  }
872  return false;
873 }
874 
877 
878  if (this->supports_fan_only_) {
879  if (this->supports_fan_only_cooling_) {
880  if (this->current_temperature > temperature + this->cooling_deadband_) {
881  // if the current temperature exceeds the target + deadband, fanning is required
882  return true;
883  } else if (this->current_temperature < temperature - this->cooling_overrun_) {
884  // if the current temperature is less than the target - overrun, fanning should stop
885  return false;
886  } else {
887  // if we get here, the current temperature is between target + deadband and target - overrun,
888  // so the action should not change unless it conflicts with the current mode
890  }
891  } else {
892  return true;
893  }
894  }
895  return false;
896 }
897 
900 
901  if (this->supports_heat_) {
902  if (this->current_temperature < temperature - this->heating_deadband_) {
903  // if the current temperature is below the target - deadband, heating is required
904  return true;
905  } else if (this->current_temperature > temperature + this->heating_overrun_) {
906  // if the current temperature is above the target + overrun, heating should stop
907  return false;
908  } else {
909  // if we get here, the current temperature is between target - deadband and target + overrun,
910  // so the action should not change unless it conflicts with the current mode
911  return (this->action == climate::CLIMATE_ACTION_HEATING) &&
913  }
914  }
915  return false;
916 }
917 
920  // the component must supports_cool_ and the climate action must be climate::CLIMATE_ACTION_COOLING. then...
921  // supplemental cooling is required if the max delta or max runtime was exceeded or the action is already engaged
922  return this->supports_cool_ && (this->action == climate::CLIMATE_ACTION_COOLING) &&
926 }
927 
930  // the component must supports_heat_ and the climate action must be climate::CLIMATE_ACTION_HEATING. then...
931  // supplemental heating is required if the max delta or max runtime was exceeded or the action is already engaged
932  return this->supports_heat_ && (this->action == climate::CLIMATE_ACTION_HEATING) &&
934  (this->current_temperature < temperature - this->supplemental_heat_delta_) ||
936 }
937 
939  bool is_default_preset) {
940  ESP_LOGCONFIG(TAG, " %s Is Default: %s", preset_name, YESNO(is_default_preset));
941 
942  if (this->supports_heat_) {
943  if (this->supports_two_points_) {
944  ESP_LOGCONFIG(TAG, " %s Default Target Temperature Low: %.1f°C", preset_name,
945  config.default_temperature_low);
946  } else {
947  ESP_LOGCONFIG(TAG, " %s Default Target Temperature Low: %.1f°C", preset_name, config.default_temperature);
948  }
949  }
950  if ((this->supports_cool_) || (this->supports_fan_only_)) {
951  if (this->supports_two_points_) {
952  ESP_LOGCONFIG(TAG, " %s Default Target Temperature High: %.1f°C", preset_name,
953  config.default_temperature_high);
954  } else {
955  ESP_LOGCONFIG(TAG, " %s Default Target Temperature High: %.1f°C", preset_name, config.default_temperature);
956  }
957  }
958 
959  if (config.mode_.has_value()) {
960  ESP_LOGCONFIG(TAG, " %s Default Mode: %s", preset_name,
961  LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
962  }
963  if (config.fan_mode_.has_value()) {
964  ESP_LOGCONFIG(TAG, " %s Default Fan Mode: %s", preset_name,
965  LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
966  }
967  if (config.swing_mode_.has_value()) {
968  ESP_LOGCONFIG(TAG, " %s Default Swing Mode: %s", preset_name,
969  LOG_STR_ARG(climate::climate_swing_mode_to_string(*config.swing_mode_)));
970  }
971 }
972 
974  auto config = this->preset_config_.find(preset);
975 
976  if (config != this->preset_config_.end()) {
977  ESP_LOGI(TAG, "Preset %s requested", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
978  if (this->change_preset_internal_(config->second) || (!this->preset.has_value()) ||
979  this->preset.value() != preset) {
980  // Fire any preset changed trigger if defined
981  Trigger<> *trig = this->preset_change_trigger_;
982  assert(trig != nullptr);
983  trig->trigger();
984 
985  this->refresh();
986  ESP_LOGI(TAG, "Preset %s applied", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
987  } else {
988  ESP_LOGI(TAG, "No changes required to apply preset %s", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
989  }
990  this->custom_preset.reset();
991  this->preset = preset;
992  } else {
993  ESP_LOGE(TAG, "Preset %s is not configured, ignoring.", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
994  }
995 }
996 
998  auto config = this->custom_preset_config_.find(custom_preset);
999 
1000  if (config != this->custom_preset_config_.end()) {
1001  ESP_LOGI(TAG, "Custom preset %s requested", custom_preset.c_str());
1002  if (this->change_preset_internal_(config->second) || (!this->custom_preset.has_value()) ||
1003  this->custom_preset.value() != custom_preset) {
1004  // Fire any preset changed trigger if defined
1005  Trigger<> *trig = this->preset_change_trigger_;
1006  assert(trig != nullptr);
1007  trig->trigger();
1008 
1009  this->refresh();
1010  ESP_LOGI(TAG, "Custom preset %s applied", custom_preset.c_str());
1011  } else {
1012  ESP_LOGI(TAG, "No changes required to apply custom preset %s", custom_preset.c_str());
1013  }
1014  this->preset.reset();
1015  this->custom_preset = custom_preset;
1016  } else {
1017  ESP_LOGE(TAG, "Custom Preset %s is not configured, ignoring.", custom_preset.c_str());
1018  }
1019 }
1020 
1022  bool something_changed = false;
1023 
1024  if (this->supports_two_points_) {
1025  if (this->target_temperature_low != config.default_temperature_low) {
1027  something_changed = true;
1028  }
1029  if (this->target_temperature_high != config.default_temperature_high) {
1031  something_changed = true;
1032  }
1033  } else {
1034  if (this->target_temperature != config.default_temperature) {
1035  this->target_temperature = config.default_temperature;
1036  something_changed = true;
1037  }
1038  }
1039 
1040  // Note: The mode, fan_mode and swing_mode can all be defined in the preset but if the climate.control call
1041  // also specifies them then the climate.control call's values will override the preset's values for that call
1042  if (config.mode_.has_value() && (this->mode != config.mode_.value())) {
1043  ESP_LOGV(TAG, "Setting mode to %s", LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
1044  this->mode = *config.mode_;
1045  something_changed = true;
1046  }
1047 
1048  if (config.fan_mode_.has_value() && (this->fan_mode != config.fan_mode_.value())) {
1049  ESP_LOGV(TAG, "Setting fan mode to %s", LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
1050  this->fan_mode = *config.fan_mode_;
1051  something_changed = true;
1052  }
1053 
1054  if (config.swing_mode_.has_value() && (this->swing_mode != config.swing_mode_.value())) {
1055  ESP_LOGV(TAG, "Setting swing mode to %s", LOG_STR_ARG(climate::climate_swing_mode_to_string(*config.swing_mode_)));
1056  this->swing_mode = *config.swing_mode_;
1057  something_changed = true;
1058  }
1059 
1060  return something_changed;
1061 }
1062 
1064  const ThermostatClimateTargetTempConfig &config) {
1065  this->preset_config_[preset] = config;
1066 }
1067 
1069  const ThermostatClimateTargetTempConfig &config) {
1070  this->custom_preset_config_[name] = config;
1071 }
1072 
1074  : cool_action_trigger_(new Trigger<>()),
1076  cool_mode_trigger_(new Trigger<>()),
1077  dry_action_trigger_(new Trigger<>()),
1078  dry_mode_trigger_(new Trigger<>()),
1079  heat_action_trigger_(new Trigger<>()),
1081  heat_mode_trigger_(new Trigger<>()),
1082  auto_mode_trigger_(new Trigger<>()),
1083  idle_action_trigger_(new Trigger<>()),
1084  off_mode_trigger_(new Trigger<>()),
1087  fan_mode_on_trigger_(new Trigger<>()),
1088  fan_mode_off_trigger_(new Trigger<>()),
1090  fan_mode_low_trigger_(new Trigger<>()),
1101  preset_change_trigger_(new Trigger<>()) {}
1102 
1105 }
1106 
1108 
1110  this->on_boot_restore_from_ = on_boot_restore_from;
1111 }
1113  this->set_point_minimum_differential_ = differential;
1114 }
1115 void ThermostatClimate::set_cool_deadband(float deadband) { this->cooling_deadband_ = deadband; }
1116 void ThermostatClimate::set_cool_overrun(float overrun) { this->cooling_overrun_ = overrun; }
1117 void ThermostatClimate::set_heat_deadband(float deadband) { this->heating_deadband_ = deadband; }
1118 void ThermostatClimate::set_heat_overrun(float overrun) { this->heating_overrun_ = overrun; }
1123  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1124 }
1127  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1128 }
1130  this->timer_[thermostat::TIMER_COOLING_ON].time =
1131  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1132 }
1134  this->timer_[thermostat::TIMER_FAN_MODE].time =
1135  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1136 }
1139  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1140 }
1142  this->timer_[thermostat::TIMER_FANNING_ON].time =
1143  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1144 }
1147  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1148 }
1151  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1152 }
1154  this->timer_[thermostat::TIMER_HEATING_ON].time =
1155  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1156 }
1158  this->timer_[thermostat::TIMER_IDLE_ON].time =
1159  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1160 }
1161 void ThermostatClimate::set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
1162 void ThermostatClimate::set_use_startup_delay(bool use_startup_delay) { this->use_startup_delay_ = use_startup_delay; }
1163 void ThermostatClimate::set_supports_heat_cool(bool supports_heat_cool) {
1164  this->supports_heat_cool_ = supports_heat_cool;
1165 }
1166 void ThermostatClimate::set_supports_auto(bool supports_auto) { this->supports_auto_ = supports_auto; }
1167 void ThermostatClimate::set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
1168 void ThermostatClimate::set_supports_dry(bool supports_dry) { this->supports_dry_ = supports_dry; }
1169 void ThermostatClimate::set_supports_fan_only(bool supports_fan_only) { this->supports_fan_only_ = supports_fan_only; }
1171  bool supports_fan_only_action_uses_fan_mode_timer) {
1172  this->supports_fan_only_action_uses_fan_mode_timer_ = supports_fan_only_action_uses_fan_mode_timer;
1173 }
1174 void ThermostatClimate::set_supports_fan_only_cooling(bool supports_fan_only_cooling) {
1175  this->supports_fan_only_cooling_ = supports_fan_only_cooling;
1176 }
1177 void ThermostatClimate::set_supports_fan_with_cooling(bool supports_fan_with_cooling) {
1178  this->supports_fan_with_cooling_ = supports_fan_with_cooling;
1179 }
1180 void ThermostatClimate::set_supports_fan_with_heating(bool supports_fan_with_heating) {
1181  this->supports_fan_with_heating_ = supports_fan_with_heating;
1182 }
1183 void ThermostatClimate::set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
1184 void ThermostatClimate::set_supports_fan_mode_on(bool supports_fan_mode_on) {
1185  this->supports_fan_mode_on_ = supports_fan_mode_on;
1186 }
1187 void ThermostatClimate::set_supports_fan_mode_off(bool supports_fan_mode_off) {
1188  this->supports_fan_mode_off_ = supports_fan_mode_off;
1189 }
1190 void ThermostatClimate::set_supports_fan_mode_auto(bool supports_fan_mode_auto) {
1191  this->supports_fan_mode_auto_ = supports_fan_mode_auto;
1192 }
1193 void ThermostatClimate::set_supports_fan_mode_low(bool supports_fan_mode_low) {
1194  this->supports_fan_mode_low_ = supports_fan_mode_low;
1195 }
1196 void ThermostatClimate::set_supports_fan_mode_medium(bool supports_fan_mode_medium) {
1197  this->supports_fan_mode_medium_ = supports_fan_mode_medium;
1198 }
1199 void ThermostatClimate::set_supports_fan_mode_high(bool supports_fan_mode_high) {
1200  this->supports_fan_mode_high_ = supports_fan_mode_high;
1201 }
1202 void ThermostatClimate::set_supports_fan_mode_middle(bool supports_fan_mode_middle) {
1203  this->supports_fan_mode_middle_ = supports_fan_mode_middle;
1204 }
1205 void ThermostatClimate::set_supports_fan_mode_focus(bool supports_fan_mode_focus) {
1206  this->supports_fan_mode_focus_ = supports_fan_mode_focus;
1207 }
1208 void ThermostatClimate::set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse) {
1209  this->supports_fan_mode_diffuse_ = supports_fan_mode_diffuse;
1210 }
1211 void ThermostatClimate::set_supports_swing_mode_both(bool supports_swing_mode_both) {
1212  this->supports_swing_mode_both_ = supports_swing_mode_both;
1213 }
1214 void ThermostatClimate::set_supports_swing_mode_off(bool supports_swing_mode_off) {
1215  this->supports_swing_mode_off_ = supports_swing_mode_off;
1216 }
1217 void ThermostatClimate::set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal) {
1218  this->supports_swing_mode_horizontal_ = supports_swing_mode_horizontal;
1219 }
1220 void ThermostatClimate::set_supports_swing_mode_vertical(bool supports_swing_mode_vertical) {
1221  this->supports_swing_mode_vertical_ = supports_swing_mode_vertical;
1222 }
1223 void ThermostatClimate::set_supports_two_points(bool supports_two_points) {
1224  this->supports_two_points_ = supports_two_points;
1225 }
1226 
1229  return this->supplemental_cool_action_trigger_;
1230 }
1235  return this->supplemental_heat_action_trigger_;
1236 }
1259 
1261  LOG_CLIMATE("", "Thermostat", this);
1262 
1263  if (this->supports_two_points_) {
1264  ESP_LOGCONFIG(TAG, " Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_);
1265  }
1266  ESP_LOGCONFIG(TAG, " Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_));
1267  if (this->supports_cool_) {
1268  ESP_LOGCONFIG(TAG, " Cooling Parameters:");
1269  ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->cooling_deadband_);
1270  ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->cooling_overrun_);
1272  ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_cool_delta_);
1273  ESP_LOGCONFIG(TAG, " Maximum Run Time: %us",
1275  }
1276  ESP_LOGCONFIG(TAG, " Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_COOLING_OFF) / 1000);
1277  ESP_LOGCONFIG(TAG, " Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_COOLING_ON) / 1000);
1278  }
1279  if (this->supports_heat_) {
1280  ESP_LOGCONFIG(TAG, " Heating Parameters:");
1281  ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->heating_deadband_);
1282  ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->heating_overrun_);
1284  ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_heat_delta_);
1285  ESP_LOGCONFIG(TAG, " Maximum Run Time: %us",
1287  }
1288  ESP_LOGCONFIG(TAG, " Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_HEATING_OFF) / 1000);
1289  ESP_LOGCONFIG(TAG, " Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_HEATING_ON) / 1000);
1290  }
1291  if (this->supports_fan_only_) {
1292  ESP_LOGCONFIG(TAG, " Fanning Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_FANNING_OFF) / 1000);
1293  ESP_LOGCONFIG(TAG, " Fanning Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_FANNING_ON) / 1000);
1294  }
1298  ESP_LOGCONFIG(TAG, " Minimum Fan Mode Switching Time: %us",
1300  }
1301  ESP_LOGCONFIG(TAG, " Minimum Idle Time: %us", this->timer_[thermostat::TIMER_IDLE_ON].time / 1000);
1302  ESP_LOGCONFIG(TAG, " Supports AUTO: %s", YESNO(this->supports_auto_));
1303  ESP_LOGCONFIG(TAG, " Supports HEAT/COOL: %s", YESNO(this->supports_heat_cool_));
1304  ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
1305  ESP_LOGCONFIG(TAG, " Supports DRY: %s", YESNO(this->supports_dry_));
1306  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY: %s", YESNO(this->supports_fan_only_));
1307  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_ACTION_USES_FAN_MODE_TIMER: %s",
1309  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_COOLING: %s", YESNO(this->supports_fan_only_cooling_));
1310  if (this->supports_cool_) {
1311  ESP_LOGCONFIG(TAG, " Supports FAN_WITH_COOLING: %s", YESNO(this->supports_fan_with_cooling_));
1312  }
1313  if (this->supports_heat_) {
1314  ESP_LOGCONFIG(TAG, " Supports FAN_WITH_HEATING: %s", YESNO(this->supports_fan_with_heating_));
1315  }
1316  ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_));
1317  ESP_LOGCONFIG(TAG, " Supports FAN MODE ON: %s", YESNO(this->supports_fan_mode_on_));
1318  ESP_LOGCONFIG(TAG, " Supports FAN MODE OFF: %s", YESNO(this->supports_fan_mode_off_));
1319  ESP_LOGCONFIG(TAG, " Supports FAN MODE AUTO: %s", YESNO(this->supports_fan_mode_auto_));
1320  ESP_LOGCONFIG(TAG, " Supports FAN MODE LOW: %s", YESNO(this->supports_fan_mode_low_));
1321  ESP_LOGCONFIG(TAG, " Supports FAN MODE MEDIUM: %s", YESNO(this->supports_fan_mode_medium_));
1322  ESP_LOGCONFIG(TAG, " Supports FAN MODE HIGH: %s", YESNO(this->supports_fan_mode_high_));
1323  ESP_LOGCONFIG(TAG, " Supports FAN MODE MIDDLE: %s", YESNO(this->supports_fan_mode_middle_));
1324  ESP_LOGCONFIG(TAG, " Supports FAN MODE FOCUS: %s", YESNO(this->supports_fan_mode_focus_));
1325  ESP_LOGCONFIG(TAG, " Supports FAN MODE DIFFUSE: %s", YESNO(this->supports_fan_mode_diffuse_));
1326  ESP_LOGCONFIG(TAG, " Supports SWING MODE BOTH: %s", YESNO(this->supports_swing_mode_both_));
1327  ESP_LOGCONFIG(TAG, " Supports SWING MODE OFF: %s", YESNO(this->supports_swing_mode_off_));
1328  ESP_LOGCONFIG(TAG, " Supports SWING MODE HORIZONTAL: %s", YESNO(this->supports_swing_mode_horizontal_));
1329  ESP_LOGCONFIG(TAG, " Supports SWING MODE VERTICAL: %s", YESNO(this->supports_swing_mode_vertical_));
1330  ESP_LOGCONFIG(TAG, " Supports TWO SET POINTS: %s", YESNO(this->supports_two_points_));
1331 
1332  ESP_LOGCONFIG(TAG, " Supported PRESETS: ");
1333  for (auto &it : this->preset_config_) {
1334  const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first));
1335 
1336  ESP_LOGCONFIG(TAG, " Supports %s: %s", preset_name, YESNO(true));
1337  this->dump_preset_config_(preset_name, it.second, it.first == this->default_preset_);
1338  }
1339 
1340  ESP_LOGCONFIG(TAG, " Supported CUSTOM PRESETS: ");
1341  for (auto &it : this->custom_preset_config_) {
1342  const auto *preset_name = it.first.c_str();
1343 
1344  ESP_LOGCONFIG(TAG, " Supports %s: %s", preset_name, YESNO(true));
1345  this->dump_preset_config_(preset_name, it.second, it.first == this->default_custom_preset_);
1346  }
1347  ESP_LOGCONFIG(TAG, " On boot, restore from: %s",
1348  this->on_boot_restore_from_ == thermostat::DEFAULT_PRESET ? "DEFAULT_PRESET" : "MEMORY");
1349 }
1350 
1352 
1354  : default_temperature(default_temperature) {}
1355 
1358  : default_temperature_low(default_temperature_low), default_temperature_high(default_temperature_high) {}
1359 
1360 } // namespace thermostat
1361 } // namespace esphome
Trigger * swing_mode_vertical_trigger_
The trigger to call when the controller should switch the swing mode to "vertical".
float set_point_minimum_differential_
Minimum differential required between set points.
This class is used to encode all control actions on a climate device.
Definition: climate.h:33
void set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal)
The fan mode is set to Low.
Definition: climate_mode.h:54
value_type const & value() const
Definition: optional.h:89
The climate device is off (inactive or no power)
Definition: climate_mode.h:33
Trigger * cool_action_trigger_
The trigger to call when the controller should switch to cooling action/mode.
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition: climate.h:204
climate::ClimateTraits traits() override
Return the traits of this controller.
void control(const climate::ClimateCall &call) override
Override control to change settings of the climate device.
const char * name
Definition: stm32flash.h:78
void add_on_state_callback(std::function< void(float)> &&callback)
Add a callback that will be called every time a filtered value arrives.
Definition: sensor.cpp:85
Trigger * swing_mode_both_trigger_
The trigger to call when the controller should switch the swing mode to "both".
std::map< std::string, ThermostatClimateTargetTempConfig > custom_preset_config_
The set of custom preset configurations this thermostat supports (eg. "My Custom Preset") ...
void set_supports_fan_mode_on(bool supports_fan_mode_on)
The fan mode is set to Both.
Definition: climate_mode.h:72
ClimatePreset
Enum for all preset modes.
Definition: climate_mode.h:80
The climate device is drying.
Definition: climate_mode.h:41
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
Definition: component.cpp:72
void set_supports_fan_mode_auto(bool supports_fan_mode_auto)
void switch_to_action_(climate::ClimateAction action, bool publish_state=true)
Switch the climate device to the given climate action.
Trigger * prev_action_trigger_
A reference to the trigger that was previously active.
Trigger * fan_mode_auto_trigger_
The trigger to call when the controller should switch the fan to "auto" mode.
float target_temperature
The target temperature of the climate device.
Definition: climate.h:183
void set_supports_fan_with_cooling(bool supports_fan_with_cooling)
Trigger * dry_action_trigger_
The trigger to call when the controller should switch to dry (dehumidification) mode.
bool supports_fan_mode_auto_
Whether the controller supports fan auto mode.
void switch_to_supplemental_action_(climate::ClimateAction action)
The climate device is in fan only mode.
Definition: climate_mode.h:43
void set_supports_fan_only(bool supports_fan_only)
const optional< ClimateMode > & get_mode() const
Definition: climate.cpp:260
The fan mode is set to Middle.
Definition: climate_mode.h:60
float prev_target_temperature_
Store previously-known temperatures.
This class contains all static data for climate devices.
bool supports_auto_
Whether the controller supports auto/cooling/drying/fanning/heating.
Trigger * fan_mode_middle_trigger_
The trigger to call when the controller should switch the fan to "middle" position.
const LogString * climate_mode_to_string(ClimateMode mode)
Convert the given ClimateMode to a human-readable string.
Definition: climate_mode.cpp:6
void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse)
void add_supported_custom_preset(const std::string &preset)
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:68
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:175
Trigger * heat_action_trigger_
The trigger to call when the controller should switch to heating action/mode.
float temperature
Definition: qmp6988.h:71
void set_supports_fan_mode_medium(bool supports_fan_mode_medium)
void set_supports_fan_mode_middle(bool supports_fan_mode_middle)
const optional< float > & get_target_temperature_low() const
Definition: climate.cpp:262
float target_temperature_high
The maximum target temperature of the climate device, for climate devices with split target temperatu...
Definition: climate.h:188
float current_temperature
The current temperature of the climate device, as reported from the integration.
Definition: climate.h:179
The fan mode is set to Diffuse.
Definition: climate_mode.h:64
void set_supports_two_points(bool supports_two_points)
bool has_value() const
Definition: optional.h:87
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
optional< climate::ClimateSwingMode > swing_mode_
void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical)
void set_supports_fan_mode_focus(bool supports_fan_mode_focus)
thermostat::OnBootRestoreFrom on_boot_restore_from_
If set to DEFAULT_PRESET then the default preset is always used.
void set_fan_mode_minimum_switching_time_in_sec(uint32_t time)
climate::ClimateAction compute_supplemental_action_()
void set_default_preset(const std::string &custom_preset)
void refresh()
Call triggers based on updated climate states (modes/actions)
void set_supports_fan_only_action_uses_fan_mode_timer(bool fan_only_action_uses_fan_mode_timer)
void switch_to_swing_mode_(climate::ClimateSwingMode swing_mode, bool publish_state=true)
Switch the climate device to the given climate swing mode.
bool hysteresis_valid()
Set point and hysteresis validation.
ClimateSwingMode
Enum for all modes a climate swing can be in.
Definition: climate_mode.h:68
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition: automation.h:95
std::string default_custom_preset_
Default custom preset to use on start up.
uint32_t timer_duration_(ThermostatClimateTimerIndex timer_index)
Trigger * preset_change_trigger_
The triggr to call when the preset mode changes.
void add_supported_preset(ClimatePreset preset)
void set_supports_heat_cool(bool supports_heat_cool)
Trigger * fan_mode_high_trigger_
The trigger to call when the controller should switch the fan to "high" speed.
float cooling_deadband_
Hysteresis values used for computing climate actions.
bool supports_fan_with_cooling_
Special flags – enables fan_only action to be called with cooling/heating actions.
void add_supported_swing_mode(ClimateSwingMode mode)
void set_supports_swing_mode_off(bool supports_swing_mode_off)
const optional< std::string > & get_custom_preset() const
Definition: climate.cpp:272
The fan mode is set to Horizontal.
Definition: climate_mode.h:76
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
float state
This member variable stores the last state that has passed through all filters.
Definition: sensor.h:135
void set_supports_fan_only_cooling(bool supports_fan_only_cooling)
const optional< ClimatePreset > & get_preset() const
Definition: climate.cpp:271
The fan mode is set to Auto.
Definition: climate_mode.h:52
void cooling_max_run_time_timer_callback_()
set_timeout() callbacks for various actions (see above)
optional< ClimatePreset > preset
The active preset of the climate device.
Definition: climate.h:210
bool supports_fan_mode_low_
Whether the controller supports various fan speeds and/or positions.
Trigger * fan_mode_low_trigger_
The trigger to call when the controller should switch the fan to "low" speed.
Trigger * fan_only_action_trigger_
The trigger to call when the controller should switch to fan-only action/mode.
void set_on_boot_restore_from(thermostat::OnBootRestoreFrom on_boot_restore_from)
bool idle_action_ready_()
Is the action ready to be called? Returns true if so.
void set_custom_preset_config(const std::string &name, const ThermostatClimateTargetTempConfig &config)
Trigger * temperature_change_trigger_
The trigger to call when the target temperature(s) change(es).
bool cooling_required_()
Check if cooling/fanning/heating actions are required; returns true if so.
bool supports_swing_mode_both_
Whether the controller supports various swing modes.
ClimateAction
Enum for the current action of the climate device. Values match those of ClimateMode.
Definition: climate_mode.h:31
ClimateTraits get_traits()
Get the traits of this climate device with all overrides applied.
Definition: climate.cpp:423
bool cancel_timer_(ThermostatClimateTimerIndex timer_index)
Trigger * fan_mode_medium_trigger_
The trigger to call when the controller should switch the fan to "medium" speed.
const LogString * climate_preset_to_string(ClimatePreset preset)
Convert the given PresetMode to a human-readable string.
The climate device is adjusting the temperatre dynamically.
Definition: climate_mode.h:27
Trigger * swing_mode_off_trigger_
The trigger to call when the controller should switch the swing mode to "off".
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:74
bool timer_active_(ThermostatClimateTimerIndex timer_index)
The climate device is actively heating.
Definition: climate_mode.h:37
The fan mode is set to Focus.
Definition: climate_mode.h:62
climate::ClimateAction supplemental_action_
Store previously-known states.
The fan mode is set to Off.
Definition: climate_mode.h:50
void add_supported_fan_mode(ClimateFanMode mode)
Trigger * idle_action_trigger_
The trigger to call when the controller should switch to idle action/off mode.
Trigger * auto_mode_trigger_
The trigger to call when the controller should switch to auto mode.
const optional< float > & get_target_temperature() const
Definition: climate.cpp:261
climate::ClimateAction delayed_climate_action()
Returns the climate action that is being delayed (check climate_action_change_delayed(), first!)
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition: climate.cpp:384
Trigger * fan_mode_off_trigger_
The trigger to call when the controller should switch off the fan.
void set_preset_config(climate::ClimatePreset preset, const ThermostatClimateTargetTempConfig &config)
The fan mode is set to High.
Definition: climate_mode.h:58
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:70
The climate device is off.
Definition: climate_mode.h:12
void set_use_startup_delay(bool use_startup_delay)
bool climate_action_change_delayed()
Returns true if a climate action/fan mode transition is being delayed.
void set_supports_fan_with_heating(bool supports_fan_with_heating)
void set_supports_action(bool supports_action)
void change_custom_preset_(const std::string &custom_preset)
Change to a provided custom preset setting; will reset temperature, mode, fan, and swing modes accord...
optional< std::string > custom_preset
The active custom preset mode of the climate device.
Definition: climate.h:213
const LogString * climate_fan_mode_to_string(ClimateFanMode fan_mode)
Convert the given ClimateFanMode to a human-readable string.
bool cooling_max_runtime_exceeded_
Flags indicating if maximum allowable run time was exceeded.
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition: climate.h:198
void switch_to_fan_mode_(climate::ClimateFanMode fan_mode, bool publish_state=true)
Switch the climate device to the given climate fan mode.
const optional< ClimateFanMode > & get_fan_mode() const
Definition: climate.cpp:269
void set_supports_fan_mode_low(bool supports_fan_mode_low)
Trigger * fan_mode_focus_trigger_
The trigger to call when the controller should switch the fan to "focus" position.
The fan mode is set to On.
Definition: climate_mode.h:48
climate::ClimateAction compute_action_(bool ignore_timers=false)
Re-compute the required action of this climate controller.
float cool_deadband()
Get current hysteresis values.
Trigger * swing_mode_horizontal_trigger_
The trigger to call when the controller should switch the swing mode to "horizontal".
std::function< void()> timer_cbf_(ThermostatClimateTimerIndex timer_index)
void set_supports_fan_mode_off(bool supports_fan_mode_off)
sensor::Sensor * sensor_
The sensor used for getting the current temperature.
std::vector< ThermostatClimateTimer > timer_
Climate action timers.
void start_timer_(ThermostatClimateTimerIndex timer_index)
Start/cancel/get status of climate action timer.
float supplemental_cool_delta_
Maximum allowable temperature deltas before engauging supplemental cooling/heating actions...
const optional< ClimateSwingMode > & get_swing_mode() const
Definition: climate.cpp:273
std::map< climate::ClimatePreset, ThermostatClimateTargetTempConfig > preset_config_
The set of standard preset configurations this thermostat supports (Eg. AWAY, ECO, etc)
climate::ClimateSwingMode prev_swing_mode_
bool change_preset_internal_(const ThermostatClimateTargetTempConfig &config)
Applies the temperature, mode, fan, and swing modes of the provided config.
bool supports_two_points_
Whether the controller supports two set points.
climate::ClimateFanMode locked_fan_mode()
Returns the fan mode that is locked in (check fan_mode_change_delayed(), first!)
void set_set_point_minimum_differential(float differential)
Definition: a4988.cpp:4
void check_temperature_change_trigger_()
Check if the temperature change trigger should be called.
void switch_to_mode_(climate::ClimateMode mode, bool publish_state=true)
Switch the climate device to the given climate mode.
The climate device is idle (monitoring climate but no action needed)
Definition: climate_mode.h:39
void set_supports_two_point_target_temperature(bool supports_two_point_target_temperature)
optional< ClimateDeviceRestoreState > restore_state_()
Restore the state of the climate device, call this from your setup() method.
Definition: climate.cpp:321
Trigger * fan_mode_on_trigger_
The trigger to call when the controller should switch on the fan.
bool supports_fan_mode_on_
Whether the controller supports turning on or off just the fan.
Trigger * fan_mode_diffuse_trigger_
The trigger to call when the controller should switch the fan to "diffuse" position.
void set_supports_current_temperature(bool supports_current_temperature)
The fan mode is set to Medium.
Definition: climate_mode.h:56
const optional< float > & get_target_temperature_high() const
Definition: climate.cpp:263
bool supports_fan_only_action_uses_fan_mode_timer_
Special flag – enables fan_modes to share timer with fan_only climate action.
Base-class for all sensors.
Definition: sensor.h:50
void set_supports_fan_mode_high(bool supports_fan_mode_high)
void dump_preset_config_(const char *preset_name, const ThermostatClimateTargetTempConfig &config, bool is_default_preset)
void set_supports_swing_mode_both(bool supports_swing_mode_both)
The climate device only has the fan enabled, no heating or cooling is taking place.
Definition: climate_mode.h:20
const uint8_t min_timer_duration_
Minimum allowable duration in seconds for action timers.
void change_preset_(climate::ClimatePreset preset)
Change to a provided preset setting; will reset temperature, mode, fan, and swing modes accordingly...
The climate device is actively cooling.
Definition: climate_mode.h:35
value_type value_or(U const &v) const
Definition: optional.h:93
void add_supported_mode(ClimateMode mode)
float target_temperature_low
The minimum target temperature of the climate device, for climate devices with split target temperatu...
Definition: climate.h:186
void stop_action()
Stop any action connected to this trigger.
Definition: automation.h:103
bool use_startup_delay_
Used to start "off" delay timers at boot.
ClimateAction action
The active state of the climate device.
Definition: climate.h:177
bool setup_complete_
setup_complete_ blocks modifying/resetting the temps immediately after boot
climate::ClimatePreset default_preset_
Default standard preset to use on start up.
bool state
Definition: fan.h:34
const LogString * climate_swing_mode_to_string(ClimateSwingMode swing_mode)
Convert the given ClimateSwingMode to a human-readable string.
bool supports_fan_only_cooling_
Special flag – enables fan to be switched based on target_temperature_high.