I am trying to use the climate PID for heating, I have a valve that uses a servo for opening and closing the heat from a heatpump.
I can manually control the servo from ESPhome with the servo component.
And I thought I can just place that ID of the servo in the heat_output: of the climate PID as it is also a 0 to 100% value I use for the servo. But I get this error:
‘ID ‘my_servo’ of type servo::Servo doesn’t inherit from output::FloatOutput. Please double check your ID is pointing to the correct value.’
When I try it with a PWM output it does not give me the error. But of course that wont turn the servo, on the pin I selected in the PWM output and connected the servo to.
So how can I use the servo as the PWM in the climate controller?
I tried some things with the number component I use for controlling the servo, using that ID. But no luck, I am not a programmer. So I am now hitting a wall, and no idea on how to get it working. I have a feeling it can’t be that hard… if you know how ofcourse…
It is using a template output to hold the value emitted by heat_output. When a new value is written, the write_action will be invoked. Here you can control the servo with servo.write.
I don’t know what the output range is from heat_output. Default seems to be 0%…100% (which translates to 0.0…1.0). The servo range is -1.0…1.0 so, the code maps the heat output value to the servo’s range.
If the range is different, you can calculate it with the following linear conversion: ((state - heat_output_min) / (heat_output_max - heat_output_min)) * (servo_max - servo_min) + servo_min
I have now this code, but my servo is not 100% ok. So waiting on a new servo head. But maybe this helps others, or maybe somebody spot’s some improvement points.
esphome:
name: PID_Control
esp8266:
board: d1_mini
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
web_server:
port: 80
dallas:
- pin: D2
number:
- platform: template
name: Servo Control
min_value: -100
initial_value: 0
max_value: 100
step: 1
optimistic: true
mode: box
set_action:
then:
- servo.write:
id: my_servo
level: !lambda 'return x / 100.0;'
sensor:
- platform: template
name: servo sensor position
id: servo_sensor
- platform: dallas
address: 0x483c01e076aeaf28
name: "Temperature"
id: temperature
- platform: template
name: p term
id: p_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: i term
id: i_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: d term
id: d_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: output value
unit_of_measurement: "%"
id: o_term
accuracy_decimals: 2
- platform: template
name: error value
id: e_term
accuracy_decimals: 2
- platform: template
name: is in deadband
id: in_deadband_term
accuracy_decimals: 0
# Take the "HEAT" value of the pid and send
# it to the frontend to graph the output voltage
- platform: pid
name: "HEAT Output PWM"
climate_id: console_thermostat
type: HEAT
output:
- platform: esp8266_pwm
id: pwm_output
pin: D3
frequency: 50 Hz
- platform: template
id: heat_output_float
type: float
write_action:
- servo.write:
id: my_servo
level: !lambda |-
return 2*state - 1; // converts range [0,1] to [-1,1]
- sensor.template.publish:
id: servo_sensor
state: !lambda |-
return 2*state - 1;
servo:
- id: my_servo
output: pwm_output
climate:
- platform: pid
name: "Thermostat"
id: console_thermostat
sensor: temperature
default_target_temperature: 25°C
heat_output: heat_output_float
# ON state change, publish the values to the x_term numbers defined
# above, so that they can be viewed in HA
on_state:
- sensor.template.publish:
id: p_term
state: !lambda 'return -id(console_thermostat).get_proportional_term() * 100.0;'
- sensor.template.publish:
id: i_term
state: !lambda 'return -id(console_thermostat).get_integral_term()* 100.0;'
- sensor.template.publish:
id: d_term
state: !lambda 'return -id(console_thermostat).get_derivative_term()* 100.0;'
- sensor.template.publish:
id: o_term
state: !lambda 'return -id(console_thermostat).get_output_value()* 100.0;'
- sensor.template.publish:
id: in_deadband_term
state: !lambda 'return id(console_thermostat).in_deadband();'
- sensor.template.publish:
id: e_term
state: !lambda 'return -id(console_thermostat).get_error_value();'
# The extents of the HA Thermostat
visual:
min_temperature: 10 °C
max_temperature: 30 °C
control_parameters:
kp: 0.6
ki: 0.0015
kd: 0
max_integral: 0.0
output_averaging_samples: 1
derivative_averaging_samples: 5
switch:
# Expose an ESP restart button to HA
- platform: restart
name: ESP Restart
id: pid_restart