Multizone thermostat incl various control options

Ai, my mistake.

Nice to see you are at least able to config the thermostat! So the custom component is now able to install the requirements?

The example has for on/off mode an indentation too much. See example for proportional config. on_off_mode should be on the same level as away_temp

Hi @Axax,

No nothing works, because he can’t install “filterpy”
That’s the whole issue.

Logger: homeassistant.util.package
Source: util/package.py:99
First occurred: 11:53:56 (1 occurrences)
Last logged: 11:53:56

Unable to install package filterpy>=1.4.4: ERROR: Command errored out with exit status 1: command: /usr/local/bin/python3 /usr/local/lib/python3.9/site-packages/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-qa8j7jjo/overlay --no-warn-script-location --no-binary :none: --only-binary :none: -i https://pypi.org/simple --find-links https://wheels.home-assistant.io/alpine-3.14/amd64/ --prefer-binary -- 'wheel<0.37.0' 'setuptools<58.0.0' 'Cython>=0.29.18,<3.0' 'pybind11>=2.4.3,<2.7.0' pythran==0.9.11 'numpy==1.19.2; python_version=='"'"'3.7'"'"' and platform_machine=='"'"'aarch64'"'"'' 'numpy==1.19.2; python_version=='"'"'3.8'"'"' and platform_machine=='"'"'aarch64'"'"'' 'numpy==1.16.5; python_version=='"'"'3.7'"'"' and platform_machine!='"'"'aarch64'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.17.3; python_version=='"'"'3.8'"'"' and platform_machine!='"'"'aarch64'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.19.3; python_version=='"'"'3.9'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.20.0; python_version=='"'"'3.7'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' 'numpy; python_version=='"'"'3.8'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' 'numpy; python_version=='"'"'3.9'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' cwd: None Complete output (262 lines): Looking in links: https://wheels.home-assistant.io/alpine-3.14/amd64/ Ignoring numpy: markers 'python_version == "3.7" and platform_machine == "aarch64"' don't match your environment Ignoring numpy: markers 'python_version == "3.8" and platform_machine == "aarch64"' don't match your environment Ignoring numpy: markers 'python_version == "3.7" and platform_machine != "aarch64" and platform_python_implementation != "PyPy"' don't match your environment Ignoring numpy: markers 'python_version == "3.8" and platform_machine != "aarch64" and platform_python_implementation != "PyPy"' don't match your environment Ignoring numpy: markers 'python_version == "3.7" and platform_python_implementation == "PyPy"' don't match your environment Ignoring numpy: markers 'python_version == "3.8" and platform_python_implementation == "PyPy"' don't match your environment Ignoring numpy: markers 'python_version == "3.9" and platform_python_implementation == "PyPy"' don't match your environment Collecting wheel<0.37.0 Downloading wheel-0.36.2-py2.py3-none-any.whl (35 kB) Collecting setuptools<58.0.0 Downloading setuptools-57.5.0-py3-none-any.whl (819 kB) Collecting Cython<3.0,>=0.29.18 Downloading Cython-0.29.24-py2.py3-none-any.whl (979 kB) Collecting pybind11<2.7.0,>=2.4.3 Downloading pybind11-2.6.2-py2.py3-none-any.whl (191 kB) Collecting pythran==0.9.11 Downloading pythran-0.9.11-py3-none-any.whl (4.2 MB) Collecting numpy==1.19.3 Downloading numpy-1.19.3.zip (7.3 MB) Installing build dependencies: started Installing build dependencies: finished with status 'done' Getting requirements to build wheel: started Getting requirements to build wheel: finished with status 'done' Preparing wheel metadata: started Preparing wheel metadata: finished with status 'error' ERROR: Command errored out with exit status 1: command: /usr/local/bin/python3 /usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpnuu60d0p cwd: /tmp/pip-install-7yic5oyg/numpy Complete output (228 lines): Running from numpy source directory. setup.py:480: UserWarning: Unrecognized setuptools command, proceeding with generating Cython sources and expanding templates run_build = parse_setuppy_commands() Processing numpy/random/_bounded_integers.pxd.in Processing numpy/random/mtrand.pyx Processing numpy/random/_pcg64.pyx Processing numpy/random/bit_generator.pyx Processing numpy/random/_sfc64.pyx Processing numpy/random/_common.pyx Processing numpy/random/_bounded_integers.pyx.in Processing numpy/random/_philox.pyx Processing numpy/random/_generator.pyx Processing numpy/random/_mt19937.pyx Cythonizing sources blas_opt_info: blas_mkl_info: customize UnixCCompiler libraries mkl_rt not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE blis_info: libraries blis not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE openblas_info: libraries openblas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE atlas_3_10_blas_threads_info: Setting PTATLAS=ATLAS libraries tatlas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE atlas_3_10_blas_info: libraries satlas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE atlas_blas_threads_info: Setting PTATLAS=ATLAS libraries ptf77blas,ptcblas,atlas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE atlas_blas_info: libraries f77blas,cblas,atlas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE accelerate_info: NOT AVAILABLE /tmp/pip-install-7yic5oyg/numpy/numpy/distutils/system_info.py:1914: UserWarning: Optimized (vendor) Blas libraries are not found. Falls back to netlib Blas library which has worse performance. A better performance should be easily gained by switching Blas library. if self._calc_info(blas): blas_info: libraries blas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE /tmp/pip-install-7yic5oyg/numpy/numpy/distutils/system_info.py:1914: UserWarning: Blas (http://www.netlib.org/blas/) libraries not found. Directories to search for the libraries can be specified in the numpy/distutils/site.cfg file (section [blas]) or by setting the BLAS environment variable. if self._calc_info(blas): blas_src_info: NOT AVAILABLE /tmp/pip-install-7yic5oyg/numpy/numpy/distutils/system_info.py:1914: UserWarning: Blas (http://www.netlib.org/blas/) sources not found. Directories to search for the sources can be specified in the numpy/distutils/site.cfg file (section [blas_src]) or by setting the BLAS_SRC environment variable. if self._calc_info(blas): NOT AVAILABLE non-existing path in 'numpy/distutils': 'site.cfg' lapack_opt_info: lapack_mkl_info: libraries mkl_rt not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE openblas_lapack_info: libraries openblas not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE openblas_clapack_info: libraries openblas,lapack not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE flame_info: libraries flame not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE atlas_3_10_threads_info: Setting PTATLAS=ATLAS libraries lapack_atlas not found in /usr/local/lib libraries tatlas,tatlas not found in /usr/local/lib libraries lapack_atlas not found in /usr/lib libraries tatlas,tatlas not found in /usr/lib <class 'numpy.distutils.system_info.atlas_3_10_threads_info'> NOT AVAILABLE atlas_3_10_info: libraries lapack_atlas not found in /usr/local/lib libraries satlas,satlas not found in /usr/local/lib libraries lapack_atlas not found in /usr/lib libraries satlas,satlas not found in /usr/lib <class 'numpy.distutils.system_info.atlas_3_10_info'> NOT AVAILABLE atlas_threads_info: Setting PTATLAS=ATLAS libraries lapack_atlas not found in /usr/local/lib libraries ptf77blas,ptcblas,atlas not found in /usr/local/lib libraries lapack_atlas not found in /usr/lib libraries ptf77blas,ptcblas,atlas not found in /usr/lib <class 'numpy.distutils.system_info.atlas_threads_info'> NOT AVAILABLE atlas_info: libraries lapack_atlas not found in /usr/local/lib libraries f77blas,cblas,atlas not found in /usr/local/lib libraries lapack_atlas not found in /usr/lib libraries f77blas,cblas,atlas not found in /usr/lib <class 'numpy.distutils.system_info.atlas_info'> NOT AVAILABLE lapack_info: libraries lapack not found in ['/usr/local/lib', '/usr/lib'] NOT AVAILABLE /tmp/pip-install-7yic5oyg/numpy/numpy/distutils/system_info.py:1748: UserWarning: Lapack (http://www.netlib.org/lapack/) libraries not found. Directories to search for the libraries can be specified in the numpy/distutils/site.cfg file (section [lapack]) or by setting the LAPACK environment variable. return getattr(self, '_calc_info_{}'.format(name))() lapack_src_info: NOT AVAILABLE /tmp/pip-install-7yic5oyg/numpy/numpy/distutils/system_info.py:1748: UserWarning: Lapack (http://www.netlib.org/lapack/) sources not found. Directories to search for the sources can be specified in the numpy/distutils/site.cfg file (section [lapack_src]) or by setting the LAPACK_SRC environment variable. return getattr(self, '_calc_info_{}'.format(name))() NOT AVAILABLE numpy_linalg_lapack_lite: FOUND: language = c define_macros = [('HAVE_BLAS_ILP64', None), ('BLAS_SYMBOL_SUFFIX', '64_')] /usr/local/lib/python3.9/distutils/dist.py:274: UserWarning: Unknown distribution option: 'define_macros' warnings.warn(msg) running dist_info running build_src build_src building py_modules sources creating build creating build/src.linux-x86_64-3.9 creating build/src.linux-x86_64-3.9/numpy creating build/src.linux-x86_64-3.9/numpy/distutils building library "npymath" sources Could not locate executable gfortran Could not locate executable f95 Could not locate executable ifort Could not locate executable ifc Could not locate executable lf95 Could not locate executable pgfortran Could not locate executable nvfortran Could not locate executable f90 Could not locate executable f77 Could not locate executable fort Could not locate executable efort Could not locate executable efc Could not locate executable g77 Could not locate executable g95 Could not locate executable pathf95 Could not locate executable nagfor don't know how to compile Fortran code on platform 'posix' Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py", line 280, in <module> main() File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py", line 263, in main json_out['return_val'] = hook(**hook_input['kwargs']) File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py", line 133, in prepare_metadata_for_build_wheel return hook(metadata_directory, config_settings) File "/tmp/pip-build-env-df_h3yqk/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 157, in prepare_metadata_for_build_wheel self.run_setup() File "/tmp/pip-build-env-df_h3yqk/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 248, in run_setup super(_BuildMetaLegacyBackend, File "/tmp/pip-build-env-df_h3yqk/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 142, in run_setup exec(compile(code, __file__, 'exec'), locals()) File "setup.py", line 508, in <module> setup_package() File "setup.py", line 500, in setup_package setup(**metadata) File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/core.py", line 169, in setup return old_setup(**new_attr) File "/tmp/pip-build-env-df_h3yqk/overlay/lib/python3.9/site-packages/setuptools/__init__.py", line 165, in setup return distutils.core.setup(**attrs) File "/usr/local/lib/python3.9/distutils/core.py", line 148, in setup dist.run_commands() File "/usr/local/lib/python3.9/distutils/dist.py", line 966, in run_commands self.run_command(cmd) File "/usr/local/lib/python3.9/distutils/dist.py", line 985, in run_command cmd_obj.run() File "/tmp/pip-build-env-df_h3yqk/overlay/lib/python3.9/site-packages/setuptools/command/dist_info.py", line 31, in run egg_info.run() File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/command/egg_info.py", line 24, in run self.run_command("build_src") File "/usr/local/lib/python3.9/distutils/cmd.py", line 313, in run_command self.distribution.run_command(command) File "/usr/local/lib/python3.9/distutils/dist.py", line 985, in run_command cmd_obj.run() File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/command/build_src.py", line 144, in run self.build_sources() File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/command/build_src.py", line 155, in build_sources self.build_library_sources(*libname_info) File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/command/build_src.py", line 288, in build_library_sources sources = self.generate_sources(sources, (lib_name, build_info)) File "/tmp/pip-install-7yic5oyg/numpy/numpy/distutils/command/build_src.py", line 378, in generate_sources source = func(extension, build_dir) File "numpy/core/setup.py", line 663, in get_mathlib_info raise RuntimeError("Broken toolchain: cannot link a simple C program") RuntimeError: Broken toolchain: cannot link a simple C program ---------------------------------------- ERROR: Command errored out with exit status 1: /usr/local/bin/python3 /usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpnuu60d0p Check the logs for full command output. WARNING: You are using pip version 20.2.4; however, version 21.3 is available. You should consider upgrading via the '/usr/local/bin/python3 -m pip install --upgrade pip' command. ---------------------------------------- ERROR: Command errored out with exit status 1: /usr/local/bin/python3 /usr/local/lib/python3.9/site-packages/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-qa8j7jjo/overlay --no-warn-script-location --no-binary :none: --only-binary :none: -i https://pypi.org/simple --find-links https://wheels.home-assistant.io/alpine-3.14/amd64/ --prefer-binary -- 'wheel<0.37.0' 'setuptools<58.0.0' 'Cython>=0.29.18,<3.0' 'pybind11>=2.4.3,<2.7.0' pythran==0.9.11 'numpy==1.19.2; python_version=='"'"'3.7'"'"' and platform_machine=='"'"'aarch64'"'"'' 'numpy==1.19.2; python_version=='"'"'3.8'"'"' and platform_machine=='"'"'aarch64'"'"'' 'numpy==1.16.5; python_version=='"'"'3.7'"'"' and platform_machine!='"'"'aarch64'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.17.3; python_version=='"'"'3.8'"'"' and platform_machine!='"'"'aarch64'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.19.3; python_version=='"'"'3.9'"'"' and platform_python_implementation != '"'"'PyPy'"'"'' 'numpy==1.20.0; python_version=='"'"'3.7'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' 'numpy; python_version=='"'"'3.8'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' 'numpy; python_version=='"'"'3.9'"'"' and platform_python_implementation=='"'"'PyPy'"'"'' Check the logs for full command output. WARNING: You are using pip version 20.2.4; however, version 21.3 is available. You should consider upgrading via the '/usr/local/bin/python3 -m pip install --upgrade pip' command.

and second error.

Logger: homeassistant.components.hassio
Source: components/hassio/__init__.py:552
Integration: Home Assistant Supervisor (documentation, issues)
First occurred: 11:53:56 (1 occurrences)
Last logged: 11:53:56

The system cannot restart because the configuration is not valid: Platform error climate.multizone_thermostat - Requirements for multizone_thermostat not found: ['filterpy>=1.4.4'].

I’m running in Proxmox.
I tried to install throug pip… but it don’t work.

really frustrating…

yup, indeed a python problem i gues.

I run hassio via proxmox as well. I will try coming days if I can reproduce te error and hopefully fix it.

Okidoki, I tried now several installations. But no succes.
I hope you wil fix it.

Thanks allot for your patience and help.

1 Like

Hi Remco, I’m running into the same problems and have started a separate topic about it. Hope that it can be solved.

Requirements for custom_component not installing anymore - #2 by koying

Finally I’ve got it working again by removing filterpy as requirement and removing all scipy functions. I’ve also did some code cleaning and tested it in HA/core. The new version is available via github updated version.

This week I’ve been testing the new version in a 6 zone configuration en seems to run without problems.

During boot there may be several warnings in HA log when sensors or switches are not ready yet. When the sensor and/or switch is ‘online’ it should change to normal operation mode on its own.

Extract of my log of a single zone

2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] initialise: woonkamer
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer.heat] Config hvac settings for mode : heat
...
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] init thermostat
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] restore old controller settings
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer.heat.pid] forcing new integral: 0.0
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] HVAC mode changed to heat
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] HVAC mode heat
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode for heat to: 4
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode (4) but no temperature reading for heat
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode for heat to: 4
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode (4) but no temperature reading for heat
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode for heat to: 4
2021-11-10 22:59:41 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode (4) but no temperature reading for heat
2021-11-10 22:59:41 WARNING (MainThread) [multizone_thermostat.woonkamer] Current temp is None, cannot compare with target
...
2021-11-10 22:59:42 INFO (MainThread) [multizone_thermostat.woonkamer] new sensor filter mode for heat to: 4

When I have some time the next weeks I’ll check if the boot warnings can be improved/limited.

1 Like

Perfect!!!

I’m running it now as we speak!!!

Great Job

Ah nice. Good too hear it finally running! Let me know if you have feedback.

Hello, I’m trying to understand how multi-zone work. What is the advantage of a multi-zone thermostat (with master and slaves) vs standalone thermostat ?

Good question.
In the most basic from a house has a single, in the livingroom positioned, thermostat. This will try to keep the livingroom at the chosen setpoint by switching the heater (gas heater, distric heating, heat pump etc). The heating of all other rooms depend on the heat requiment of the livingroom.

This can be upgraded by valves and thermostat per room to have better control per room. This is heating individually per zone/room.

Some systems still use the main thermostat (most likely the livingroom) as primary switch to control the heater. In this case, when a secondary room needs heating, it still depends on the main thermostat: when the main thermostat does not require heat there will be no heater activity thus the secondary room will warm up.

One of the operation modes of the multizone thermostat uses the weighted average of all rooms (satellites) heat requirement plus setpoints to determine the temperature error. This error can be used to control the heater.

In total three control options are available for the master which are:

  • weather (heat requirement depending outdoor temperature)
  • PID based on weighted room temps+setpoints
  • PID based on max valve position of all satellites (extra heat when satellite valve is opened too much. This means there is a lot of required heat for that room)

Each satellite has the same control options except PID on valve position.

Edit:
This part is only the software operation. Please check if hardware modifications to you’re heating system are required! For instance: maybe the system needs to be equipped with a bypass valve to handle situations where too much valves are closed but still heat is required.

Thanks for this explanation. I’ve implemented multi zone thermostat based on markferry work.

Expect the fact that I can change generic thermostat with PID thermostat, I’m still trying to find an advantage of you solution versus the other one

Hello, is it possible to configure a minimum cycle duration for a gas boiler in a proportional mode ?

I think it’s minimal_diff , but don’t know how to use it

