Skip to content

Commit

Permalink
Merge pull request #36 from vindaalex/development
Browse files Browse the repository at this point in the history
bugfix ha 2024.4
  • Loading branch information
vindaalex authored May 3, 2024
2 parents c96f09f + d697d54 commit 04a53cd
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 71 deletions.
105 changes: 60 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This is a home assistant custom component. It is a thermostat including various

Note:
This is only the required software to create a (zoned) thermostat. Especially zoned heating systems will affect the flow in your heating system vy closing and opening valves. Please check your heating system if modifications are requried to handle the flow variations, such as: pump settings, bypass valves etc.

## Installation:
1. Go to <conf-dir> default /homeassistant/.homeassistant/ (it's where your configuration.yaml is)
2. Create <conf-dir>/custom_components/ directory if it does not already exist
Expand All @@ -15,19 +16,55 @@ This is only the required software to create a (zoned) thermostat. Especially zo
5. Set up the multizone_thermostat and have fun


# thanx to:
## thanx to:
by borrowing and continuouing on code from:
- DB-CL https://github.com/DB-CL/home-assistant/tree/new_generic_thermostat stale pull request with detailed seperation of hvac modes
- fabian degger (PID thermostat) originator PID control in generic thermostat, https://github.com/aendle/custom_components


# Explanatory notes
Within this readme several abbreviations are used to describe the working and used methodolgy. Hereunder the most relevant are described.

## Pulse Width Modulation (PWM)
"PWM" stands for Pulse Width Modulation. Pulse Width Modulation is a technique often used in conjunction with PID controllers to regulate the amount of power delivered to a system, such as the heating elements in each zone of your underfloor heating system.

Pulse Width Modulation (PWM) is used to adjust the amount of power delivered to an electronic device by effectively turning the heating (or cooling) on and off at a "fast" rate. The "width" of the "on" time (the pulse) is varied (modulated) to represent a specific power delivery level. When the pulse is wider (meaning the device is on for a longer period), more power is delivered to the heating element, increasing the temperature. Conversely, a narrower pulse delivers less power, reducing the temperature.

https://en.wikipedia.org/wiki/Pulse-width_modulation

## proportional–integral–derivative controller (PID)

The PID controller calculates the difference between a desired setpoint (the target temperature) and the actual temperature measured by the sensors in each zone. Based on this difference (the error), and the rate of temperature change, the PID controller adjusts the PWM signal to increase or decrease the heat output, aiming to minimize the error over time and maintain a stable temperature in each zone.

The use of PWM in your underfloor heating system allows for precise control over the temperature in each zone by adjusting the duty cycle of the electrical power to the heating elements. This method is efficient and can lead to more uniform temperature control and potentially lower energy consumption, as it adjusts the heating output to the actual need in each zone.

PID controller explained:
- https://en.wikipedia.org/wiki/PID_controller
- [https://controlguru.com/table-of-contents/](https://controlguru.com/table-of-contents/)

config examples:
slow low temperature underfloor heating:
PID_mode:
kp: 30
ki: 0.005
kd: -24000

high temperature radiator:
PID_mode:
kp: 80
ki: 0.09
kd: -5000

* underfloor heating parameter optimisation: https://www.google.nl/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwi5htyg5_buAhXeQxUIHaZHB5QQFjAAegQIBBAD&url=https%3A%2F%2Fwww.mdpi.com%2F1996-1073%2F13%2F8%2F2068%2Fhtml&usg=AOvVaw3CukGrgPjpIO2eKM619BIn

# Operation modes
The multizone thermostat can operate in two modes:
- thermostats can operate stand-alone, thus without interaction with others
- thermostats can operate under the control of a master controller scheduling and balancing the heat request

Per room a thermostat needs to be configured. A thermostat can operate by either hyesteris (on-off mode) or proportional mode (weather compensation and PID mode). The PID and weather compensation can be combined or one of both can be used. Only a satellite operating in proportional mode can be used as satellite as hysteris operation (on-off by a dT) cannot run in synchronised mode with other satellites and the master.

When a master controller is included it will coordinate for all enlisted satellites the valve opening and closures. When the master hvac mode is heat or cool it will trigger the satellites to update their controller and from that moment it interacts with the master. A satellite interaction with the master will be updated when the master is activated or switched off. When the master is activated to heat or cool, the controller routines of all satellites are synced to the master controller. When the master is switched off the satellite will return to their stand-alone mode with individual settings. The master itself receives the satellite state (pwm signal) and return the moment the satellite has to open or close valves. The master determines the moment when the satellite valves is opened, the satellite itself still determines the valve opening time.
When a master controller is included it will coordinate for all enlisted satellites the valve opening and closures. When the master hvac mode is heat or cool it will trigger the satellites to update their controller and from that moment it interacts with the master. A satellite interaction with the master will be updated when the master is activated or switched off. When the master is activated to heat or cool, the controller routines of all satellites are synced to the master controller. When the master is switched off the satellite will return to their stand-alone mode with individual settings. The master itself receives the satellite state (PWM signal) and return the moment the satellite has to open or close valves. The master determines the moment when the satellite valves is opened, the satellite itself still determines the valve opening time.

# Examples
See the examples folder for examples.
Expand Down Expand Up @@ -60,7 +97,7 @@ sensors (at least one sensor needs to be specified):
* initial_preset_mode (Optional): Set the default mode. Default is normal operational mode. Allowed alternative is any in 'extra_presets'. The 'inital_preset_mode' needs to be present in the 'extra_presets' of the 'initial_hvac_mode'

* precision (Optional): specifiy setpoint precision: 0.1, 0.5 or 1
* detailed_output (Optional): include detailed control output including PID contributions and sub-control (pwm) output. To include detailed output use 'True'. Use this option limited for debugging and tuning only as it increases the database size. Default = False
* detailed_output (Optional): include detailed control output including PID contributions and sub-control (PWM) output. To include detailed output use 'True'. Use this option limited for debugging and tuning only as it increases the database size. Default = False

checks for sensor and switch:
* sensor_stale_duration (Optional): safety routine "emergency mode" to turn switches off when sensor has not updated for a specified time period. Specify time period. Activation of emergency mode is visible via a forced climate preset state. Default is not activated.
Expand Down Expand Up @@ -104,19 +141,19 @@ Two control modes are included to control the proportional thermostat. A single
- Weather compensating: control by room- and outdoor temperature

The proportional controller is called periodically and specified by control_interval.
If no pwm interval is defined, it will set the state of "heater" from 0 to "pwm_scale" value as for a proportional valve. Else, when "pwm_duration" is specified it will operate in on-off mode and will switch proportionally with the pwm signal.
If no PWM interval is defined, it will set the state of "heater" from 0 to "PWM_scale" value as for a proportional valve. Else, when "PWM_duration" is specified it will operate in on-off mode and will switch proportionally with the PWM signal.

* control_interval (Required): interval that controller is updated. The satellites should have a control_interval equal to the master or the master control_interval should be dividable by the satellite control_interval. Specify a time period.
* pwm_duration (Optional): Set period time for pwm signal. If it's not set, pwm is sending proportional value to switch. Specify a time period. For a on-off valve the control_interval should be equal or multiplication of the "control_interval". Default = 0 (proportional valve)
* pwm_scale (Optional): Set analog output offset to 0. Example: If it's 500 the output value can be between 0 and 500. Proportional valve might have 99 as upper max, use 99 in such case. Default = 100
* pwm_resolution (optional): Set the resolution of the pwm_scale between min and max difference. Default = 50 (50 steps between 0 and pwm_scale)
* pwm_threshold (Optional): Set the minimal difference before activating switch. To avoid very short off-on-off or on-off-on changes. Default is not acitvated
* bounded_scale_to_master(Optional): scale proporitional valves with the master's pwm. 'bounded_scale_to_master' defines the scale limit. For example:
* PWM_duration (Optional): Set period time for PWM signal. If it's not set, PWM is sending proportional value to switch. Specify a time period. For a on-off valve the control_interval should be equal or multiplication of the "control_interval". Default = 0 (proportional valve)
* PWM_scale (Optional): Set analog output offset to 0. Example: If it's 500 the output value can be between 0 and 500. Proportional valve might have 99 as upper max, use 99 in such case. Default = 100
* PWM_resolution (optional): Set the resolution of the PWM_scale between min and max difference. Default = 50 (50 steps between 0 and PWM_scale)
* PWM_threshold (Optional): Set the minimal difference before activating switch. To avoid very short off-on-off or on-off-on changes. Default is not acitvated
* bounded_scale_to_master(Optional): scale proporitional valves with the master's PWM. 'bounded_scale_to_master' defines the scale limit. For example:
- bounded scale = 3
- prop valve pwm = 15
- master pwm = 25
- master pwm scale = 100
- valve pwm output = 15 / min( 25/100, 3)
- prop valve PWM = 15
- master PWM = 25
- master PWM scale = 100
- valve PWM output = 15 / min( 25/100, 3)

Default = 1 (no scaling)

Expand All @@ -132,8 +169,8 @@ with the data (as sub):
* kp (Required): Set PID parameter, p control value.
* ki (Required): Set PID parameter, i control value.
* kd (Required): Set PID parameter, d control value.
* pwm_scale_low (Optional): Overide lower bound pwm scale for this mode. Default = 0
* pwm_scale_high (Optional): Overide upper bound pwm scale for this mode. Default = 'pwm_scale'
* PWM_scale_low (Optional): Overide lower bound PWM scale for this mode. Default = 0
* PWM_scale_high (Optional): Overide upper bound PWM scale for this mode. Default = 'PWM_scale'
* window_open_tempdrop (Optional): notice temporarily opened window. Define minimum temperature drop speed below which PID is frozen to avoid integral and derative build-up. drop in Celcius per hour. Should be negative value. Default = off.

##### Weather compensating controller (Optional) (sub of proportional mode)
Expand All @@ -147,8 +184,8 @@ cool mode: ka negitive, kb positive
with the data (as sub):
* ka (Required): Set PID parameter, ka control value.
* kb (Required): Set PID parameter, kb control value.
* pwm_scale_low (Optional): Overide lower bound pwm scale for this mode. Default = pwm_scale * -1
* pwm_scale_high (Optional): Overide upper bound pwm scale for this mode. Default = 'pwm_scale'
* PWM_scale_low (Optional): Overide lower bound PWM scale for this mode. Default = PWM_scale * -1
* PWM_scale_high (Optional): Overide upper bound PWM scale for this mode. Default = 'PWM_scale'

# Master configuration
The configuration scheme is similar as for a satellite only with the following differences.
Expand Down Expand Up @@ -190,18 +227,18 @@ The preset mode changes on the master will be synced to the satellites.
The master can operate in 'minimal_on', 'balanced' or 'continuous' mode. This will determine the satellite timing scheduling. For the minimal_on mode the master valve is opened as short as possible, for balanced mode the opening time is balanced between heating power and duration and for continuous mode the valve opening time is extended as long as possible. All satellite valves operating as on-off switch are used for the nesting are scheduled in time to get a balanced heat requirement. In 'continuous' mode the satellite timing is scheduled aimed such that a continuous heat requirement is created. The master valve will be opened continuous when sufficient heat is needed. In low demand conditions an on-off mode is maintained.

The controller is called periodically and specified by control_interval.
If no pwm interval is defined, it will set the state of "heater" from 0 to "pwm_scale" value as for a proportional valve. Else, when pwm is specified it will operate in on-off mode and will switch proportionally with the pwm signal.
If no PWM interval is defined, it will set the state of "heater" from 0 to "PWM_scale" value as for a proportional valve. Else, when PWM is specified it will operate in on-off mode and will switch proportionally with the PWM signal.

with the data (as sub):
* satelites (Required): between square brackets defined list of thermostats by their name
* operation_mode (Optional): satellite nesting method: "minimal_on", "balanced" or "continuous". Default = "balanced"
* lower_load_scale (Optional): For nesting assumed minimum required load heater. Default = 0.15. (a minimum heating capacity of 15% assumed based on 100% when all rooms required heat)
* control_interval (Required): interval that controller is updated. The satellites should have a control_interval equal to the master or the master control_interval should be dividable by the satellite control_interval. Specify a time period.
* pwm_duration (Optional): Set period time for pwm signal. If it's not set, pwm is sending proportional value to switch. Specify a time period. Default = 0
* pwm_scale (Optional): Set analog output offset to 0. Example: If it's 500 the output value can be between 0 and 500. Default = 100
* pwm_resolution (optional): Set the resolution of the pwm_scale between min and max difference. Default = 50 (50 steps between 0 and 100)
* pwm_threshold (Optional): Set the minimal difference before activating switch. To avoid very short off-on-off or on-off-on changes. Default is not acitvated
* min_opening_for_propvalve (optional): Set the minimal percentage (between 0 and 1) active pwm when a proportional valve requires heat. Default 0 (* pwm_scale)
* PWM_duration (Optional): Set period time for PWM signal. If it's not set, PWM is sending proportional value to switch. Specify a time period. Default = 0
* PWM_scale (Optional): Set analog output offset to 0. Example: If it's 500 the output value can be between 0 and 500. Default = 100
* PWM_resolution (optional): Set the resolution of the PWM_scale between min and max difference. Default = 50 (50 steps between 0 and 100)
* PWM_threshold (Optional): Set the minimal difference before activating switch. To avoid very short off-on-off or on-off-on changes. Default is not acitvated
* min_opening_for_propvalve (optional): Set the minimal percentage (between 0 and 1) active PWM when a proportional valve requires heat. Default 0 (* PWM_scale)
* compensate_valve_lag (optional): Delay the opening of the master valve to assure that flow is guaranteed. Specify a time period. Default no delay.


Expand All @@ -211,28 +248,6 @@ The filter intesity is defined by a factor between 0 to 5 (integer).
0 = no filter
5 = max smoothing

# PID controller:
https://en.wikipedia.org/wiki/PID_controller

examples:
slow low temperature underfloor heating:
PID_mode:
kp: 30
ki: 0.005
kd: -24000

high temperature radiator:
PID_mode:
kp: 80
ki: 0.09
kd: -5000

* underfloor heating parameter optimisation: https://www.google.nl/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwi5htyg5_buAhXeQxUIHaZHB5QQFjAAegQIBBAD&url=https%3A%2F%2Fwww.mdpi.com%2F1996-1073%2F13%2F8%2F2068%2Fhtml&usg=AOvVaw3CukGrgPjpIO2eKM619BIn

PID controller explained. Would recommoned to read some of it:
[https://controlguru.com/table-of-contents/](https://controlguru.com/table-of-contents/)


# DEBUGGING:
debugging is possible by enabling logger in configuration with following configuration
```
Expand Down
15 changes: 8 additions & 7 deletions custom_components/multizone_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import DOMAIN as HA_DOMAIN, CoreState, HomeAssistant, callback
from homeassistant.core import DOMAIN as HA_DOMAIN, CoreState, HomeAssistant, callback, Event
from homeassistant.exceptions import ConditionError
from homeassistant.helpers import condition
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand All @@ -60,7 +60,7 @@
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.template import state_attr
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, EventType
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

from . import DOMAIN, PLATFORMS, UKF_config, hvac_setting, services
from .const import (
Expand Down Expand Up @@ -190,6 +190,7 @@ class MultiZoneThermostat(ClimateEntity, RestoreEntity):
"""Representation of a MultiZone Thermostat device."""

_attr_should_poll = False
_enable_turn_on_off_backwards_compatibility = False

def __init__(
self,
Expand Down Expand Up @@ -997,7 +998,7 @@ async def _async_routine_track_satelites(

@callback
def _async_indoor_temp_change(
self, event: EventType[EventStateChangedData]
self, event: Event[EventStateChangedData]
) -> None:
"""Handle temperature change.
Expand Down Expand Up @@ -1035,7 +1036,7 @@ def _async_indoor_temp_change(

@callback
def _async_outdoor_temp_change(
self, event: EventType[EventStateChangedData]
self, event: Event[EventStateChangedData]
) -> None:
"""Handle outdoor temperature changes.
Expand Down Expand Up @@ -1152,7 +1153,7 @@ def _async_stuck_switch_check(self, now) -> None:
)

@callback
def _async_satelite_change(self, event: EventType[EventStateChangedData]) -> None:
def _async_satelite_change(self, event: Event[EventStateChangedData]) -> None:
"""Handle satelite thermostat changes."""
new_state = event.data.get("new_state")
if not new_state:
Expand Down Expand Up @@ -1197,7 +1198,7 @@ def _async_satelite_change(self, event: EventType[EventStateChangedData]) -> Non
# self.schedule_update_ha_state(force_refresh=False)

@callback
def _async_switches_change(self, event: EventType[EventStateChangedData]) -> None:
def _async_switches_change(self, event: Event[EventStateChangedData]) -> None:
"""Handle device switch state changes."""
new_state = event.data.get("new_state")
entity_id = event.data.get(ATTR_ENTITY_ID)
Expand Down Expand Up @@ -2128,7 +2129,7 @@ def _is_valve_open(self, hvac_mode: HVACMode | None = None) -> bool:
def supported_features(self):
"""Return the list of supported features."""
return (
ClimateEntityFeature.PRESET_MODE | ClimateEntityFeature.TARGET_TEMPERATURE
ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON | ClimateEntityFeature.PRESET_MODE | ClimateEntityFeature.TARGET_TEMPERATURE
)

@property
Expand Down
Loading

0 comments on commit 04a53cd

Please sign in to comment.