|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
IO-Homecontrol 2W protocol definitions. More...
#include <cstdint>#include <cstring>#include <string>Go to the source code of this file.
Classes | |
| struct | esphome::home_io_control::IoFrame |
| Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data). More... | |
| struct | esphome::home_io_control::IoDevice |
| Runtime state of a paired IO‑Homecontrol device. More... | |
Namespaces | |
| namespace | esphome |
| namespace | esphome::home_io_control |
Functions | |
| void | esphome::home_io_control::init_frame (IoFrame &f, bool is_2w=true, bool start=false, bool end=false, bool low_power=false) |
| Initialize an IoFrame header (ctrl0/ctrl1) with flags. | |
| void | esphome::home_io_control::set_dst (IoFrame &f, const uint8_t id[NODE_ID_SIZE]) |
| Set destination node ID. | |
| void | esphome::home_io_control::set_src (IoFrame &f, const uint8_t id[NODE_ID_SIZE]) |
| Set source node ID. | |
| bool | esphome::home_io_control::set_cmd (IoFrame &f, uint8_t cmd, const uint8_t *params=nullptr, uint8_t params_len=0) |
| Set command and payload. | |
| uint8_t | esphome::home_io_control::frame_length (const IoFrame &f) |
| Get total frame length from ctrl0. | |
| bool | esphome::home_io_control::is_start (const IoFrame &f) |
| Check START flag. | |
| bool | esphome::home_io_control::is_end (const IoFrame &f) |
| Check END flag. | |
| uint8_t | esphome::home_io_control::serialize (const IoFrame &f, uint8_t *buf, uint8_t buf_size) |
| Serialize a parsed frame into a wire buffer (without CRC). | |
| bool | esphome::home_io_control::parse (const uint8_t *buf, uint8_t buf_len, IoFrame &f) |
| Parse a wire buffer into a parsed IoFrame (validates length and CTRL0). | |
| const char * | esphome::home_io_control::device_type_name (DeviceType type) |
| Convert a DeviceType to a lowercase string identifier. | |
| DeviceCapabilityClass | esphome::home_io_control::device_capability_class (DeviceType type) |
| Map a raw IO‑Homecontrol type to the closest ESPHome/Home Assistant entity family. | |
| const char * | esphome::home_io_control::device_capability_class_name (DeviceType type) |
| Get a human‑readable name for a capability class. | |
| bool | esphome::home_io_control::device_supports_position_control (DeviceType type) |
| Does this device type support precise position control (0–100)? | |
| bool | esphome::home_io_control::device_supports_binary_control (DeviceType type) |
| Does this device type support binary on/off control? | |
| bool | esphome::home_io_control::device_supports_status_requests (DeviceType type) |
| Does this device type support status request commands (0x03)? | |
| bool | esphome::home_io_control::device_supports_tilt (DeviceType type) |
| Does this device type support tilt (slat angle) control? | |
| DeviceType | esphome::home_io_control::decode_packed_device_type (uint8_t type_msb, uint8_t type_subtype) |
| Decode a protocol-packed device type from two metadata bytes. | |
| uint8_t | esphome::home_io_control::decode_packed_device_subtype (uint8_t type_subtype) |
| Decode a protocol-packed device subtype from the second metadata byte. | |
| const char * | esphome::home_io_control::device_operation_profile_name (DeviceType type) |
| Human‑readable operation profile name for a device type. | |
| bool | esphome::home_io_control::hex_to_bytes (const std::string &hex, uint8_t *out, uint8_t len) |
| Convert a hex string (e.g., "123ABC") to a byte array. | |
| std::string | esphome::home_io_control::node_id_to_string (const uint8_t id[NODE_ID_SIZE]) |
| Format a 3‑byte node ID as a 6‑character uppercase hex string. | |
| bool | esphome::home_io_control::default_inverted_for_type (DeviceType type) |
| Determine whether a device type has inverted position mapping by default. | |
| void | esphome::home_io_control::decode_position_report (uint16_t target_raw, uint16_t current_raw, bool is_stopped, float &target, float &position) |
| Decode target/current position values from a status frame. | |
| bool | esphome::home_io_control::has_reached_target_position (float target, float position) |
| Has the device reached its target within tolerance? | |
| float | esphome::home_io_control::decode_tilt_report (uint16_t tilt_raw) |
| Decode tilt angle from raw 16‑bit value. | |
| uint16_t | esphome::home_io_control::crc_ccitt (const uint8_t *data, uint8_t len) |
| CRC-CCITT used by the IO-Homecontrol protocol for frame validation. | |
Variables | |
| static constexpr uint32_t | esphome::home_io_control::FREQ_CH1 = 868250000 |
| The protocol uses 3 frequency channels in the 868 MHz ISM band. | |
| static constexpr uint32_t | esphome::home_io_control::FREQ_CH2 = 868950000 |
| Channel 2: 868.95 MHz (1W and 2W, TX channel). | |
| static constexpr uint32_t | esphome::home_io_control::FREQ_CH3 = 869850000 |
| Channel 3: 869.85 MHz (2W only). | |
| static constexpr uint16_t | esphome::home_io_control::LONG_PREAMBLE = 1024 |
| Preamble is a sequence of 0xAA bytes that precedes every frame. | |
| static constexpr uint16_t | esphome::home_io_control::SHORT_PREAMBLE = 8 |
| 8 bytes for response/continuation frames | |
| static constexpr uint16_t | esphome::home_io_control::SX1262_AUTH_RESPONSE_PREAMBLE = 64 |
| SX1262-specific preamble for the outbound 0x3D challenge response. | |
| static constexpr int32_t | esphome::home_io_control::SX1262_EXCHANGE_RESPONSE_WAIT_SLICE_MS = 90 |
| SX1262-specific per-channel dwell while waiting for authenticated exchange responses. | |
| static constexpr int32_t | esphome::home_io_control::HOP_TIME_US = 2700 |
| Timing constants for frequency hopping and response waiting. | |
| static constexpr int32_t | esphome::home_io_control::RESPONSE_CHANNEL_WAIT_MS = 50 |
| Per-channel dwell while waiting for an exchange response. | |
| static constexpr int32_t | esphome::home_io_control::RESPONSE_WAIT_MS = 500 |
| Wait for response to non-start frame. | |
| static constexpr int32_t | esphome::home_io_control::RESPONSE_START_WAIT_MS = 300 |
| Wait for response to start frame (longer). | |
| static constexpr int32_t | esphome::home_io_control::RESPONSE_AUTH_WAIT_MS |
| Wait for final response after challenge response. | |
| static constexpr int32_t | esphome::home_io_control::EXCHANGE_RETRY_DELAY_MS = 250 |
| Gap between retries within one HA command. | |
| static constexpr uint8_t | esphome::home_io_control::EXCHANGE_RETRY_COUNT = 3 |
| Attempts per command before reporting failure. | |
| static constexpr int16_t | esphome::home_io_control::LBT_RSSI_THRESHOLD_DBM = -90 |
| Listen-before-talk (LBT) parameters for ETSI EN 300 220 compliance. | |
| static constexpr uint8_t | esphome::home_io_control::LBT_MAX_RETRIES = 5 |
| Max carrier-sense attempts before TX anyway. | |
| static constexpr uint8_t | esphome::home_io_control::LBT_RETRY_DELAY_MS = 5 |
| Backoff between LBT checks (≥ 5ms per ETSI). | |
| static constexpr uint8_t | esphome::home_io_control::NODE_ID_SIZE = 3 |
| Device/node addresses are 3 bytes (e.g., "123ABC"). | |
| static constexpr uint8_t | esphome::home_io_control::NODE_ID_STRING_SIZE = NODE_ID_SIZE * 2 + 1 |
| Uppercase hex node ID plus null terminator. | |
| static constexpr uint8_t | esphome::home_io_control::HMAC_SIZE = 6 |
| Authentication HMAC is 6 bytes (truncated AES output). | |
| static constexpr uint8_t | esphome::home_io_control::AES_KEY_SIZE = 16 |
| AES-128 key size. | |
| static constexpr uint8_t | esphome::home_io_control::AES_BLOCK_SIZE = 16 |
| AES block size. | |
| static constexpr uint8_t | esphome::home_io_control::IV_SIZE = 16 |
| Initialization vector size for AES. | |
| static constexpr uint8_t | esphome::home_io_control::IV_PADDING = 0x55 |
| Padding byte used in IV construction. | |
| static constexpr uint8_t | esphome::home_io_control::BITS_PER_BYTE = 8 |
| Number of bits in one protocol byte. | |
| static constexpr uint8_t | esphome::home_io_control::FRAME_MIN_SIZE = 9 |
| Minimum frame: CTRL0+CTRL1+DST(3)+SRC(3)+CMD(1). | |
| static constexpr uint8_t | esphome::home_io_control::FRAME_MAX_SIZE = 32 |
| Maximum frame size (9 header + 23 data). | |
| static constexpr uint8_t | esphome::home_io_control::FRAME_MAX_DATA_SIZE = 23 |
| Maximum data bytes after command ID. | |
| static constexpr uint8_t | esphome::home_io_control::CTRL0_END = 0x80 |
| Control byte 0 (CTRL0) bit definitions. | |
| static constexpr uint8_t | esphome::home_io_control::CTRL0_START = 0x40 |
| Bit 6: first frame in exchange (uses long preamble). | |
| static constexpr uint8_t | esphome::home_io_control::CTRL0_PROTOCOL_1W = 0x20 |
| Bit 5: 1=OneWay protocol, 0=TwoWay protocol. | |
| static constexpr uint8_t | esphome::home_io_control::CTRL0_LENGTH_MASK = 0x1F |
| Bits [4:0]: frame length - 1. | |
| static constexpr uint8_t | esphome::home_io_control::CTRL1_LOW_POWER = 0x20 |
| Control byte 1 (CTRL1) bit definitions. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_EXECUTE = 0x00 |
| Set position/open/close/stop — requires authentication. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_PRIVATE = 0x03 |
| Get device status — no authentication needed. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_PRIVATE_RESP = 0x04 |
| Response to 0x00 and 0x03 (contains position data). | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_REQ = 0x28 |
| Broadcast discovery request. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_RESP = 0x29 |
| Device responds with its ID and type. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_SPE_REQ = 0x2A |
| Discover sub-devices (e.g., light on garage door). | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_SPE_RESP = 0x2B |
| Sub-device response. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_CONFIRM = 0x2C |
| Confirm discovery to device. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_DISCOVER_CONFIRM_ACK = 0x2D |
| Device acknowledges confirmation. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_KEY_INIT = 0x31 |
| Initiate key transfer to device. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_KEY_TRANSFER = 0x32 |
| Send encrypted system key to device. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_KEY_CONFIRM = 0x33 |
| Device confirms key was received. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_CHALLENGE_REQ = 0x3C |
| Device sends 6-byte random challenge. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_CHALLENGE_RESP = 0x3D |
| Controller responds with HMAC proof. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_GET_NAME = 0x50 |
| Request device name. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_GET_NAME_RESP = 0x51 |
| Device name response. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_GET_INFO2 = 0x56 |
| Request device type/model info. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_GET_INFO2_RESP = 0x57 |
| Device type/model response. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_SET_CONFIG1 = 0x6F |
| Configure device to auto-send status updates. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_SET_CONFIG1_RESP = 0x70 |
| Config response. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_STATUS_UPDATE = 0x71 |
| Device-initiated status update (needs auth). | |
| static constexpr uint8_t | esphome::home_io_control::CMD_STATUS_UPDATE_RESP = 0x72 |
| Acknowledge status update. | |
| static constexpr uint8_t | esphome::home_io_control::CMD_ERROR_RESP = 0xFE |
| Error response to any command. | |
| static constexpr uint8_t | esphome::home_io_control::POS_STOP = 0xD2 |
| Position values in the IO protocol. | |
| static constexpr uint8_t | esphome::home_io_control::POS_UNKNOWN = 0xD4 |
| Position unknown. | |
| static constexpr uint8_t | esphome::home_io_control::POS_FAVORITE = 0xD8 |
| Move to favorite/"My" position. | |
| static constexpr uint16_t | esphome::home_io_control::STATUS_POS_MAX = 0xC800 |
| In status responses, position is encoded as a 16-bit value where 0x0000 = fully open (0%) and 0xC800 = fully closed (100%). | |
| static constexpr uint16_t | esphome::home_io_control::STATUS_POS_TOLERANCE_RAW = 100 |
| Target-reached tolerance expressed in raw IO-homecontrol position units. | |
| static constexpr uint8_t | esphome::home_io_control::STATUS_STOPPED = 0x01 |
| Status byte flags in CMD_PRIVATE_RESP and CMD_STATUS_UPDATE. | |
| static constexpr uint8_t | esphome::home_io_control::STATUS_EXPECTED = 0x80 |
| Byte 1 bit 7: device will send auto status update. | |
| static constexpr uint8_t | esphome::home_io_control::STATUS_TILT_SELECTOR = 0x20 |
| Extended status payload marker for tilt-capable devices. | |
| static constexpr uint8_t | esphome::home_io_control::DEVICE_METADATA_SIZE = 2 |
| Packed device metadata uses two bytes where the high 8 bits carry the upper type bits and the low byte carries both the remaining type bits and the 6-bit manufacturer subtype. | |
| static constexpr uint8_t | esphome::home_io_control::DEVICE_TYPE_LOW_BITS_SHIFT = 2 |
| static constexpr uint8_t | esphome::home_io_control::DEVICE_TYPE_HIGH_BITS_SHIFT = 6 |
| static constexpr uint8_t | esphome::home_io_control::DEVICE_SUBTYPE_MASK = 0x3F |
| static constexpr uint8_t | esphome::home_io_control::TRANSFER_KEY [AES_KEY_SIZE] |
| The transfer key is a hardcoded key used ONLY during pairing to obfuscate the system key during over-the-air transfer. | |
| static constexpr uint16_t | esphome::home_io_control::CRC_POLYNOMIAL_REVERSED = 0x8408 |
| Reversed CRC-CCITT polynomial used by IO-homecontrol. | |
| static constexpr uint16_t | esphome::home_io_control::CRC_LSB_MASK = 0x0001 |
| Least-significant-bit mask for reflected CRC update. | |
| static constexpr uint8_t | esphome::home_io_control::BROADCAST_DISCOVER [NODE_ID_SIZE] = {0x00, 0x00, 0x3B} |
| Broadcast address for device discovery (0x00003B). | |
| static constexpr float | esphome::home_io_control::UNKNOWN_POSITION = 212.0F |
| Sentinel value meaning "position is not known yet". | |
| static constexpr uint8_t | esphome::home_io_control::DEVICE_NAME_BUFFER_SIZE = 32 |
| Device name storage including null terminator. | |
IO-Homecontrol 2W protocol definitions.
IO-Homecontrol is a proprietary wireless protocol used by Somfy, Velux, and other manufacturers for controlling shutters, awnings, blinds, and similar devices. "2W" means two-way: the controller sends commands and receives status feedback.
The protocol uses FSK modulation at 868 MHz with frequency hopping across 3 channels. Communication is encrypted with AES-128 and authenticated with a 6-byte HMAC. Each installation has a unique 16-byte "system key" shared between controller and devices.
Definition in file proto_frame.h.