Hi Edouard,

I was not familiar with this topic thus cannot say directly which one you should use. There seem to be several variations which were created more or less at the same time period.

The main advantage of my version (for me at least) is that I control the main valve based on outdoor temperature (by linear trend) which directly compensates the heat loss. This is further adjusted by the max valve opening of each zone and the average room-setpoint temp scaled by room size.
Furthermore the satelite states are updated tot the master, and numerous adjustments can be made.

For me it is providing all options and insight for setting up - tuning of my heating system. But best is to try several versions to se which one fits you best.

Yes it should be minimal_diff. I think this should work:

  - platform: multizone_thermostat
    name: pid
    unique_id: mz_pid
    sensor: sensor.fake_sensor_1
    sensor_filter: 4
    initial_hvac_mode: "off"
    initial_preset_mode: "none"
    room_area: 60
    precision: 0.1
    sensor_stale_duration:
      hours: 3
    passive_switch_check: True
    heat:
      entity_id: input_number.fake_pwm_heat
      passive_switch_duration:
        hours: 5
      min_temp: 15
      max_temp: 24
      initial_target_temp: 21
      away_temp: 12
      proportional_mode:
        control_interval:
          seconds: 100
        difference: 100
        pwm:
          seconds: 600
        minimal_diff: 5
        PID_mode:
          kp: 30
          ki: 0.003
          kd: -24000
          window_open_tempdrop: -3.6

This example has a control range of 0 to 100 and should result in switch activation when control value is above 5.

I just made a big update to the code. If you have some issues please try the new version.

Thanks a lot, I will try the new version.

Just released an update as the previous version did not properly initiate the temperature filter.
see version 0.4.1 bugfixes for more details

Hey @axax
I used adrien.b 's PID Thermostat, but wanted to try something different, since I run multi zone heating. Previously, I just used automation outside of thermostat to determine if main switch should be on/off (this gives signal to heat pump to heat). With 7 different zones, there were times when one zone stopped heating, heater went off, and few minutes later, there was demand from other zone, so it started again. Not the end of the world, but not ideal for heatpump either, so I wanted to see how yours behave.

