Skip to content

Commit

Permalink
Implementing max_on_percent setting (#632)
Browse files Browse the repository at this point in the history
* implementing max_on_percent setting

* remove % sign from log message

* README updated: created new export-mode section, moved self-regulation expert settings to new section, added new section about on-time clamping
  • Loading branch information
ms5 authored Nov 17, 2024
1 parent c1d1e8f commit 289ccc7
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 77 deletions.
183 changes: 107 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,82 +389,6 @@ These three parameters make it possible to modulate the regulation and avoid mul
Self-regulation consists of forcing the equipment to go further by forcing its set temperature regularly. Its consumption can therefore be increased, as well as its wear.

#### Self-regulation in Expert mode

In **Expert** mode you can finely adjust the auto-regulation parameters to achieve your objectives and optimize as best as possible. The algorithm calculates the difference between the setpoint and the actual temperature of the room. This discrepancy is called error.
The adjustable parameters are as follows:
1. `kp`: the factor applied to the raw error,
2. `ki`: the factor applied to the accumulation of errors,
3. `k_ext`: the factor applied to the difference between the interior temperature and the exterior temperature,
4. `offset_max`: the maximum correction (offset) that the regulation can apply,
5. `stabilization_threshold`: a stabilization threshold which, when reached by the error, resets the accumulation of errors to 0,
6. `accumulated_error_threshold`: the maximum for error accumulation.

For tuning, these observations must be taken into account:
1. `kp * error` will give the offset linked to the raw error. This offset is directly proportional to the error and will be 0 when the target is reached,
2. the accumulation of the error makes it possible to correct the stabilization of the curve while there remains an error. The error accumulates and the offset therefore gradually increases which should eventually stabilize at the target temperature. For this fundamental parameter to have an effect it must not be too small. An average value is 30
3. `ki * accumulated_error_threshold` will give the maximum offset linked to the accumulation of the error,
4. `k_ext` allows a correction to be applied immediately (without waiting for errors to accumulate) when the outside temperature is very different from the target temperature. If the stabilization is done too high when the temperature differences are significant, it is because this parameter is too high. It should be possible to cancel completely to let the first 2 offsets take place

The pre-programmed values are as follows:

Slow régulation :

kp: 0.2 # 20% of the current internal regulation offset are caused by the current difference of target temperature and room temperature
ki: 0.8 / 288.0 # 80% of the current internal regulation offset are caused by the average offset of the past 24 hours
k_ext: 1.0 / 25.0 # this will add 1°C to the offset when it's 25°C colder outdoor than indoor
offset_max: 2.0 # limit to a final offset of -2°C to +2°C
stabilization_threshold: 0.0 # this needs to be disabled as otherwise the long term accumulated error will always be reset when the temp briefly crosses from/to below/above the target
accumulated_error_threshold: 2.0 * 288 # this allows up to 2°C long term offset in both directions

Light régulation :

kp: 0.2
ki: 0.05
k_ext: 0.05
offset_max: 1.5
stabilization_threshold: 0.1
accumulated_error_threshold: 10

Medium régulation :

kp: 0.3
ki: 0.05
k_ext: 0.1
offset_max: 2
stabilization_threshold: 0.1
accumulated_error_threshold: 20

Strong régulation :

"""Strong parameters for regulation
A set of parameters which doesn't take into account the external temp
and concentrate to internal temp error + accumulated error.
This should work for cold external conditions which else generates
high external_offset"""

kp: 0.4
ki: 0.08
k_ext: 0.0
offset_max: 5
stabilization_threshold: 0.1
accumulated_error_threshold: 50

To use Expert mode you must declare the values you want to use for each of these parameters in your `configuration.yaml` in the following form:
```
versatile_thermostat:
auto_regulation_expert:
kp: 0.4
ki: 0.08
k_ext: 0.0
offset_max: 5
stabilization_threshold: 0.1
accumulated_error_threshold: 50
```
and of course, configure the VTherm's self-regulation mode in **Expert** mode. All VTherms in Expert mode will use these same settings.

For the changes to be taken into account, you must either **completely restart Home Assistant** or just the **Versatile Thermostat integration** (Dev tools / Yaml / reloading the configuration / Versatile Thermostat).

#### Internal temperature compensation
Sometimes, a device’s internal temperature sensor (like in a TRV or AC) can give inaccurate readings, especially if it’s too close to a heat source. This can cause the device to stop heating too soon.
For example:
Expand Down Expand Up @@ -800,6 +724,113 @@ context:
> ![Tip](images/tips.png) _*Notes*_
> Controlling a central boiler using software or hardware such as home automation can pose risks to its proper functioning. Before using these functions, make sure that your boiler has safety functions and that they are working. Turning on a boiler if all the taps are closed can generate excess pressure, for example.

## Expert Mode Settings

Expert Mode settings refer to Settings made in the Home Assistant `configuration.yaml` file under the `versatile_thermostat` section. You might have to add this section by yourself to the `configuration.yaml` file.

These settings are meant to be used only in **specific niche cases and with careful considerations**.


The following sections describe the available export mode settings in detail with examples on how to configure them. Be aware that these settings require a **complete restart** of Home Assistant or a **reload of Versatile Thermostat integration** (Dev tools / Yaml / reloading the configuration / Versatile Thermostat) to take effect.


### Self-regulation in Expert mode

In **Expert** mode you can finely adjust the auto-regulation parameters to achieve your objectives and optimize as best as possible. The algorithm calculates the difference between the setpoint and the actual temperature of the room. This discrepancy is called error.
The adjustable parameters are as follows:
1. `kp`: the factor applied to the raw error,
2. `ki`: the factor applied to the accumulation of errors,
3. `k_ext`: the factor applied to the difference between the interior temperature and the exterior temperature,
4. `offset_max`: the maximum correction (offset) that the regulation can apply,
5. `stabilization_threshold`: a stabilization threshold which, when reached by the error, resets the accumulation of errors to 0,
6. `accumulated_error_threshold`: the maximum for error accumulation.

For tuning, these observations must be taken into account:
1. `kp * error` will give the offset linked to the raw error. This offset is directly proportional to the error and will be 0 when the target is reached,
2. the accumulation of the error makes it possible to correct the stabilization of the curve while there remains an error. The error accumulates and the offset therefore gradually increases which should eventually stabilize at the target temperature. For this fundamental parameter to have an effect it must not be too small. An average value is 30
3. `ki * accumulated_error_threshold` will give the maximum offset linked to the accumulation of the error,
4. `k_ext` allows a correction to be applied immediately (without waiting for errors to accumulate) when the outside temperature is very different from the target temperature. If the stabilization is done too high when the temperature differences are significant, it is because this parameter is too high. It should be possible to cancel completely to let the first 2 offsets take place

The pre-programmed values are as follows:

Slow régulation :

kp: 0.2 # 20% of the current internal regulation offset are caused by the current difference of target temperature and room temperature
ki: 0.8 / 288.0 # 80% of the current internal regulation offset are caused by the average offset of the past 24 hours
k_ext: 1.0 / 25.0 # this will add 1°C to the offset when it's 25°C colder outdoor than indoor
offset_max: 2.0 # limit to a final offset of -2°C to +2°C
stabilization_threshold: 0.0 # this needs to be disabled as otherwise the long term accumulated error will always be reset when the temp briefly crosses from/to below/above the target
accumulated_error_threshold: 2.0 * 288 # this allows up to 2°C long term offset in both directions

Light régulation :

kp: 0.2
ki: 0.05
k_ext: 0.05
offset_max: 1.5
stabilization_threshold: 0.1
accumulated_error_threshold: 10

Medium régulation :

kp: 0.3
ki: 0.05
k_ext: 0.1
offset_max: 2
stabilization_threshold: 0.1
accumulated_error_threshold: 20

Strong régulation :

"""Strong parameters for regulation
A set of parameters which doesn't take into account the external temp
and concentrate to internal temp error + accumulated error.
This should work for cold external conditions which else generates
high external_offset"""

kp: 0.4
ki: 0.08
k_ext: 0.0
offset_max: 5
stabilization_threshold: 0.1
accumulated_error_threshold: 50

To use Expert mode you must declare the values you want to use for each of these parameters in your `configuration.yaml` in the following form:
```
versatile_thermostat:
auto_regulation_expert:
kp: 0.4
ki: 0.08
k_ext: 0.0
offset_max: 5
stabilization_threshold: 0.1
accumulated_error_threshold: 50
```
and of course, configure the VTherm's self-regulation mode in **Expert** mode. All VTherms in Expert mode will use these same settings.

For the changes to be taken into account, you must either **completely restart Home Assistant** or just the **Versatile Thermostat integration** (Dev tools / Yaml / reloading the configuration / Versatile Thermostat).


### On Time Clamping (max_on_percent)


The calculated on time percent can be limited to a maximum percentage of the cycle duration. This setting has to be made in expert mode and will be used for all Versatile Thermostats.

```
versatile_thermostat:
max_on_percent: 0.8
```

The example above limits the maximum ON time to 80% (0.8) of the cycle length. If the cycle length is for example 600 seconds (10min), the maximum ON time will be limited to 480 seconds (8min). The remaining 120 seconds of the cycle will always remain in the OFF state.

There are three debug attributes of interest regarding this feature:

* `max_on_percent` # clamping setting as configured in expert mode
* `calculated_on_percent` # calculated on percent without clamping applied
* `on_percent` # used on percent with clamping applied


<details>
<summary>Parameter summary</summary>

Expand Down
2 changes: 2 additions & 0 deletions custom_components/versatile_thermostat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
CONF_THERMOSTAT_SWITCH,
CONF_THERMOSTAT_CLIMATE,
CONF_THERMOSTAT_VALVE,
CONF_MAX_ON_PERCENT,
)

from .vtherm_api import VersatileThermostatAPI
Expand Down Expand Up @@ -86,6 +87,7 @@
CONF_AUTO_REGULATION_EXPERT: vol.Schema(SELF_REGULATION_PARAM_SCHEMA),
CONF_SHORT_EMA_PARAMS: vol.Schema(EMA_PARAM_SCHEMA),
CONF_SAFETY_MODE: vol.Schema(SAFETY_MODE_PARAM_SCHEMA),
vol.Optional(CONF_MAX_ON_PERCENT): vol.Coerce(float),
}
),
},
Expand Down
6 changes: 5 additions & 1 deletion custom_components/versatile_thermostat/base_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
"is_device_active",
"target_temperature_step",
"is_used_by_central_boiler",
"temperature_slope"
"temperature_slope",
"max_on_percent"
}
)
)
Expand Down Expand Up @@ -507,6 +508,8 @@ def post_init(self, config_entry: ConfigData):
entry_infos.get(CONF_WINDOW_ACTION) or CONF_WINDOW_TURN_OFF
)

self._max_on_percent = api._max_on_percent

_LOGGER.debug(
"%s - Creation of a new VersatileThermostat entity: unique_id=%s",
self,
Expand Down Expand Up @@ -2666,6 +2669,7 @@ def update_custom_attributes(self):
"is_used_by_central_boiler": self.is_used_by_central_boiler,
"temperature_slope": round(self.last_temperature_slope or 0, 3),
"hvac_off_reason": self.hvac_off_reason,
"max_on_percent": self._max_on_percent,
}

_LOGGER_ENERGY.debug(
Expand Down
1 change: 1 addition & 0 deletions custom_components/versatile_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
# Global params into configuration.yaml
CONF_SHORT_EMA_PARAMS = "short_ema_params"
CONF_SAFETY_MODE = "safety_mode"
CONF_MAX_ON_PERCENT = "max_on_percent"

CONF_USE_MAIN_CENTRAL_CONFIG = "use_main_central_config"
CONF_USE_TPI_CENTRAL_CONFIG = "use_tpi_central_config"
Expand Down
11 changes: 11 additions & 0 deletions custom_components/versatile_thermostat/prop_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(
cycle_min: int,
minimal_activation_delay: int,
vtherm_entity_id: str = None,
max_on_percent: float = None,
) -> None:
"""Initialisation of the Proportional Algorithm"""
_LOGGER.debug(
Expand Down Expand Up @@ -78,6 +79,7 @@ def __init__(
self._off_time_sec = self._cycle_min * 60
self._security = False
self._default_on_percent = 0
self._max_on_percent = max_on_percent

def calculate(
self,
Expand Down Expand Up @@ -161,6 +163,15 @@ def _calculate_internal(self):
)
self._on_percent = self._calculated_on_percent

if self._max_on_percent is not None and self._on_percent > self._max_on_percent:
_LOGGER.debug(
"%s - Heating period clamped to %s (instead of %s) due to max_on_percent setting.",
self._vtherm_entity_id,
self._max_on_percent,
self._on_percent,
)
self._on_percent = self._max_on_percent

self._on_time_sec = self._on_percent * self._cycle_min * 60

# Do not heat for less than xx sec
Expand Down
5 changes: 5 additions & 0 deletions custom_components/versatile_thermostat/thermostat_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ThermostatOverSwitch(BaseThermostat[UnderlyingSwitch]):
"tpi_coef_int",
"tpi_coef_ext",
"power_percent",
"calculated_on_percent",
}
)
)
Expand Down Expand Up @@ -84,6 +85,7 @@ def post_init(self, config_entry: ConfigData):
self._cycle_min,
self._minimal_activation_delay,
self.name,
max_on_percent=self._max_on_percent,
)

lst_switches = config_entry.get(CONF_UNDERLYING_LIST)
Expand Down Expand Up @@ -149,6 +151,9 @@ def update_custom_attributes(self):
self._attr_extra_state_attributes["function"] = self._proportional_function
self._attr_extra_state_attributes["tpi_coef_int"] = self._tpi_coef_int
self._attr_extra_state_attributes["tpi_coef_ext"] = self._tpi_coef_ext
self._attr_extra_state_attributes[
"calculated_on_percent"
] = self._prop_algorithm.calculated_on_percent

self.async_write_ha_state()
_LOGGER.debug(
Expand Down
5 changes: 5 additions & 0 deletions custom_components/versatile_thermostat/thermostat_valve.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ThermostatOverValve(BaseThermostat[UnderlyingValve]): # pylint: disable=a
"auto_regulation_dpercent",
"auto_regulation_period_min",
"last_calculation_timestamp",
"calculated_on_percent",
}
)
)
Expand Down Expand Up @@ -99,6 +100,7 @@ def post_init(self, config_entry: ConfigData):
self._cycle_min,
self._minimal_activation_delay,
self.name,
max_on_percent=self._max_on_percent,
)

lst_valves = config_entry.get(CONF_UNDERLYING_LIST)
Expand Down Expand Up @@ -182,6 +184,9 @@ def update_custom_attributes(self):
if self._last_calculation_timestamp
else None
)
self._attr_extra_state_attributes[
"calculated_on_percent"
] = self._prop_algorithm.calculated_on_percent

self.async_write_ha_state()
_LOGGER.debug(
Expand Down
8 changes: 8 additions & 0 deletions custom_components/versatile_thermostat/vtherm_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
CONF_SAFETY_MODE,
CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_CENTRAL_CONFIG,
CONF_MAX_ON_PERCENT,
)

VTHERM_API_NAME = "vtherm_api"
Expand Down Expand Up @@ -60,6 +61,7 @@ def __init__(self) -> None:
self._central_mode_select = None
# A dict that will store all Number entities which holds the temperature
self._number_temperatures = dict()
self._max_on_percent = None

def find_central_configuration(self):
"""Search for a central configuration"""
Expand Down Expand Up @@ -107,6 +109,12 @@ def set_global_config(self, config):
if self._safety_mode:
_LOGGER.debug("We have found safet_mode params %s", self._safety_mode)

self._max_on_percent = config.get(CONF_MAX_ON_PERCENT)
if self._max_on_percent:
_LOGGER.debug(
"We have found max_on_percent setting %s", self._max_on_percent
)

def register_central_boiler(self, central_boiler_entity):
"""Register the central boiler entity. This is used by the CentralBoilerBinarySensor
class to register itself at creation"""
Expand Down
Loading

0 comments on commit 289ccc7

Please sign in to comment.