This page documents the YAML configuration for the home_io_control external component and its ESPHome platforms.
How It Works
IO-Homecontrol is a proprietary 868 MHz radio protocol used by Somfy, Velux, and other manufacturers for motorized shutters, blinds, awnings, and related home devices. This component implements the 2-Way (2W) variant, which means the controller sends commands and devices reply with position feedback.
Key concepts:
- Node ID: Every participant on the radio network has a unique 3-byte address (e.g., C0FFEE). You choose one for your controller and each device has one factory-assigned.
- System key: A 16-byte AES key shared between the controller and all paired devices. Commands that change device state (open, close, set position) are authenticated with this key using a challenge-response exchange.
- Frequency hopping: The controller hops between three 868 MHz channels (~2.7 ms per channel) while idle, listening for incoming status updates.
- Pairing: Before a device can be controlled, it must be paired — the controller transmits the system key to the device over a short encrypted exchange. The device must be in pairing mode (PROG button) during this step.
- YAML as source of truth: Device type and subtype live in the YAML config. Cover inversion can be forced with invert_position, otherwise the controller falls back to the learned device profile. Pairing prints a ready-to-paste YAML snippet in the logs when enough metadata is known.
- Automatic status polling: The controller periodically polls each device for its current position. Devices can also push unsolicited status updates, which the controller authenticates and processes automatically.
Minimal Example
external_components:
- source: github://laberning/home_io_control
spi:
clk_pin: 5
mosi_pin: 27
miso_pin: 19
home_io_control:
cs_pin: 18
rst_pin: 14
dio0_pin: 26
node_id: "C0FFEE"
system_key: "00112233445566778899AABBCCDDEEFF"
cover:
- platform: home_io_control
name: "Patio Awning"
device_class: awning
io_device_id: "FEEB1E"
button:
- platform: home_io_control
name: "Discover & Pair"
Home IO Control Component
The home_io_control: block defines the shared radio/controller hub. All cover, light, switch, and button entities attach to this hub.
home_io_control:
cs_pin: 18
rst_pin: 14
dio0_pin: 26
node_id: "C0FFEE"
system_key: "00112233445566778899AABBCCDDEEFF"
Configuration variables:
- id (Optional): Manually specify the hub ID for code generation. Use this when entity blocks should reference a specific hub with home_io_control_id.
- cs_pin (Required): SPI chip select pin for the radio.
- rst_pin (Required): Radio reset pin.
- dio0_pin (Optional): SX1276 DIO0 interrupt pin.
- dio4_pin (Optional): SX1276 DIO4 preamble-detect pin. Most boards do not wire this.
- dio1_pin (Optional): SX1262 DIO1 interrupt pin.
- busy_pin (Optional): SX1262 BUSY pin.
- node_id (Required): 3-byte controller ID as exactly 6 hexadecimal characters.
- system_key (Required): 16-byte installation key as exactly 32 hexadecimal characters.
- tx_power (Optional, default: 17): Radio transmit power. The schema currently accepts 0 to 22.
- pa_pin (Optional, default: BOOST): SX1276 PA path. Valid values are BOOST and RFO.
- radio_type (Optional): Force radio selection. Valid values are sx1276 and sx1262. If omitted, the component auto-detects.
- fem_en_pin (Optional): Front-end module enable pin for boards with an external RF front-end.
- vfem_pin (Optional): Front-end module power pin for boards with an external RF front-end.
- fem_pa_pin (Optional): Front-end module PA select pin for boards with an external RF front-end.
- tcxo_voltage (Optional, default: 1_8V): SX1262 TCXO voltage. Valid values are 1_6V, 1_7V, 1_8V, 2_2V, 2_4V, 2_7V, 3_0V, and 3_3V.
Notes:
- The SPI bus itself is configured separately in the top-level spi: block.
- The component extends ESPHome's SPI device schema, so standard SPI-device options apply in addition to the keys above.
- SX1276 and SX1262 use different interrupt pin sets. Only configure the pins for the radio you actually have.
Radio-Specific Pin Requirements
| Radio | Required hub pins | Optional hub pins | Typical extra setting |
| SX1276 | cs_pin, rst_pin, dio0_pin | dio4_pin | pa_pin: BOOST |
| SX1262 | cs_pin, rst_pin, dio1_pin, busy_pin | fem_en_pin, vfem_pin, fem_pa_pin | radio_type: sx1262, tcxo_voltage: 1_8V |
Cover Platform
Use the cover platform for position-capable IO-homecontrol devices such as shutters, awnings, blinds, openers, curtains, and related families.
cover:
- platform: home_io_control
id: patio_awning
name: "Patio Awning"
device_class: awning
io_device_id: "FEEB1E"
invert_position: true
status_poll_interval: 2s
linked_remotes:
- "ABCDEF"
Configuration variables:
- home_io_control_id (Optional): Reference to the home_io_control hub to use.
- io_device_id (Required): 3-byte IO-homecontrol device ID as exactly 6 hexadecimal characters.
- io_device_type (Optional): Declare the IO-homecontrol device type. Use a named value such as awning when available, or a raw integer such as 0x11 if pairing reports a type that does not yet have a named YAML alias. When omitted, the controller may learn the type later from radio metadata.
- io_subtype (Optional): Device subtype value (0–63), as reported by the device. When omitted, the controller may learn it later from radio metadata.
- invert_position (Optional): Explicitly override the open/close position mapping. When omitted, the controller uses the learned device profile and automatically inverts families such as horizontal awnings once their type is known.
- status_poll_interval (Optional): Poll interval used for bounded follow-up status checks while this device is expected to be changing state. The minimum supported value is 500ms. When omitted, the controller keeps the legacy single follow-up settle poll after local commands or overheard remote activity, but does not continue repeated movement polling.
- linked_remotes (Optional): List of remote node IDs (6 hex characters each) that control this device. When activity from a linked remote is overheard on the radio, the controller automatically polls the device for fresh status 2 seconds later. This is particularly useful for 1W (one-way) remotes whose radio address differs from the device's 2W ID.
- All standard options from the ESPHome cover base schema also apply, including id, name, device_class, icon, entity metadata, MQTT options, and cover automations such as on_opening, on_closing, and on_idle.
Notes:
- This is the primary and best-validated platform in the repo.
- Additional recognized cover families include venetian blinds, dual shutters, louvre blinds, rolling door openers, curtain tracks, and swinging shutters.
- status_poll_interval is movement-scoped, not a continuous background refresh. The hub only keeps polling while a local command or overheard remote activity suggests that the device should still be changing, and it stops automatically once the device reports a stable state or the bounded polling window expires.
- Unsolicited 0x71 device status updates are always applied to the entity state. They only extend automatic repeated polling when status_poll_interval is configured; without it, the hub falls back to the single settle poll armed by the original command or remote activity.
Light Platform
Use the light platform for binary on/off IO-homecontrol light devices.
light:
- platform: home_io_control
id: garden_light
name: "Garden Light"
io_device_id: "D15C05"
Configuration variables:
- home_io_control_id (Optional): Reference to the home_io_control hub to use.
- io_device_id (Required): 3-byte IO-homecontrol device ID as exactly 6 hexadecimal characters.
- io_device_type (Optional): Declare the IO-homecontrol device type. Use the named value light when known, or a raw integer such as 0x06 if you are working from a pairing log that reports a not-yet-exposed alias. When omitted, the controller may learn the type later from radio metadata.
- io_subtype (Optional): Device subtype value (0–63), as reported by the device. When omitted, the controller may learn it later from radio metadata.
- status_poll_interval (Optional): Poll interval used for bounded follow-up status checks while this device is expected to be changing state. The minimum supported value is 500ms. When omitted, the controller keeps the default single settle poll after a local command or overheard remote activity.
- linked_remotes (Optional): List of remote node IDs (6 hex characters each) that control this device. See the cover platform for details.
- All standard options from the ESPHome light schema also apply.
Notes:
- This platform is intentionally binary only. Dimming is not exposed.
- The current implementation is still experimental and untested on local hardware in this repo.
- Known non-light device families will be rejected once the device type is known.
Switch Platform
Use the switch platform for binary on/off IO-homecontrol switch devices.
switch:
- platform: home_io_control
id: irrigation_switch
name: "Irrigation Switch"
io_device_id: "112233"
Configuration variables:
- home_io_control_id (Optional): Reference to the home_io_control hub to use.
- io_device_id (Required): 3-byte IO-homecontrol device ID as exactly 6 hexadecimal characters.
- io_device_type (Optional): Declare the IO-homecontrol device type. Use the named value on_off_switch when known, or a raw integer such as 0x0F if pairing reports a type without a named YAML alias yet. When omitted, the controller may learn the type later from radio metadata.
- io_subtype (Optional): Device subtype value (0–63), as reported by the device. When omitted, the controller may learn it later from radio metadata.
- status_poll_interval (Optional): Poll interval used for bounded follow-up status checks while this device is expected to be changing state. The minimum supported value is 500ms. When omitted, the controller keeps the default single settle poll after a local command or overheard remote activity.
- linked_remotes (Optional): List of remote node IDs (6 hex characters each) that control this device. See the cover platform for details.
- All standard options from the ESPHome switch schema also apply.
Notes:
- This platform is also experimental and currently limited to binary on/off semantics.
- Known non-switch device families will be rejected once the device type is known.
Button Platform
Use the button platform to expose a Home Assistant button that starts discovery and pairing.
button:
- platform: home_io_control
name: "Discover & Pair"
Configuration variables:
- home_io_control_id (Optional): Reference to the home_io_control hub to use.
- All standard options from the ESPHome button schema also apply.
Notes:
- The generated button defaults to the config entity category.
- Pair devices one at a time.
Complete Examples
Minimal SX1276 Cover Controller
esphome:
name: io-homecontrol-sx1276
esp32:
variant: esp32
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
logger:
api:
ota:
- platform: esphome
spi:
clk_pin: 5
mosi_pin: 27
miso_pin: 19
external_components:
- source: github://laberning/home_io_control
home_io_control:
cs_pin: 18
rst_pin: 14
dio0_pin: 26
node_id: "C0FFEE"
system_key: "00112233445566778899AABBCCDDEEFF"
cover:
- platform: home_io_control
name: "Awning"
device_class: awning
io_device_id: "FEEB1E"
io_device_type: "awning"
io_subtype: 0
invert_position: true
button:
- platform: home_io_control
name: "Discover & Pair"
Minimal SX1262 Cover Controller
esphome:
name: io-homecontrol-sx1262
esp32:
variant: esp32s3
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
logger:
api:
ota:
- platform: esphome
spi:
clk_pin: 9
mosi_pin: 10
miso_pin: 11
external_components:
- source: github://laberning/home_io_control
home_io_control:
cs_pin: 8
rst_pin: 12
dio1_pin: 14
busy_pin: 13
radio_type: sx1262
tcxo_voltage: 1_8V
node_id: "C0FFEE"
system_key: "00112233445566778899AABBCCDDEEFF"
cover:
- platform: home_io_control
name: "Awning"
device_class: awning
io_device_id: "FEEB1E"
io_device_type: "awning"
io_subtype: 0
invert_position: true
button:
- platform: home_io_control
name: "Discover & Pair"
Minimal Example with all Device Types: Cover, Light, and Switch
home_io_control:
cs_pin: 18
rst_pin: 14
dio0_pin: 26
node_id: "C0FFEE"
system_key: "00112233445566778899AABBCCDDEEFF"
cover:
- platform: home_io_control
id: patio_awning
name: "Patio Awning"
device_class: awning
io_device_id: "123ABC"
io_device_type: "awning"
io_subtype: 0
light:
- platform: home_io_control
id: garden_light
name: "Garden Light"
io_device_id: "D15C05"
io_device_type: "light"
io_subtype: 0
switch:
- platform: home_io_control
id: irrigation_switch
name: "Irrigation Switch"
io_device_id: "D0661E"
io_device_type: "on_off_switch"
io_subtype: 0
button:
- platform: home_io_control
name: "Discover & Pair"
Repo-Backed Example Configs
For larger working examples, see the configs already in this repo:
- config/heltec-wifi-lora-32-v2.yaml: SX1276 Heltec LoRa32 V2 controller config with one awning cover, a Discover & Pair button, and an OLED status display that shows recent activity.
- config/heltec-wifi-lora-32-v2-all-types.yaml: SX1276 Heltec LoRa32 V2 controller config without OLED support that exercises every currently supported ESPHome platform in this component: cover, light, switch, and the Discover & Pair button, all with dummy device IDs ready to replace.
- config/heltec-wifi-lora-32-v3.yaml: SX1262 Heltec WiFi LoRa32 V3/V3.2 controller config with one awning cover, a Discover & Pair button, and an OLED status display tuned for the V3 pinout and TCXO settings.
- config/heltec-wifi-lora-32-v3-monitor.yaml: SX1262 passive monitor config for Heltec WiFi LoRa32 V3/V3.2 that keeps the radio in RX, enables IOHOME_FRAME_LOG, and logs parsed traffic without creating entities or exposing a pairing button.
Pairing Workflow
- Choose a controller node_id (any unique 6-character hex string) and system_key (32-character hex string). Keep these consistent across firmware updates.
- Flash the firmware with at least the home_io_control: hub and a button: entity configured.
- Put exactly one target device into pairing mode by pressing its PROG button. The pairing window is short — typically a few seconds.
- Press the Discover & Pair button entity in Home Assistant within that window.
- Watch the ESPHome logs. On success you will either get a ready-to-paste YAML snippet with io_device_id, io_device_type, and io_subtype, or a follow-up message explaining why a snippet could not be generated.
- Copy io_device_type and io_subtype from the log snippet and add them, together with io_device_id, to the appropriate cover:, light:, or switch: entry in your YAML. If the log uses a raw numeric type such as 0x11, keep that exact value in YAML.
- Reflash with the updated YAML. The entity will appear in Home Assistant and the controller will begin polling the device for status.
- If pairing reports that the type is unsupported or that discovery metadata was incomplete, follow the log guidance and please file a GitHub issue with the raw type/subtype, device model, and pairing log so support can be added.
Device Type and Capability Notes
- Cover-like families (shutters, awnings, blinds, openers, curtains) are the primary supported path today. These support full position control (0–100%).
- Binary light and switch support exists, but remains experimental and has not been validated against real hardware.
- Raw type IDs in YAML: io_device_type accepts both named values such as awning and raw integers such as 0x11. Raw values are useful when pairing discovers a valid IO-homecontrol type that this project does not yet expose under a named YAML alias.
- Device type learning: The YAML-declared io_device_type is the permanent, authoritative type. The controller may still learn a device's type from radio for runtime profile selection when the type is not declared in YAML, but it will never overwrite a YAML-declared type.
- Inversion defaults: Some device families (e.g., horizontal awnings) default to inverted position mapping. When invert_position is omitted, the cover entity follows that learned device profile automatically. Setting invert_position explicitly overrides the learned value.
- Additional reference-derived device types such as locks, heating devices, sensors, and beacons are recognized for classification and logging, but they do not yet have dedicated ESPHome platform support.
See Also