ESPHome 2025.10.0-dev
Loading...
Searching...
No Matches
thermostat_climate.cpp
Go to the documentation of this file.
4#include "esphome/core/log.h"
5
6namespace esphome {
7namespace thermostat {
8
9static const char *const TAG = "thermostat.climate";
10
12 if (this->use_startup_delay_) {
13 // start timers so that no actions are called for a moment
19 }
20 // add a callback so that whenever the sensor state changes we can take action
21 this->sensor_->add_on_state_callback([this](float state) {
23 // required action may have changed, recompute, refresh, we'll publish_state() later
24 this->switch_to_action_(this->compute_action_(), false);
26 // current temperature and possibly action changed, so publish the new state
27 this->publish_state();
28 });
29 this->current_temperature = this->sensor_->state;
30
31 // register for humidity values and get initial state
32 if (this->humidity_sensor_ != nullptr) {
33 this->humidity_sensor_->add_on_state_callback([this](float state) {
34 this->current_humidity = state;
35 this->publish_state();
36 });
38 }
39
40 auto use_default_preset = true;
41
43 // restore all climate data, if possible
44 auto restore = this->restore_state_();
45 if (restore.has_value()) {
46 use_default_preset = false;
47 restore->to_call(this).perform();
48 }
49 }
50
51 // Either we failed to restore state or the user has requested we always apply the default preset
52 if (use_default_preset) {
55 } else if (!this->default_custom_preset_.empty()) {
57 }
58 }
59
60 // refresh the climate action based on the restored settings, we'll publish_state() later
61 this->switch_to_action_(this->compute_action_(), false);
63 this->setup_complete_ = true;
64 this->publish_state();
65}
66
68 for (auto &timer : this->timer_) {
69 if (timer.active && (timer.started + timer.time < App.get_loop_component_start_time())) {
70 timer.active = false;
71 timer.func();
72 }
73 }
74}
75
80
82 this->switch_to_mode_(this->mode, false);
83 this->switch_to_action_(this->compute_action_(), false);
85 this->switch_to_fan_mode_(this->fan_mode.value(), false);
86 this->switch_to_swing_mode_(this->swing_mode, false);
88 this->publish_state();
89}
90
92 bool state_mismatch = this->action != this->compute_action_(true);
93
94 switch (this->compute_action_(true)) {
97 return state_mismatch && (!this->idle_action_ready_());
99 return state_mismatch && (!this->cooling_action_ready_());
101 return state_mismatch && (!this->heating_action_ready_());
103 return state_mismatch && (!this->fanning_action_ready_());
105 return state_mismatch && (!this->drying_action_ready_());
106 default:
107 break;
108 }
109 return false;
110}
111
113 bool state_mismatch = this->fan_mode.value_or(climate::CLIMATE_FAN_ON) != this->prev_fan_mode_;
114 return state_mismatch && (!this->fan_mode_ready_());
115}
116
118
120
122 if ((this->supports_cool_ || (this->supports_fan_only_ && this->supports_fan_only_cooling_)) &&
123 (std::isnan(this->cooling_deadband_) || std::isnan(this->cooling_overrun_)))
124 return false;
125
126 if (this->supports_heat_ && (std::isnan(this->heating_deadband_) || std::isnan(this->heating_overrun_)))
127 return false;
128
129 return true;
130}
131
136
138 if (std::isnan(this->target_temperature)) {
139 // default to the midpoint between visual min and max
140 this->target_temperature =
143 } else {
144 // target_temperature must be between the visual minimum and the visual maximum
145 this->target_temperature = clamp(this->target_temperature, this->get_traits().get_visual_min_temperature(),
146 this->get_traits().get_visual_max_temperature());
147 }
148}
149
150void ThermostatClimate::validate_target_temperatures(const bool pin_target_temperature_high) {
151 if (!this->supports_two_points_) {
153 } else if (pin_target_temperature_high) {
154 // if target_temperature_high is set less than target_temperature_low, move down target_temperature_low
157 } else {
158 // if target_temperature_low is set greater than target_temperature_high, move up target_temperature_high
161 }
162}
163
165 if (std::isnan(this->target_temperature_low)) {
167 } else {
168 float target_temperature_low_upper_limit =
171 this->get_traits().get_visual_min_temperature(), this->get_traits().get_visual_max_temperature())
173 this->target_temperature_low = clamp(this->target_temperature_low, this->get_traits().get_visual_min_temperature(),
174 target_temperature_low_upper_limit);
175 }
176}
177
179 if (std::isnan(this->target_temperature_high)) {
181 } else {
182 float target_temperature_high_lower_limit =
185 this->get_traits().get_visual_min_temperature(), this->get_traits().get_visual_max_temperature())
187 this->target_temperature_high = clamp(this->target_temperature_high, target_temperature_high_lower_limit,
188 this->get_traits().get_visual_max_temperature());
189 }
190}
191
193 bool target_temperature_high_changed = false;
194
195 if (call.get_preset().has_value()) {
196 // setup_complete_ blocks modifying/resetting the temps immediately after boot
197 if (this->setup_complete_) {
198 this->change_preset_(call.get_preset().value());
199 } else {
200 this->preset = call.get_preset().value();
201 }
202 }
203 if (call.get_custom_preset().has_value()) {
204 // setup_complete_ blocks modifying/resetting the temps immediately after boot
205 if (this->setup_complete_) {
207 } else {
208 this->custom_preset = call.get_custom_preset().value();
209 }
210 }
211
212 if (call.get_mode().has_value()) {
213 this->mode = call.get_mode().value();
214 }
215 if (call.get_fan_mode().has_value()) {
216 this->fan_mode = call.get_fan_mode().value();
217 }
218 if (call.get_swing_mode().has_value()) {
219 this->swing_mode = call.get_swing_mode().value();
220 }
221 if (this->supports_two_points_) {
224 }
225 if (call.get_target_temperature_high().has_value()) {
226 target_temperature_high_changed = this->target_temperature_high != call.get_target_temperature_high().value();
228 }
229 // ensure the two set points are valid and adjust one of them if necessary
230 this->validate_target_temperatures(target_temperature_high_changed ||
232 } else {
233 if (call.get_target_temperature().has_value()) {
236 }
237 }
238 // make any changes happen
239 this->refresh();
240}
241
245 if (this->humidity_sensor_ != nullptr)
247
248 if (this->supports_auto_)
250 if (this->supports_heat_cool_)
252 if (this->supports_cool_)
254 if (this->supports_dry_)
256 if (this->supports_fan_only_)
258 if (this->supports_heat_)
260
261 if (this->supports_fan_mode_on_)
263 if (this->supports_fan_mode_off_)
265 if (this->supports_fan_mode_auto_)
267 if (this->supports_fan_mode_low_)
271 if (this->supports_fan_mode_high_)
275 if (this->supports_fan_mode_focus_)
279 if (this->supports_fan_mode_quiet_)
281
286 if (this->supports_swing_mode_off_)
290
291 for (auto &it : this->preset_config_) {
293 }
294 for (auto &it : this->custom_preset_config_) {
296 }
297
300 return traits;
301}
302
304 auto target_action = climate::CLIMATE_ACTION_IDLE;
305 // if any hysteresis values or current_temperature is not valid, we go to OFF;
306 if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
308 }
309 // do not change the action if an "ON" timer is running
310 if ((!ignore_timers) && (this->timer_active_(thermostat::THERMOSTAT_TIMER_IDLE_ON) ||
314 return this->action;
315 }
316
317 // ensure set point(s) is/are valid before computing the action
319 // everything has been validated so we can now safely compute the action
320 switch (this->mode) {
321 // if the climate mode is OFF then the climate action must be OFF
323 target_action = climate::CLIMATE_ACTION_OFF;
324 break;
326 if (this->fanning_required_())
327 target_action = climate::CLIMATE_ACTION_FAN;
328 break;
330 target_action = climate::CLIMATE_ACTION_DRYING;
331 break;
333 if (this->cooling_required_() && this->heating_required_()) {
334 // this is bad and should never happen, so just stop.
335 // target_action = climate::CLIMATE_ACTION_IDLE;
336 } else if (this->cooling_required_()) {
337 target_action = climate::CLIMATE_ACTION_COOLING;
338 } else if (this->heating_required_()) {
339 target_action = climate::CLIMATE_ACTION_HEATING;
340 }
341 break;
343 if (this->cooling_required_()) {
344 target_action = climate::CLIMATE_ACTION_COOLING;
345 }
346 break;
348 if (this->heating_required_()) {
349 target_action = climate::CLIMATE_ACTION_HEATING;
350 }
351 break;
353 if (this->supports_two_points_) {
354 if (this->cooling_required_() && this->heating_required_()) {
355 // this is bad and should never happen, so just stop.
356 // target_action = climate::CLIMATE_ACTION_IDLE;
357 } else if (this->cooling_required_()) {
358 target_action = climate::CLIMATE_ACTION_COOLING;
359 } else if (this->heating_required_()) {
360 target_action = climate::CLIMATE_ACTION_HEATING;
361 }
362 } else if (this->supports_cool_ && this->cooling_required_()) {
363 target_action = climate::CLIMATE_ACTION_COOLING;
364 } else if (this->supports_heat_ && this->heating_required_()) {
365 target_action = climate::CLIMATE_ACTION_HEATING;
366 }
367 break;
368 default:
369 break;
370 }
371 // do not abruptly switch actions. cycle through IDLE, first. we'll catch this at the next update.
373 (target_action == climate::CLIMATE_ACTION_HEATING)) ||
375 ((target_action == climate::CLIMATE_ACTION_COOLING) || (target_action == climate::CLIMATE_ACTION_DRYING)))) {
377 }
378
379 return target_action;
380}
381
383 auto target_action = climate::CLIMATE_ACTION_IDLE;
384 // if any hysteresis values or current_temperature is not valid, we go to OFF;
385 if (std::isnan(this->current_temperature) || !this->hysteresis_valid()) {
387 }
388
389 // ensure set point(s) is/are valid before computing the action
391 // everything has been validated so we can now safely compute the action
392 switch (this->mode) {
393 // if the climate mode is OFF then the climate action must be OFF
395 target_action = climate::CLIMATE_ACTION_OFF;
396 break;
399 // this is bad and should never happen, so just stop.
400 // target_action = climate::CLIMATE_ACTION_IDLE;
401 } else if (this->supplemental_cooling_required_()) {
402 target_action = climate::CLIMATE_ACTION_COOLING;
403 } else if (this->supplemental_heating_required_()) {
404 target_action = climate::CLIMATE_ACTION_HEATING;
405 }
406 break;
408 if (this->supplemental_cooling_required_()) {
409 target_action = climate::CLIMATE_ACTION_COOLING;
410 }
411 break;
413 if (this->supplemental_heating_required_()) {
414 target_action = climate::CLIMATE_ACTION_HEATING;
415 }
416 break;
417 default:
418 break;
419 }
420
421 return target_action;
422}
423
425 // setup_complete_ helps us ensure an action is called immediately after boot
426 if ((action == this->action) && this->setup_complete_) {
427 // already in target mode
428 return;
429 }
430
431 if (((action == climate::CLIMATE_ACTION_OFF && this->action == climate::CLIMATE_ACTION_IDLE) ||
433 this->setup_complete_) {
434 // switching from OFF to IDLE or vice-versa -- this is only a visual difference.
435 // OFF means user manually disabled, IDLE means the temperature is in target range.
436 this->action = action;
437 if (publish_state)
438 this->publish_state();
439 return;
440 }
441
442 bool action_ready = false;
443 Trigger<> *trig = this->idle_action_trigger_, *trig_fan = nullptr;
444 switch (action) {
447 if (this->idle_action_ready_()) {
449 if (this->action == climate::CLIMATE_ACTION_COOLING)
451 if (this->action == climate::CLIMATE_ACTION_FAN) {
454 } else {
456 }
457 }
458 if (this->action == climate::CLIMATE_ACTION_HEATING)
460 // trig = this->idle_action_trigger_;
461 ESP_LOGVV(TAG, "Switching to IDLE/OFF action");
462 this->cooling_max_runtime_exceeded_ = false;
463 this->heating_max_runtime_exceeded_ = false;
464 action_ready = true;
465 }
466 break;
468 if (this->cooling_action_ready_()) {
471 if (this->supports_fan_with_cooling_) {
473 trig_fan = this->fan_only_action_trigger_;
474 }
475 this->cooling_max_runtime_exceeded_ = false;
476 trig = this->cool_action_trigger_;
477 ESP_LOGVV(TAG, "Switching to COOLING action");
478 action_ready = true;
479 }
480 break;
482 if (this->heating_action_ready_()) {
485 if (this->supports_fan_with_heating_) {
487 trig_fan = this->fan_only_action_trigger_;
488 }
489 this->heating_max_runtime_exceeded_ = false;
490 trig = this->heat_action_trigger_;
491 ESP_LOGVV(TAG, "Switching to HEATING action");
492 action_ready = true;
493 }
494 break;
496 if (this->fanning_action_ready_()) {
499 } else {
501 }
502 trig = this->fan_only_action_trigger_;
503 ESP_LOGVV(TAG, "Switching to FAN_ONLY action");
504 action_ready = true;
505 }
506 break;
508 if (this->drying_action_ready_()) {
511 trig = this->dry_action_trigger_;
512 ESP_LOGVV(TAG, "Switching to DRYING action");
513 action_ready = true;
514 }
515 break;
516 default:
517 // we cannot report an invalid mode back to HA (even if it asked for one)
518 // and must assume some valid value
520 // trig = this->idle_action_trigger_;
521 }
522
523 if (action_ready) {
524 if (this->prev_action_trigger_ != nullptr) {
526 this->prev_action_trigger_ = nullptr;
527 }
528 this->action = action;
529 this->prev_action_trigger_ = trig;
530 if (trig != nullptr) {
531 trig->trigger();
532 }
533 // if enabled, call the fan_only action with cooling/heating actions
534 if (trig_fan != nullptr) {
535 ESP_LOGVV(TAG, "Calling FAN_ONLY action with HEATING/COOLING action");
536 trig_fan->trigger();
537 }
538 if (publish_state)
539 this->publish_state();
540 }
541}
542
544 // setup_complete_ helps us ensure an action is called immediately after boot
545 if ((action == this->supplemental_action_) && this->setup_complete_) {
546 // already in target mode
547 return;
548 }
549
550 switch (action) {
555 break;
558 break;
561 break;
562 default:
563 return;
564 }
565 ESP_LOGVV(TAG, "Updating supplemental action");
568}
569
571 Trigger<> *trig = nullptr;
572
573 switch (this->supplemental_action_) {
577 }
579 ESP_LOGVV(TAG, "Calling supplemental COOLING action");
580 break;
584 }
586 ESP_LOGVV(TAG, "Calling supplemental HEATING action");
587 break;
588 default:
589 break;
590 }
591
592 if (trig != nullptr) {
593 trig->trigger();
594 }
595}
596
598 // setup_complete_ helps us ensure an action is called immediately after boot
599 if ((fan_mode == this->prev_fan_mode_) && this->setup_complete_) {
600 // already in target mode
601 return;
602 }
603
604 this->fan_mode = fan_mode;
605 if (publish_state)
606 this->publish_state();
607
608 if (this->fan_mode_ready_()) {
609 Trigger<> *trig = this->fan_mode_auto_trigger_;
610 switch (fan_mode) {
612 trig = this->fan_mode_on_trigger_;
613 ESP_LOGVV(TAG, "Switching to FAN_ON mode");
614 break;
616 trig = this->fan_mode_off_trigger_;
617 ESP_LOGVV(TAG, "Switching to FAN_OFF mode");
618 break;
620 // trig = this->fan_mode_auto_trigger_;
621 ESP_LOGVV(TAG, "Switching to FAN_AUTO mode");
622 break;
624 trig = this->fan_mode_low_trigger_;
625 ESP_LOGVV(TAG, "Switching to FAN_LOW mode");
626 break;
628 trig = this->fan_mode_medium_trigger_;
629 ESP_LOGVV(TAG, "Switching to FAN_MEDIUM mode");
630 break;
632 trig = this->fan_mode_high_trigger_;
633 ESP_LOGVV(TAG, "Switching to FAN_HIGH mode");
634 break;
636 trig = this->fan_mode_middle_trigger_;
637 ESP_LOGVV(TAG, "Switching to FAN_MIDDLE mode");
638 break;
640 trig = this->fan_mode_focus_trigger_;
641 ESP_LOGVV(TAG, "Switching to FAN_FOCUS mode");
642 break;
644 trig = this->fan_mode_diffuse_trigger_;
645 ESP_LOGVV(TAG, "Switching to FAN_DIFFUSE mode");
646 break;
648 trig = this->fan_mode_quiet_trigger_;
649 ESP_LOGVV(TAG, "Switching to FAN_QUIET mode");
650 break;
651 default:
652 // we cannot report an invalid mode back to HA (even if it asked for one)
653 // and must assume some valid value
655 // trig = this->fan_mode_auto_trigger_;
656 }
657 if (this->prev_fan_mode_trigger_ != nullptr) {
659 this->prev_fan_mode_trigger_ = nullptr;
660 }
662 if (trig != nullptr) {
663 trig->trigger();
664 }
665 this->prev_fan_mode_ = fan_mode;
666 this->prev_fan_mode_trigger_ = trig;
667 }
668}
669
671 // setup_complete_ helps us ensure an action is called immediately after boot
672 if ((mode == this->prev_mode_) && this->setup_complete_) {
673 // already in target mode
674 return;
675 }
676
677 if (this->prev_mode_trigger_ != nullptr) {
679 this->prev_mode_trigger_ = nullptr;
680 }
681 Trigger<> *trig = this->off_mode_trigger_;
682 switch (mode) {
684 trig = this->auto_mode_trigger_;
685 break;
687 trig = this->heat_cool_mode_trigger_;
688 break;
690 trig = this->cool_mode_trigger_;
691 break;
693 trig = this->heat_mode_trigger_;
694 break;
696 trig = this->fan_only_mode_trigger_;
697 break;
699 trig = this->dry_mode_trigger_;
700 break;
702 default:
703 // we cannot report an invalid mode back to HA (even if it asked for one)
704 // and must assume some valid value
706 // trig = this->off_mode_trigger_;
707 }
708 if (trig != nullptr) {
709 trig->trigger();
710 }
711 this->mode = mode;
712 this->prev_mode_ = mode;
713 this->prev_mode_trigger_ = trig;
714 if (publish_state) {
715 this->publish_state();
716 }
717}
718
720 // setup_complete_ helps us ensure an action is called immediately after boot
721 if ((swing_mode == this->prev_swing_mode_) && this->setup_complete_) {
722 // already in target mode
723 return;
724 }
725
726 if (this->prev_swing_mode_trigger_ != nullptr) {
728 this->prev_swing_mode_trigger_ = nullptr;
729 }
731 switch (swing_mode) {
733 trig = this->swing_mode_both_trigger_;
734 break;
737 break;
739 // trig = this->swing_mode_off_trigger_;
740 break;
742 trig = this->swing_mode_vertical_trigger_;
743 break;
744 default:
745 // we cannot report an invalid mode back to HA (even if it asked for one)
746 // and must assume some valid value
747 swing_mode = climate::CLIMATE_SWING_OFF;
748 // trig = this->swing_mode_off_trigger_;
749 }
750 if (trig != nullptr) {
751 trig->trigger();
752 }
753 this->swing_mode = swing_mode;
755 this->prev_swing_mode_trigger_ = trig;
756 if (publish_state)
757 this->publish_state();
758}
759
770
777
784
786
794
801
803 if (this->timer_duration_(timer_index) > 0) {
804 this->timer_[timer_index].started = millis();
805 this->timer_[timer_index].active = true;
806 }
807}
808
810 auto ret = this->timer_[timer_index].active;
811 this->timer_[timer_index].active = false;
812 return ret;
813}
814
816 return this->timer_[timer_index].active;
817}
818
820 return this->timer_[timer_index].time;
821}
822
824 return this->timer_[timer_index].func;
825}
826
828 ESP_LOGVV(TAG, "cooling_max_run_time timer expired");
832}
833
835 ESP_LOGVV(TAG, "cooling_off timer expired");
836 this->switch_to_action_(this->compute_action_());
838}
839
841 ESP_LOGVV(TAG, "cooling_on timer expired");
842 this->switch_to_action_(this->compute_action_());
844}
845
847 ESP_LOGVV(TAG, "fan_mode timer expired");
850 this->switch_to_action_(this->compute_action_());
851}
852
854 ESP_LOGVV(TAG, "fanning_off timer expired");
855 this->switch_to_action_(this->compute_action_());
856}
857
859 ESP_LOGVV(TAG, "fanning_on timer expired");
860 this->switch_to_action_(this->compute_action_());
861}
862
864 ESP_LOGVV(TAG, "heating_max_run_time timer expired");
868}
869
871 ESP_LOGVV(TAG, "heating_off timer expired");
872 this->switch_to_action_(this->compute_action_());
874}
875
877 ESP_LOGVV(TAG, "heating_on timer expired");
878 this->switch_to_action_(this->compute_action_());
880}
881
883 ESP_LOGVV(TAG, "idle_on timer expired");
884 this->switch_to_action_(this->compute_action_());
886}
887
889 if (this->supports_two_points_) {
890 // setup_complete_ helps us ensure an action is called immediately after boot
893 return; // nothing changed, no reason to trigger
894 } else {
895 // save the new temperatures so we can check them again later; the trigger will fire below
898 }
899 } else {
900 if ((this->prev_target_temperature_ == this->target_temperature) && this->setup_complete_) {
901 return; // nothing changed, no reason to trigger
902 } else {
903 // save the new temperature so we can check it again later; the trigger will fire below
905 }
906 }
907 // trigger the action
909 if (trig != nullptr) {
910 trig->trigger();
911 }
912}
913
916
917 if (this->supports_cool_) {
919 // if the current temperature exceeds the target + deadband, cooling is required
920 return true;
922 // if the current temperature is less than the target - overrun, cooling should stop
923 return false;
924 } else {
925 // if we get here, the current temperature is between target + deadband and target - overrun,
926 // so the action should not change unless it conflicts with the current mode
927 return (this->action == climate::CLIMATE_ACTION_COOLING) &&
929 }
930 }
931 return false;
932}
933
936
937 if (this->supports_fan_only_) {
938 if (this->supports_fan_only_cooling_) {
940 // if the current temperature exceeds the target + deadband, fanning is required
941 return true;
943 // if the current temperature is less than the target - overrun, fanning should stop
944 return false;
945 } else {
946 // if we get here, the current temperature is between target + deadband and target - overrun,
947 // so the action should not change unless it conflicts with the current mode
949 }
950 } else {
951 return true;
952 }
953 }
954 return false;
955}
956
959
960 if (this->supports_heat_) {
962 // if the current temperature is below the target - deadband, heating is required
963 return true;
964 } else if (this->current_temperature > temperature + this->heating_overrun_) {
965 // if the current temperature is above the target + overrun, heating should stop
966 return false;
967 } else {
968 // if we get here, the current temperature is between target - deadband and target + overrun,
969 // so the action should not change unless it conflicts with the current mode
970 return (this->action == climate::CLIMATE_ACTION_HEATING) &&
972 }
973 }
974 return false;
975}
976
979 // the component must supports_cool_ and the climate action must be climate::CLIMATE_ACTION_COOLING. then...
980 // supplemental cooling is required if the max delta or max runtime was exceeded or the action is already engaged
981 return this->supports_cool_ && (this->action == climate::CLIMATE_ACTION_COOLING) &&
985}
986
989 // the component must supports_heat_ and the climate action must be climate::CLIMATE_ACTION_HEATING. then...
990 // supplemental heating is required if the max delta or max runtime was exceeded or the action is already engaged
991 return this->supports_heat_ && (this->action == climate::CLIMATE_ACTION_HEATING) &&
995}
996
998 if (this->supports_heat_) {
999 ESP_LOGCONFIG(TAG, " Default Target Temperature Low: %.1f°C",
1001 }
1002 if ((this->supports_cool_) || (this->supports_fan_only_)) {
1003 ESP_LOGCONFIG(TAG, " Default Target Temperature High: %.1f°C",
1005 }
1006
1007 if (config.mode_.has_value()) {
1008 ESP_LOGCONFIG(TAG, " Default Mode: %s", LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
1009 }
1010 if (config.fan_mode_.has_value()) {
1011 ESP_LOGCONFIG(TAG, " Default Fan Mode: %s",
1012 LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
1013 }
1014 if (config.swing_mode_.has_value()) {
1015 ESP_LOGCONFIG(TAG, " Default Swing Mode: %s",
1017 }
1018}
1019
1021 auto config = this->preset_config_.find(preset);
1022
1023 if (config != this->preset_config_.end()) {
1024 ESP_LOGV(TAG, "Preset %s requested", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
1025 if (this->change_preset_internal_(config->second) || (!this->preset.has_value()) ||
1026 this->preset.value() != preset) {
1027 // Fire any preset changed trigger if defined
1028 Trigger<> *trig = this->preset_change_trigger_;
1029 this->preset = preset;
1030 if (trig != nullptr) {
1031 trig->trigger();
1032 }
1033
1034 this->refresh();
1035 ESP_LOGI(TAG, "Preset %s applied", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
1036 } else {
1037 ESP_LOGI(TAG, "No changes required to apply preset %s", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
1038 }
1039 this->custom_preset.reset();
1040 this->preset = preset;
1041 } else {
1042 ESP_LOGW(TAG, "Preset %s not configured; ignoring", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
1043 }
1044}
1045
1047 auto config = this->custom_preset_config_.find(custom_preset);
1048
1049 if (config != this->custom_preset_config_.end()) {
1050 ESP_LOGV(TAG, "Custom preset %s requested", custom_preset.c_str());
1051 if (this->change_preset_internal_(config->second) || (!this->custom_preset.has_value()) ||
1052 this->custom_preset.value() != custom_preset) {
1053 // Fire any preset changed trigger if defined
1054 Trigger<> *trig = this->preset_change_trigger_;
1055 this->custom_preset = custom_preset;
1056 if (trig != nullptr) {
1057 trig->trigger();
1058 }
1059
1060 this->refresh();
1061 ESP_LOGI(TAG, "Custom preset %s applied", custom_preset.c_str());
1062 } else {
1063 ESP_LOGI(TAG, "No changes required to apply custom preset %s", custom_preset.c_str());
1064 }
1065 this->preset.reset();
1066 this->custom_preset = custom_preset;
1067 } else {
1068 ESP_LOGW(TAG, "Custom preset %s not configured; ignoring", custom_preset.c_str());
1069 }
1070}
1071
1073 bool something_changed = false;
1074
1075 if (this->supports_two_points_) {
1076 if (this->target_temperature_low != config.default_temperature_low) {
1078 something_changed = true;
1079 }
1082 something_changed = true;
1083 }
1084 } else {
1085 if (this->target_temperature != config.default_temperature) {
1087 something_changed = true;
1088 }
1089 }
1090
1091 // Note: The mode, fan_mode and swing_mode can all be defined in the preset but if the climate.control call
1092 // also specifies them then the climate.control call's values will override the preset's values for that call
1093 if (config.mode_.has_value() && (this->mode != config.mode_.value())) {
1094 ESP_LOGV(TAG, "Setting mode to %s", LOG_STR_ARG(climate::climate_mode_to_string(*config.mode_)));
1095 this->mode = *config.mode_;
1096 something_changed = true;
1097 }
1098
1099 if (config.fan_mode_.has_value() && (this->fan_mode != config.fan_mode_.value())) {
1100 ESP_LOGV(TAG, "Setting fan mode to %s", LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
1101 this->fan_mode = *config.fan_mode_;
1102 something_changed = true;
1103 }
1104
1105 if (config.swing_mode_.has_value() && (this->swing_mode != config.swing_mode_.value())) {
1106 ESP_LOGV(TAG, "Setting swing mode to %s", LOG_STR_ARG(climate::climate_swing_mode_to_string(*config.swing_mode_)));
1107 this->swing_mode = *config.swing_mode_;
1108 something_changed = true;
1109 }
1110
1111 return something_changed;
1112}
1113
1118
1120 const ThermostatClimateTargetTempConfig &config) {
1121 this->custom_preset_config_[name] = config;
1122}
1123
1125 : cool_action_trigger_(new Trigger<>()),
1126 supplemental_cool_action_trigger_(new Trigger<>()),
1127 cool_mode_trigger_(new Trigger<>()),
1128 dry_action_trigger_(new Trigger<>()),
1129 dry_mode_trigger_(new Trigger<>()),
1130 heat_action_trigger_(new Trigger<>()),
1131 supplemental_heat_action_trigger_(new Trigger<>()),
1132 heat_mode_trigger_(new Trigger<>()),
1133 heat_cool_mode_trigger_(new Trigger<>()),
1134 auto_mode_trigger_(new Trigger<>()),
1135 idle_action_trigger_(new Trigger<>()),
1136 off_mode_trigger_(new Trigger<>()),
1137 fan_only_action_trigger_(new Trigger<>()),
1138 fan_only_mode_trigger_(new Trigger<>()),
1139 fan_mode_on_trigger_(new Trigger<>()),
1140 fan_mode_off_trigger_(new Trigger<>()),
1141 fan_mode_auto_trigger_(new Trigger<>()),
1142 fan_mode_low_trigger_(new Trigger<>()),
1143 fan_mode_medium_trigger_(new Trigger<>()),
1144 fan_mode_high_trigger_(new Trigger<>()),
1145 fan_mode_middle_trigger_(new Trigger<>()),
1146 fan_mode_focus_trigger_(new Trigger<>()),
1147 fan_mode_diffuse_trigger_(new Trigger<>()),
1148 fan_mode_quiet_trigger_(new Trigger<>()),
1149 swing_mode_both_trigger_(new Trigger<>()),
1150 swing_mode_off_trigger_(new Trigger<>()),
1151 swing_mode_horizontal_trigger_(new Trigger<>()),
1152 swing_mode_vertical_trigger_(new Trigger<>()),
1153 temperature_change_trigger_(new Trigger<>()),
1154 preset_change_trigger_(new Trigger<>()) {}
1155
1159
1161
1163 this->on_boot_restore_from_ = on_boot_restore_from;
1164}
1166 this->set_point_minimum_differential_ = differential;
1167}
1168void ThermostatClimate::set_cool_deadband(float deadband) { this->cooling_deadband_ = deadband; }
1169void ThermostatClimate::set_cool_overrun(float overrun) { this->cooling_overrun_ = overrun; }
1170void ThermostatClimate::set_heat_deadband(float deadband) { this->heating_deadband_ = deadband; }
1171void ThermostatClimate::set_heat_overrun(float overrun) { this->heating_overrun_ = overrun; }
1184 1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1185}
1196 1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1197}
1208 1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1209}
1212 1000 * (time < this->min_timer_duration_ ? this->min_timer_duration_ : time);
1213}
1216 this->humidity_sensor_ = humidity_sensor;
1217}
1218void ThermostatClimate::set_use_startup_delay(bool use_startup_delay) { this->use_startup_delay_ = use_startup_delay; }
1219void ThermostatClimate::set_supports_heat_cool(bool supports_heat_cool) {
1220 this->supports_heat_cool_ = supports_heat_cool;
1221}
1222void ThermostatClimate::set_supports_auto(bool supports_auto) { this->supports_auto_ = supports_auto; }
1223void ThermostatClimate::set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
1224void ThermostatClimate::set_supports_dry(bool supports_dry) { this->supports_dry_ = supports_dry; }
1225void ThermostatClimate::set_supports_fan_only(bool supports_fan_only) { this->supports_fan_only_ = supports_fan_only; }
1227 bool supports_fan_only_action_uses_fan_mode_timer) {
1228 this->supports_fan_only_action_uses_fan_mode_timer_ = supports_fan_only_action_uses_fan_mode_timer;
1229}
1230void ThermostatClimate::set_supports_fan_only_cooling(bool supports_fan_only_cooling) {
1231 this->supports_fan_only_cooling_ = supports_fan_only_cooling;
1232}
1233void ThermostatClimate::set_supports_fan_with_cooling(bool supports_fan_with_cooling) {
1234 this->supports_fan_with_cooling_ = supports_fan_with_cooling;
1235}
1236void ThermostatClimate::set_supports_fan_with_heating(bool supports_fan_with_heating) {
1237 this->supports_fan_with_heating_ = supports_fan_with_heating;
1238}
1239void ThermostatClimate::set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
1240void ThermostatClimate::set_supports_fan_mode_on(bool supports_fan_mode_on) {
1241 this->supports_fan_mode_on_ = supports_fan_mode_on;
1242}
1243void ThermostatClimate::set_supports_fan_mode_off(bool supports_fan_mode_off) {
1244 this->supports_fan_mode_off_ = supports_fan_mode_off;
1245}
1246void ThermostatClimate::set_supports_fan_mode_auto(bool supports_fan_mode_auto) {
1247 this->supports_fan_mode_auto_ = supports_fan_mode_auto;
1248}
1249void ThermostatClimate::set_supports_fan_mode_low(bool supports_fan_mode_low) {
1250 this->supports_fan_mode_low_ = supports_fan_mode_low;
1251}
1252void ThermostatClimate::set_supports_fan_mode_medium(bool supports_fan_mode_medium) {
1253 this->supports_fan_mode_medium_ = supports_fan_mode_medium;
1254}
1255void ThermostatClimate::set_supports_fan_mode_high(bool supports_fan_mode_high) {
1256 this->supports_fan_mode_high_ = supports_fan_mode_high;
1257}
1258void ThermostatClimate::set_supports_fan_mode_middle(bool supports_fan_mode_middle) {
1259 this->supports_fan_mode_middle_ = supports_fan_mode_middle;
1260}
1261void ThermostatClimate::set_supports_fan_mode_focus(bool supports_fan_mode_focus) {
1262 this->supports_fan_mode_focus_ = supports_fan_mode_focus;
1263}
1264void ThermostatClimate::set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse) {
1265 this->supports_fan_mode_diffuse_ = supports_fan_mode_diffuse;
1266}
1267void ThermostatClimate::set_supports_fan_mode_quiet(bool supports_fan_mode_quiet) {
1268 this->supports_fan_mode_quiet_ = supports_fan_mode_quiet;
1269}
1270void ThermostatClimate::set_supports_swing_mode_both(bool supports_swing_mode_both) {
1271 this->supports_swing_mode_both_ = supports_swing_mode_both;
1272}
1273void ThermostatClimate::set_supports_swing_mode_off(bool supports_swing_mode_off) {
1274 this->supports_swing_mode_off_ = supports_swing_mode_off;
1275}
1276void ThermostatClimate::set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal) {
1277 this->supports_swing_mode_horizontal_ = supports_swing_mode_horizontal;
1278}
1279void ThermostatClimate::set_supports_swing_mode_vertical(bool supports_swing_mode_vertical) {
1280 this->supports_swing_mode_vertical_ = supports_swing_mode_vertical;
1281}
1282void ThermostatClimate::set_supports_two_points(bool supports_two_points) {
1283 this->supports_two_points_ = supports_two_points;
1284}
1285
1320
1322 LOG_CLIMATE("", "Thermostat", this);
1323
1324 ESP_LOGCONFIG(TAG,
1325 " On boot, restore from: %s\n"
1326 " Use Start-up Delay: %s",
1327 this->on_boot_restore_from_ == thermostat::DEFAULT_PRESET ? "DEFAULT_PRESET" : "MEMORY",
1328 YESNO(this->use_startup_delay_));
1329 if (this->supports_two_points_) {
1330 ESP_LOGCONFIG(TAG, " Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_);
1331 }
1332 if (this->supports_cool_) {
1333 ESP_LOGCONFIG(TAG,
1334 " Cooling Parameters:\n"
1335 " Deadband: %.1f°C\n"
1336 " Overrun: %.1f°C\n"
1337 " Minimum Off Time: %" PRIu32 "s\n"
1338 " Minimum Run Time: %" PRIu32 "s",
1342 if ((this->supplemental_cool_delta_ > 0) ||
1344 ESP_LOGCONFIG(TAG,
1345 " Maximum Run Time: %" PRIu32 "s\n"
1346 " Supplemental Delta: %.1f°C",
1349 }
1350 }
1351 if (this->supports_heat_) {
1352 ESP_LOGCONFIG(TAG,
1353 " Heating Parameters:\n"
1354 " Deadband: %.1f°C\n"
1355 " Overrun: %.1f°C\n"
1356 " Minimum Off Time: %" PRIu32 "s\n"
1357 " Minimum Run Time: %" PRIu32 "s",
1361 if ((this->supplemental_heat_delta_ > 0) ||
1363 ESP_LOGCONFIG(TAG,
1364 " Maximum Run Time: %" PRIu32 "s\n"
1365 " Supplemental Delta: %.1f°C",
1368 }
1369 }
1370 if (this->supports_fan_only_) {
1371 ESP_LOGCONFIG(TAG,
1372 " Fan Parameters:\n"
1373 " Minimum Off Time: %" PRIu32 "s\n"
1374 " Minimum Run Time: %" PRIu32 "s",
1377 }
1382 ESP_LOGCONFIG(TAG, " Minimum Fan Mode Switching Time: %" PRIu32 "s",
1384 }
1385 ESP_LOGCONFIG(TAG,
1386 " Minimum Idle Time: %" PRIu32 "s\n"
1387 " Supported MODES:\n"
1388 " AUTO: %s\n"
1389 " HEAT/COOL: %s\n"
1390 " HEAT: %s\n"
1391 " COOL: %s\n"
1392 " DRY: %s\n"
1393 " FAN_ONLY: %s\n"
1394 " FAN_ONLY_ACTION_USES_FAN_MODE_TIMER: %s\n"
1395 " FAN_ONLY_COOLING: %s",
1396 this->timer_[thermostat::THERMOSTAT_TIMER_IDLE_ON].time / 1000, YESNO(this->supports_auto_),
1397 YESNO(this->supports_heat_cool_), YESNO(this->supports_heat_), YESNO(this->supports_cool_),
1398 YESNO(this->supports_dry_), YESNO(this->supports_fan_only_),
1400 if (this->supports_cool_) {
1401 ESP_LOGCONFIG(TAG, " FAN_WITH_COOLING: %s", YESNO(this->supports_fan_with_cooling_));
1402 }
1403 if (this->supports_heat_) {
1404 ESP_LOGCONFIG(TAG, " FAN_WITH_HEATING: %s", YESNO(this->supports_fan_with_heating_));
1405 }
1406 ESP_LOGCONFIG(TAG,
1407 " Supported FAN MODES:\n"
1408 " ON: %s\n"
1409 " OFF: %s\n"
1410 " AUTO: %s\n"
1411 " LOW: %s\n"
1412 " MEDIUM: %s\n"
1413 " HIGH: %s\n"
1414 " MIDDLE: %s\n"
1415 " FOCUS: %s\n"
1416 " DIFFUSE: %s\n"
1417 " QUIET: %s\n"
1418 " Supported SWING MODES:\n"
1419 " BOTH: %s\n"
1420 " OFF: %s\n"
1421 " HORIZONTAL: %s\n"
1422 " VERTICAL: %s\n"
1423 " Supports TWO SET POINTS: %s",
1424 YESNO(this->supports_fan_mode_on_), YESNO(this->supports_fan_mode_off_),
1425 YESNO(this->supports_fan_mode_auto_), YESNO(this->supports_fan_mode_low_),
1426 YESNO(this->supports_fan_mode_medium_), YESNO(this->supports_fan_mode_high_),
1427 YESNO(this->supports_fan_mode_middle_), YESNO(this->supports_fan_mode_focus_),
1428 YESNO(this->supports_fan_mode_diffuse_), YESNO(this->supports_fan_mode_quiet_),
1429 YESNO(this->supports_swing_mode_both_), YESNO(this->supports_swing_mode_off_),
1431 YESNO(this->supports_two_points_));
1432
1433 if (!this->preset_config_.empty()) {
1434 ESP_LOGCONFIG(TAG, " Supported PRESETS:");
1435 for (auto &it : this->preset_config_) {
1436 const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first));
1437 ESP_LOGCONFIG(TAG, " %s:%s", preset_name, it.first == this->default_preset_ ? " (default)" : "");
1438 this->dump_preset_config_(preset_name, it.second);
1439 }
1440 }
1441
1442 if (!this->custom_preset_config_.empty()) {
1443 ESP_LOGCONFIG(TAG, " Supported CUSTOM PRESETS:");
1444 for (auto &it : this->custom_preset_config_) {
1445 const auto *preset_name = it.first.c_str();
1446 ESP_LOGCONFIG(TAG, " %s:%s", preset_name, it.first == this->default_custom_preset_ ? " (default)" : "");
1447 this->dump_preset_config_(preset_name, it.second);
1448 }
1449 }
1450}
1451
1453
1455 : default_temperature(default_temperature) {}
1456
1458 float default_temperature_high)
1459 : default_temperature_low(default_temperature_low), default_temperature_high(default_temperature_high) {}
1460
1461} // namespace thermostat
1462} // namespace esphome
BedjetMode mode
BedJet operating mode.
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void stop_action()
Stop any action connected to this trigger.
Definition automation.h:153
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:145
This class is used to encode all control actions on a climate device.
Definition climate.h:33
const optional< ClimateSwingMode > & get_swing_mode() const
Definition climate.cpp:282
const optional< std::string > & get_custom_preset() const
Definition climate.cpp:281
const optional< float > & get_target_temperature_low() const
Definition climate.cpp:275
const optional< float > & get_target_temperature() const
Definition climate.cpp:274
const optional< ClimatePreset > & get_preset() const
Definition climate.cpp:280
const optional< float > & get_target_temperature_high() const
Definition climate.cpp:276
const optional< ClimateFanMode > & get_fan_mode() const
Definition climate.cpp:278
const optional< ClimateMode > & get_mode() const
Definition climate.cpp:273
ClimateMode mode
The active mode of the climate device.
Definition climate.h:173
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:199
ClimateTraits get_traits()
Get the traits of this climate device with all overrides applied.
Definition climate.cpp:443
float target_temperature
The target temperature of the climate device.
Definition climate.h:186
float current_humidity
The current humidity of the climate device, as reported from the integration.
Definition climate.h:182
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:202
float target_temperature_low
The minimum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:189
optional< std::string > custom_preset
The active custom preset mode of the climate device.
Definition climate.h:211
float current_temperature
The current temperature of the climate device, as reported from the integration.
Definition climate.h:179
ClimateAction action
The active state of the climate device.
Definition climate.h:176
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:398
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:208
optional< ClimateDeviceRestoreState > restore_state_()
Restore the state of the climate device, call this from your setup() method.
Definition climate.cpp:329
float target_temperature_high
The maximum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:191
This class contains all static data for climate devices.
void add_supported_fan_mode(ClimateFanMode mode)
void set_supports_action(bool supports_action)
void set_supports_current_humidity(bool supports_current_humidity)
void add_supported_custom_preset(const std::string &preset)
void add_supported_preset(ClimatePreset preset)
void set_supports_two_point_target_temperature(bool supports_two_point_target_temperature)
void add_supported_mode(ClimateMode mode)
void set_supports_current_temperature(bool supports_current_temperature)
void add_supported_swing_mode(ClimateSwingMode mode)
bool has_value() const
Definition optional.h:92
value_type value_or(U const &v) const
Definition optional.h:98
value_type const & value() const
Definition optional.h:94
Base-class for all sensors.
Definition sensor.h:42
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:88
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:116
Trigger * swing_mode_off_trigger_
The trigger to call when the controller should switch the swing mode to "off".
void set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal)
Trigger * idle_action_trigger_
The trigger to call when the controller should switch to idle action/off mode.
void switch_to_action_(climate::ClimateAction action, bool publish_state=true)
Switch the climate device to the given climate action.
void set_supports_fan_mode_on(bool supports_fan_mode_on)
Trigger * preset_change_trigger_
The trigger to call when the preset mode changes.
float cooling_deadband_
Hysteresis values used for computing climate actions.
Trigger * heat_action_trigger_
The trigger to call when the controller should switch to heating action/mode.
void control(const climate::ClimateCall &call) override
Override control to change settings of the climate device.
void validate_target_temperatures(bool pin_target_temperature_high)
bool use_startup_delay_
Used to start "off" delay timers at boot.
void set_on_boot_restore_from(OnBootRestoreFrom on_boot_restore_from)
float cool_deadband()
Get current hysteresis values.
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)
bool cooling_max_runtime_exceeded_
Flags indicating if maximum allowable run time was exceeded.
const uint8_t min_timer_duration_
Minimum allowable duration in seconds for action timers.
Trigger * fan_mode_low_trigger_
The trigger to call when the controller should switch the fan to "low" speed.
OnBootRestoreFrom on_boot_restore_from_
If set to DEFAULT_PRESET then the default preset is always used.
void set_supports_two_points(bool supports_two_points)
Trigger * fan_mode_auto_trigger_
The trigger to call when the controller should switch the fan to "auto" mode.
void set_supports_fan_only_cooling(bool supports_fan_only_cooling)
bool supports_fan_mode_on_
Whether the controller supports turning on or off just the fan.
void set_supports_fan_only_action_uses_fan_mode_timer(bool fan_only_action_uses_fan_mode_timer)
float set_point_minimum_differential_
Minimum differential required between set points.
bool supports_fan_with_cooling_
Special flags – enables fan_only action to be called with cooling/heating actions.
void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse)
void switch_to_swing_mode_(climate::ClimateSwingMode swing_mode, bool publish_state=true)
Switch the climate device to the given climate swing mode.
Trigger * fan_mode_diffuse_trigger_
The trigger to call when the controller should switch the fan to "diffuse" position.
Trigger * fan_only_action_trigger_
The trigger to call when the controller should switch to fan-only action/mode.
Trigger * cool_action_trigger_
The trigger to call when the controller should switch to cooling action/mode.
Trigger * swing_mode_vertical_trigger_
The trigger to call when the controller should switch the swing mode to "vertical".
bool change_preset_internal_(const ThermostatClimateTargetTempConfig &config)
Applies the temperature, mode, fan, and swing modes of the provided config.
bool hysteresis_valid()
Set point and hysteresis validation.
void set_supports_fan_mode_auto(bool supports_fan_mode_auto)
void switch_to_supplemental_action_(climate::ClimateAction action)
Trigger * dry_action_trigger_
The trigger to call when the controller should switch to dry (dehumidification) mode.
void switch_to_mode_(climate::ClimateMode mode, bool publish_state=true)
Switch the climate device to the given climate mode.
Trigger * swing_mode_both_trigger_
The trigger to call when the controller should switch the swing mode to "both".
void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical)
void set_supports_fan_only(bool supports_fan_only)
bool supports_fan_only_action_uses_fan_mode_timer_
Special flag – enables fan_modes to share timer with fan_only climate action.
void set_supports_swing_mode_off(bool supports_swing_mode_off)
void switch_to_fan_mode_(climate::ClimateFanMode fan_mode, bool publish_state=true)
Switch the climate device to the given climate fan mode.
void dump_preset_config_(const char *preset_name, const ThermostatClimateTargetTempConfig &config)
bool supports_swing_mode_both_
Whether the controller supports various swing modes.
climate::ClimateTraits traits() override
Return the traits of this controller.
Trigger * swing_mode_horizontal_trigger_
The trigger to call when the controller should switch the swing mode to "horizontal".
Trigger * fan_mode_focus_trigger_
The trigger to call when the controller should switch the fan to "focus" position.
climate::ClimateFanMode locked_fan_mode()
Returns the fan mode that is locked in (check fan_mode_change_delayed(), first!)
void set_humidity_sensor(sensor::Sensor *humidity_sensor)
void set_supports_fan_mode_middle(bool supports_fan_mode_middle)
Trigger * temperature_change_trigger_
The trigger to call when the target temperature(s) change(es).
void set_supports_fan_mode_low(bool supports_fan_mode_low)
Trigger * fan_mode_off_trigger_
The trigger to call when the controller should switch off the fan.
bool timer_active_(ThermostatClimateTimerIndex timer_index)
float supplemental_cool_delta_
Maximum allowable temperature deltas before engaging supplemental cooling/heating actions.
std::map< std::string, ThermostatClimateTargetTempConfig > custom_preset_config_
The set of custom preset configurations this thermostat supports (eg. "My Custom Preset")
void set_supports_heat_cool(bool supports_heat_cool)
void set_supports_fan_mode_quiet(bool supports_fan_mode_quiet)
climate::ClimateAction delayed_climate_action()
Returns the climate action that is being delayed (check climate_action_change_delayed(),...
sensor::Sensor * sensor_
The sensor used for getting the current temperature.
void set_supports_fan_mode_medium(bool supports_fan_mode_medium)
uint32_t timer_duration_(ThermostatClimateTimerIndex timer_index)
void set_supports_swing_mode_both(bool supports_swing_mode_both)
void start_timer_(ThermostatClimateTimerIndex timer_index)
Start/cancel/get status of climate action timer.
Trigger * fan_mode_high_trigger_
The trigger to call when the controller should switch the fan to "high" speed.
void set_set_point_minimum_differential(float differential)
void set_custom_preset_config(const std::string &name, const ThermostatClimateTargetTempConfig &config)
bool supports_fan_mode_low_
Whether the controller supports various fan speeds and/or positions.
bool supports_fan_only_cooling_
Special flag – enables fan to be switched based on target_temperature_high.
Trigger * prev_action_trigger_
A reference to the trigger that was previously active.
bool supports_auto_
Whether the controller supports auto/cooling/drying/fanning/heating.
climate::ClimateAction supplemental_action_
The current supplemental action.
std::array< ThermostatClimateTimer, THERMOSTAT_TIMER_COUNT > timer_
Climate action timers.
void set_fan_mode_minimum_switching_time_in_sec(uint32_t time)
void set_preset_config(climate::ClimatePreset preset, const ThermostatClimateTargetTempConfig &config)
void set_supports_fan_with_cooling(bool supports_fan_with_cooling)
Trigger * fan_mode_medium_trigger_
The trigger to call when the controller should switch the fan to "medium" speed.
Trigger * fan_mode_middle_trigger_
The trigger to call when the controller should switch the fan to "middle" position.
void set_supports_fan_mode_focus(bool supports_fan_mode_focus)
void check_temperature_change_trigger_()
Check if the temperature change trigger should be called.
Trigger * fan_mode_on_trigger_
The trigger to call when the controller should switch on the fan.
void set_supports_fan_mode_off(bool supports_fan_mode_off)
climate::ClimateFanMode prev_fan_mode_
Store previously-known states.
void set_use_startup_delay(bool use_startup_delay)
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...
bool cancel_timer_(ThermostatClimateTimerIndex timer_index)
climate::ClimateAction compute_supplemental_action_()
float prev_target_temperature_
Store previously-known temperatures.
climate::ClimatePreset default_preset_
Default standard preset to use on start up.
sensor::Sensor * humidity_sensor_
The sensor used for getting the current humidity.
void cooling_max_run_time_timer_callback_()
set_timeout() callbacks for various actions (see above)
bool supports_fan_mode_auto_
Whether the controller supports fan auto mode.
climate::ClimateAction compute_action_(bool ignore_timers=false)
Re-compute the required action of this climate controller.
std::map< climate::ClimatePreset, ThermostatClimateTargetTempConfig > preset_config_
The set of standard preset configurations this thermostat supports (Eg. AWAY, ECO,...
bool supports_two_points_
Whether the controller supports two set points.
std::string default_custom_preset_
Default custom preset to use on start up.
bool setup_complete_
setup_complete_ blocks modifying/resetting the temps immediately after boot
void set_supports_fan_mode_high(bool supports_fan_mode_high)
bool idle_action_ready_()
Is the action ready to be called? Returns true if so.
void change_preset_(climate::ClimatePreset preset)
Change to a provided preset setting; will reset temperature, mode, fan, and swing modes accordingly.
void refresh()
Call triggers based on updated climate states (modes/actions)
void set_default_preset(const std::string &custom_preset)
Trigger * fan_mode_quiet_trigger_
The trigger to call when the controller should switch the fan to "quiet" position.
Trigger * heat_cool_mode_trigger_
The trigger to call when the controller should switch to heat/cool mode.
std::function< void()> timer_cbf_(ThermostatClimateTimerIndex timer_index)
Trigger * auto_mode_trigger_
The trigger to call when the controller should switch to auto mode.
bool cooling_required_()
Check if cooling/fanning/heating actions are required; returns true if so.
ClimateSwingMode swing_mode
Definition climate.h:11
uint8_t custom_preset
Definition climate.h:9
ClimateFanMode fan_mode
Definition climate.h:3
ClimatePreset preset
Definition climate.h:8
bool state
Definition fan.h:0
const LogString * climate_swing_mode_to_string(ClimateSwingMode swing_mode)
Convert the given ClimateSwingMode to a human-readable string.
const LogString * climate_preset_to_string(ClimatePreset preset)
Convert the given PresetMode to a human-readable string.
ClimatePreset
Enum for all preset modes.
@ CLIMATE_PRESET_NONE
No preset is active.
const LogString * climate_fan_mode_to_string(ClimateFanMode fan_mode)
Convert the given ClimateFanMode to a human-readable string.
ClimateSwingMode
Enum for all modes a climate swing can be in.
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_HORIZONTAL
The fan mode is set to Horizontal.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
@ CLIMATE_SWING_BOTH
The fan mode is set to Both.
ClimateMode
Enum for all modes a climate device can be in.
@ CLIMATE_MODE_DRY
The climate device is set to dry/humidity mode.
@ CLIMATE_MODE_FAN_ONLY
The climate device only has the fan enabled, no heating or cooling is taking place.
@ CLIMATE_MODE_HEAT
The climate device is set to heat to reach the target temperature.
@ CLIMATE_MODE_COOL
The climate device is set to cool to reach the target temperature.
@ CLIMATE_MODE_HEAT_COOL
The climate device is set to heat/cool to reach the target temperature.
@ CLIMATE_MODE_OFF
The climate device is off.
@ CLIMATE_MODE_AUTO
The climate device is adjusting the temperature dynamically.
const LogString * climate_mode_to_string(ClimateMode mode)
Convert the given ClimateMode to a human-readable string.
ClimateAction
Enum for the current action of the climate device. Values match those of ClimateMode.
@ CLIMATE_ACTION_OFF
The climate device is off (inactive or no power)
@ CLIMATE_ACTION_IDLE
The climate device is idle (monitoring climate but no action needed)
@ CLIMATE_ACTION_DRYING
The climate device is drying.
@ CLIMATE_ACTION_HEATING
The climate device is actively heating.
@ CLIMATE_ACTION_COOLING
The climate device is actively cooling.
@ CLIMATE_ACTION_FAN
The climate device is in fan only mode.
@ CLIMATE_FAN_MEDIUM
The fan mode is set to Medium.
@ CLIMATE_FAN_DIFFUSE
The fan mode is set to Diffuse.
@ CLIMATE_FAN_ON
The fan mode is set to On.
@ CLIMATE_FAN_AUTO
The fan mode is set to Auto.
@ CLIMATE_FAN_FOCUS
The fan mode is set to Focus.
@ CLIMATE_FAN_LOW
The fan mode is set to Low.
@ CLIMATE_FAN_MIDDLE
The fan mode is set to Middle.
@ CLIMATE_FAN_QUIET
The fan mode is set to Quiet.
@ CLIMATE_FAN_OFF
The fan mode is set to Off.
@ CLIMATE_FAN_HIGH
The fan mode is set to High.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.
optional< climate::ClimateSwingMode > swing_mode_
uint16_t temperature
Definition sun_gtil2.cpp:12