Skip to content

Instantly share code, notes, and snippets.

@mmackowiak
Last active September 16, 2025 13:53
Show Gist options
  • Select an option

  • Save mmackowiak/84092d0863d3b7f6330b96bd64fcb267 to your computer and use it in GitHub Desktop.

Select an option

Save mmackowiak/84092d0863d3b7f6330b96bd64fcb267 to your computer and use it in GitHub Desktop.
# TRV Temperature Calibration Blueprint
# Updated for zigbee2mqtt versions where current_temperature includes calibration offset
blueprint:
name: Temperature Calibration
description: Temperature calibration for Zigbee valve TS0601
domain: automation
input:
valve:
name: Smart Valve
selector:
entity:
domain: climate
temp_sensor:
name: External Temperature Sensor
selector:
entity:
domain: sensor
device_class: temperature
calibration_entity:
name: Calibration Entity
description: The number entity for local_temperature_calibration
selector:
entity:
domain: number
variables:
valve: !input valve
temp_sensor: !input temp_sensor
calibration_entity: !input calibration_entity
# Minimum change needed to update calibration
calibration_threshold: 0.25
# Maximum calibration offset allowed (±5°C)
max_calibration: 5.0
# Get current values
external_temp: "{{ states(temp_sensor) | float(0) | round(1) }}"
current_calibration: "{{ states(calibration_entity) | float(0) | round(1) }}"
# IMPORTANT: current_temperature now INCLUDES the calibration offset
# So we need to subtract it to get the raw TRV sensor reading
current_temp_with_calibration: "{{ state_attr(valve, 'current_temperature') | float(0) | round(1) }}"
trv_raw_reading: "{{ (current_temp_with_calibration - current_calibration) | round(1) }}"
# Calculate the new calibration needed (rounded to 0.5°C increments)
# New calibration = External temp - Raw TRV reading
new_calibration: "{{ ((external_temp - trv_raw_reading) * 2) | round(0) / 2 }}"
# Calculate how much the calibration would change
calibration_change: "{{ (new_calibration - current_calibration) | abs | round(2) }}"
trigger:
- platform: time_pattern
minutes: "/10"
condition:
- condition: and
conditions:
# Ensure all required data is available
- condition: template
value_template: "{{ states(temp_sensor) not in ['unavailable', 'unknown', '', 'none'] }}"
- condition: template
value_template: "{{ states(calibration_entity) not in ['unavailable', 'unknown', '', 'none'] }}"
- condition: template
value_template: "{{ state_attr(valve, 'current_temperature') not in [none, 'unavailable', 'unknown'] }}"
action:
- if:
- condition: template
value_template: "{{ calibration_change >= calibration_threshold }}"
- condition: template
value_template: "{{ new_calibration | abs <= max_calibration }}"
then:
- service: number.set_value
target:
entity_id: "{{ calibration_entity }}"
data:
value: "{{ new_calibration }}"
@mmackowiak
Copy link
Author

Just a note: in Z2M 2.0 local_temperature already includes local_temperature_calibration, so the old blueprint would start oscillating calibration value over time. Updated version accounts for that and also uses dedicated calibration number entity, as local_temperature_calibration is no longer a state in climate entity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment