Skip to content

Instantly share code, notes, and snippets.

@sway
Created June 13, 2026 12:55
Show Gist options
  • Select an option

  • Save sway/1be17b4ab3e57e236c61ecfcfd03f648 to your computer and use it in GitHub Desktop.

Select an option

Save sway/1be17b4ab3e57e236c61ecfcfd03f648 to your computer and use it in GitHub Desktop.
Tado X HA Blueprint for updating offset
blueprint:
name: Tado X – Temperature offset via external sensor (per TRV)
description: >
Keeps the temperature offset of an individual Tado X radiator valve (VA04)
or temperature sensor (SU04) in sync with a separate reference sensor.
Requires the **ha-tado-x** custom integration (HACS):
https://github.com/exabird/ha-tado-x
The blueprint targets a single **device** (not a room/climate entity), so
you can calibrate each TRV independently even when multiple valves share
the same room in Tado.
**How it works**
When either the Tado device temperature sensor or the reference sensor
changes, the automation recalculates the offset as:
new_offset = (reference_temp – tado_raw_temp) rounded to 1 decimal
The service call is skipped when:
- the reference sensor is unavailable / returns 0
- the computed offset is the same as the current one (within 0.1 °C)
**Logging** – set the logger level in `configuration.yaml` to see details:
```yaml
logger:
default: error
logs:
blueprints.tado_x.offset: debug
```
domain: automation
author: adapted for Tado X from clausd84/tado_temp_offset.yaml
input:
tado_device:
name: Tado X device (TRV or temperature sensor)
description: >
Select the individual Tado X radiator valve (VA04) or temperature
sensor (SU04) you want to calibrate. Each TRV is a separate device,
so you can create one automation per valve.
selector:
device:
integration: tado_x
# Tado X radiator valves and standalone sensors both expose a
# temperature sensor entity – narrow down to those device models if
# your installation mixes other device types.
tado_temp_sensor:
name: Tado X temperature entity (from the selected device)
description: >
Pick the **temperature sensor entity** that belongs to the device
selected above (e.g. `sensor.living_room_valve_temperature`). This is
the raw measurement the TRV reports before any offset is applied.
Tip: all Tado X temperature entities follow the pattern
`sensor.<device_name>_temperature`.
selector:
entity:
domain: sensor
device_class: temperature
reference_sensor:
name: Reference temperature sensor
description: >
The external sensor whose reading should be used as the true room
temperature (e.g. an Aqara, Zigbee, or ESPHome thermometer placed
away from the radiator).
selector:
entity:
domain: sensor
device_class: temperature
min_change:
name: Minimum offset change to trigger an update (°C)
description: >
Only call the Tado X API when the required offset change is at least
this large. Prevents constant tiny adjustments that drain the battery
and generate valve noise. Default: 0.1 °C.
default: 0.1
selector:
number:
min: 0.1
max: 2.0
step: 0.1
unit_of_measurement: "°C"
mode: slider
variables:
tado_device: !input tado_device
tado_temp_sensor: !input tado_temp_sensor
reference_sensor: !input reference_sensor
min_change: !input min_change
# Current raw temperature as reported by the TRV (before offset)
tado_raw_temp: >
{{ states(tado_temp_sensor) | float(none) }}
# Reference (true room) temperature
ref_temp: >
{{ states(reference_sensor) | float(none) }}
# Offset needed: how far the TRV reading is from reality
# Positive → TRV reads too low → we need a positive offset
# Negative → TRV reads too high → we need a negative offset
new_offset: >
{% if tado_raw_temp is not none and ref_temp is not none %}
{{ (ref_temp - tado_raw_temp) | round(1) }}
{% else %}
none
{% endif %}
trigger:
- platform: state
entity_id: !input tado_temp_sensor
- platform: state
entity_id: !input reference_sensor
condition:
# Both sensors must be available
- condition: template
value_template: >
{{ tado_raw_temp is not none and tado_raw_temp != 0
and ref_temp is not none and ref_temp != 0 }}
# Reference sensor must not be unavailable/unknown
- condition: template
value_template: >
{{ states(reference_sensor) not in ['unavailable', 'unknown', 'none'] }}
# Only act when the change exceeds the configured threshold
- condition: template
value_template: >
{{ new_offset is not none
and (new_offset | abs) >= (min_change | float) }}
action:
- service: system_log.write
data:
message: >
[Tado X offset] device={{ tado_device }}
tado_raw={{ tado_raw_temp }}°C ref={{ ref_temp }}°C
→ setting offset to {{ new_offset }}°C
level: info
logger: blueprints.tado_x.offset
- service: system_log.write
data:
message: >
[Tado X offset DEBUG]
tado_temp_sensor={{ tado_temp_sensor }}
reference_sensor={{ reference_sensor }}
tado_raw_temp={{ tado_raw_temp }}
ref_temp={{ ref_temp }}
new_offset={{ new_offset }}
min_change={{ min_change }}
level: debug
logger: blueprints.tado_x.offset
- action: tado_x.set_temperature_offset
data:
device_id: "{{ tado_device }}"
offset: "{{ new_offset }}"
mode: single
max_exceeded: silent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment