ATAG ONE: new native openHAB binding (no more MQTT/Homie bridge)

Hi all,

This follows on from two older threads here — OpenTherm / ATAG ONE from 2019, which clarified that the ATAG ONE doesn’t need an OpenTherm gateway since it has its own local API, and ATAG ONE support via Homie/MQTT, where @ArdKuijpers has been maintaining atagone-mqtt as a bridge for the past few years.

TL;DR: I built a native openHAB binding for the ATAG ONE. No more Docker container, no MQTT broker, no Homie topic mapping — openHAB talks to the thermostat directly over its local LAN API.

Why move off the MQTT bridge

atagone-mqtt has done its job for years, but the more I leaned on it, the more the architecture itself became the problem, not the code in it:

  • It’s three moving parts (the bridge process, an MQTT broker, openHAB’s MQTT binding) standing between openHAB and a device that’s sitting on the same LAN.
  • Everything comes through as generic MQTT/Homie topics, so you lose proper typing — no native Units of Measurement, no proper DateTime/Number:Temperature channels, just strings and numbers you have to interpret yourself in item configs.
  • Timing-sensitive stuff (the vacation/duration handling, the boiler’s post-write restart window) is genuinely fiddly to get right, and doing it correctly through an extra hop made debugging much harder than it needed to be.

A native binding removes all of that. It’s a direct client for the same local HTTP API (port 10000) the bridge and kozmoz/atag-one-api already talk to — it just cuts out everything in between.

What it does today

  • Discovery: passive UDP listener (the thermostat broadcasts on port 11000), auto-populates the Inbox. Manual Thing configuration also works if you’d rather skip that.
  • Reads: room/outside/CH/DHW temperatures, water pressure, burner status and modulation, burning hours, weather status, device/boiler error codes, plus a set of advanced diagnostic channels (WiFi signal, voltage, PCB temp, etc.) behind “show advanced.”
  • Writes: target temperature, HVAC mode, holiday (vacation) mode — with real start/end date channels, not a hardcoded duration — and fireplace mode, where writing a duration activates it for exactly that duration.

Over in the Homie/MQTT thread, @ArdKuijpers made a good point about weather compensation: the ATAG ONE already does this natively if you set Operating mode to weather-dependent, so there’s no need to reimplement it. That’s actually part of why I went this direction — the binding just reads weather-status and hvac-mode straight off the device, so whatever mode you’ve configured on the thermostat is exactly what shows up, no separate logic to keep in sync.

Extend mode is exposed read-only for the same reason — it activates automatically when you write a setpoint while in auto mode, so there’s no separate “activate extend” API call to expose; the channel just reflects what the device is already doing.

Small shoutout to @herikw’s home-assistant-custom-components — it was one of my references for the protocol’s enum values while building this.

How it compares to atagone-mqtt

I went back through the bridge’s actual source, so here’s a grounded comparison including two places the bridge is currently ahead:

atagone-mqtt (bridge) atagone binding (native)
Architecture Bridge process + MQTT broker + Homie mapping Talks to the device directly
Discovery Auto-discovered via Homie MQTT Auto-discovered via its own UDP listener — equivalent, not an advantage
Typing Generic MQTT payloads Native Number:Temperature, Number:Time, DateTime with proper Units of Measurement
Vacation mode Day-count only, held in a Python variable Real vacation-start/vacation-end DateTime channels derived from the device’s own state
Extend mode Settable directly (ch_mode=4 + duration) Exposed read-only — in my testing, writing ch_mode=4 directly caused problems; the channel instead reflects the device’s real auto-activate-on-setpoint behavior
Fireplace/extend duration In-process default (60 min), forgotten on bridge restart, never reads the device’s stored value Reads the device’s actual stored default; writing activates for exactly the duration given
Enum/mode mapping Inherited from pyatag’s STATES table Independently re-verified against live device captures, cross-checked against kozmoz/atag-one-api, pyatag, and herikw’s HA integration

Status

It’s been through several rounds of testing against my own unit (including the write paths — vacation, fireplace, target temp) and a full code-quality/hardening pass. The PR is up: [atagone] Initial contribution by Ltty · Pull Request #21481 · openhab/openhab-addons · GitHub (opened as a draft for now — I’ll mark it ready for review shortly).

If anyone wants to try it early or has an ATAG ONE and is up for testing before it merges, here’s the JAR: Release ATAG ONE binding v0.1.0-beta (pre-release, for testing) · Ltty/openhab-addons · GitHub

@higgers — this should answer where things stand since your question in the other thread.

If it follows the Homie MQTT standard, OH should be able to auto discover them. I’m not super up on the Homie standard so can’t speak to the other issues and this is definitely not an argument against an official binding by any means. But if there is a problem with the Homie binding in OH at least an issue should be filed.

And if you post this to the marketplace it will be easier for user to install and test out until it gets merged.

Thanks Rich, and fair correction on discovery. You’re right, Homie MQTT devices do get auto-discovered by the MQTT binding. The binding’s UDP discovery is roughly equivalent, not an advantage. No bug to file. I wasn’t precise on this one, not a gap in the Homie binding.