Thermostat with PID controller

Hi! I have a big mess in my heating system in my house. All my life I have lived in apartment flats with central heating. But this time I am living in an apartment flat which is heated by combi boiler. I renovated the house knowing that the heater system’s piping was new allready, so I did not change it. A huge mistake… It is BAD! :smiley: After the boiler the heated water gets devided into two. One is for 5 bedrooms, 3 bathrooms. The other one is for kitchen and living room. The problem is, one is three times longer then the other. So, most of the water is circulated in my livingroom area, which makes rest of the house hard to heat. The plumber did not add any valves and pipes are hidden in bricket walls (cement apartment). I found the pipe behind the dishwasher, break the wall just enough to work and add a valve there. Then made myself a step motor controller driven by ESPHOME and connected it to the valve. Now I can reduce the water circulation in living room, which makes the rest of the house much easier to heat.

Now, what I need is to pid control this valve (which has allready a step motor working on it) to control my living room temperature. In week days only between 18.30 and 01.00 we are using the living room. Rest of the time either we are at work, or sleeping. So, I want to let it cool down up to 16-17C. And on 17.30 it will start to heat the room back up to 21C. In my tests, I saw that, if I completely shutoff livingroom, rest of the rooms heats up way better. I allready have a high power pump in my system. So, I beleive the plumbing is seriously bad. Probably at some point when joining pipes, they overheated pvc pipe and caused it to melt inside and reduce the inside area. This happens in pvc plumbing if an amateur does it. But for now, there is nothing I can do about it.

So I need a thermostat that controls the stepper motor.

I allready use an ESP8266 + DHT22 based temperature sensor in living room; but I don’t know where to start. My heater is not electric. PWM is not for me. How can I get the pid output and change it to drive a stepper motor? I have no clue. Can anybody help me?

In my country floor heating elements also work with heated water. So in discussion above, I could not be sure either you are talking about an electric floor heater or water based floor heater.

If anybody can get me started, I will appriciate much.

Thank you for the cool feature!
I have electric underfloor heating set up in 6 zones, in each zone there is a floor temperature sensor and a room temperature sensor.
How can I set up the PID controller to take both into account? I guess I would need to cascade 2 PID controllers, first the floor one (with a max_temp limit), and the room one on top of that?

1 Like

heater (Required): entity_id for heater control, should be a toggle device or a valve accepting direct input between 0% and 100%. If a valve is used, pwm parameter should be set to 0.

Hello, what kind of heating system is it ? If floor heating, I don’t recommend changing the temperature with such big steps during the night, as you will consume a lot of energy in the morning to heat up the room.

If you only have water radiators and rooms are in parallel, I think the best would be to use some connected thermostatic valves like Netatmo or Tado. Each room can then request the boiler to heat and regulate rooms independently.

@adrien.b I’ve sent a pull request adding support for cascading PIDs.
It works really well.

1 Like

Hi @Huseyin_Ozsut .
Take a look at https://community.home-assistant.io/t/zigbee-based-climate-solution/630920/4?u=guff666. In this, I explained how I control our CH in multiple rooms. It’s not directly comparable, but may give you some ideas.
Gareth

I’m looking a software thermostat for my HA , I’m not able to get this working

I have installed via HACS but the hvac_action is always idle, I cannot see any action on switch what go wrong with my configuration?

I’m looking for a simple ON/OFF thermostat, any ide?

- platform: smart_thermostat
  name: Smart Thermostat
  heater: switch.fancoil_1
  cooler: switch.fancoil_1
  target_sensor: sensor.lumi_temperature
  outdoor_sensor: sensor.temperatura_esterna
  min_temp: 7
  max_temp: 30
  ac_mode: True
  target_temp: 19
  target_temp_step: 0.1
  hot_tolerance: 0.3
  cold_tolerance: 0.3
  precision: 0.1
  keep_alive:
    seconds: 60
  kp: 5
  ki: 0.01
  kd: 500
  pwm: 00:15:00
  min_cycle_duration: 00:05:00
  force_off_state: True
  sampling_period: 00:10:00

