|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
The climate: entity drives electrical heaters, a heating temperature interface and a generic heat pump, and what its card offers follows the device kind. A towel dryer reports the same kind as a radiator, so its entry adds io_model: towel_dryer; see Towel dryers. A heater with a night light adds io_model: heater_with_light; see Heaters with a night light. A heater with an adjustable setpoint (node type 52, subtype 1) is driven over its private register protocol (CMD_WRITE_PRIVATE, 0x20): the hub reads and writes registers such as the setpoint, the mode and the room temperature, and the entity shows what the heater reports. A plain electrical heater (node type 52, subtype 0) is commanded with heating levels in the standard EXECUTE (the eight-byte frame a Cozytouch bridge was heard sending in issue #228, with the level in the main parameter) and read with the ordinary status request. Reads and writes of the register protocol are confirmed on an Atlantic AGILIA IO radiator (see ADR 0054 for the design). The heating-level control of the plain heater is experimental, with no hardware confirmation yet (see ADR 0055).
Other heating devices (exterior heating is a fan; the Atlantic heat pump and boiler) have no profile, so a climate: entity bound to one of them (by raw type value) fails at boot with a log line saying so. Scan Paired Devices and Discover & Pair print a ready-to-paste climate: block for either kind.
climate: - platform: home_io_control name: "Living Room Radiator" io_device_id: "FEEB22" io_device_type: "electrical_heater" io_subtype: 1 status_poll_interval: 5min # optional; default 5 min, at least 60 s
What the card shows for each heater kind:
| Electrical heater with adjustable setpoint (io_subtype: 1) | Plain electrical heater (io_subtype: 0), experimental | |
|---|---|---|
| Control path | Private registers | Heating level in the standard EXECUTE |
| Modes | off, heat (manual), auto | off, heat (comfort level) |
| Presets | custom Program and Auto (the heater's own automatic modes) | away (frost protection), eco, comfort, boost; custom Comfort -1, Comfort -2; custom Secured, shown when the heater reports it and never set |
| Target temperature | 7.0 °C up to the heater's own maximum (28.0 °C until it reports one), 0.5 °C step | None: the card shows a setpoint control that the entity ignores |
| Current temperature | Yes | No |
| Action | heating, idle, off | No |
| Companion entities | Window binary sensor; Open Window Detection switch (disabled by default) | None |
An Atlantic Adelis towel dryer reports the same type and subtype as the AGILIA radiator (node type 52, subtype 1), so the hub cannot tell the two apart on the radio. Add io_model: towel_dryer to its entry to get the towel dryer's own card:
climate: - platform: home_io_control name: "Bathroom towel dryer" io_device_id: "BD684B" io_device_type: "electrical_heater" io_subtype: 1 io_model: towel_dryer system_key: !secret towel_dryer_key
| Towel dryer (io_model: towel_dryer) | |
|---|---|
| Control path | Private registers, with the towel dryer's own mode and temporary-state registers |
| Modes | off, heat (the display's MANUEL), auto (the display's PROG) |
| Presets | boost; custom Drying; none ends a boost or a drying run; comfort and eco are shown while the dryer's program runs (experimental, not selectable) |
| Target temperature | As for the radiator: 7.0 °C up to the heater's own maximum, 0.5 °C step; while the dryer's program runs, the temperature it heats to right now |
| Current temperature | Yes |
| Action | heating while the element runs (including boost and drying), idle, off |
| Companion entities | None: the towel dryer has no window function |
Everything is confirmed on two Adelis units: the readings (mode, boost and drying, room temperature, setpoint, whether the element runs) and the writes (target, mode, starting and ending boost and drying), each checked against the dryer's display.
The towel dryer is polled with five register reads (room temperature, setpoint, mode, temporary state, working rate); the first poll also reads its maximum setpoint and its eco setback. Boost and drying run for the duration set on the display.
While the mode is PROG and no boost or drying runs, each poll adds a sixth read, of the temperature the dryer holds right now. The card then shows that temperature as the target and the comfort or eco preset of the period that runs: comfort when the temperature equals the comfort setpoint, eco when it equals the comfort setpoint minus the eco setback. Selecting either preset sends nothing. A temperature that fits neither shows as the target with no preset, and the hub reads the setback again. Setting a target from Home Assistant still writes the comfort setpoint, so during an eco period the card keeps showing the eco temperature. This is experimental: it was read on one unit, in one comfort period and one eco period; the Atlantic Adelis page has the detail.
Without io_model: a towel dryer runs as a radiator: the target and the room temperature work, but the mode writes go to the radiator's register, boost and drying are missing, and the window entities do nothing. At the first poll the hub reads every 52/1 heater's model name and logs it, for example Device BD684B reports model name "ADELIS 2 DIGIT". It also logs a warning when the declaration looks wrong: a heater declared as a towel dryer that holds no towel-dryer mode, or one declared as anything else that does. The warning never changes what the hub does.
A Sauter Hekla has a dimmable night light and reports the same type and subtype as the AGILIA radiator. Add io_model: heater_with_light to its entry, and a night_light: block to get a light entity for it:
climate: - platform: home_io_control name: "Kids' room heater" io_device_id: "29FB38" io_device_type: "electrical_heater" io_subtype: 1 io_model: heater_with_light night_light: name: "Kids' room night light"
The heater itself works as the radiator does: the same card, the same window entities. night_light: takes the options of any ESPHome light, and it is rejected on a heater without io_model: heater_with_light.
Experimental and untested: no capture or hardware report exists for either. A heating temperature interface (node type 14, io_device_type: heating_temperature_interface) and a generic heat pump (node type 22, subtype 0, io_device_type: heat_pump) carry a temperature or a named setpoint in the standard EXECUTE's main parameter, and report it in the ordinary status read. The Atlantic heat pump and boiler subtypes (22/1, 22/2) have a different protocol and are not supported.
| Heating temperature interface | Heat pump | |
|---|---|---|
| Modes | off, heat (manual), auto | off, heat |
| Presets | comfort, eco; custom Secured | comfort, eco; custom Setback, Halted |
| Target temperature | 5.0–30.0 °C, 0.5 °C step | 5.0–30.0 °C, 0.5 °C step |
| Current temperature, action | None: nothing in the protocol this entity reads carries one | None |
| Temperature range on the wire | −40 to +80 °C, assumed; min_temperature: / max_temperature: override it | −40 to +80 °C, fixed |
| Companion entities | None | None |
climate: - platform: home_io_control name: "Thermostat" io_device_id: "6F7092" io_device_type: "heating_temperature_interface" min_temperature: -30 # optional: the range the thermostat encodes over max_temperature: 70
The usual companion diagnostic sensors (Device Name, Active Issue, Last Contact, RSSI, Exchange Failures, Unconfirmed Exchanges, Last Commanded By, Last Command Source) are generated as for the other platforms. Last Contact shows when the heater last answered a poll. A heater with an adjustable setpoint also gets a Window binary sensor (device_class: window) and an Open Window Detection switch. Both are experimental, and they are generated only when the YAML names the heater kind with io_device_type: "electrical_heater" and io_subtype: 1, and not for a towel dryer (io_model: towel_dryer). A heater with a night light gets a light entity when its entry has a night_light: block; see Heaters with a night light.
The setpoint goes on the wire as a 16-bit little-endian value in tenths of a degree (round(10 × °C), so 28.0 °C is 18 01). This component accepts 7.0–28.0 °C, 28.0 being the ceiling Atlantic radiator manuals document, and rejects anything outside that range rather than clamping or truncating. Setpoints above 25.5 °C need the second byte, and that part of the encoding is unverified on real hardware. If your radiator's own panel allows a different maximum, that is worth reporting.
7.0–12.0 °C is the frost-protection (hors-gel) band on these radiators, not a comfort setpoint; the panel's own comfort range starts at 12 °C. The codec still accepts 7–12 °C so a frost-protection setpoint can be commanded directly.
Takes device_id, function, and value. It reaches heaters that use the private register protocol (io_subtype: 1); a plain heater is commanded through the climate: entity only. verified is always false: an acknowledged write means the heater took the frame, and the climate entity reads the register back to show the result.
| function | value | Effect |
|---|---|---|
| power_on | (ignored) | Wake / retrieve paired devices. |
| set_temperature | float °C, 7.0–28.0 | Setpoint. |
| set_mode | auto | manual | prog | off | Operating mode. |
| set_presence | on | off | Presence / absence. The AGILIA IO acknowledges it; no visible effect observed. |
| set_open_window_detection | on | off | Switches the heater's open-window detection on or off (register 0x0106). |
| window_open | (ignored) | Reads the heater's window sensor (register 0x010E) and reports window open or window closed in the result message. |
| midnight_sync | (ignored) | Reads register 0x0130 (the comfort/eco/auto setpoint block). Despite the name, the payload is a 0x60 read, not a clock-set — the device's clock register is 0x010F and this component never writes it. Provided for protocol exploration; the ACK payload is logged at DEBUG. |
action: esphome.hioc_heltec_v2_heating_control data: device_id: "FEEB22" function: set_temperature value: "20.5"
An unknown function, an out-of-range temperature, or a non-climate device_id is reported in the result event's message and nothing is transmitted. A CMD_ERROR_RESP from the device surfaces its decoded result code in result_code / result_code_name. For power_on and midnight_sync (which are register reads) the 0x21 ACK payload is written to the DEBUG log — a midnight_sync read returns the ~17-byte setpoint block, which can help settle the 25.5-vs-28 °C question on real hardware.