The Tado API v2

Posted in Posted on 2017-01-07 15:00

I’ve been poking around in the Tado smart thermostat API again as the web application now uses v2. Here are the API calls I have found, including how to manually adjust the heating temperature. Tado haven’t published their API so this could change and break at any time.

In the descriptions below I list the API call then an example curl command to make the call, followed by an example response. I have replaced some parts of the response with “xxx” (for strings) or “123” (for numbers) so as not to reveal my personal data.

Authentication

To make any of the calls work, you first have to authenticate yourself (log in). It seems that you can just put your username and password as parameters for any call (this is what the Android mobile app does). For earlier versions of the API you could just log in and store a cookie but for v2 if you do not want to use your password every time you need to authenticate using OAuth (OAuth2 actually).

Username and Password

This is the simplest form of authentication. For any of the calls listed below you just need to specify your username and password as parameters. The examples below all assume you are using OAuth2 but you can easily adjust. For instance, replace:

$ curl "https://my.tado.com/api/v2/me" -H "Authorization: Bearer `cat /tmp/tadotoken`"

with

$ curl "https://my.tado.com/api/v2/me" -d username=you@yourEmail.whatever -d password=yourPassword

OAuth2

OAuth2 is primarily intended for authorisation but here we are basically using it for authentication. Hopefully Tado will add in API methods to allow us to add or remove devices and other clients. Right now we have to pretend to be the already-authorised existing web application client.

To use OAuth you have to send over your username and password and you get a token back plus an expiry time (currently 10 minutes) and a special token you could use to refresh the first one without sending the password again. To get all this you use the following call:

$ curl -s "https://my.tado.com/oauth/token" -d client_id=tado-webapp -d grant_type=password -d scope=home.user -d username=you@yourEmail.whatever -d password=yourPasssword

That returns some JSON data:

{
  "access_token": "eyJraW...somethingReallyQuiteLong...0UQ",
  "token_type": "bearer",
  "refresh_token": "xxx",
  "expires_in": 599,
  "scope": "home.user"
}

If you don’t have curl installed then just do sudo apt-get install curl first (similarly for perl below). Obviously, you need to replace yourPassword with your password and you@yourEmail.whatever with your email address that you use to log in to your Tado account. The information is sent over HTTPS so it is encrypted and no-one can see the password.

To execute any other commands we need to get hold of just the access_token and save it. The following command does just that by running the output through a Perl regular expression and then saving it in /tmp/tadotoken:

$ curl -s "https://my.tado.com/oauth/token" -d client_id=tado-webapp -d grant_type=password -d password=yourPasssword -d scope=home.user -d username=you@yourEmail.whatever | perl -pe 's/^.*"access_token"\s*:\s*"([^"]*).*/$1/' > /tmp/tadotoken

Alternatively, you could install jq (with sudo apt-get install jq) which is a command line JSON processor and do the job slightly more intuitively:

$ curl -s "https://my.tado.com/oauth/token" -d client_id=tado-webapp -d grant_type=password -d password=yourPasssword -d scope=home.user -d username=you@yourEmail.whatever  | jq -r '.access_token' > /tmp/tadotoken

The -r flag is needed because otherwise jq puts quotes around the value of the access token.

Once the token expires it’s probably easiest just to get a new one from scratch using the same command, but you can use the refresh token as follows:

$ curl -X POST -s "https://my.tado.com/oauth/token" -d client_id=tado-webapp -d grant_type=refresh_token -d refresh_token=REFRESH_TOKEN -d scope=home.user

That returns the same JSON as the first command with the password in so you can process it in the same way to extract a new access token.

To use some of the API you need to know your home’s ID number. You can get this using the /api/v2/me call. I have replaced my home ID with “99999” in the following documentation: you should insert yours instead.

Tado mobile API v1.6

We have a special mention here for a method in v1.6 of the mobile API (as used by the Android app). The method lets you access the graph data that you can see plotted in the mobile app (but for some reason, not in the webapp).

/mobile/1.6/getTemperaturePlotData