I’m using this smart thermostat for a warm water underfloor heating system with 7 zones. The system is pretty slow to warm a zone/room up (say 0.5 degrees celsius per hour), and has a lot of inertia, and I’m struggling to work out how best to configure things to avoid a big overshoot and get each room warm for the hours of day that are most useful and allow it to cool off at night, say.

Here you can see a room with a 20.5 degrees target between about 8am and 7pm, and otherwise effectively off.

It would make sense for the heating to kick in at 6am or so, and then to stop heating far before it does to avoid the overshoot. As things stand the room is on average warming during the evening+night than it is during the day, which is the opposite of what’s needed!

- platform: smart_thermostat
  name: Study
  unique_id: thermo_study
  heater: switch.upperheating_zone5_study
  target_sensor: sensor.study_t_h_sensor_temperature
  outdoor_sensor: sensor.tesla_wall_connector_handle_temperature
  min_temp: 8
  max_temp: 24
  ac_mode: False
  target_temp: 20.5
  keep_alive:
    seconds: 300
  away_temp: 14
  sleep_temp: 18
  home_temp: 20.5
  eco_temp: 9
  kp: 30
  ki: 0.005
  kd: -24000
  pwm: 00:15:00
  min_cycle_duration: 180
  min_off_cycle_duration: 180
  target_temp_step: 0.1
  precision: 0.1

Any advice for how to configure this more helpfully?

The only advice is to stop changing the setpoint of underfloor heating systems. Inertia is much too big.
I tried with 1°C decrease in my living room during night, and it never recovered before the end of the morning, even with a commercial thermostat with PID and predictive heating.
So now I keep it steady, and it doesn’t consume more gas than before.

3 Likes

Hi,

I would like to control my underfloor heating via HA.

Insulation (U-value): 0.21 to 0.24 W/m²K
Outdoor sensor: Available
Actuator: on:off
Room thermostat wall: Available

This is underfloor heating from JOCO, which is not as sluggish as classic underfloor heating systems.

Parts of the heating system:

  • 3 cm XPS insulation
  • Pipe spacing 12.5 cm
  • Pipe diameter: 16x2 mm
  • Full surface also in the curves: 2.5 mm aluminum
  • 5 mm reinforcement mat (plastic honeycomb mat filled with tile adhesive)
  • 7 mm tile adhesive
  • 7 mm tile

Ergo the distance from the heating surface to the Feet is just 19 mm. At the end of the article a few pictures for those interested :wink:

Since you have a lot of parameters to choose from here:

I wanted to ask what basic configuration is best to start with.

  • Are there parameters I should leave out?
  • Are there parameters I should add?
  • Which values are useful for the start?

Here is an initial situation:

climate:
  - platform: smart_thermostat
    name: Smart Thermostat Example
    unique_id: smart_thermostat_example
    heater: switch.on_off_heater
    target_sensor: sensor.MyWallThermostat_temperature
    outdoor_sensor: sensor.MyOutdoor_temperature
    min_temp: 7
    max_temp: 28
    ac_mode: False
    target_temp: 22
    keep_alive:
      seconds: 60
    away_temp: 14
    kp: 5
    ki: 0.01
    kd: 500
    ke: 0.5
    pwm: 00:15:00



Thanks for your tips.

########################################’

My Solution

I can now explain it to myself. I took this setting as a basis and let it run for several days. You just have to wait until some temperature oscillations have been recorded. Preferably without windows or door openings.:

climate:
  # DG - Fußbodenheizung
  - platform: smart_thermostat
    name: DG - Fußbodenheizung - HASmartThermostat
    unique_id: DG-Fussbodenheizung-HASmartThermostat
    heater: switch.eltako_gw1_00_00_00_50
    target_sensor: sensor.hm_tc_it_wm_w_eu_oeq1668843_temperatur
    outdoor_sensor: sensor.heizgeraet1_aussentemperatur
    min_temp: 5
    max_temp: 24
    ac_mode: False
    target_temp: 21.0
    keep_alive:
      seconds: 300
    away_temp: 20.0
    sleep_temp: 19
    home_temp: 21.0
    eco_temp: 5
    kp: 100
    ki: 0.0
    kd: 0.0
    ke: 0.5
    pwm: 00:15:00
    min_cycle_duration: 180
    min_off_cycle_duration: 180
    target_temp_step: 0.1
    precision: 0.1

