Thermostat with PID controller

You can use something like that :

SELECT mean("current_temperature") AS "mean_current_temperature", mean("control_output") AS "mean_control_output", mean("temperature") AS "mean_temperature" FROM "home_assistant"."autogen"."state" WHERE time > :dashboardTime: AND time < :upperDashboardTime: AND "entity_id"='salle_de_bain' GROUP BY time(:interval:) FILL(null)

I generated a new beta release with services to set the PID gains, set the preset modes temperatures and clear the integral component of the PID.
These changes will ease the tuning of the PID, allowing to adjust the gains without requiring a restart.

It also adds a unique_id parameter to be able to customize the entity through UI.

Hey guys, any idea how to export the data from home assistant to use them in ?

If you have an external SQL database, you can export it in its web visualisation tool (like chronograf for InfluxDB).

Otherwise you may use an automation to write a CSV file at each status update of the thermostat, as explained here :

Is this smart thermostat also suitable for multi zone heating?
I have underfloor heating (hot water in concrete) and currently I am running 7 generic thermostats. I have a little overshoot (0,5 degree celsius), usually reaching that after 1,5-2 hours after reaching target temperature.
So for instance, if I have a schedule to heat to 22, if I reach 22 at 6 PM, usually between 7-8 PM, it would rise up to 22,5 degree celsius.
Anyhow, the way I have my thermostats defined right now is that for the heater - I specify switch that opens/closes acutators to let the hot water in to the zone. Those valves themselves take 2-3 minutes to fully open, around the same time to close. On the top of it, I run automation every minute to check if any of the zones is opened and if yes, give signal to heat pump.
The problem is that heatpump has its own cycles. If you send the signal for heat, it won’t start immediately so for instance if I have zone opened for one hour, that does not mean that pump is delivering 100% of power for one hour as there is water pump that cycles water, checks inlet water temperature and compares it to set value.
I have replaced those thermostats with smart thermostats, without any further checking/tuning, and what I ended up with was zones opening ocasionally for few minutes, resulting in giving signal to heat pump to start heating, which took between 1-9 minutes, which isn’t ideal.

So I am wondering if anyone here is using it in combination with multi zone heating and “master switch” to give signal to heater.

Hello, it should work, but you should set the min_cycle_duration parameter to more than 10 minutes to ensure the system will heat up.
You may also use min_off_cycle_duration to differentiate if the time to switch off is shorter or longer than the time to switch on.

You may also give a try to Multizone Thermostat
which is similar but that can drive a master.

Thanks adrien.b, I looked at that too but so far it seems less “trustworthy” to me :slight_smile:
Thinking out loud, if I set min_cycle_duration to 30 minutes, it means that should zone require heat (setpoint is higher than actual temperature), it will open valves for zone for 30 minutes (or more), and in the same manner min_off_cycle_duration will specify how long it is off and won’t turn back on.
What will the end result be in terms of “hvac_action”? Will it go to idle, or stay in “heating”.
I am asking to find the best fit for that extra automation.

For example. 8 AM, I have scheduler to set target temperature to 24, and current temperature is 21. It should open valves for zone and keep them opened for at least 30 minutes. From experience I know that temperature won’t rise significantly after 30 minutes, so I might have 21,2 degrees.
In theory then valves should remain open and hvac_action will still be “heating” (until all this dynamic magic determines that they should be closed). Once that decision is made, and valves close, hvac action will result in “idle” (with or without target temperature reached yet). At that point, valves will remain closed for at least 30 minutes. My extra automation will turn off heater because zone will close).

What will happen after those 30 minutes if target temperature is not reached yet? Will it turn on another on cycle for next 30 minutes?

Or am I overshooting it with 30 minutes? That’s why I was wondering if anyone actually has any experience.
Also are there any recommended values to define for slow heating like concrete underfloor heating? I just used configuration from example

      seconds: 60
    away_temp: 14
    kp : 5
    ki : 0.01
    kd : 500
    pwm : 00:15:00

Please note that the min_cycle_duration should not be set to the time it takes for the temperature to rise, but to the time it takes for your heating system to settle. For your underfloor heating it would be for example the time for the water return to be at the expected temperature (for example, some circulators uses the delta-T between water output and return to adjust the speed), ensuring optimal heat distribution in the loops.
It may take 10 to 15 minutes only. Then the min_cycle_duration will ensure the heat will be distributed correctly.
The on time will then be adjusted by the PID based on the PWM duration. As the underfloor heating is very slow, you should increase the PWM to 30 to 60 minutes.
For example, using min_cycle_duration at 15mn and pwm to 60mn :

  • If PID output is 5%, meaning 0.05 * 60 = 3 minutes, the heater will switch on but the min_cycle_duration will force it to remain on during 15 minutes.
  • If PID output is 33%, meaning 0.33 * 60 = 20 minutes, the heater will switch on for 20 minutes.

You can see the min_cycle_duration will limit the lower power the thermostat will be able to modulate, that’s why it should be kept as low as possible.

For the Kp, Ki and Kd gains, you may look at the history charts you got with the generic thermostat to extract the amplitude and period, and compute by hand the ultimate and final gains as explained in this post on my Github :

It works quite well.