$ curl -X POST -s "https://my.tado.com/mobile/1.6/getTemperaturePlotData" -d fromDate=2017-02-04T23:42:00.012Z -d toDate=2017-02-06T00:17:59.047Z -d zoneId=1  -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "success": true,
  "minInsideTemperature": 17.695,
  "maxInsideTemperature": 22.695,
  "plotdata": [
    {
      "timestamp": "2017-02-04T23:42:00.012Z",
      "rxControlPhase": "COOLDOWN",
      "heatingOn": null,
      "insideTemperature": 20.67,
      "virtSolarIntensity": null,
      "thermostatOperation": "HOME",
      "setPointTemperature": 10,
      "hotWaterProduction": null
    },
    ... one entry approximately every 3 minutes ...
  ],
  "dayStatistics": {
    "2017-02-04": {
      "day": 1486166400000,
      "SLEEP": 0,
      "HOME": 86400000,
      "AWAY": 0,
      "MANUAL": 0,
      "NO_FREEZE": 0,
      "UNDEFINED": 0,
      "NO_INTERNET": 0
    },
    "2017-02-05": {
      "day": 1486252800000,
      "SLEEP": 0,
      "HOME": 86400000,
      "AWAY": 0,
      "MANUAL": 0,
      "NO_FREEZE": 0,
      "UNDEFINED": 0,
      "NO_INTERNET": 0
    },
    "2017-02-06": {
      "day": 1486339200000,
      "SLEEP": 0,
      "HOME": 75052283,
      "AWAY": 0,
      "MANUAL": 0,
      "NO_FREEZE": 0,
      "UNDEFINED": 0,
      "NO_INTERNET": 0
    }
  },
  "noConnection": [],
  "privacy": []
}

If you wanted to extract all the insideTemperature values from that mass of data you could pipe it through the excellent jq and do:

$ curl -X POST -s "https://my.tado.com/mobile/1.6/getTemperaturePlotData" -d fromDate=2017-02-04T23:42:00.012Z -d toDate=2017-02-06T00:17:59.047Z -d zoneId=1  -H "Authorization: Bearer `cat /tmp/tadotoken`" | jq '.plotdata | .[].insideTemperature'

For the POST parameters, you need to supply the fromDate and toDate in the full ISO 8601 format (not forgetting the “Z” on the end). I expect that for most installations the zoneId will be 1, but see the /api/v2/homes/99999/zones method further down to find out what your zones are.

Tado API v2

/api/v2/me

A GET on this endpoint provides information about the authenticated user, the home(s) and mobile devices.

$ curl "https://my.tado.com/api/v2/me" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "name": "xxx",
  "email": "xxx",
  "username": "xxx",
  "homes": [
    {
      "id": 99999,
      "name": "xxx"
    }
  ],
  "locale": "en_GB",
  "mobileDevices": [
    {
      "name": "xxx",
      "id": 12345,
      "settings": {
        "geoTrackingEnabled": true
      },
      "location": {
        "stale": true,
        "atHome": true,
        "bearingFromHome": {
          "degrees": 152.29927711986,
          "radians": 2.6581238341488
        },
        "relativeDistanceFromHomeFence": 0
      },
      "deviceMetadata": {
        "platform": "Android",
        "osVersion": "1.2.3",
        "model": "xxx",
        "locale": "en"
      }
    },
    etc
  ]
}

/api/v2/homes/99999

Once you have your home ID, you can use a GET here to find all sorts of information about the home.

$ curl "https://my.tado.com/api/v2/homes/99999" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "id": 99999,
  "name": "Phillips",
  "dateTimeZone": "Europe\/London",
  "temperatureUnit": "CELSIUS",
  "installationCompleted": true,
  "partner": null,
  "simpleSmartScheduleEnabled": true,
  "contactDetails": {
    "name": "Stephen C Phillips",
    "email": "xxx",
    "phone": "+4412345678901"
  },
  "address": {
    "addressLine1": "xxx",
    "addressLine2": null,
    "zipCode": "xxx",
    "city": "Southampton",
    "state": null,
    "country": "GBR"
  },
  "geolocation": {
    "latitude": 50.1234567,
    "longitude": -1.1234567
  }
}

