diff --git a/esphome/components/pid/climate.py b/esphome/components/pid/climate.py index 97a98efc20..446c614f14 100644 --- a/esphome/components/pid/climate.py +++ b/esphome/components/pid/climate.py @@ -8,6 +8,7 @@ pid_ns = cg.esphome_ns.namespace('pid') PIDClimate = pid_ns.class_('PIDClimate', climate.Climate, cg.Component) PIDAutotuneAction = pid_ns.class_('PIDAutotuneAction', automation.Action) PIDResetIntegralTermAction = pid_ns.class_('PIDResetIntegralTermAction', automation.Action) +PIDSetControlParametersAction = pid_ns.class_('PIDSetControlParametersAction', automation.Action) CONF_DEFAULT_TARGET_TEMPERATURE = 'default_target_temperature' @@ -90,3 +91,28 @@ def esp8266_set_frequency_to_code(config, action_id, template_arg, args): cg.add(var.set_positive_output(config[CONF_POSITIVE_OUTPUT])) cg.add(var.set_negative_output(config[CONF_NEGATIVE_OUTPUT])) yield var + + +@automation.register_action( + 'climate.pid.set_control_parameters', + PIDSetControlParametersAction, + automation.maybe_simple_id({ + cv.Required(CONF_ID): cv.use_id(PIDClimate), + cv.Required(CONF_KP): cv.templatable(cv.float_), + cv.Optional(CONF_KI, default=0.0): cv.templatable(cv.float_), + cv.Optional(CONF_KD, default=0.0): cv.templatable(cv.float_), + }) +) +def set_control_parameters(config, action_id, template_arg, args): + paren = yield cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + + kp_template_ = yield cg.templatable(config[CONF_KP], args, float) + cg.add(var.set_kp(kp_template_)) + + ki_template_ = yield cg.templatable(config[CONF_KI], args, float) + cg.add(var.set_ki(ki_template_)) + + kd_template_ = yield cg.templatable(config[CONF_KD], args, float) + cg.add(var.set_kd(kd_template_)) + yield var diff --git a/esphome/components/pid/pid_climate.h b/esphome/components/pid/pid_climate.h index 12436e225c..f11d768867 100644 --- a/esphome/components/pid/pid_climate.h +++ b/esphome/components/pid/pid_climate.h @@ -29,6 +29,9 @@ class PIDClimate : public climate::Climate, public Component { float get_output_value() const { return output_value_; } float get_error_value() const { return controller_.error; } + float get_kp() { return controller_.kp; } + float get_ki() { return controller_.ki; } + float get_kd() { return controller_.kd; } float get_proportional_term() const { return controller_.proportional_term; } float get_integral_term() const { return controller_.integral_term; } float get_derivative_term() const { return controller_.derivative_term; } @@ -101,5 +104,27 @@ template class PIDResetIntegralTermAction : public Action PIDClimate *parent_; }; +template class PIDSetControlParametersAction : public Action { + public: + PIDSetControlParametersAction(PIDClimate *parent) : parent_(parent) {} + + void play(Ts... x) { + auto kp = this->kp_.value(x...); + auto ki = this->ki_.value(x...); + auto kd = this->kd_.value(x...); + + this->parent_->set_kp(kp); + this->parent_->set_ki(ki); + this->parent_->set_kd(kd); + } + + protected: + TEMPLATABLE_VALUE(float, kp) + TEMPLATABLE_VALUE(float, ki) + TEMPLATABLE_VALUE(float, kd) + + PIDClimate *parent_; +}; + } // namespace pid } // namespace esphome diff --git a/esphome/components/pid/sensor/__init__.py b/esphome/components/pid/sensor/__init__.py index cfab23d204..ff8cf15eb5 100644 --- a/esphome/components/pid/sensor/__init__.py +++ b/esphome/components/pid/sensor/__init__.py @@ -15,6 +15,9 @@ PID_CLIMATE_SENSOR_TYPES = { 'DERIVATIVE': PIDClimateSensorType.PID_SENSOR_TYPE_DERIVATIVE, 'HEAT': PIDClimateSensorType.PID_SENSOR_TYPE_HEAT, 'COOL': PIDClimateSensorType.PID_SENSOR_TYPE_COOL, + 'KP': PIDClimateSensorType.PID_SENSOR_TYPE_KP, + 'KI': PIDClimateSensorType.PID_SENSOR_TYPE_KI, + 'KD': PIDClimateSensorType.PID_SENSOR_TYPE_KD, } CONF_CLIMATE_ID = 'climate_id' diff --git a/esphome/components/pid/sensor/pid_climate_sensor.cpp b/esphome/components/pid/sensor/pid_climate_sensor.cpp index 6241a139f6..f60627b6ac 100644 --- a/esphome/components/pid/sensor/pid_climate_sensor.cpp +++ b/esphome/components/pid/sensor/pid_climate_sensor.cpp @@ -35,6 +35,18 @@ void PIDClimateSensor::update_from_parent_() { case PID_SENSOR_TYPE_COOL: value = clamp(-this->parent_->get_output_value(), 0.0f, 1.0f); break; + case PID_SENSOR_TYPE_KP: + value = this->parent_->get_kp(); + this->publish_state(value); + return; + case PID_SENSOR_TYPE_KI: + value = this->parent_->get_ki(); + this->publish_state(value); + return; + case PID_SENSOR_TYPE_KD: + value = this->parent_->get_kd(); + this->publish_state(value); + return; default: value = NAN; break; diff --git a/esphome/components/pid/sensor/pid_climate_sensor.h b/esphome/components/pid/sensor/pid_climate_sensor.h index 85759f1eaf..f3774610f8 100644 --- a/esphome/components/pid/sensor/pid_climate_sensor.h +++ b/esphome/components/pid/sensor/pid_climate_sensor.h @@ -14,6 +14,9 @@ enum PIDClimateSensorType { PID_SENSOR_TYPE_DERIVATIVE, PID_SENSOR_TYPE_HEAT, PID_SENSOR_TYPE_COOL, + PID_SENSOR_TYPE_KP, + PID_SENSOR_TYPE_KI, + PID_SENSOR_TYPE_KD, }; class PIDClimateSensor : public sensor::Sensor, public Component { diff --git a/tests/test3.yaml b/tests/test3.yaml index ef464fd5b7..3854a528f4 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -169,6 +169,13 @@ api: then: - tm1651.turn_off: id: tm1651_battery + - service: pid_set_control_parameters + then: + - climate.pid.set_control_parameters: + id: pid_climate + kp: 1.0 + kd: 1.0 + ki: 1.0 wifi: ssid: 'MySSID' @@ -681,6 +688,17 @@ climate: away_config: default_target_temperature_low: 16°C default_target_temperature_high: 20°C + - platform: pid + id: pid_climate + name: "PID Climate Controller" + sensor: ha_hello_world + default_target_temperature: 21°C + heat_output: my_slow_pwm + control_parameters: + kp: 0.0 + ki: 0.0 + kd: 0.0 + cover: - platform: endstop @@ -761,6 +779,11 @@ output: id: dimmer1 gate_pin: GPIO5 zero_cross_pin: GPIO12 + - platform: slow_pwm + pin: GPIO5 + id: my_slow_pwm + period: 15s + mcp23017: id: mcp23017_hub