Change the parameters via the services so that something happens !!!

It is important to know that the PID values etc. After initialization, you do not have to change them in the Config but via the services for anything to happen. The same applies to (away_temp, sleep_temp, home_temp, eco_temp etc.) !

My Calculation example PID Source:

I became aware of this through this link: Smart Thermostat - le chauffage contrôlé par PID - #186 par Toniob - Intégration - Home Assistant Communauté Francophone

Solution found in this link: Autotune feature usage. · ScratMan/HASmartThermostat · Discussion #21 · GitHub

Quote from the second link:

#####################START######################
Hello,

If autotune fails (it really depends on the regularity of the oscillation), you can extract the required information from the temperature history manually (and you can do it as soon as you have a full period of oscillation, while the autotune often needs to wait several cycles) :
Measure the amplitude of the oscillation Yosc (in degrees) and the oscillation period tosc (in seconds).

Screenshot

This will allow computing the ultimate gain Ku:
Ku = 8.0 * difference / (Yosc * pi)
(difference = 100 by default)

Next, depending on the autotune rule you prefer (it provides different results) you can compute the gains Kp, Ki and Kd using the divisors of the selected rule :

ruler divisor1 divisor2 divisor3
“ziegler-nichols” 34 40 160
“tyreus-luyben” 44 9 126
“ciancone-marlin” 66 88 162
“pessen-integral” 28 50 133
“some-overshoot” 60 40 60
“no-overshoot” 100 40 60
“brewing” 2.5 6 380

using the formulas below :

Kp = Ku / divisor1
Ki = Kp / (tosc / divisor2)
Kd = Kp * (tosc / divisor3)

Example with some measures made on the chart above :
Oscillation amplitude Yosc = 2.1°C, oscillation period tosc = 10200 seconds.
According to Ziegler-Nichols the gains will be :

Ku = 8 * 100 / (2.1 * pi) = 121.261
Kp = 121.261 / 34 = 3.567
Ki = 3.567 / (10200 / 40) = 0.01499
Kd = 3.567 * (10200 / 160) = 227.396

The resulting gains are a good starting point, you should then tune them to match your requirements, if you need more reactivity or stability, or to decrease an overshoot.
#####################ENDE######################

My setting based on the calculation with ziegler-nichols:

climate:
  # DG - Fußbodenheizung
  - platform: smart_thermostat
    name: DG - Fußbodenheizung - HASmartThermostat
    unique_id: DG-Fussbodenheizung-HASmartThermostat
    heater: switch.eltako_gw1_00_00_00_50
    target_sensor: sensor.hm_tc_it_wm_w_eu_oeq1668843_temperatur
    outdoor_sensor: sensor.heizgeraet1_aussentemperatur
    min_temp: 5
    max_temp: 24
    ac_mode: False
    target_temp: 21.0
    keep_alive:
      seconds: 300
    away_temp: 20.0
    sleep_temp: 20
    home_temp: 21.0
    eco_temp: 5
    kp: 18.724
    ki: 0.01510
    kd: 5802.451
    ke: 0.5
    pwm: 00:15:00
    min_cycle_duration: 180
    min_off_cycle_duration: 180
    target_temp_step: 0.1
    precision: 0.1

First long-term result after the first calculation.
Previously, 25°C was reached in some cases. With a setpoint of 20.5°C.

I hope this helps some of you.
Sorry for the english :wink:

1 Like

Hi,

Thank you for this fantastic integration. I have just one question: is it possible to calculate the time the thermostat was on for a day, week, month, or year? It would be nice to have a graph showing the time on.

Thanks.

Maybe with Home Assistant statistics using the heater switch. But I have no clue about how to do it.

You could use the History Stats sensor for periods that fit within the purge history time of the recorder, but not for months and years.

If you create a sensor that cumulatively counts how long something was on, then Utility Meter can create the day/week/month/year stats:

You could combine the two to get what you want:
Use a history stats sensor to count on time for today using the start of today as the beginning of the period, and now for the end of the period. Then use a utility meter to create a total for forever/year/week/month.

Hi,

I would like to configure my home smart PID regulator before winter and since I have time now I can start to make some work :slight_smile: . I have an issue that is not so obvious to me.

In my home I have several rooms and each of them have separate valves and wall thermostat. It means that I can control each room separately with set-up temperature for example of wall thermostat or from central from HA.

House has only one source of heating system (gas boiler) that can control by ON & OFF.

Till now I had a problem to control properly rooms since it was one sensor that took control over boiler and other rooms like office or bedrooms have been to cold or to hot.

By this integrity I can make an virtual thermostat and can control each of the room that is very nice. As well virtual thermostat can control of several valves etc. including boiler as well. But my question is how can I ensure that when Virtual thermostat will take control of room (valve) will start boiler and will not off when other rooms will require boiler since it supply whole house?
And I’m not sure how to make it correct due to the goal is to keep boiler ON till each rooms will meet required temperature. After that to shutdown boiler. And as well each rooms if will need more heat from boiler have to ON boiler to be able to heat room.

Is there anyone who had such case as solve it somehow :slight_smile: ?

Hello, it all depends on how the system is supposed to operate. You may drive the valves opening directly with the virtual thermostat (with pwm: 0 ), and use an input boolean template to make a logical “or” so that the boiler is switched on if at least one valve is opened.

Sounds nice :slight_smile:
Do you have an example or where can I find so I could read a code and understood how it works?

Hello everyone, I want to use this component with Oventrop actuators via a solid state relay. It is designed with a wax filler and heats up in 2 minutes to fully open the valve, will this thermostat be suitable and will I be able to configure the system?

The winter is coming and many like myself are struggling to setup this integration, I’ve found this very useful simulator that has quite been a life saver, check it out - PID Simulator download | SourceForge.net

There are two versions, I found the first one more easy to use.

Hi, is it possible to modify the preset mode icons?
After the latest OS update, I lost the mode icons. Now, the only way I can fix this issue is by setting them manually. I’ve successfully done this with the AC integration (Daikin), but I’m not able to do it with the Smart Thermostat.

I modified the icons.json file like this, but it’s not working:

{
  "services": {
    "clear_integral":  "mdi:thermostat-cog",
    "set_pid_mode": "mdi:thermostat-cog",
    "set_pid_gain":  "mdi:thermostat-cog",
    "set_preset_temp": "mdi:thermostat"
  },
  "entity": {
    "climate": {
      "smart_thermostat": {
        "state_attributes": {
          "preset_mode": {
            "state": {
              "home": "mdi:home",
              "boost": "mdi:rocket-launch"
            }
          }
        }
      }
    }
  }
}

Are anyone here still running HASmartThermostat thermostats from ? Are these still working?

As of yesterday all of mine became unavailable and reports "This entity is no longer being provided by the smart_thermostat integration. If the entity is no longer in use, delete it in settings."

Everything just stopped working yesterday at 13.30 (No update, no restart):

The log shows the following:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config.py", line 1437, in _async_load_and_validate_platform_integration
    platform = await p_integration.integration.async_get_platform(domain)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1070, in async_get_platform
    platforms = await self.async_get_platforms((platform_name,))
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1145, in async_get_platforms
    import_future.result()
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1133, in async_get_platforms
    platforms.update(self._load_platforms(platform_names))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1060, in _load_platforms
    platform_name: self._load_platform(platform_name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1232, in _load_platform
    cache[full_name] = self._import_platform(platform_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 1264, in _import_platform
    return importlib.import_module(f"{self.pkg_path}.{platform_name}")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/config/custom_components/smart_thermostat/climate.py", line 38, in <module>
    from homeassistant.core import DOMAIN as HA_DOMAIN, CoreState, Event, EventStateChangedData, callback
ImportError: cannot import name 'EventStateChangedData' from 'homeassistant.core' (/usr/src/homeassistant/homeassistant/core.py)

Very odd!

/Tonkin