/api/v2/homes/99999/weather

A GET on this endpoint returns the weather at the home’s location. The solar intensity is used by Tado to help determine the likely rate of heat loss from the home and therefore how much heating will be required. I guess the charts in the Tado app shows the sun as shining if the intensity was over some threshold.

$ curl "https://my.tado.com/api/v2/homes/99999/weather" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "solarIntensity": {
    "type": "PERCENTAGE",
    "percentage": 15.06,
    "timestamp": "2017-01-07T14:36:43.507Z"
  },
  "outsideTemperature": {
    "celsius": 10.25,
    "fahrenheit": 50.45,
    "timestamp": "2017-01-07T14:36:43.507Z",
    "type": "TEMPERATURE",
    "precision": {
      "celsius": 0.01,
      "fahrenheit": 0.01
    }
  },
  "weatherState": {
    "type": "WEATHER_STATE",
    "value": "SCATTERED_RAIN",
    "timestamp": "2017-01-07T14:36:43.507Z"
  }
}

So to get the outside temperature you could do the following:

$ curl -s "https://my.tado.com/api/v2/homes/38923/weather" -H "Authorization: Bearer `cat /tmp/tadotok en`" | jq '.outsideTemperature.celsius'

The -s flag for curl stops it reporting the progress statistics about the data transfer so that all you see is the actual temperature data.

For the weatherState I have observed SCATTERED_RAIN, FOGGY and NIGHT_CLOUDY so far.

/api/v2/homes/99999/devices

A GET on /devices returns lots of information about the Tado hardware installed in your home. In the example below I think “BU01” is the boiler controller, “GW02” is the gateway unit which plugs into my ethernet and provides the gateway between the wireless network Tado uses and the internet, and “RU01” is the remote thermostat.

$ curl "https://my.tado.com/api/v2/homes/99999/devices" -H "Authorization: Bearer `cat /tmp/tadotoken`"
[
  {
    "deviceType": "BU01",
    "serialNo": "BUxxx",
    "shortSerialNo": "BUx",
    "currentFwVersion": "12.34",
    "connectionState": {
      "value": true,
      "timestamp": "2017-01-07T14:28:41.122Z"
    },
    "characteristics": {
      "capabilities": [
        "IDENTIFY"
      ]
    }
  },
  {
    "deviceType": "GW02",
    "serialNo": "GWxxx",
    "shortSerialNo": "GWx",
    "currentFwVersion": "12.3",
    "connectionState": {
      "value": true,
      "timestamp": "2017-01-07T14:41:07.547Z"
    },
    "characteristics": {
      "capabilities": [

      ]
    },
    "gatewayOperation": "NORMAL"
  },
  {
    "deviceType": "RU01",
    "serialNo": "RUxxx",
    "shortSerialNo": "RUx",
    "currentFwVersion": "12.34",
    "connectionState": {
      "value": true,
      "timestamp": "2017-01-07T14:25:04.634Z"
    },
    "characteristics": {
      "capabilities": [
        "INSIDE_TEMPERATURE_MEASUREMENT",
        "IDENTIFY"
      ]
    }
  }
]

/api/v2/homes/99999/installations

A GET here returns more info on the Tado hardware in the home.

$ curl "https://my.tado.com/api/v2/homes/99999/installations" -H "Authorization: Bearer `cat /tmp/tadotoken`"
[
  {
    "id": 0,
    "type": "SALE_FITTING_ST_G1",
    "revision": 1,
    "state": "COMPLETED",
    "devices": [
      {
        "deviceType": "BU01",
        "serialNo": "BUxxx",
        "shortSerialNo": "BUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:28:41.122Z"
        },
        "characteristics": {
          "capabilities": [
            "IDENTIFY"
          ]
        }
      },
      {
        "deviceType": "RU01",
        "serialNo": "RUxxx",
        "shortSerialNo": "RUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:25:04.634Z"
        },
        "characteristics": {
          "capabilities": [
            "INSIDE_TEMPERATURE_MEASUREMENT",
            "IDENTIFY"
          ]
        }
      }
    ]
  }
]