Thanks. I started with one room and will monitor how it goes:

- platform: smart_thermostat
  name: Office
  unique_id: office_smart_thermostat
  heater: switch.heating_4
  target_sensor: sensor.temperature_4
  min_temp: 17
  max_temp: 28
  ac_mode: false
  target_temp: 21
    minutes: 3
  away_temp: 17
  min_cycle_duration: 00:20:00
#  min_off_cycle_duration: 00:10:00
  kp : 7.493
  ki : 0.009366
  kd : 1498.6
  pwm : 01:00:00

First attempt wasn’t really ideal. As you can see from graph below, while last 2 days, heating usually started at 6 AM where I have my set temp changed from 21,5 to 22 - heating was on for 2,5 - 3 hours.
Today with config above, at 6 AM it started, and lasted until 1:30 PM (on and off). By heating I mean valves that were opening/closing. Also heating after temperature was already above set point. Any advice?

In my opinion, your minimum cycle duration is too long Vs your PWM. So you’ll only have 30% minimum power.
Try to double the PWM, and you should monitor the p, i and d attributes to see which one compensates each other. You may need to increase the kd for an early stop when the temperature starts to increase.

However, it’s not really recommended to decrease the temperature during the night on a floor heating, the inertia being huge, the little saving you gain during the night is compensated by the longer heating period to bring it back to comfort temperature in the morning.

You are right. The overshoot isn’t really huge, and as it can be seen from the graph, once heated in the morning, temperature lasts throughout the day.
But it keeps me entertained :slight_smile: I will double the pwm and observe results.

1°C amplitude between the minimum and the maximum is big. By experience, when sitting in the sofa, watching TV, a -0.5°C variation can make it really uncomfortable. That’s why I bought my Netatmo thermostat that features a PID. And this thermostat gave me the idea to use a PID in the generic thermostat from HA.

With a PID, and once correctly tuned, you can get a ±0.1°C oscillation around the set point, and it’s particularly interesting with systems with big inertia.

Strange issue with v2021.12.2-beta4:

The set temperature reverts to 22 after changing it. No presets active. Also, upon restart, set temperature dropped to 18.
Also “on” time is dubious.
Any thoughts?


- platform: smart_thermostat
  name: Heating
  unique_id: climate.heating
  heater: switch.heater
  target_sensor: sensor.temperature
  keep_alive: 60
  kp: 10
  ki: 0.01
  kd: 1000
  pwm: 600
  min_cycle_duration: 300
  min_off_cycle_duration: 120
  sampling_period: 300
  force_pid_refresh: 60
  target_temp_step: 0.1
  precision: 0.1
  min_temp: 7
  max_temp: 35
  ac_mode: false
  away_temp: 18
  eco_temp: 20
  boost_temp: 24
  comfort_temp: 22
  home_temp: 21.6
  sleep_temp: 21.8
  activity_temp: 21.4

Hello, the set temperature reverting to 22 is really strange. Is there a time commonality (reverting every X seconds) ? Did you try without the force_pid_refresh setting ?
Please check there is no scheduler or automation that could refresh the set point of the thermostat, too.

Regarding the on time, it’s due to the force_pid_refresh parameter that forces computing the PID, and as the PID output value is different, the PWM is refreshed more often. If you really need to refresh the PID (it’s to help working with very slow sensors), you should set it at least to half the sampling_period.

Here is today after changing PWM to 2 hours. Little less overshoot, heating shorter in few longer cycles, compared to yesterday.

Here is also PID data from last 24 hours

And different graph for temperature (set vs. measured, I am not sure how to put hvac_action there using influxDB as it is “undefined” because of being string I guess?)

I would appreciate advice, as I honestly have no clue how this works :slight_smile: I did increase kd from 1498.6 to 1900… just as a guess

Interesting, when your set point rises, the PID_P remains almost flat : if you do large set point variations, you need bigger kp to react fast. I would say multiply P, let’s set it to 70.
Your PID_I is increasing quite fast, with larger kp it will increase the overshoot, I would recommend to decrease ki to 0.004.
And PID_D is totally flat while your temperature takes 0.5°C in 3 hours with 50% output. Let’s boost that kd to 50000 to see how it behaves.
Use the set_pid_gain service to set the values, so that you don’t need to restart HA.

1 Like

I am fine with reboot, but I will use service in the future. I set them accordingly, will monitor tomorrow. Thank you for having patience with me.

Kp: 70
Ki: 0.004
Kd: 50000

I assume that this tuning would be unique for each zone if I decide to convert other generic thermostats? Or I could apply same settings to others as well? Because so far, I am still catching up and do not quite understand what has influence on things.

1 Like

The gains depends on the heating system (type, power…), the volume of the room and the insulation of the house.
So as far it’s in the same house with same heating source and the room volume is similar, the settings should just match.

You’ll find in the readme on GitHub some useful links explaining how a PID is working.

Hi. Removing the force_pid_refresh fixed the “on” time problem. I don’t know about the set temperature reverting to 22. Thanks!

Regarding the new service in latest beta (set_pid_mode), by turning off PID the thermostat behaves like a generic thermostat, how can the “cold_tolerance” and “hot_tolerance” parameters be set? I don’t see any equivalent in smart_thermostat.