npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tado2mqtt

v0.1.0

Published

Interface between the tado° cloud (heating zones, hot water, home presence) and MQTT

Readme

tado2mqtt

Interface between the tado° cloud and MQTT, following the mqtt-smarthome convention, built on mqtt-interfaces-core.

Heating zones, hot water and the home presence become retained status topics; target temperatures, modes and the presence are set over MQTT; Home Assistant finds every zone through MQTT discovery. The api allows 100 requests a day without Auto-Assist, so the adapter polls once per interval for all zones at once and keeps a budget with a reserve for commands.

Use TadoLocal next to it when you want local control without the cloud: it talks HomeKit to the bridge on the lan. tado2mqtt adds what only the cloud knows: heating power, the schedule, the home presence, the manual-override state.

Install

npm install -g tado2mqtt
tado2mqtt --login                       # once: approve the device code in a browser
tado2mqtt -u mqtt://broker              # run in the foreground
sudo tado2mqtt --install -n tado -u mqtt://broker   # systemd service tado2mqtt@tado

--login prints a url and a code; open the url, log in with the tado account and approve. The refresh token goes to <state-dir>/tokens.json and rotates from there. A running instance without tokens starts the same flow by itself: the url and the code are in the log and retained on <name>/status/login until approved, with a new code whenever one expires, so an unattended service (a container) can be logged in from any dashboard that shows the topic.

Docker

Multi-arch image (amd64, arm64, armv7). The login happens while running:

docker run -d --name tado2mqtt --restart unless-stopped -v tado2mqtt:/data \
  -e TADO2MQTT_MQTT_URL=mqtt://broker ghcr.io/handijk/tado2mqtt
docker logs tado2mqtt     # "login: open https://login.tado.com/oauth2/device?user_code=... and approve"

/data is the state directory: tokens.json and budget.json live there. The image runs as uid 1000; a bind mount must be writable for that user.

Topics

Instance name tado (--name); status payloads are {"val": ..., "ts": ..., "lc": ...} unless --no-json-payloads.

| topic | retained | value | | ----------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- | | tado/connected | yes | 0 gone, 1 broker only, 2 the last poll succeeded | | tado/status/login | yes | {verification_uri, verification_uri_complete, user_code, expires_at} while a login is pending; cleared after | | tado/status/home/id, .../home/name | yes | the home | | tado/status/home/presence | yes | HOME or AWAY | | tado/status/home/presence_locked | yes | true when set by hand, false under geofencing | | tado/status/bridge/zones | yes | number of zones | | tado/status/bridge/quota | yes | {used, limit, reserve, remaining, reset, blocked, api} | | tado/status/zones/<zone>/temperature | yes | °C | | tado/status/zones/<zone>/humidity | yes | % | | tado/status/zones/<zone>/heating_power | yes | % (heating zones) | | tado/status/zones/<zone>/target_temperature | yes | °C, null when off | | tado/status/zones/<zone>/power | yes | ON or OFF | | tado/status/zones/<zone>/mode | yes | auto (schedule), heat (manual override), off | | tado/status/zones/<zone>/action | yes | heating, idle, off | | tado/status/zones/<zone>/overlay_active | yes | true while a manual override is on | | tado/status/zones/<zone>/overlay | yes | {termination: {type, expiry, remainingTimeInSeconds}} or null | | tado/status/zones/<zone>/open_window | yes | true while open-window detection pauses the zone | | tado/status/zones/<zone>/open_window_remaining | yes | seconds, or null | | tado/status/zones/<zone>/link | yes | ONLINE or OFFLINE | | tado/status/zones/<zone>/next_schedule_change | yes | ISO time or null | | tado/status/zones/<zone>/tado_mode | yes | HOME or AWAY as the zone sees it | | tado/status/zones/<zone>/id, .../name, .../type | yes | the zone (HEATING, HOT_WATER, AIR_CONDITIONING) |

<zone> is the zone name as a slug (Woonkamer → woonkamer), or the zone id with --zone-topics id. Two zones with the same slug get their id appended. A renamed zone moves to new topics and the old ones are cleared.

Commands

| topic | payload | | ------------------------------------------ | ------------------------------------------------------------------------- | | tado/set/zones/<zone>/target_temperature | 21.5 — manual override at that temperature, --termination long | | tado/set/zones/<zone>/mode | auto back to the schedule, heat override at the current target, off | | tado/set/zones/<zone>/power | off override with heating off, on back to the schedule | | tado/set/zones/<zone>/overlay | {"temperature": 21, "power": "ON", "termination": "manual"} | | tado/set/home/presence | HOME, AWAY or AUTO (geofencing) |

termination is next_time_block (until the schedule changes, the default), manual (until changed again) or a number of seconds. Every command is followed by a poll, so the status reflects what tado did, not what was asked.

Home Assistant

Discovery is on by default (--no-ha-discovery turns it off and clears it). The home is the bridge device with a presence select and the quota sensor; every zone is a device of its own behind it with a climate entity (modes auto, heat, off; action from the heating power), humidity, heating power, open window and manual-override sensors. A hot water zone is a switch.

The request budget

tado allows 100 api requests a day per account without Auto-Assist and answers every request with its own counters. The adapter spends them like this:

| what | requests | | ---------------------------------------------------- | ------------------------------------- | | the home, once | 1 | | zone states, every --poll-interval (20 min) | 1 per poll, 72 a day | | zone list + presence, every --zones-interval (6 h) | 2 per refresh, 8 a day | | every command | 2 (the command and the poll after it) |

Polling stops when only --budget-reserve requests are left (10), so commands still work; a 429 blocks until the api's window resets. tado/status/bridge/quota shows where the day stands.

Options

Run tado2mqtt --help for the full list; every option is also an environment variable (TADO2MQTT_POLL_INTERVAL, …), see --config-schema.

| option | default | | | ------------------ | ------------------------- | ------------------------------------------------------------------------------- | | --state-dir | $STATE_DIRECTORY or . | tokens, counters | | --token-file | <state-dir>/tokens.json | | | --refresh-token | | a refresh token from another tado client, used once when there is no token file | | --home-id | the first home | | | --poll-interval | 1200 | seconds between zone state polls | | --zones-interval | 21600 | seconds between zone list and presence refreshes | | --daily-limit | 100 | requests a day the budget allows | | --budget-reserve | 10 | requests kept for commands | | --termination | next_time_block | manual, next_time_block or seconds | | --zone-topics | name | name or id | | --login | | run the login on the terminal and exit |

Shared options: --mqtt-url/-u, --mqtt-username, --mqtt-password, --mqtt-tls-ca, --name/-n, --json-payloads, --ha-discovery, --ha-prefix, --maintenance, --stats-interval, --verbosity/-v, --install, --uninstall, --config-schema.

License

MIT