Introduction
Tado X radiator thermostats measure the temperature directly at the radiator, often leading to inaccurate readings. With this solution, you can automatically adjust the temperature offset by using external room thermostats as a reference.
This guide shows you how to set the offset via Home Assistant by regularly generating a new access token and calculating the temperature difference between the room thermostat and the radiator thermostat.
Requirements
- Home Assistant (HA)
- Tado X radiator thermostats
- A separate room thermostat for more accurate measurements
- Developer tools in Firefox or Chrome to retrieve the refresh token
Step 1: Retrieve the Refresh Token
- Open the developer tab (before logging in!):
- Open app.tado.com, but do not log in yet!
- Open the developer tools with F12 and go to the Network tab → XHR.
- Now log in.
- Click on the first POST result. There, you will find the refresh token and client ID in the response, which you will need later in the
configuration.yaml
.
- Create a JSON file in Home Assistant Open the File Editor or the Studio Code Server and create the following file
/config/tado_rooms_devices.json
and/config/tado_response.json
with the following content:
{"refresh_token":"YOUR_REFRESH_TOKEN"}
Step 2: Add Shell Commands to configuration.yaml
Open your configuration.yaml
and add the following Shell Commands: ADD YOUR CLIENT ID
shell_command:
get_tado_token: >-
curl -s -X POST "https://login.tado.com/oauth2/token"
-d "client_id=>>>>>>>>>>>>>>>>CLIENT_ID_HERE<<<<<<<<<<<<<<<<<<"
-d "grant_type=refresh_token"
-d "refresh_token=$(jq -r '.refresh_token' /config/tado_response.json)"
> /config/tado_response.json
set_temperature_offset: >-
curl "https://hops.tado.com/homes/1763547/roomsAndDevices/devices/{{ device }}?ngsw-bypass=true"
-X PATCH
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0"
-H "Accept: application/json, text/plain, */*"
-H "Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3"
-H "Accept-Encoding: gzip, deflate, br, zstd"
-H "Content-Type: application/json"
-H "Referer: https://app.tado.com/"
-H "X-Amzn-Trace-Id: tado=webapp-2025.3.6.10.51-release/v3676"
-H "Origin: https://app.tado.com"
-H "Sec-Fetch-Dest: empty"
-H "Sec-Fetch-Mode: cors"
-H "Sec-Fetch-Site: same-site"
-H "Authorization: Bearer {{ access_token }}"
-H "Connection: keep-alive"
-H "Priority: u=0"
-H "TE: trailers"
--data-raw '{"temperatureOffset":{{ offset }}}'
get_tado_access_token: "jq -r '.access_token' /config/tado_response.json"
get_tado_rooms_devices_json: "jq -r '.' /config/tado_rooms_devices.json"
get_tado_temperature_as_measured: >-
jq -r '.rooms[].devices[] | select(.serialNumber=="{{ device }}") | .temperatureAsMeasured' /config/tado_rooms_devices.json
get_tado_rooms_devices: >-
curl -s "https://hops.tado.com/homes/1763547/roomsAndDevices?ngsw-bypass=true"
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0"
-H "Accept: application/json, text/plain, */*"
-H "Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3"
-H "Accept-Encoding: gzip, deflate, br, zstd"
-H "Referer: https://app.tado.com/"
-H "X-Amzn-Trace-Id: tado=webapp-2025.3.7.9.55-release/v3677"
-H "Origin: https://app.tado.com"
-H "Sec-Fetch-Dest: empty"
-H "Sec-Fetch-Mode: cors"
-H "Sec-Fetch-Site: same-site"
-H "Authorization: Bearer $(jq -r '.access_token' /config/tado_response.json)"
-H "Connection: keep-alive"
-H "TE: trailers"
> /config/tado_rooms_devices.json
Save and restart Home Assistant!
Step 3: Automation to Refresh the Access Token
Since the Access Token expires every 10 minutes, a new one must be generated regularly. Create a new automation with the following YAML code:
alias: Tado Load New Access Token Every 9 Minutes
description: ""
trigger:
- platform: time_pattern
minutes: "/9"
action:
- service: shell_command.get_tado_token
mode: single
Step 4: Automation to Calculate the Offset
Each time the temperature from the room thermostat or the Tado radiator valve changes, the offset is calculated and set:
alias: Offset berechnen
description: ""
triggers:
- trigger: state
entity_id:
- sensor.ROOMTermostat
- trigger: state
entity_id:
- sensor.Tado_Radiator_Termostat
conditions: []
actions:
- action: shell_command.get_tado_rooms_devices
metadata: {}
data: {}
- action: shell_command.get_tado_temperature_as_measured
metadata: {}
data:
device: VAxxxxxxxxxx
response_variable: temperature_as_measured
- action: shell_command.get_tado_access_token
data: {}
response_variable: bearer
- action: shell_command.set_temperature_offset
data:
device: VAxxxxxxxxxx
offset: >-
{{ ((states('sensor.ROOMTermostat') | float(0)) -
(temperature_as_measured.stdout | float(0))) | round(1) }}
access_token: "{{bearer.stdout}}"
- delay:
hours: 0
minutes: 0
seconds: 30
milliseconds: 0
enabled: true
mode: single
Explanations:
- INSERT_YOUR_DEVICE_SERIAL_NUMBER_HERE: Replace
VAxxxxxxxxxx
with the serial number of your Tado radiator thermostat. sensor.ROOMTermostat
= Room thermostat for accurate measurement.sensor.Tado_Radiator_Termostat
= Tado radiator thermostat.
Step 5: Testing & Activation
- Generate the Access Token: Go to Developer Tools → Actions and start
shell_command.get_tado_token
. - Check the file: Open
/config/tado_response.json
and ensure that theaccess_token
is stored. - Start the automation:
- Activate the 9-minute token renewal.
- Activate the offset calculation automation.
- Check the temperature values and offset values in Home Assistant.
- Ensure that the offset is applied in the Tado app.