Thermostat with PID controller

I too would like to control my floor heating with a PID thermostat.
It’s water based and the valve needs about 3 minutes to open/close.

I thinkt the correct values are:

  minutes: 3
  minutes: 15

Which version would you recommend? Dev or master?
Which PID values would you recommend to start with?

Thanks for your answer.

Thanks for your work on this!

Hello, I’m new in Home Assistant and I’m try to learn the yaml language. I alredy do a servo control with a slider, and my goal is regulate the position of the servo with the PID control. I don’t now exactly if I can do that with this integration because I don’t know how to get the output value of the PID.
I’m in the wrong way?


It seems the development of this thermostat is stopped

I tried to use it to control a towel dryer in the bathroom using a pilot wire switching between comfort and OFF modes.
The control seems OK, but the autotune leaded to ZeroDivisionError exception, so it couldn’t adjust the PID parameters automatically.

I used the following configuration (I had to comment the initial_operation_mode parameter, it seems it doesn’t exist in the integration) :

- platform: smart_thermostat
  name: salle_de_bain
  heater: switch.seche_serviette
  target_sensor: sensor.popp_mold_salle_de_bain_temperature
  min_temp: 7
  max_temp: 30
  ac_mode: False
  target_temp: 24
  seconds: 5
  # initial_operation_mode: "off"
  kp : 5
  ki : 3
  kd : 2
  pwm : 1
  autotune : ziegler-nichols
  difference : 100
  noiseband : 0.5

Error message :

2021-10-01 20:37:32 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/config/custom_components/smart_thermostat/", line 433, in _async_control_heating
await self.calc_output()
File "/config/custom_components/smart_thermostat/", line 476, in calc_output
params = self.pidAutotune.get_pid_parameters(self.autotune)
File "/config/custom_components/smart_thermostat/pid_controller/", line 188, in get_pid_parameters
ki = kp / (self._Pu / divisors[1])
ZeroDivisionError: float division by zero

I ended up using the generic thermostat for the moment, I’ll try to manually adjust the PID parameters using rule of thumb method as described here : in order to measure and compensate the inertia.

Hi adrien.b,

the autotune never worked correctly and, to my knowledge, was created for brewing.
I see two options currently:

  1. You use the version in the master branch with the values @MudiStar suggested.
  2. You use the version in the dev branch with the values @fabian.n suggested.

As the heating period starts now, I will try both out and report my findings.

I used PID tuner to provide my heater/temperature data vs time and compute some values. It gave me the following :

  kp : 4.672847736461644
  ki : 0.0008760855108256681
  kd : 5025.328799581739

I’ll see how it works

1 Like

Hi Adrien,

Last winter I’ve been creating an update based on this PID thermostat and another thermostat routine (which unfortunately was not released in HA) and expanded it as I needed a zoned heating system (but it still can be used as a single standalone thermostat). You could have a look zoned heating here including some additional explanation about the PID settings in the readme file. I’ve been using it for the last year (and performs quite well to my needs at least).

Regarding the autotune I found it to be tricky, especially for slow varying systems and the large influence of the weather. However I’ve still included the option but did not test it.

I’m trying to control underfloor heating and every room has it’s own temperature sensor and wax actuator. All I have is controlling the actuator to set the temperature. The system is very slow and needs constant pulsing so the floors don’t’ get too cold or too hot. The concrete floors hold so much temperature that if I’m not careful close to the set point then I overshoots by 2°c or so and the temperature in the room is rising for hours after I have turned off the vax actuators.

Hi Stefan

Great question. I am planning a similar application myself (haven’t started yet) but I do have a control engineering education.

Based on your description it sounds like you have a large delay in your system (caused by the concrete heat reservoir between the heat source and the room temperature to be controlled) or possibly a second-order system.

Controlling systems of these types, especially those with delays, is tricky! If you’re not careful, the combined (closed-loop) system with your controller could be unstable, although it sounds like you have already made some good intuitive decisions.

Here are a few pointers which may help:

  1. The biggest practical problem with PI/PID control is the various different conventions for defining the two/three parameters. In the following notes, I am using the interacting formulation (as opposed to non-interactive or parallel conventions). They are all mathematically equivalent, it’s just that the parameter values are defined differently in each, so you need to be very careful which convention you are implementing.

  2. To control a simple system with a stable exponential dynamic (known as a first-order system), including those with a delay, you only need a PI controller (i.e. no derivative term).

  3. A simple but reliable heuristic for setting a PI controller for a first-order system with a delay is:

Kc = (1 / Kp) x (T1 / (T1 + theta) )
Ti = T1


Kc = PI controller gain
Ti = PI controller integration time constant (units of time)
Kp = process gain (of the heating process)
T1 = time constant of the process (units of time)
theta = delay of the process.

While this calculation is easy, what you need are good estimates of Kp, T1 and theta. These you can get by doing a step test of your system, provided you can run it in open loop (i.e. manual with no feedback controller). It’s broadly known as system identification but a step test would suffice:

Step 1. Wait until your system reaches an equilibrium point with the heater off or at a constant setting
Step 2. Make a step change in the heater setting (higher or lower) and record the response of your system (i.e. the room temperature) until it reaches a new equilibrium, which could take a while in your case.

Kp = (T2 - T1) / (H2 - H1) where T1, T2 and H1, H2 are the initial and final temperatures, heater settings (e.g. a temp close to the region in which you want to control).
theta = you can probably estimate this as the time from when the heater setting changed to the first indication that the temperature clearly started to change.

T1 = (t_63% - t_step - theta) where t_step is the time when the step change to the input was made, and t_63% is the time when the room temperature reached 63% of it’s final equilibrium temperature (i.e. 0.63*T2).

  1. If this doesn’t work a more advanced solution to control your system would be possible if you have a temperature measurement for the concrete floor. It sounds like the dynamic between the heater and the floor temperature may be faster than the dynamic between the floor temperature and the room temperature, (I am speculating, but this could be why you are experiencing overshooting of the room temperature). If you can get this extra measurement then you could implement a cascade control system (two control loops running at different sampling rates) which should solve that problem. But this may not be necessary if the PI solution above gives you good enough performance.

Hope this helps! I would be happy to discuss further offline since I will probably be encountering the same problems myself. Feel free to message me directly.


All my tentatives to make the smart thermostat work in my bathroom fails. I tried with different combinations of pid, but everytime it fails, heating while the temperature is already too high or not heating while the temperature is 1°C below the setting. :triumph:

Could you include some more details, like:

  • PID settings
  • how do you read your temperature (irregular such as battery + zigBee or continuous regular by wired sensor)
  • temperature reading for tested period (half to whole day)
  • Control output signal for same period

Now my settings are as follows :

And I have this curve on the climate history.

The temperature is measured by a Popp Mold Zwave sensor (battery powered), reporting temperature as soon as it sees a 0.1°C change, and minimum every 15mn if the temperature doesn’t change.

As you can see, after 4pm it started to heat while temperature was higher than setting, and when the target became 24°C, it didn’t react. I had to add 0.5°C to the setting to make it switch on.

The temperature reading with irregular intervals could be tricky. Maybe first try without kd.

The keep_alive is set once per hour. I think a regular control update will be better and I personally use each minute, thus three PID controller updates per pwm interval.

You could give it a try with these settings. I would expect that it would stabilise slow: ki is low and would need quite some time to stabilise before the temperature oscillations are gone. After activation first the kp will be dominant which will determine on-off signal and meanwhile the integral part for ki will build-up to define the ‘mean’ required ‘on time’. Hereafter it should behave more stable.

Could you give this a try and present the output graph?

    keep_alive: #time before update of PID controller
      seconds: 60
    kp : 10
    ki : 0.001
    kd : 0
    #duration of cycle in seconds
    pwm : 180
    difference : 100

Removed , my mistake

Thanks for your help, I think I’m moving forward thanks to your support.

I set the thermostat as you suggested, and then this morning it started to modulate the heater activity, but with very fast on/off sequences.

So at 7am I modified the pwm to 900 seconds, and the min_cycle_duration and keep_alive parameters to 5 minutes (300 seconds, third of pwm), and it slows down the cycling.

However, it seems it still doesn’t deliver sufficient power to maintain the 24°C target.

I don’t understand how this pulse width modulation is working. In my experience, a pulse width modulating device is defined by a modulation frequency and pulse width limits (minimum 10% to maximum 90% on, in example). Then it sets the pulse width depending on the error between input and output.

But on this thermostat, it seems the pulse are always 5mn ON, and 15mn OFF. And there is no modulation.

Nice to see improvement.

The KP part sets the pwm on time based on the error, the ki is the integral of that error over time. Thus when the error is present for a longer period the integral increases which will extend the on duration of the pwm. This results in a lower error and thereby lower on duration by the KP part.

In this case the ki seems to be too low, you could try it to 0.05.

Hi, with Ki = 0.05, it clearly modulates.
The spike @21°C corresponds to the reboot to set Ki. I then manually set the temperature to 23°C after boot and waited for the schedule to rise to 24°C. There is no anticipation of the temperature crossing the setting, so missing derivative coefficient. It still enables the heater while the temperature is above the setting.

The integral builds up when the temperature is less than the setpoint and the longer and the lower it is below setpoint it increases the integral part which keeps the switch longer ‘on’. The integral contribution will reduce when the temperature is above setpoint. The longer and higher above setpoint the more the integral will reduce.

In normal operation the integral part will fill slowly and the temperature reaches the setpoint gradually and as it reaches setpoint the integral part will not increase anymore as the error is very small.

The pi settings do need some tuning. I expect the overshoot what you see may result in an oscillation and dampen out. For example see here schematic effects pi settings. So by keeping the setpoint constant for a longer period the oscillation will start and you will be able to identify the part (KP or KI) which has to change (probably to lower).

After testing and improved KP and KI setting, only then I would start to see how it behaves to scheduling the setpoint by first letting the temperature stabilise at setpoint and then an adjustment to a new setpoint and keep this setpoint also for a while to see how it stabilises. Based in these result some further adjustments may be needed.

Hi guys, I see you are struggling with the PID control for the thermostat. I am the developer of the free pidtuner tool, I can answer any questions you might have regarding PID tuning.

First I would like to point you to this FAQ regarding PID tuning with the tool:

Then I would recommend that you use the canonical arduino PID implementation from Brett Beauregard:

Some PID implementation make some weird additions to the basic algorithm takes helps some people to wrap their heads around manual tuning, but you really don’t need that if you use a tuning tool. Furthermore, most tools assume a standard PID implementation.

You don’t really need to be math experts or have years of experience with PIDs to have a good PID tuning, as long as you use a tool correctly, that’s what tools are for.

Hope this information is useful.

1 Like

Thanks @pidtuner for the FAQ, sure it will help.
My issue is to understant what to provide to the PID tuner. I need to tune the PID for the heating in my bathroom, but the input of the smart thermostat component is a set point in °C while the output of the component is ON/OFF periods.
You mention in the FAQ that the variables should be taken with PID OFF, and generate the step without changing the set point. But how can I make a step in the process output of a thermostat without changing the set point ?

If the output of the PID is directly ON/OFF, then what you need to do is a series of ON and OFF periods long enough that the temperature dynamics (°C measurement) can be observed in the data with good enough precision (as stated in the FAQ).

This is assuming:

  • That the PID inside the thermostat component indeed uses the °C setpoint and °C measurement to calculate the error that is fed into the PID block.

  • That the PID indeed outputs ON/OFF directly.

  • That the PID takes standard Kp, Ki and Kd (or Kp, Ti and Td) tuning parameters.

Then what you have to put into the tool is the ON/OFF signal as input, the °C measurement as output and the time in seconds.