|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Status: Accepted · Recorded: 2026-09
Every hub-level control entity — the two arming switches (accept_foreign_pairing, recover_oneway_key), Scan Paired Devices, the tuning: {ui_controls: true} numbers/selects, each 1W identity's command buttons — is created dynamically from a flag inside the home_io_control: block. None of them needs a device to bind to (see HubBoundEntity), so none of them takes a separate platform entry.
Discover & Pair was the one exception: it shipped early as its own button: platform (button.py), before the flag-driven shape existed, and was never migrated. That inconsistency — one hub-level button needing a whole extra top-level YAML key that its siblings don't — is what this ADR fixes.
Default the new home_io_control.discover_and_pair_button flag to true, so a bare hub block reproduces "the button just works" for new users. Rejected: it doesn't reproduce anything, since a bare hub block creates no pairing button today either — the legacy button: entry is the only thing that ever did. Worse, it actively breaks every user who does have that entry: ESPHome refuses two button entities with the same object id, the hub's dynamic creation runs inside to_code() (after the legacy entry has already claimed the name during earlier schema validation), and that collision surfaces as an uncaught cv.Invalid traceback, not a clean validation message. The flag defaults to false, exactly like its three siblings.
Auto-suppress the duplicate via a FINAL_VALIDATE_SCHEMA cross-check (detect the legacy entry from the hub's own final-validate pass and silently skip the dynamic button). Rejected: the companion ID for a dynamically-created entity has to be declared during CONFIG_SCHEMA evaluation, long before FINAL_VALIDATE_SCHEMA runs (see ADR 0009 — an ID declared any later is silently dropped at runtime). Un-declaring one after the fact, once the component count has already been sized from it, is unverified territory for a purely cosmetic problem. With the flag defaulting to false, the collision this would have suppressed cannot happen in the first place.
Add discover_and_pair_button (default false) to the hub schema, wired exactly like scan_paired_devices_button: an _inject_hub_entity_id()-based post-validator declares the button's and its companion "Last Pairing Result" sensor's IDs during schema validation, and a create_discover_and_pair_button() helper builds both from to_code() when the flag is set.
The legacy button: platform (button.py) is not deleted outright. It keeps working exactly as before, with two additions:
Removal is deferred to a later release: turn CONFIG_SCHEMA into cv.invalid(...) (ESPHome's own idiom for a retired platform), then delete the file entirely once nobody's build depends on it.