Update ha-thermostat-calibration.yaml
revising logic to follow time pattern
This commit is contained in:
parent
26e8744b59
commit
d92a8734ed
1 changed files with 38 additions and 56 deletions
|
|
@ -1,10 +1,13 @@
|
||||||
blueprint:
|
blueprint:
|
||||||
name: Area Valve Temperature Offset Calibration
|
name: Area Valve Temperature Offset Calibration
|
||||||
author: Andreas Gammelgaard Damsbo
|
author: Andreas Gammelgaard Damsbo (Revised by AI)
|
||||||
description: |
|
description: |
|
||||||
Automatically calibrate the temperature offset of ALL smart radiator valves (TRVs)
|
Automatically calibrate the temperature offset of ALL smart radiator valves (TRVs)
|
||||||
in a specified area using readings from an external room temperature sensor.
|
in a specified area using readings from an external room temperature sensor.
|
||||||
|
|
||||||
|
This version runs on a time schedule and only updates the offset if the calculated
|
||||||
|
value differs from the current value on the valve, reducing unnecessary communication.
|
||||||
|
|
||||||
The blueprint discovers all climate entities in the chosen area and updates their
|
The blueprint discovers all climate entities in the chosen area and updates their
|
||||||
corresponding temperature offset entities based on the difference between each
|
corresponding temperature offset entities based on the difference between each
|
||||||
valve's internal sensor and the actual room temperature.
|
valve's internal sensor and the actual room temperature.
|
||||||
|
|
@ -12,18 +15,7 @@ blueprint:
|
||||||
Example use case:
|
Example use case:
|
||||||
- **area**: Living Room
|
- **area**: Living Room
|
||||||
- **external_sensor**: sensor.living_room_temperature
|
- **external_sensor**: sensor.living_room_temperature
|
||||||
- **rounding_step**: 1.0
|
- **run_interval**: /10 (every 10 minutes)
|
||||||
|
|
||||||
The blueprint will find all thermostats in "Living Room" and calibrate each one
|
|
||||||
to match the external sensor reading. Thermostats without offset entities are
|
|
||||||
automatically skipped.
|
|
||||||
|
|
||||||
Manual correction:
|
|
||||||
Use the **manual_correction** slider to bias the calculated offset in cases where
|
|
||||||
valves tend to stop heating too early or overheat even after calibration.
|
|
||||||
|
|
||||||
- Positive value (e.g., +0.3 °C): Valves assume room is warmer → reduce heating sooner
|
|
||||||
- Negative value (e.g., -0.3 °C): Valves assume room is cooler → prolong heating
|
|
||||||
|
|
||||||
domain: automation
|
domain: automation
|
||||||
source_url: https://gdamsbo.dk/forgejo/andreas/ha-thermostat-calibration/raw/branch/main/ha-thermostat-calibration.yaml
|
source_url: https://gdamsbo.dk/forgejo/andreas/ha-thermostat-calibration/raw/branch/main/ha-thermostat-calibration.yaml
|
||||||
|
|
@ -33,8 +25,7 @@ blueprint:
|
||||||
name: Area
|
name: Area
|
||||||
description: >
|
description: >
|
||||||
Select the area containing the thermostatic valves you want to calibrate.
|
Select the area containing the thermostatic valves you want to calibrate.
|
||||||
All climate entities in this area will be automatically calibrated using
|
All climate entities in this area will be automatically calibrated.
|
||||||
the external temperature sensor.
|
|
||||||
selector:
|
selector:
|
||||||
area: {}
|
area: {}
|
||||||
|
|
||||||
|
|
@ -42,28 +33,20 @@ blueprint:
|
||||||
name: External temperature sensor
|
name: External temperature sensor
|
||||||
description: >
|
description: >
|
||||||
Select the temperature sensor that measures the actual room temperature
|
Select the temperature sensor that measures the actual room temperature
|
||||||
for this area. This should be a reliable sensor that provides accurate
|
for this area.
|
||||||
ambient temperature readings.
|
|
||||||
Example: sensor.living_room_temperature
|
|
||||||
selector:
|
selector:
|
||||||
entity:
|
entity:
|
||||||
domain: sensor
|
domain: sensor
|
||||||
device_class: temperature
|
device_class: temperature
|
||||||
|
|
||||||
min_interval:
|
run_interval:
|
||||||
name: Minimum time between updates
|
name: Run Interval
|
||||||
description: >
|
description: >
|
||||||
The minimum amount of time (in seconds) that must pass before offsets
|
How often to check for offset updates. Format is a time pattern string
|
||||||
can be updated again. This prevents valves from being recalibrated too often.
|
(e.g., '/10' for every 10 minutes, '0' for every hour on the hour).
|
||||||
A typical value is 300 seconds (5 minutes).
|
default: "/10"
|
||||||
default: 300
|
|
||||||
selector:
|
selector:
|
||||||
number:
|
text: {}
|
||||||
min: 30
|
|
||||||
max: 3600
|
|
||||||
step: 1
|
|
||||||
mode: box
|
|
||||||
unit_of_measurement: s
|
|
||||||
|
|
||||||
rounding_step:
|
rounding_step:
|
||||||
name: Rounding step for offset value
|
name: Rounding step for offset value
|
||||||
|
|
@ -83,10 +66,8 @@ blueprint:
|
||||||
name: Manual correction (bias)
|
name: Manual correction (bias)
|
||||||
description: >
|
description: >
|
||||||
Additional manual bias applied to computed offsets **before rounding**.
|
Additional manual bias applied to computed offsets **before rounding**.
|
||||||
Use this if valves still behave undesirably after calibration:
|
Positive value makes valves think it's warmer (reduces heating sooner).
|
||||||
- **Positive value** (e.g., +0.1…+1.0 °C): Makes valves think it's **warmer** → **reduces** heating sooner
|
Negative value makes valves think it's cooler (prolongs heating).
|
||||||
- **Negative value** (e.g., -0.1…-1.0 °C): Makes valves think it's **cooler** → **prolongs** heating
|
|
||||||
Recommended start: 0.0 °C. Adjust in small steps (±0.1 °C) and observe behavior.
|
|
||||||
default: 0.0
|
default: 0.0
|
||||||
selector:
|
selector:
|
||||||
number:
|
number:
|
||||||
|
|
@ -100,8 +81,7 @@ blueprint:
|
||||||
name: Offset entity suffix pattern
|
name: Offset entity suffix pattern
|
||||||
description: >
|
description: >
|
||||||
The text pattern used to identify offset number entities.
|
The text pattern used to identify offset number entities.
|
||||||
By default, looks for entities containing "_local_temperature_offset".
|
Default: "_local_temperature_offset"
|
||||||
Only change this if your devices use a different naming pattern.
|
|
||||||
default: "_local_temperature_offset"
|
default: "_local_temperature_offset"
|
||||||
selector:
|
selector:
|
||||||
text: {}
|
text: {}
|
||||||
|
|
@ -111,19 +91,10 @@ max: 10
|
||||||
max_exceeded: silent
|
max_exceeded: silent
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
- platform: state
|
- platform: time_pattern
|
||||||
entity_id: !input external_sensor
|
minutes: !input run_interval
|
||||||
- platform: state
|
|
||||||
entity_id: climate.*
|
|
||||||
attribute: current_temperature
|
|
||||||
|
|
||||||
action:
|
action:
|
||||||
# Rate limiting check
|
|
||||||
- condition: template
|
|
||||||
value_template: >
|
|
||||||
{% set last = state_attr(this.entity_id, 'last_triggered') %}
|
|
||||||
{{ last is none or (as_timestamp(now()) - as_timestamp(last)) > min_interval }}
|
|
||||||
|
|
||||||
# Process each climate entity in the area
|
# Process each climate entity in the area
|
||||||
- repeat:
|
- repeat:
|
||||||
for_each: >
|
for_each: >
|
||||||
|
|
@ -147,19 +118,30 @@ action:
|
||||||
{% set offset_entities = entities | select('match', '^number\.') | select('search', offset_entity_suffix) | list %}
|
{% set offset_entities = entities | select('match', '^number\.') | select('search', offset_entity_suffix) | list %}
|
||||||
{{ offset_entities[0] if offset_entities else '' }}
|
{{ offset_entities[0] if offset_entities else '' }}
|
||||||
|
|
||||||
# Skip if no offset entity found
|
# Skip if no offset entity found or is unavailable
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ offset_entity != '' }}"
|
value_template: "{{ offset_entity != '' and states(offset_entity) not in ['unknown', 'unavailable'] }}"
|
||||||
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ states(offset_entity) not in ['unknown', 'unavailable'] }}"
|
|
||||||
|
|
||||||
# Calculate and set new offset
|
# Calculate and set new offset
|
||||||
- variables:
|
- variables:
|
||||||
current_offset: "{{ states(offset_entity) | float(0) }}"
|
current_offset: "{{ states(offset_entity) | float(0) }}"
|
||||||
raw_offset: "{{ external_temp - (valve_temp - current_offset) + manual_correction }}"
|
|
||||||
new_offset: "{{ ((raw_offset / rounding_step) | round(0)) * rounding_step }}"
|
|
||||||
|
|
||||||
|
# 1. Calculate the required offset based on the difference
|
||||||
|
# Required Offset = External Temp - (Valve Internal Temp - Current Offset) + Manual Correction
|
||||||
|
raw_offset_required: "{{ external_temp - (valve_temp - current_offset) + manual_correction }}"
|
||||||
|
|
||||||
|
# 2. Round the raw offset to the nearest rounding_step
|
||||||
|
# Safely scale, round, and scale back to minimize floating point errors
|
||||||
|
new_offset: >
|
||||||
|
{% set step = rounding_step | float(1.0) %}
|
||||||
|
{% set scale = (1 / step) | round(0) %}
|
||||||
|
{{ (raw_offset_required * scale) | round(0) / scale }}
|
||||||
|
|
||||||
|
# Only update if the calculated value is different from the current value
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ new_offset | round(3) != current_offset | round(3) }}"
|
||||||
|
|
||||||
|
# Set new offset
|
||||||
- service: number.set_value
|
- service: number.set_value
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ offset_entity }}"
|
entity_id: "{{ offset_entity }}"
|
||||||
|
|
@ -173,7 +155,7 @@ action:
|
||||||
variables:
|
variables:
|
||||||
target_area: !input target_area
|
target_area: !input target_area
|
||||||
external_sensor: !input external_sensor
|
external_sensor: !input external_sensor
|
||||||
min_interval: !input min_interval
|
run_interval: !input run_interval
|
||||||
rounding_step: !input rounding_step
|
rounding_step: !input rounding_step
|
||||||
manual_correction: !input manual_correction
|
manual_correction: !input manual_correction
|
||||||
offset_entity_suffix: !input offset_entity_suffix
|
offset_entity_suffix: !input offset_entity_suffix
|
||||||
Loading…
Add table
Reference in a new issue