/api/v2/homes/99999/users

A GET on this endpoint provides a combination of the users and their mobile devices.

$ curl "https://my.tado.com/api/v2/homes/99999/users" -H "Authorization: Bearer `cat /tmp/tadotoken`"
[
  {
    "name": "xxx",
    "email": "xxx@example.com",
    "username": "xxx@example.com",
    "homes": [
      {
        "id": 99999,
        "name": "xxx"
      }
    ],
    "locale": "en_GB",
    "mobileDevices": [
      {
        "name": "xxxPhone",
        "id": 123456,
        "settings": {
          "geoTrackingEnabled": true
        },
        "location": {
          "stale": false,
          "atHome": true,
          "bearingFromHome": {
            "degrees": 57.29429990161771,
            "radians": 0.9999741759082923
          },
          "relativeDistanceFromHomeFence": 0
        },
        "deviceMetadata": {
          "platform": "Android",
          "osVersion": "1.2.3",
          "model": "xxx",
          "locale": "en"
        }
      },
      etc
    ]
  },
  etc
]

/api/v2/homes/99999/mobileDevices

A GET on mobileDevices gives some potentially useful information: a list of all mobile devices that are linked to your home vua the Tado app, including their bearing from the home to help provide the small radar view of device locations.

$ curl "https://my.tado.com/api/v2/homes/99999/mobileDevices" -H "Authorization: Bearer `cat /tmp/tadotoken`"
[
  {
    "name": "xxx",
    "id": 12345,
    "settings": {
      "geoTrackingEnabled": true
    },
    "location": {
      "stale": true,
      "atHome": true,
      "bearingFromHome": {
        "degrees": 152.29927711986,
        "radians": 2.6581238341488
      },
      "relativeDistanceFromHomeFence": 0
    },
    "deviceMetadata": {
      "platform": "Android",
      "osVersion": "1.2.3",
      "model": "xxx",
      "locale": "en"
    }
  },
  etc
]

/api/v2/homes/99999/mobileDevices/deviceID

I expected that you’d be able to do a GET on e.g. https://my.tado.com/api/v2/homes/99999/mobileDevices/12345 where 12345 is the ID of one of the devices to get the subset of information about a specific device but this call returns a 404.

However, what you can do is delete a device. Attached to my Tado at the moment are 4 mobile phones but two of them are zombies: they were registered via the app but then after an app upgrade we had to log in again and the two phones appeared for a second time. You can remove a device through the web app but also through an HTTP DELETE command:

curl -X DELETE "https://my.tado.com/api/v2/homes/99999/mobileDevices/deviceID" -H "Authorization: Bearer `cat /tmp/tadotoken`"

/api/v2/homes/99999/zones

$ curl "https://my.tado.com/api/v2/homes/99999/zones" -H "Authorization: Bearer `cat /tmp/tadotoken`"
[
  {
    "id": 1,
    "name": "Heating",
    "type": "HEATING",
    "deviceTypes": [
      "BU01",
      "RU01"
    ],
    "devices": [
      {
        "deviceType": "BU01",
        "serialNo": "BUxxx",
        "shortSerialNo": "BUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:28:41.122Z"
        },
        "characteristics": {
          "capabilities": [
            "IDENTIFY"
          ]
        },
        "duties": [
          "CIRCUIT_DRIVER"
        ]
      },
      {
        "deviceType": "RU01",
        "serialNo": "RUxxx",
        "shortSerialNo": "RUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:25:04.634Z"
        },
        "characteristics": {
          "capabilities": [
            "INSIDE_TEMPERATURE_MEASUREMENT",
            "IDENTIFY"
          ]
        },
        "duties": [
          "ZONE_UI",
          "ZONE_LEADER"
        ]
      }
    ],
    "reportAvailable": true,
    "supportsDazzle": true,
    "dazzleEnabled": true
  },
  {
    "id": 0,
    "name": "Hot Water",
    "type": "HOT_WATER",
    "deviceTypes": [
      "BU01",
      "RU01"
    ],
    "devices": [
      {
        "deviceType": "BU01",
        "serialNo": "BUxxx",
        "shortSerialNo": "BUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:28:41.122Z"
        },
        "characteristics": {
          "capabilities": [
            "IDENTIFY"
          ]
        },
        "duties": [
          "ZONE_DRIVER"
        ]
      },
      {
        "deviceType": "RU01",
        "serialNo": "RUxxx",
        "shortSerialNo": "RUx",
        "currentFwVersion": "12.34",
        "connectionState": {
          "value": true,
          "timestamp": "2017-01-07T14:25:04.634Z"
        },
        "characteristics": {
          "capabilities": [
            "INSIDE_TEMPERATURE_MEASUREMENT",
            "IDENTIFY"
          ]
        },
        "duties": [
          "ZONE_UI",
          "ZONE_LEADER"
        ]
      }
    ],
    "reportAvailable": false,
    "supportsDazzle": false,
    "dazzleEnabled": true
  }
]

/api/v2/homes/99999/zones/0/state

Here’s where we get some key information. The “state” of a HOT_WATER zone might tell us if the hot water heating is on or off. It looks as though it is possible to obtain the temperature of the domestic hot water as well - perhaps I am missing a sensor?

$ curl "https://my.tado.com/api/v2/homes/99999/zones/0/state" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "tadoMode": "HOME",
  "geolocationOverride": true,
  "geolocationOverrideDisableTime": "2017-01-07T18:00:00Z",
  "preparation": null,
  "setting": {
    "type": "HOT_WATER",
    "power": "OFF",
    "temperature": null
  },
  "overlayType": null,
  "overlay": null,
  "link": {
    "state": "ONLINE"
  },
  "activityDataPoints": {

  },
  "sensorDataPoints": {

  }
}

/api/v2/homes/99999/zones/0/capabilities

$ curl "https://my.tado.com/api/v2/homes/99999/zones/0/capabilities" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "type": "HOT_WATER",
  "canSetTemperature": false
}

/api/v2/homes/99999/zones/1/state

A GET on the state for the central heating zone tells us the target and actual temperature and the humidity. Also the heatingPower, but I don’t know what that is.

$ curl "https://my.tado.com/api/v2/homes/99999/zones/1/state" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "tadoMode": "HOME",
  "geolocationOverride": false,
  "geolocationOverrideDisableTime": null,
  "preparation": null,
  "setting": {
    "type": "HEATING",
    "power": "ON",
    "temperature": {
      "celsius": 19.5,
      "fahrenheit": 67.1
    }
  },
  "overlayType": null,
  "overlay": null,
  "link": {
    "state": "ONLINE"
  },
  "activityDataPoints": {
    "heatingPower": {
      "type": "PERCENTAGE",
      "percentage": 20,
      "timestamp": "2017-01-07T14:30:59.439Z"
    }
  },
  "sensorDataPoints": {
    "insideTemperature": {
      "celsius": 19.37,
      "fahrenheit": 66.87,
      "timestamp": "2017-01-07T14:24:48.623Z",
      "type": "TEMPERATURE",
      "precision": {
        "celsius": 0.1,
        "fahrenheit": 0.1
      }
    },
    "humidity": {
      "type": "PERCENTAGE",
      "percentage": 58.7,
      "timestamp": "2017-01-07T14:24:48.623Z"
    }
  }
}

To extract the key pieces of information you could do the following:

$ curl -s "https://my.tado.com/api/v2/homes/99999/zones/1/state" -H "Authorization: Bearer `cat /tmp/tadotoken`" | jq '.setting.power .setting.temperature.celsius, .sensorDataPoints.insideTemperature.celsius, .sensorDataPoints.humidity.percentage'

That would return something like:

"ON"
19.5
19.69
60.5

/api/v2/homes/99999/zones/1/capabilities

$ curl "https://my.tado.com/api/v2/homes/99999/zones/1/capabilities" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "type": "HEATING",
  "temperatures": {
    "celsius": {
      "min": 5,
      "max": 25,
      "step": 0.1
    },
    "fahrenheit": {
      "min": 41,
      "max": 77,
      "step": 0.1
    }
  }
}

/api/v2/homes/99999/zones/1/overlay

Using a PUT on this endpoint we can manually set the heating temperature (an “overlay”) and query the manual setting. So to set the temperature to 21°C for example:

$ curl -X PUT "https://my.tado.com/api/v2/homes/38923/zones/1/overlay" -H "Authorization: Bearer `cat /tmp/tadotoken`" -H "Content-Type:application/json;charset=UTF-8" --data-binary '{"setting":{"type":"HEATING","power":"ON","temperature":{"celsius":21}},"termination":{"type":"MANUAL"}}'

The request payload is defined in the --data-binary argument and you must also define the content-type of the request data with the additional Content-Type header. Alternative termination types are TADO_MODE for stopping manual control when the next Tado mode change occurs or “TIMER” in which case you must also define how many seconds you want the manual mode to persist for. The request payload for that would be something like:

{
  "setting": {
    "type": "HEATING",
    "power": "ON",
    "temperature": {
      "celsius": 21
    }
  },
  "termination": {
    "type": "TIMER",
    "durationInSeconds": 900
  }
}

The response confirms the setting:

{
  "type": "MANUAL",
  "setting": {
    "type": "HEATING",
    "power": "ON",
    "temperature": {
      "celsius": 21,
      "fahrenheit": 69.8
    }
  },
  "termination": {
    "type": "TIMER",
    "durationInSeconds": 900,
    "expiry": "2017-01-08T13:31:36Z",
    "remainingTimeInSeconds": 763,
    "projectedExpiry": "2017-01-08T13:31:36Z"
  }
}

A GET on the endpoint will also return the JSON response above if an overlay is defined.

To remove manual control, you just do an HTTP DELETE on the same resource:

$ curl -X DELETE "https://my.tado.com/api/v2/homes/38923/zones/1/overlay" -H "Authorization: Bearer `cat /tmp/tadotoken`"

/api/v2/homes/99999/zones/1/schedule/activeTimetable

A GET here will return the type of schedule you have configured: I have the same programme for Mon-Fri and different ones on Sat and Sun (hence THREE_DAY).

$ curl "https://my.tado.com/api/v2/homes/99999/zones/1/schedule/activeTimetable" -H "Authorization: Bearer `cat /tmp/tadotoken`"
{
  "id": 1,
  "type": "THREE_DAY"
}

You can do a PUT on this endpoint with a payload of e.g. {"id":0} for instance to switch to a Mon-Sun schedule. To do this you have to add the data and its content type:

$ curl -X PUT "https://my.tado.com/api/v2/homes/38923/zones/1/schedule/activeTimetable" -H "Authorization: Bearer `cat /tmp/tadotoken`" -H "Content-Type:application/json;charset=UTF-8" --data-binary '{"id":0}'

/api/v2/users/name%40example.com/language

There is at least one method in this namespace, acting on a “user” resource (using the URL-endcoded email address as the identifier). Here you can do a PUT to change the language setting for a user, e.g.:

$ curl -X PUT "https://my.tado.com/api/v2/users/user%40example.com/language" -H "Authorization: Bearer `cat /tmp/tadotoken`" -H "Content-Type:application/json;charset=UTF-8" --data-binary '{"language":"en"}'

Any more?

I’ve seen a few more methods to do with configuring the schedule, but it’s all getting a bit complicated. Is there anything specific anyone wants to do with the API that I could try to document the method for?

Changelog

  • 2017-02-07: added instructions on using username/password authentication; added /mobile/1.6/getTemperaturePlotData call.

Comments

Comments powered by Disqus