ESPHome 2025.9.0-dev
Loading...
Searching...
No Matches
pid_climate.cpp
Go to the documentation of this file.
1#include "pid_climate.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace pid {
6
7static const char *const TAG = "pid.climate";
8
10 this->sensor_->add_on_state_callback([this](float state) {
11 // only publish if state/current temperature has changed in two digits of precision
12 this->do_publish_ = roundf(state * 100) != roundf(this->current_temperature * 100);
14 this->update_pid_();
15 });
16 this->current_temperature = this->sensor_->state;
17
18 // register for humidity values and get initial state
19 if (this->humidity_sensor_ != nullptr) {
20 this->humidity_sensor_->add_on_state_callback([this](float state) {
21 this->current_humidity = state;
22 this->publish_state();
23 });
25 }
26
27 // restore set points
28 auto restore = this->restore_state_();
29 if (restore.has_value()) {
30 restore->to_call(this).perform();
31 } else {
32 // restore from defaults, change_away handles those for us
33 if (supports_heat_() && supports_cool_()) {
35 } else if (supports_cool_()) {
37 } else if (supports_heat_()) {
39 }
41 }
42}
44 if (call.get_mode().has_value())
45 this->mode = *call.get_mode();
46 if (call.get_target_temperature().has_value())
48
49 // If switching to off mode, set output immediately
51 this->write_output_(0.0f);
52
53 this->publish_state();
54}
75 LOG_CLIMATE("", "PID Climate", this);
76 ESP_LOGCONFIG(TAG,
77 " Control Parameters:\n"
78 " kp: %.5f, ki: %.5f, kd: %.5f, output samples: %d",
79 controller_.kp_, controller_.ki_, controller_.kd_, controller_.output_samples_);
80
81 if (controller_.threshold_low_ == 0 && controller_.threshold_high_ == 0) {
82 ESP_LOGCONFIG(TAG, " Deadband disabled.");
83 } else {
84 ESP_LOGCONFIG(TAG,
85 " Deadband Parameters:\n"
86 " threshold: %0.5f to %0.5f, multipliers(kp: %.5f, ki: %.5f, kd: %.5f), "
87 "output samples: %d",
88 controller_.threshold_low_, controller_.threshold_high_, controller_.kp_multiplier_,
89 controller_.ki_multiplier_, controller_.kd_multiplier_, controller_.deadband_output_samples_);
90 }
91
92 if (this->autotuner_ != nullptr) {
93 this->autotuner_->dump_config();
94 }
95}
96void PIDClimate::write_output_(float value) {
97 this->output_value_ = value;
98
99 // first ensure outputs are off (both outputs not active at the same time)
100 if (this->supports_cool_() && value >= 0)
101 this->cool_output_->set_level(0.0f);
102 if (this->supports_heat_() && value <= 0)
103 this->heat_output_->set_level(0.0f);
104
105 // value < 0 means cool, > 0 means heat
106 if (this->supports_cool_() && value < 0)
107 this->cool_output_->set_level(std::min(1.0f, -value));
108 if (this->supports_heat_() && value > 0)
109 this->heat_output_->set_level(std::min(1.0f, value));
110
111 // Update action variable for user feedback what's happening
112 climate::ClimateAction new_action;
113 if (this->supports_cool_() && value < 0) {
115 } else if (this->supports_heat_() && value > 0) {
117 } else if (this->mode == climate::CLIMATE_MODE_OFF) {
118 new_action = climate::CLIMATE_ACTION_OFF;
119 } else {
120 new_action = climate::CLIMATE_ACTION_IDLE;
121 }
122
123 if (new_action != this->action) {
124 this->action = new_action;
125 this->do_publish_ = true;
126 }
127 this->pid_computed_callback_.call();
128}
130 float value;
131 if (std::isnan(this->current_temperature) || std::isnan(this->target_temperature)) {
132 // if any control parameters are nan, turn off all outputs
133 value = 0.0;
134 } else {
135 // Update PID controller irrespective of current mode, to not mess up D/I terms
136 // In non-auto mode, we just discard the output value
137 value = this->controller_.update(this->target_temperature, this->current_temperature);
138
139 // Check autotuner
140 if (this->autotuner_ != nullptr && !this->autotuner_->is_finished()) {
141 auto res = this->autotuner_->update(this->target_temperature, this->current_temperature);
142 if (res.result_params.has_value()) {
143 this->controller_.kp_ = res.result_params->kp;
144 this->controller_.ki_ = res.result_params->ki;
145 this->controller_.kd_ = res.result_params->kd;
146 // keep autotuner instance so that subsequent dump_configs will print the long result message.
147 } else {
148 value = res.output;
149 }
150 }
151 }
152
153 if (this->mode == climate::CLIMATE_MODE_OFF) {
154 this->write_output_(0.0);
155 } else {
156 this->write_output_(value);
157 }
158
159 if (this->do_publish_)
160 this->publish_state();
161}
162void PIDClimate::start_autotune(std::unique_ptr<PIDAutotuner> &&autotune) {
163 this->autotuner_ = std::move(autotune);
164 float min_value = this->supports_cool_() ? -1.0f : 0.0f;
165 float max_value = this->supports_heat_() ? 1.0f : 0.0f;
166 this->autotuner_->config(min_value, max_value);
167 this->autotuner_->set_autotuner_id(this->get_object_id());
168
169 ESP_LOGI(TAG,
170 "%s: Autotune has started. This can take a long time depending on the "
171 "responsiveness of your system. Your system "
172 "output will be altered to deliberately oscillate above and below the setpoint multiple times. "
173 "Until your sensor provides a reading, the autotuner may display \'nan\'",
174 this->get_object_id().c_str());
175
176 this->set_interval("autotune-progress", 10000, [this]() {
177 if (this->autotuner_ != nullptr && !this->autotuner_->is_finished())
178 this->autotuner_->dump_config();
179 });
180
182 ESP_LOGW(TAG, "%s: !!! For PID autotuner you need to set AUTO (also called heat/cool) mode!",
183 this->get_object_id().c_str());
184 }
185}
186
188
189} // namespace pid
190} // namespace esphome
void set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.cpp:89
std::string get_object_id() const
This class is used to encode all control actions on a climate device.
Definition climate.h:33
const optional< float > & get_target_temperature() const
Definition climate.cpp:274
const optional< ClimateMode > & get_mode() const
Definition climate.cpp:273
ClimateMode mode
The active mode of the climate device.
Definition climate.h:173
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
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:395
optional< ClimateDeviceRestoreState > restore_state_()
Restore the state of the climate device, call this from your setup() method.
Definition climate.cpp:329
This class contains all static data for climate devices.
void set_supported_modes(std::set< ClimateMode > modes)
void set_supports_action(bool supports_action)
void set_supports_current_humidity(bool supports_current_humidity)
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 set_level(float state)
Set the level of this float output, this is called from the front-end.
void start_autotune(std::unique_ptr< PIDAutotuner > &&autotune)
PIDController controller_
Definition pid_climate.h:95
output::FloatOutput * cool_output_
Definition pid_climate.h:93
sensor::Sensor * sensor_
The sensor used for getting the current temperature.
Definition pid_climate.h:90
void dump_config() override
bool supports_cool_() const
Definition pid_climate.h:84
void write_output_(float value)
void setup() override
std::unique_ptr< PIDAutotuner > autotuner_
void control(const climate::ClimateCall &call) override
Override control to change settings of the climate device.
CallbackManager< void()> pid_computed_callback_
Definition pid_climate.h:98
float output_value_
Output value as reported by the PID controller, for PIDClimateSensor.
Definition pid_climate.h:97
sensor::Sensor * humidity_sensor_
The sensor used for getting the current humidity.
Definition pid_climate.h:92
climate::ClimateTraits traits() override
Return the traits of this controller.
bool supports_heat_() const
Definition pid_climate.h:85
output::FloatOutput * heat_output_
Definition pid_climate.h:94
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:60
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:133
bool state
Definition fan.h:0
@ 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.
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_HEATING
The climate device is actively heating.
@ CLIMATE_ACTION_COOLING
The climate device is actively cooling.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
float update(float setpoint, float process_value)