ESPHome  2022.6.3
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  // restore all climate data, if possible
29  auto restore = this->restore_state_();
30  if (restore.has_value()) {
31  restore->to_call(this).perform();
32  } else {
33  // restore from defaults, change_away handles temps for us
34  this->mode = this->default_mode_;
36  }
37  // refresh the climate action based on the restored settings, we'll publish_state() later
38  this->switch_to_action_(this->compute_action_(), false);
40  this->setup_complete_ = true;
41  this->publish_state();
42 }
43 
48 
50  this->switch_to_mode_(this->mode, false);
51  this->switch_to_action_(this->compute_action_(), false);
53  this->switch_to_fan_mode_(this->fan_mode.value(), false);
54  this->switch_to_swing_mode_(this->swing_mode, false);
56  this->publish_state();
57 }
58 
60  bool state_mismatch = this->action != this->compute_action_(true);
61 
62  switch (this->compute_action_(true)) {
65  return state_mismatch && (!this->idle_action_ready_());
67  return state_mismatch && (!this->cooling_action_ready_());
69  return state_mismatch && (!this->heating_action_ready_());
71  return state_mismatch && (!this->fanning_action_ready_());
73  return state_mismatch && (!this->drying_action_ready_());
74  default:
75  break;
76  }
77  return false;
78 }
79 
81  bool state_mismatch = this->fan_mode.value_or(climate::CLIMATE_FAN_ON) != this->prev_fan_mode_;
82  return state_mismatch && (!this->fan_mode_ready_());
83 }
84 
86 
88 
90  if ((this->supports_cool_ || (this->supports_fan_only_ && this->supports_fan_only_cooling_)) &&
91  (std::isnan(this->cooling_deadband_) || std::isnan(this->cooling_overrun_)))
92  return false;
93 
94  if (this->supports_heat_ && (std::isnan(this->heating_deadband_) || std::isnan(this->heating_overrun_)))
95  return false;
96 
97  return true;
98 }
99 
101  if (std::isnan(this->target_temperature)) {
102  this->target_temperature =
105  } else {
106  // target_temperature must be between the visual minimum and the visual maximum
107  if (this->target_temperature < this->get_traits().get_visual_min_temperature())
109  if (this->target_temperature > this->get_traits().get_visual_max_temperature())
111  }
112 }
113 
115  if (this->supports_two_points_) {
118  } else {
120  }
121 }
122 
124  if (std::isnan(this->target_temperature_low)) {
126  } else {
127  // target_temperature_low must not be lower than the visual minimum
128  if (this->target_temperature_low < this->get_traits().get_visual_min_temperature())
130  // target_temperature_low must not be greater than the visual maximum minus set_point_minimum_differential_
131  if (this->target_temperature_low >
132  this->get_traits().get_visual_max_temperature() - this->set_point_minimum_differential_) {
133  this->target_temperature_low =
135  }
136  // if target_temperature_low is set greater than target_temperature_high, move up target_temperature_high
139  }
140 }
141 
143  if (std::isnan(this->target_temperature_high)) {
145  } else {
146  // target_temperature_high must not be lower than the visual maximum
147  if (this->target_temperature_high > this->get_traits().get_visual_max_temperature())
149  // target_temperature_high must not be lower than the visual minimum plus set_point_minimum_differential_
150  if (this->target_temperature_high <
151  this->get_traits().get_visual_min_temperature() + this->set_point_minimum_differential_) {
154  }
155  // if target_temperature_high is set less than target_temperature_low, move down target_temperature_low
156  if (this->target_temperature_high < this->target_temperature_low + this->set_point_minimum_differential_)
158  }
159 }
160 
162  if (call.get_preset().has_value()) {
163  // setup_complete_ blocks modifying/resetting the temps immediately after boot
164  if (this->setup_complete_) {
165  this->change_preset_(*call.get_preset());
166  } else {
167  this->preset = *call.get_preset();
168  }
169  }
170  if (call.get_custom_preset().has_value()) {
171  // setup_complete_ blocks modifying/resetting the temps immediately after boot
172  if (this->setup_complete_) {
174  } else {
175  this->custom_preset = *call.get_custom_preset();
176  }
177  }
178 
179  if (call.get_mode().has_value())
180  this->mode = *call.get_mode();
181  if (call.get_fan_mode().has_value())
182  this->fan_mode = *call.get_fan_mode();
183  if (call.get_swing_mode().has_value())
184  this->swing_mode = *call.get_swing_mode();
185  if (this->supports_two_points_) {
186  if (call.get_target_temperature_low().has_value()) {
189  }
190  if (call.get_target_temperature_high().has_value()) {
193  }
194  } else {
195  if (call.get_target_temperature().has_value()) {
198  }
199  }
200  // make any changes happen
201  refresh();
202 }
203 
207  if (supports_auto_)
211  if (supports_cool_)
213  if (supports_dry_)
215  if (supports_fan_only_)
217  if (supports_heat_)
219 
238 
247 
248  for (auto &it : this->preset_config_) {
249  traits.add_supported_preset(it.first);
250  }
251  for (auto &it : this->custom_preset_config_) {
253  }
254 
257  return traits;
258 }
259 
261  auto target_action = climate::CLIMATE_ACTION_IDLE;
262  // if any hysteresis values or current_temperature is not valid, we go to OFF;
263  if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
265  }
266  // do not change the action if an "ON" timer is running
267  if ((!ignore_timers) &&
270  return this->action;
271  }
272 
273  // ensure set point(s) is/are valid before computing the action
275  // everything has been validated so we can now safely compute the action
276  switch (this->mode) {
277  // if the climate mode is OFF then the climate action must be OFF
279  target_action = climate::CLIMATE_ACTION_OFF;
280  break;
282  if (this->fanning_required_())
283  target_action = climate::CLIMATE_ACTION_FAN;
284  break;
286  target_action = climate::CLIMATE_ACTION_DRYING;
287  break;
289  if (this->cooling_required_() && this->heating_required_()) {
290  // this is bad and should never happen, so just stop.
291  // target_action = climate::CLIMATE_ACTION_IDLE;
292  } else if (this->cooling_required_()) {
293  target_action = climate::CLIMATE_ACTION_COOLING;
294  } else if (this->heating_required_()) {
295  target_action = climate::CLIMATE_ACTION_HEATING;
296  }
297  break;
299  if (this->cooling_required_()) {
300  target_action = climate::CLIMATE_ACTION_COOLING;
301  }
302  break;
304  if (this->heating_required_()) {
305  target_action = climate::CLIMATE_ACTION_HEATING;
306  }
307  break;
308  default:
309  break;
310  }
311  // do not abruptly switch actions. cycle through IDLE, first. we'll catch this at the next update.
313  (target_action == climate::CLIMATE_ACTION_HEATING)) ||
315  ((target_action == climate::CLIMATE_ACTION_COOLING) || (target_action == climate::CLIMATE_ACTION_DRYING)))) {
317  }
318 
319  return target_action;
320 }
321 
323  auto target_action = climate::CLIMATE_ACTION_IDLE;
324  // if any hysteresis values or current_temperature is not valid, we go to OFF;
325  if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
327  }
328 
329  // ensure set point(s) is/are valid before computing the action
331  // everything has been validated so we can now safely compute the action
332  switch (this->mode) {
333  // if the climate mode is OFF then the climate action must be OFF
335  target_action = climate::CLIMATE_ACTION_OFF;
336  break;
339  // this is bad and should never happen, so just stop.
340  // target_action = climate::CLIMATE_ACTION_IDLE;
341  } else if (this->supplemental_cooling_required_()) {
342  target_action = climate::CLIMATE_ACTION_COOLING;
343  } else if (this->supplemental_heating_required_()) {
344  target_action = climate::CLIMATE_ACTION_HEATING;
345  }
346  break;
348  if (this->supplemental_cooling_required_()) {
349  target_action = climate::CLIMATE_ACTION_COOLING;
350  }
351  break;
353  if (this->supplemental_heating_required_()) {
354  target_action = climate::CLIMATE_ACTION_HEATING;
355  }
356  break;
357  default:
358  break;
359  }
360 
361  return target_action;
362 }
363 
365  // setup_complete_ helps us ensure an action is called immediately after boot
366  if ((action == this->action) && this->setup_complete_) {
367  // already in target mode
368  return;
369  }
370 
371  if (((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) ||
372  (action == climate::CLIMATE_ACTION_IDLE && this->action == climate::CLIMATE_ACTION_OFF)) &&
373  this->setup_complete_) {
374  // switching from OFF to IDLE or vice-versa -- this is only a visual difference.
375  // OFF means user manually disabled, IDLE means the temperature is in target range.
376  this->action = action;
377  if (publish_state)
378  this->publish_state();
379  return;
380  }
381 
382  bool action_ready = false;
383  Trigger<> *trig = this->idle_action_trigger_, *trig_fan = nullptr;
384  switch (action) {
387  if (this->idle_action_ready_()) {
389  if (this->action == climate::CLIMATE_ACTION_COOLING)
391  if (this->action == climate::CLIMATE_ACTION_FAN) {
394  } else {
396  }
397  }
398  if (this->action == climate::CLIMATE_ACTION_HEATING)
400  // trig = this->idle_action_trigger_;
401  ESP_LOGVV(TAG, "Switching to IDLE/OFF action");
402  this->cooling_max_runtime_exceeded_ = false;
403  this->heating_max_runtime_exceeded_ = false;
404  action_ready = true;
405  }
406  break;
408  if (this->cooling_action_ready_()) {
411  if (this->supports_fan_with_cooling_) {
413  trig_fan = this->fan_only_action_trigger_;
414  }
415  trig = this->cool_action_trigger_;
416  ESP_LOGVV(TAG, "Switching to COOLING action");
417  action_ready = true;
418  }
419  break;
421  if (this->heating_action_ready_()) {
424  if (this->supports_fan_with_heating_) {
426  trig_fan = this->fan_only_action_trigger_;
427  }
428  trig = this->heat_action_trigger_;
429  ESP_LOGVV(TAG, "Switching to HEATING action");
430  action_ready = true;
431  }
432  break;
434  if (this->fanning_action_ready_()) {
437  } else {
439  }
440  trig = this->fan_only_action_trigger_;
441  ESP_LOGVV(TAG, "Switching to FAN_ONLY action");
442  action_ready = true;
443  }
444  break;
446  if (this->drying_action_ready_()) {
449  trig = this->dry_action_trigger_;
450  ESP_LOGVV(TAG, "Switching to DRYING action");
451  action_ready = true;
452  }
453  break;
454  default:
455  // we cannot report an invalid mode back to HA (even if it asked for one)
456  // and must assume some valid value
458  // trig = this->idle_action_trigger_;
459  }
460 
461  if (action_ready) {
462  if (this->prev_action_trigger_ != nullptr) {
464  this->prev_action_trigger_ = nullptr;
465  }
466  this->action = action;
467  this->prev_action_trigger_ = trig;
468  assert(trig != nullptr);
469  trig->trigger();
470  // if enabled, call the fan_only action with cooling/heating actions
471  if (trig_fan != nullptr) {
472  ESP_LOGVV(TAG, "Calling FAN_ONLY action with HEATING/COOLING action");
473  trig_fan->trigger();
474  }
475  if (publish_state)
476  this->publish_state();
477  }
478 }
479 
481  // setup_complete_ helps us ensure an action is called immediately after boot
482  if ((action == this->supplemental_action_) && this->setup_complete_) {
483  // already in target mode
484  return;
485  }
486 
487  switch (action) {
492  break;
495  break;
498  break;
499  default:
500  return;
501  }
502  ESP_LOGVV(TAG, "Updating supplemental action...");
505 }
506 
508  Trigger<> *trig = nullptr;
509 
510  switch (this->supplemental_action_) {
514  }
516  ESP_LOGVV(TAG, "Calling supplemental COOLING action");
517  break;
521  }
523  ESP_LOGVV(TAG, "Calling supplemental HEATING action");
524  break;
525  default:
526  break;
527  }
528 
529  if (trig != nullptr) {
530  assert(trig != nullptr);
531  trig->trigger();
532  }
533 }
534 
536  // setup_complete_ helps us ensure an action is called immediately after boot
537  if ((fan_mode == this->prev_fan_mode_) && this->setup_complete_) {
538  // already in target mode
539  return;
540  }
541 
542  this->fan_mode = fan_mode;
543  if (publish_state)
544  this->publish_state();
545 
546  if (this->fan_mode_ready_()) {
547  Trigger<> *trig = this->fan_mode_auto_trigger_;
548  switch (fan_mode) {
550  trig = this->fan_mode_on_trigger_;
551  ESP_LOGVV(TAG, "Switching to FAN_ON mode");
552  break;
554  trig = this->fan_mode_off_trigger_;
555  ESP_LOGVV(TAG, "Switching to FAN_OFF mode");
556  break;
558  // trig = this->fan_mode_auto_trigger_;
559  ESP_LOGVV(TAG, "Switching to FAN_AUTO mode");
560  break;
562  trig = this->fan_mode_low_trigger_;
563  ESP_LOGVV(TAG, "Switching to FAN_LOW mode");
564  break;
566  trig = this->fan_mode_medium_trigger_;
567  ESP_LOGVV(TAG, "Switching to FAN_MEDIUM mode");
568  break;
570  trig = this->fan_mode_high_trigger_;
571  ESP_LOGVV(TAG, "Switching to FAN_HIGH mode");
572  break;
574  trig = this->fan_mode_middle_trigger_;
575  ESP_LOGVV(TAG, "Switching to FAN_MIDDLE mode");
576  break;
578  trig = this->fan_mode_focus_trigger_;
579  ESP_LOGVV(TAG, "Switching to FAN_FOCUS mode");
580  break;
582  trig = this->fan_mode_diffuse_trigger_;
583  ESP_LOGVV(TAG, "Switching to FAN_DIFFUSE mode");
584  break;
585  default:
586  // we cannot report an invalid mode back to HA (even if it asked for one)
587  // and must assume some valid value
588  fan_mode = climate::CLIMATE_FAN_AUTO;
589  // trig = this->fan_mode_auto_trigger_;
590  }
591  if (this->prev_fan_mode_trigger_ != nullptr) {
593  this->prev_fan_mode_trigger_ = nullptr;
594  }
596  assert(trig != nullptr);
597  trig->trigger();
598  this->prev_fan_mode_ = fan_mode;
599  this->prev_fan_mode_trigger_ = trig;
600  }
601 }
602 
604  // setup_complete_ helps us ensure an action is called immediately after boot
605  if ((mode == this->prev_mode_) && this->setup_complete_) {
606  // already in target mode
607  return;
608  }
609 
610  if (this->prev_mode_trigger_ != nullptr) {
612  this->prev_mode_trigger_ = nullptr;
613  }
614  Trigger<> *trig = this->auto_mode_trigger_;
615  switch (mode) {
617  trig = this->off_mode_trigger_;
618  break;
620  // trig = this->auto_mode_trigger_;
621  break;
623  trig = this->cool_mode_trigger_;
624  break;
626  trig = this->heat_mode_trigger_;
627  break;
629  trig = this->fan_only_mode_trigger_;
630  break;
632  trig = this->dry_mode_trigger_;
633  break;
634  default:
635  // we cannot report an invalid mode back to HA (even if it asked for one)
636  // and must assume some valid value
638  // trig = this->auto_mode_trigger_;
639  }
640  assert(trig != nullptr);
641  trig->trigger();
642  this->mode = mode;
643  this->prev_mode_ = mode;
644  this->prev_mode_trigger_ = trig;
645  if (publish_state)
646  this->publish_state();
647 }
648 
650  // setup_complete_ helps us ensure an action is called immediately after boot
651  if ((swing_mode == this->prev_swing_mode_) && this->setup_complete_) {
652  // already in target mode
653  return;
654  }
655 
656  if (this->prev_swing_mode_trigger_ != nullptr) {
658  this->prev_swing_mode_trigger_ = nullptr;
659  }
660  Trigger<> *trig = this->swing_mode_off_trigger_;
661  switch (swing_mode) {
663  trig = this->swing_mode_both_trigger_;
664  break;
666  trig = this->swing_mode_horizontal_trigger_;
667  break;
669  // trig = this->swing_mode_off_trigger_;
670  break;
672  trig = this->swing_mode_vertical_trigger_;
673  break;
674  default:
675  // we cannot report an invalid mode back to HA (even if it asked for one)
676  // and must assume some valid value
677  swing_mode = climate::CLIMATE_SWING_OFF;
678  // trig = this->swing_mode_off_trigger_;
679  }
680  assert(trig != nullptr);
681  trig->trigger();
682  this->swing_mode = swing_mode;
684  this->prev_swing_mode_trigger_ = trig;
685  if (publish_state)
686  this->publish_state();
687 }
688 
693  }
696 }
697 
701 }
702 
706 }
707 
709 
712  return !(this->timer_active_(thermostat::TIMER_FAN_MODE));
713  }
715 }
716 
720 }
721 
723  if (this->timer_duration_(timer_index) > 0) {
724  this->set_timeout(this->timer_[timer_index].name, this->timer_duration_(timer_index),
725  this->timer_cbf_(timer_index));
726  this->timer_[timer_index].active = true;
727  }
728 }
729 
731  this->timer_[timer_index].active = false;
732  return this->cancel_timeout(this->timer_[timer_index].name);
733 }
734 
736  return this->timer_[timer_index].active;
737 }
738 
740  return this->timer_[timer_index].time;
741 }
742 
743 std::function<void()> ThermostatClimate::timer_cbf_(ThermostatClimateTimerIndex timer_index) {
744  return this->timer_[timer_index].func;
745 }
746 
748  ESP_LOGVV(TAG, "cooling_max_run_time timer expired");
749  this->timer_[thermostat::TIMER_COOLING_MAX_RUN_TIME].active = false;
750  this->cooling_max_runtime_exceeded_ = true;
753 }
754 
756  ESP_LOGVV(TAG, "cooling_off timer expired");
757  this->timer_[thermostat::TIMER_COOLING_OFF].active = false;
758  this->switch_to_action_(this->compute_action_());
760 }
761 
763  ESP_LOGVV(TAG, "cooling_on timer expired");
764  this->timer_[thermostat::TIMER_COOLING_ON].active = false;
765  this->switch_to_action_(this->compute_action_());
767 }
768 
770  ESP_LOGVV(TAG, "fan_mode timer expired");
771  this->timer_[thermostat::TIMER_FAN_MODE].active = false;
774  this->switch_to_action_(this->compute_action_());
775 }
776 
778  ESP_LOGVV(TAG, "fanning_off timer expired");
779  this->timer_[thermostat::TIMER_FANNING_OFF].active = false;
780  this->switch_to_action_(this->compute_action_());
781 }
782 
784  ESP_LOGVV(TAG, "fanning_on timer expired");
785  this->timer_[thermostat::TIMER_FANNING_ON].active = false;
786  this->switch_to_action_(this->compute_action_());
787 }
788 
790  ESP_LOGVV(TAG, "heating_max_run_time timer expired");
791  this->timer_[thermostat::TIMER_HEATING_MAX_RUN_TIME].active = false;
792  this->heating_max_runtime_exceeded_ = true;
795 }
796 
798  ESP_LOGVV(TAG, "heating_off timer expired");
799  this->timer_[thermostat::TIMER_HEATING_OFF].active = false;
800  this->switch_to_action_(this->compute_action_());
802 }
803 
805  ESP_LOGVV(TAG, "heating_on timer expired");
806  this->timer_[thermostat::TIMER_HEATING_ON].active = false;
807  this->switch_to_action_(this->compute_action_());
809 }
810 
812  ESP_LOGVV(TAG, "idle_on timer expired");
813  this->timer_[thermostat::TIMER_IDLE_ON].active = false;
814  this->switch_to_action_(this->compute_action_());
816 }
817 
819  if (this->supports_two_points_) {
820  // setup_complete_ helps us ensure an action is called immediately after boot
823  return; // nothing changed, no reason to trigger
824  } else {
825  // save the new temperatures so we can check them again later; the trigger will fire below
828  }
829  } else {
830  if ((this->prev_target_temperature_ == this->target_temperature) && this->setup_complete_) {
831  return; // nothing changed, no reason to trigger
832  } else {
833  // save the new temperature so we can check it again later; the trigger will fire below
835  }
836  }
837  // trigger the action
839  assert(trig != nullptr);
840  trig->trigger();
841 }
842 
845 
846  if (this->supports_cool_) {
847  if (this->current_temperature > temperature + this->cooling_deadband_) {
848  // if the current temperature exceeds the target + deadband, cooling is required
849  return true;
850  } else if (this->current_temperature < temperature - this->cooling_overrun_) {
851  // if the current temperature is less than the target - overrun, cooling should stop
852  return false;
853  } else {
854  // if we get here, the current temperature is between target + deadband and target - overrun,
855  // so the action should not change unless it conflicts with the current mode
856  return (this->action == climate::CLIMATE_ACTION_COOLING) &&
858  }
859  }
860  return false;
861 }
862 
865 
866  if (this->supports_fan_only_) {
867  if (this->supports_fan_only_cooling_) {
868  if (this->current_temperature > temperature + this->cooling_deadband_) {
869  // if the current temperature exceeds the target + deadband, fanning is required
870  return true;
871  } else if (this->current_temperature < temperature - this->cooling_overrun_) {
872  // if the current temperature is less than the target - overrun, fanning should stop
873  return false;
874  } else {
875  // if we get here, the current temperature is between target + deadband and target - overrun,
876  // so the action should not change unless it conflicts with the current mode
878  }
879  } else {
880  return true;
881  }
882  }
883  return false;
884 }
885 
888 
889  if (this->supports_heat_) {
890  if (this->current_temperature < temperature - this->heating_deadband_) {
891  // if the current temperature is below the target - deadband, heating is required
892  return true;
893  } else if (this->current_temperature > temperature + this->heating_overrun_) {
894  // if the current temperature is above the target + overrun, heating should stop
895  return false;
896  } else {
897  // if we get here, the current temperature is between target - deadband and target + overrun,
898  // so the action should not change unless it conflicts with the current mode
899  return (this->action == climate::CLIMATE_ACTION_HEATING) &&
901  }
902  }
903  return false;
904 }
905 
908  // the component must supports_cool_ and the climate action must be climate::CLIMATE_ACTION_COOLING. then...
909  // supplemental cooling is required if the max delta or max runtime was exceeded or the action is already engaged
910  return this->supports_cool_ && (this->action == climate::CLIMATE_ACTION_COOLING) &&
914 }
915 
918  // the component must supports_heat_ and the climate action must be climate::CLIMATE_ACTION_HEATING. then...
919  // supplemental heating is required if the max delta or max runtime was exceeded or the action is already engaged
920  return this->supports_heat_ && (this->action == climate::CLIMATE_ACTION_HEATING) &&
922  (this->current_temperature < temperature - this->supplemental_heat_delta_) ||
924 }
925 
927  const ThermostatClimateTargetTempConfig &config) {
928  const auto *preset_name = preset.c_str();
929 
930  if (this->supports_heat_) {
931  if (this->supports_two_points_) {
932  ESP_LOGCONFIG(TAG, " %s Default Target Temperature Low: %.1f°C", preset_name,
933  config.default_temperature_low);
934  } else {
935  ESP_LOGCONFIG(TAG, " %s Default Target Temperature Low: %.1f°C", preset_name, config.default_temperature);
936  }
937  }
938  if ((this->supports_cool_) || (this->supports_fan_only_)) {
939  if (this->supports_two_points_) {
940  ESP_LOGCONFIG(TAG, " %s Default Target Temperature High: %.1f°C", preset_name,
941  config.default_temperature_high);
942  } else {
943  ESP_LOGCONFIG(TAG, " %s Default Target Temperature High: %.1f°C", preset_name, config.default_temperature);
944  }
945  }
946 
947  if (config.mode_.has_value()) {
948  ESP_LOGCONFIG(TAG, " %s Default Mode: %s", preset_name,
949  LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
950  }
951  if (config.fan_mode_.has_value()) {
952  ESP_LOGCONFIG(TAG, " %s Default Fan Mode: %s", preset_name,
953  LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
954  }
955  if (config.swing_mode_.has_value()) {
956  ESP_LOGCONFIG(TAG, " %s Default Swing Mode: %s", preset_name,
957  LOG_STR_ARG(climate::climate_swing_mode_to_string(*config.swing_mode_)));
958  }
959 }
960 
962  auto config = this->preset_config_.find(preset);
963 
964  if (config != this->preset_config_.end()) {
965  ESP_LOGI(TAG, "Switching to preset %s", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
966  this->change_preset_internal_(config->second);
967 
968  this->custom_preset.reset();
969  this->preset = preset;
970  } else {
971  ESP_LOGE(TAG, "Preset %s is not configured, ignoring.", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
972  }
973 }
974 
976  auto config = this->custom_preset_config_.find(custom_preset);
977 
978  if (config != this->custom_preset_config_.end()) {
979  ESP_LOGI(TAG, "Switching to custom preset %s", custom_preset.c_str());
980  this->change_preset_internal_(config->second);
981 
982  this->preset.reset();
983  this->custom_preset = custom_preset;
984  } else {
985  ESP_LOGE(TAG, "Custom Preset %s is not configured, ignoring.", custom_preset.c_str());
986  }
987 }
988 
990  if (this->supports_two_points_) {
993  } else {
995  }
996 
997  // Note: The mode, fan_mode, and swing_mode can all be defined on the preset but if the climate.control call
998  // also specifies them then the control's version will override these for that call
999  if (config.mode_.has_value()) {
1000  this->mode = *config.mode_;
1001  ESP_LOGV(TAG, "Setting mode to %s", LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
1002  }
1003 
1004  if (config.fan_mode_.has_value()) {
1005  this->fan_mode = *config.fan_mode_;
1006  ESP_LOGV(TAG, "Setting fan mode to %s", LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
1007  }
1008 
1009  if (config.swing_mode_.has_value()) {
1010  ESP_LOGV(TAG, "Setting swing mode to %s", LOG_STR_ARG(climate::climate_swing_mode_to_string(*config.swing_mode_)));
1011  this->swing_mode = *config.swing_mode_;
1012  }
1013 
1014  // Fire any preset changed trigger if defined
1015  if (this->preset != preset) {
1016  Trigger<> *trig = this->preset_change_trigger_;
1017  assert(trig != nullptr);
1018  trig->trigger();
1019  }
1020 
1021  this->refresh();
1022 }
1023 
1025  const ThermostatClimateTargetTempConfig &config) {
1026  this->preset_config_[preset] = config;
1027 }
1028 
1030  const ThermostatClimateTargetTempConfig &config) {
1031  this->custom_preset_config_[name] = config;
1032 }
1033 
1035  : cool_action_trigger_(new Trigger<>()),
1037  cool_mode_trigger_(new Trigger<>()),
1038  dry_action_trigger_(new Trigger<>()),
1039  dry_mode_trigger_(new Trigger<>()),
1040  heat_action_trigger_(new Trigger<>()),
1042  heat_mode_trigger_(new Trigger<>()),
1043  auto_mode_trigger_(new Trigger<>()),
1044  idle_action_trigger_(new Trigger<>()),
1045  off_mode_trigger_(new Trigger<>()),
1048  fan_mode_on_trigger_(new Trigger<>()),
1049  fan_mode_off_trigger_(new Trigger<>()),
1051  fan_mode_low_trigger_(new Trigger<>()),
1062  preset_change_trigger_(new Trigger<>()) {}
1063 
1064 void ThermostatClimate::set_default_mode(climate::ClimateMode default_mode) { this->default_mode_ = default_mode; }
1066  this->set_point_minimum_differential_ = differential;
1067 }
1068 void ThermostatClimate::set_cool_deadband(float deadband) { this->cooling_deadband_ = deadband; }
1069 void ThermostatClimate::set_cool_overrun(float overrun) { this->cooling_overrun_ = overrun; }
1070 void ThermostatClimate::set_heat_deadband(float deadband) { this->heating_deadband_ = deadband; }
1071 void ThermostatClimate::set_heat_overrun(float overrun) { this->heating_overrun_ = overrun; }
1076  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1077 }
1080  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1081 }
1083  this->timer_[thermostat::TIMER_COOLING_ON].time =
1084  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1085 }
1087  this->timer_[thermostat::TIMER_FAN_MODE].time =
1088  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1089 }
1092  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1093 }
1095  this->timer_[thermostat::TIMER_FANNING_ON].time =
1096  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1097 }
1100  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1101 }
1104  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1105 }
1107  this->timer_[thermostat::TIMER_HEATING_ON].time =
1108  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1109 }
1111  this->timer_[thermostat::TIMER_IDLE_ON].time =
1112  1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1113 }
1114 void ThermostatClimate::set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
1115 void ThermostatClimate::set_use_startup_delay(bool use_startup_delay) { this->use_startup_delay_ = use_startup_delay; }
1116 void ThermostatClimate::set_supports_heat_cool(bool supports_heat_cool) {
1117  this->supports_heat_cool_ = supports_heat_cool;
1118 }
1119 void ThermostatClimate::set_supports_auto(bool supports_auto) { this->supports_auto_ = supports_auto; }
1120 void ThermostatClimate::set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
1121 void ThermostatClimate::set_supports_dry(bool supports_dry) { this->supports_dry_ = supports_dry; }
1122 void ThermostatClimate::set_supports_fan_only(bool supports_fan_only) { this->supports_fan_only_ = supports_fan_only; }
1124  bool supports_fan_only_action_uses_fan_mode_timer) {
1125  this->supports_fan_only_action_uses_fan_mode_timer_ = supports_fan_only_action_uses_fan_mode_timer;
1126 }
1127 void ThermostatClimate::set_supports_fan_only_cooling(bool supports_fan_only_cooling) {
1128  this->supports_fan_only_cooling_ = supports_fan_only_cooling;
1129 }
1130 void ThermostatClimate::set_supports_fan_with_cooling(bool supports_fan_with_cooling) {
1131  this->supports_fan_with_cooling_ = supports_fan_with_cooling;
1132 }
1133 void ThermostatClimate::set_supports_fan_with_heating(bool supports_fan_with_heating) {
1134  this->supports_fan_with_heating_ = supports_fan_with_heating;
1135 }
1136 void ThermostatClimate::set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
1137 void ThermostatClimate::set_supports_fan_mode_on(bool supports_fan_mode_on) {
1138  this->supports_fan_mode_on_ = supports_fan_mode_on;
1139 }
1140 void ThermostatClimate::set_supports_fan_mode_off(bool supports_fan_mode_off) {
1141  this->supports_fan_mode_off_ = supports_fan_mode_off;
1142 }
1143 void ThermostatClimate::set_supports_fan_mode_auto(bool supports_fan_mode_auto) {
1144  this->supports_fan_mode_auto_ = supports_fan_mode_auto;
1145 }
1146 void ThermostatClimate::set_supports_fan_mode_low(bool supports_fan_mode_low) {
1147  this->supports_fan_mode_low_ = supports_fan_mode_low;
1148 }
1149 void ThermostatClimate::set_supports_fan_mode_medium(bool supports_fan_mode_medium) {
1150  this->supports_fan_mode_medium_ = supports_fan_mode_medium;
1151 }
1152 void ThermostatClimate::set_supports_fan_mode_high(bool supports_fan_mode_high) {
1153  this->supports_fan_mode_high_ = supports_fan_mode_high;
1154 }
1155 void ThermostatClimate::set_supports_fan_mode_middle(bool supports_fan_mode_middle) {
1156  this->supports_fan_mode_middle_ = supports_fan_mode_middle;
1157 }
1158 void ThermostatClimate::set_supports_fan_mode_focus(bool supports_fan_mode_focus) {
1159  this->supports_fan_mode_focus_ = supports_fan_mode_focus;
1160 }
1161 void ThermostatClimate::set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse) {
1162  this->supports_fan_mode_diffuse_ = supports_fan_mode_diffuse;
1163 }
1164 void ThermostatClimate::set_supports_swing_mode_both(bool supports_swing_mode_both) {
1165  this->supports_swing_mode_both_ = supports_swing_mode_both;
1166 }
1167 void ThermostatClimate::set_supports_swing_mode_off(bool supports_swing_mode_off) {
1168  this->supports_swing_mode_off_ = supports_swing_mode_off;
1169 }
1170 void ThermostatClimate::set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal) {
1171  this->supports_swing_mode_horizontal_ = supports_swing_mode_horizontal;
1172 }
1173 void ThermostatClimate::set_supports_swing_mode_vertical(bool supports_swing_mode_vertical) {
1174  this->supports_swing_mode_vertical_ = supports_swing_mode_vertical;
1175 }
1176 void ThermostatClimate::set_supports_two_points(bool supports_two_points) {
1177  this->supports_two_points_ = supports_two_points;
1178 }
1179 
1182  return this->supplemental_cool_action_trigger_;
1183 }
1188  return this->supplemental_heat_action_trigger_;
1189 }
1212 
1214  LOG_CLIMATE("", "Thermostat", this);
1215 
1216  if (this->supports_two_points_)
1217  ESP_LOGCONFIG(TAG, " Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_);
1218  ESP_LOGCONFIG(TAG, " Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_));
1219  if (this->supports_cool_) {
1220  ESP_LOGCONFIG(TAG, " Cooling Parameters:");
1221  ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->cooling_deadband_);
1222  ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->cooling_overrun_);
1224  ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_cool_delta_);
1225  ESP_LOGCONFIG(TAG, " Maximum Run Time: %us",
1227  }
1228  ESP_LOGCONFIG(TAG, " Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_COOLING_OFF) / 1000);
1229  ESP_LOGCONFIG(TAG, " Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_COOLING_ON) / 1000);
1230  }
1231  if (this->supports_heat_) {
1232  ESP_LOGCONFIG(TAG, " Heating Parameters:");
1233  ESP_LOGCONFIG(TAG, " Deadband: %.1f°C", this->heating_deadband_);
1234  ESP_LOGCONFIG(TAG, " Overrun: %.1f°C", this->heating_overrun_);
1236  ESP_LOGCONFIG(TAG, " Supplemental Delta: %.1f°C", this->supplemental_heat_delta_);
1237  ESP_LOGCONFIG(TAG, " Maximum Run Time: %us",
1239  }
1240  ESP_LOGCONFIG(TAG, " Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_HEATING_OFF) / 1000);
1241  ESP_LOGCONFIG(TAG, " Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_HEATING_ON) / 1000);
1242  }
1243  if (this->supports_fan_only_) {
1244  ESP_LOGCONFIG(TAG, " Fanning Minimum Off Time: %us", this->timer_duration_(thermostat::TIMER_FANNING_OFF) / 1000);
1245  ESP_LOGCONFIG(TAG, " Fanning Minimum Run Time: %us", this->timer_duration_(thermostat::TIMER_FANNING_ON) / 1000);
1246  }
1250  ESP_LOGCONFIG(TAG, " Minimum Fan Mode Switching Time: %us",
1252  }
1253  ESP_LOGCONFIG(TAG, " Minimum Idle Time: %us", this->timer_[thermostat::TIMER_IDLE_ON].time / 1000);
1254  ESP_LOGCONFIG(TAG, " Supports AUTO: %s", YESNO(this->supports_auto_));
1255  ESP_LOGCONFIG(TAG, " Supports HEAT/COOL: %s", YESNO(this->supports_heat_cool_));
1256  ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
1257  ESP_LOGCONFIG(TAG, " Supports DRY: %s", YESNO(this->supports_dry_));
1258  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY: %s", YESNO(this->supports_fan_only_));
1259  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_ACTION_USES_FAN_MODE_TIMER: %s",
1261  ESP_LOGCONFIG(TAG, " Supports FAN_ONLY_COOLING: %s", YESNO(this->supports_fan_only_cooling_));
1262  if (this->supports_cool_)
1263  ESP_LOGCONFIG(TAG, " Supports FAN_WITH_COOLING: %s", YESNO(this->supports_fan_with_cooling_));
1264  if (this->supports_heat_)
1265  ESP_LOGCONFIG(TAG, " Supports FAN_WITH_HEATING: %s", YESNO(this->supports_fan_with_heating_));
1266  ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_));
1267  ESP_LOGCONFIG(TAG, " Supports FAN MODE ON: %s", YESNO(this->supports_fan_mode_on_));
1268  ESP_LOGCONFIG(TAG, " Supports FAN MODE OFF: %s", YESNO(this->supports_fan_mode_off_));
1269  ESP_LOGCONFIG(TAG, " Supports FAN MODE AUTO: %s", YESNO(this->supports_fan_mode_auto_));
1270  ESP_LOGCONFIG(TAG, " Supports FAN MODE LOW: %s", YESNO(this->supports_fan_mode_low_));
1271  ESP_LOGCONFIG(TAG, " Supports FAN MODE MEDIUM: %s", YESNO(this->supports_fan_mode_medium_));
1272  ESP_LOGCONFIG(TAG, " Supports FAN MODE HIGH: %s", YESNO(this->supports_fan_mode_high_));
1273  ESP_LOGCONFIG(TAG, " Supports FAN MODE MIDDLE: %s", YESNO(this->supports_fan_mode_middle_));
1274  ESP_LOGCONFIG(TAG, " Supports FAN MODE FOCUS: %s", YESNO(this->supports_fan_mode_focus_));
1275  ESP_LOGCONFIG(TAG, " Supports FAN MODE DIFFUSE: %s", YESNO(this->supports_fan_mode_diffuse_));
1276  ESP_LOGCONFIG(TAG, " Supports SWING MODE BOTH: %s", YESNO(this->supports_swing_mode_both_));
1277  ESP_LOGCONFIG(TAG, " Supports SWING MODE OFF: %s", YESNO(this->supports_swing_mode_off_));
1278  ESP_LOGCONFIG(TAG, " Supports SWING MODE HORIZONTAL: %s", YESNO(this->supports_swing_mode_horizontal_));
1279  ESP_LOGCONFIG(TAG, " Supports SWING MODE VERTICAL: %s", YESNO(this->supports_swing_mode_vertical_));
1280  ESP_LOGCONFIG(TAG, " Supports TWO SET POINTS: %s", YESNO(this->supports_two_points_));
1281 
1282  ESP_LOGCONFIG(TAG, " Supported PRESETS: ");
1283  for (auto &it : this->preset_config_) {
1284  const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first));
1285 
1286  ESP_LOGCONFIG(TAG, " Supports %s: %s", preset_name, YESNO(true));
1287  this->dump_preset_config_(preset_name, it.second);
1288  }
1289 
1290  ESP_LOGCONFIG(TAG, " Supported CUSTOM PRESETS: ");
1291  for (auto &it : this->custom_preset_config_) {
1292  const auto *preset_name = it.first.c_str();
1293 
1294  ESP_LOGCONFIG(TAG, " Supports %s: %s", preset_name, YESNO(true));
1295  this->dump_preset_config_(preset_name, it.second);
1296  }
1297 }
1298 
1300 
1302  : default_temperature(default_temperature) {}
1303 
1306  : default_temperature_low(default_temperature_low), default_temperature_high(default_temperature_high) {}
1307 
1308 } // namespace thermostat
1309 } // 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:83
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:71
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
Device is in home preset.
Definition: climate_mode.h:84
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:67
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)
void set_fan_mode_minimum_switching_time_in_sec(uint32_t time)
climate::ClimateAction compute_supplemental_action_()
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
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:132
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.
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".
void change_preset_internal_(const ThermostatClimateTargetTempConfig &config)
Applies the temperature, mode, fan, and swing modes of the provded config.
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_
void dump_preset_config_(const std::string &preset_name, const ThermostatClimateTargetTempConfig &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
void set_default_mode(climate::ClimateMode default_mode)
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:47
void set_supports_fan_mode_high(bool supports_fan_mode_high)
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
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.