First of all, any news on if or when this will be included in HACS repository?

Secondly, I literally just deployed it, mostly followed examples as I am bit confused which values do what. The documentation isn’t greatest :slight_smile: But I noticed that some room, despite being 0,2 degrees below setpoint, did not change hvac action to heating.

Also, I don’t quite get the % of valve opened. I have simple on/off valves (NC), that open when zones need heat. My main switch is just signal for heat pump to start heating.

I tried to use room area ratio, not sure I got that right. Below is my config.
Any recommendations you can suggest? I have underfloor heating, which is really slow to react. With adrien’s PID thermostat, I used following settings:

  kp : 100
  ki : 0.003
  kd : 220000
  ke: 0.588
  pwm : 02:00:00
  sampling_period: 00:10:00

But in your multizone, I kept the default you suggested for underfloor heating:

- platform: multizone_thermostat
  name: master_thermostat
  sensor_out: sensor.espaltherma_outside
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  precision: 0.1
  heat:
    entity_id: switch.heat_pump_switch
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 600
      PID_mode:
        kp: 3
        ki: 0
        kd: 0
      weather_mode:
        ka: 2
        kb: -6
      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]
        goal: 150
        kp: -0.15
        ki: 0
        kd: 0
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: living_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_7
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 40
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: guest_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_5
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor_2
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: bathroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_6
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 10
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor_3
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: office
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_4
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: master_bathroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_2
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: master_bedroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_3
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_2
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

- platform: multizone_thermostat
  name: kids_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_4
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_3
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 60
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 180
      PID_mode:
        kp: 30
        ki: 0.005
        kd: -24000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: True
  restore_parameters: False
  restore_integral: True

Hi Stomko,

I intended to send just a short explanation but it gradually increased so hope it makes still some sense. :wink:

First of all, any news on if or when this will be included in HACS repository?

It is. You can add the repository as custom repository. I did not include it (yet) in the standard due to the complex operation, config and possible consequence when used not correctly.

Secondly, I literally just deployed it, mostly followed examples as I am bit confused which values do what. The documentation isn’t greatest :slight_smile:

If you are willing to spend some time, could you create a new issue in github (or by any other way) give me some feedback what needs further updates/improvement. Maybe after you’ve concluded this thermostat works for you or not?

But I noticed that some room, despite being 0,2 degrees below setpoint, did not change hvac action to heating.

I expect it might start with a warning and in emergency mode as it waits for a first update of the temperature reading (indoor and/or outdoor depending the config). The pwm and control routine loop independantly of each other. The control value is calculated each control_interval and each sensor (in- or outdoor) change. The pwm loop is checking each 1/10 of the pwm set interval when pwm > 0. The control value (valve_pos) is used in the pwm loop operation (duration open/close).
It could therefore take a short moment to actually see it acting. In your case I think the following should occur:

  1. thermostat starts with a warning
  2. control value update by control_interval
  3. no change due to no latest sensor change
  4. loop 2-3 until a receive of temperature sensor update
  5. update control value
  6. pwm loop updated

Check the attributes of the climate entity and search for valve_pos. This value will be between 0-100 and defines the valve on-off time ratio. Thus as soon this value is larger than 0 your valve should be switched on within the pwm defined period. When the valve_posis less than specified minimal_diff the valve is not switched on to avoid short activations.
Note several valve_pos could be present: one per control mode (*_valve_pos) and a combined (summed) as valve_pos. The latter is used for the pwm.

Also, I don’t quite get the % of valve opened. I have simple on/off valves (NC), that open when zones need heat. My main switch is just signal for heat pump to start heating.

In case pwm is not specified or as pwm = 0 it gives a numerical value as output instead of switching a switch between on-off. I have for instance a radiator valve which requires a valve position.
Another use could be for instance to use the weather_mode in combination with pwm=0 to output a required water temperature of the heating system.

Regarding your config, in general it seems to be oke. You can use your own PID values and interval times. In my config I use the weather mode to control the main valve and did not include it in the room thermostats to avoid control interference. as it would amplify the weahter compensation.

