Created
June 13, 2026 12:55
-
-
Save sway/1be17b4ab3e57e236c61ecfcfd03f648 to your computer and use it in GitHub Desktop.
Tado X HA Blueprint for updating offset
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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