See the modified example below.

You could start with all restore_* = False to assure a clean start.

- platform: multizone_thermostat
  name: master_thermostat
  sensor_out: sensor.espaltherma_outside
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  precision: 0.1
  heat:
    entity_id: switch.heat_pump_switch
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 180
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 600
      PID_mode:
        kp: 3
        ki: 0
        kd: 0
      weather_mode:
        ka: 2
        kb: -6
      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]
        goal: 80
        kp: -0.15
        ki: 0
        kd: 0
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: living_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_7
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 40
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: guest_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_5
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor_2
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: bathroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_6
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 10
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_ground_floor_3
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: office
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_4
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: master_bathroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_2
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: master_bedroom
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_3
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_2
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

- platform: multizone_thermostat
  name: kids_room
  sensor: sensor.aerq_temperature_and_humidity_sensor_v2_0_air_temperature_4
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  room_area: 20
  precision: 0.1
  heat:
    entity_id: switch.underfloor_heating_1st_floor_3
    min_temp: 17
    max_temp: 28
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 600
      difference: 100
      minimal_diff: 5
      pwm:
        hours: 2
      PID_mode:
        kp: 100
        ki: 0.003
        kd: -220000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

some explanation for the “master_thermostat”. All combinations are here possible iwth or without PID_mode, weather_mode and (goal,kp,ki,kd) in MASTER_mode.

      PID_mode:
        kp: 3
        ki: 0
        kd: 0

fine tuning of weather_mode. This reacts to the averaged (by room area) setpoints and room temps to change in my case the main
valve on-off time. It gives extra or less valve_pos depending the error between avg setpoint and room temps.

      weather_mode:
        ka: 2
        kb: -6

In this case the main controller of the valve_pos by outside temperature and averaged (by room area) room temps. valve_pos= dT*ka + kb

      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]

Marker that this is the master thermostat. Specify which rooms to use for averaging. Only those which have the same preset mode (heat or cool) will be included. When preset mode is different (for instance master at heat and rooms at cool or off are excluded).

        goal: 80
        kp: -0.15
        ki: 0
        kd: 0

In this case fine tuning of weather_mode. Adjust the valve_pos to get max valve opening of all included rooms at goal = 80 (max of valve_pos per room).

So you could use alternative config options. Note that I did not test these variations myself.

Examples are:

  1. only weather mode
- platform: multizone_thermostat
  name: master_thermostat
  sensor_out: sensor.espaltherma_outside
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  precision: 0.1
  heat:
    entity_id: switch.heat_pump_switch
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 180
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 600
      weather_mode:
        ka: 2
        kb: -6
      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False
  1. Try to acihieve max 80% opening (expect it would result in max flow in one room thus minimum water temperature) and per room PID and optionally weather compensation.
    master mode only
- platform: multizone_thermostat
  name: master_thermostat
  sensor_out: sensor.espaltherma_outside
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  precision: 0.1
  heat:
    entity_id: switch.heat_pump_switch
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 180
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 600
      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]
        goal: 80
        kp: -2
        ki: -0.0001
        kd: 100000
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

3)master by PID only. thus operating on averaged setpoints and room temps.

- platform: multizone_thermostat
- platform: multizone_thermostat
  name: master_thermostat
  sensor_out: sensor.espaltherma_outside
  sensor_filter: 3
  initial_hvac_mode: "off"
  initial_preset_mode: "none"
  precision: 0.1
  heat:
    entity_id: switch.heat_pump_switch
    initial_target_temp: 20
    away_temp: 17
    proportional_mode:
      control_interval:
        seconds: 180
      difference: 100
      minimal_diff: 5
      pwm:
        seconds: 600
      PID_mode:
        kp: 3
        ki: 0
        kd: 0
      MASTER_mode:
        satelites: [living_room, guest_room, bathroom, office, master_bathroom, master_bedroom, kids_room]
  sensor_stale_duration:
    hours: 12
  restore_from_old_state: False
  restore_parameters: False
  restore_integral: False

Thanks. I have created issue #13 on github. Thanks for helping out.