243 0x16, 0xAA, 0x47, 0x39, 0x49, 0x88, 0x43, 0x73};
278void init_frame(
IoFrame &f,
bool is_2w =
true,
bool start =
false,
bool end =
false,
bool low_power =
false);
293bool set_cmd(
IoFrame &f, uint8_t cmd,
const uint8_t *params =
nullptr, uint8_t params_len = 0);
317bool parse(
const uint8_t *buf, uint8_t buf_len,
IoFrame &f);
469bool hex_to_bytes(
const std::string &hex, uint8_t *out, uint8_t len);
498 std::string &normalized_name);
529void decode_position_report(uint16_t target_raw, uint16_t current_raw,
bool is_stopped,
float &target,
float &position);
544uint16_t
crc_ccitt(
const uint8_t *data, uint8_t len);
bool set_cmd(IoFrame &f, uint8_t cmd, const uint8_t *params, uint8_t params_len)
Set command and payload.
static constexpr uint8_t DEVICE_NAME_BUFFER_SIZE
Device name storage including null terminator.
const char * device_operation_profile_name(DeviceType type)
Human‑readable operation profile name for a device type.
static constexpr uint8_t RESULT_OUT_OF_RANGE
Requested value is out of range.
static constexpr uint8_t RESULT_CALIBRATING
Node is calibrating.
static constexpr uint8_t BITS_PER_BYTE
Number of bits in one protocol byte.
static constexpr uint8_t DEVICE_METADATA_SIZE
Packed device metadata uses two bytes where the high 8 bits carry the upper type bits and the low byt...
static constexpr float UNKNOWN_POSITION
Sentinel value meaning "position is not known yet".
static constexpr uint8_t CMD_DISCOVER_REQ
Broadcast discovery request.
static constexpr uint8_t NODE_ID_SIZE
Device/node addresses are 3 bytes (e.g., "123ABC").
static constexpr uint8_t AES_BLOCK_SIZE
AES block size.
static constexpr uint8_t CMD_SET_CONFIG1
Configure device to auto-send status updates.
static constexpr uint16_t STATUS_POS_MAX
In status responses, position is encoded as a 16-bit value where 0x0000 = fully open (0%) and 0xC800 ...
static constexpr uint8_t RESULT_COLOUR_NOT_REACHABLE
Requested colour not reachable.
static constexpr uint8_t RESULT_LIMITATION_BY_AUTOMATIC_CYCLE
Parameter limited by an automatic cycle.
static constexpr uint8_t CMD_KEY_TRANSFER
Send encrypted system key to device.
static constexpr uint8_t RESULT_TARGET_MODIFIED
Node modified the requested target value.
static constexpr uint8_t FRAME_MIN_SIZE
Minimum frame: CTRL0+CTRL1+DST(3)+SRC(3)+CMD(1).
static constexpr uint8_t RESULT_REACHED_WRONG_POSITION
Node stopped in another position than expected.
static constexpr uint8_t RESULT_LIMITATION_BY_MYSELF
Parameter limited by the node itself.
static constexpr uint8_t TRANSFER_KEY[AES_KEY_SIZE]
The transfer key is a hardcoded key used ONLY during pairing to obfuscate the system key during over-...
static constexpr uint8_t CMD_ERROR_RESP
Error response to any command.
static constexpr uint8_t CMD_GET_NAME_RESP
Device name response.
static constexpr uint8_t RESULT_AUTOMATIC_CYCLE_ENGAGED
Node entered automatic cycle mode.
static constexpr uint8_t CMD_DISCOVER_CONFIRM_ACK
Device acknowledges confirmation.
static constexpr uint8_t DEVICE_TYPE_HIGH_BITS_SHIFT
DeviceType
Device type identifiers reported by IO‑Homecontrol products.
@ LOUVRE_BLIND
Louvre blind.
@ GATE_OPENER
Gate opener.
@ DUAL_SHUTTER
Dual-section shutter.
@ HEATING_TEMPERATURE_INTERFACE
Heating temperature interface.
@ BEACON
Beacon (unpaired/announcement).
@ EXTERNAL_VENETIAN_BLIND
External venetian blind.
@ UNKNOWN
Unknown/unspecified device.
@ INTRUSION_ALARM
Intrusion alarm.
@ WINDOW_OPENER
Window opening actuator.
@ SWINGING_SHUTTER
Swinging shutter.
@ HORIZONTAL_AWNING
Horizontal awning (open/close inverted).
@ ROLLING_DOOR_OPENER
Rolling door opener.
@ ON_OFF_SWITCH
Generic on/off switch.
@ SCREEN
Insect/privacy screen.
@ EXTERIOR_HEATING
Exterior heating.
@ VENTILATION_POINT
Ventilation point.
@ VENETIAN_BLIND
Venetian blind.
@ ROLLER_SHUTTER
Roller shutter.
@ CURTAIN_TRACK
Curtain track.
@ GARAGE_OPENER
Garage door opener.
static constexpr uint8_t RESULT_MODE_NOT_IMPLEMENTED
Mode is not supported by the node.
static constexpr uint8_t RESULT_COMMAND_OVERRULED
Command was overruled by a newer command.
static constexpr uint8_t CTRL0_END
Control byte 0 (CTRL0) bit definitions.
static constexpr uint8_t FRAME_MAX_DATA_SIZE
Maximum data bytes after command ID.
static constexpr uint8_t POS_UNKNOWN
Position unknown.
static constexpr uint8_t RESULT_BAD_INDEX_RECEIVED
Invalid index received.
static constexpr uint8_t RESULT_MANUALLY_OPERATED
Manually operated by a user.
static constexpr uint16_t STATUS_POS_TOLERANCE_RAW
Target-reached tolerance expressed in raw IO-homecontrol position units.
DeviceCapabilityClass device_capability_class(DeviceType type)
Map a raw IO‑Homecontrol type to the closest ESPHome/Home Assistant entity family.
static constexpr uint8_t CMD_STATUS_UPDATE
Device-initiated status update (needs auth).
bool default_inverted_for_type(DeviceType type)
Determine whether a device type has inverted position mapping by default.
static constexpr uint16_t LATIN1_CODEPOINT_MAX
Highest Unicode code point representable in Latin-1.
static constexpr uint8_t RESULT_LIMITATION_BY_UNKNOWN_DEVICE
Parameter limited by an unknown device.
static constexpr uint8_t LBT_MAX_RETRIES
Max carrier-sense attempts before TX anyway.
bool is_start(const IoFrame &f)
Check START flag.
static constexpr uint8_t RESULT_LOCK_POSITION_OPEN
Lock command failed because the door is open.
static constexpr uint32_t FREQ_CH1
The protocol uses 3 frequency channels in the 868 MHz ISM band.
bool device_supports_position_control(DeviceType type)
Does this device type support precise position control (0–100)?
static constexpr uint8_t RESULT_WRONG_SYSTEMKEY
Node contains the wrong system key.
static constexpr uint32_t FREQ_CH3
Channel 3: 869.85 MHz (2W only).
static constexpr uint8_t CMD_GET_NAME
Request device name.
static constexpr int32_t HOP_TIME_US
Timing constants for frequency hopping and response waiting.
static constexpr uint8_t CTRL0_PROTOCOL_1W
Bit 5: 1=OneWay protocol, 0=TwoWay protocol.
const char * device_type_name(DeviceType type)
Convert a DeviceType to a lowercase string identifier.
static constexpr uint8_t CTRL0_START
Bit 6: first frame in exchange (uses long preamble).
bool device_supports_binary_control(DeviceType type)
Does this device type support binary on/off control?
static constexpr uint8_t CMD_DISCOVER_SPE_RESP
Sub-device response.
static constexpr uint8_t RESULT_LIMITATION_BY_EMERGENCY
Parameter limited by an emergency.
uint16_t crc_ccitt(const uint8_t *data, uint8_t len)
CRC-CCITT used by the IO-Homecontrol protocol for frame validation.
static constexpr uint8_t HMAC_SIZE
Authentication HMAC is 6 bytes (truncated AES output).
static constexpr uint8_t RESULT_NODE_WAITING_FOR_POWER
Node is waiting for power.
void init_frame(IoFrame &f, bool is_2w, bool start, bool end, bool low_power)
Initialize an IoFrame header (ctrl0/ctrl1) with flags.
static constexpr uint8_t RESULT_BATTERY_LEVEL
Battery level is low.
static constexpr uint8_t RESULT_MOTION_TIME_TOO_LONG
Target was not reached in time.
float decode_tilt_report(uint16_t tilt_raw)
Decode tilt angle from raw 16‑bit value.
static constexpr uint8_t RESULT_THERMAL_PROTECTION
Node entered thermal protection mode.
static constexpr uint8_t RESULT_POWER_CONSUMPTION_TOO_HIGH
Node power consumption is too high.
static constexpr uint8_t RESULT_ERROR_DURING_EXECUTION
Generic execution failure.
uint8_t frame_length(const IoFrame &f)
Get total frame length from ctrl0.
bool device_supports_lock_control(DeviceType type)
Does this device type support binary lock/unlock control via execute commands?
static constexpr uint8_t FRAME_MAX_SIZE
Maximum frame size (9 header + 23 data).
static constexpr uint8_t DEVICE_NAME_WRITE_PAYLOAD_SIZE
Fixed write payload: 15 visible chars plus trailing null/padding.
static constexpr uint8_t CMD_KEY_CONFIRM
Device confirms key was received.
static constexpr int32_t EXCHANGE_RETRY_DELAY_MS
Gap between retries within one HA command.
static constexpr uint8_t RESULT_PARAMETER_LIMITED
Parameter limited by an unknown device.
static constexpr uint8_t CMD_KEY_INIT
Initiate key transfer to device.
static constexpr uint8_t RESULT_LIMITATION_BY_RAIN
Parameter limited by a rain sensor.
static constexpr uint8_t RESULT_USER_ACTION
User action overrode the command.
const char * command_result_description(uint8_t result)
Return a human-readable explanation for a CMD_ERROR_RESP result code.
void set_dst(IoFrame &f, const uint8_t id[NODE_ID_SIZE])
Set destination node ID.
DeviceType decode_packed_device_type(uint8_t type_msb, uint8_t type_subtype)
Decode a protocol-packed device type from two metadata bytes.
const char * device_name_validation_error_name(DeviceNameValidationError error)
Return a stable symbolic name for a device-name validation result.
const char * command_result_name(uint8_t result)
Return a stable symbolic name for a CMD_ERROR_RESP result code.
static constexpr uint8_t NODE_ID_STRING_SIZE
Uppercase hex node ID plus null terminator.
bool is_end(const IoFrame &f)
Check END flag.
static constexpr uint8_t CMD_SET_NAME_RESP
Device-name write response.
DeviceNameValidationError
Validation result for outbound device-name writes.
@ UNSUPPORTED_CHAR
Name contains characters outside Latin-1.
@ TOO_LONG
Name exceeds the 15-character write limit.
@ NONE
Name is valid and encodable.
@ EMPTY
Name is empty after normalization.
@ INVALID_UTF8
Name contains malformed UTF-8 bytes.
static constexpr uint8_t RESULT_DEAD_BOLT_ERROR
Dead bolt error.
static constexpr uint8_t RESULT_NO_EXECUTION
Node did not move.
static constexpr uint16_t CRC_LSB_MASK
Least-significant-bit mask for reflected CRC update.
static constexpr int32_t SX1262_EXCHANGE_RESPONSE_WAIT_SLICE_MS
SX1262-specific per-channel dwell while waiting for authenticated exchange responses.
bool parse(const uint8_t *buf, uint8_t buf_len, IoFrame &f)
Parse a wire buffer into a parsed IoFrame (validates length and CTRL0).
std::string trim_ascii_whitespace(const std::string &value)
Trim leading and trailing ASCII whitespace from a string.
static constexpr uint8_t RESULT_LIMITATION_BY_WIND
Parameter limited by a wind sensor.
static constexpr uint8_t RESULT_LIMITATION_BY_UPS
Parameter limited by a power supply.
static constexpr uint8_t CMD_DISCOVER_SPE_REQ
Discover sub-devices (e.g., light on garage door).
static constexpr uint8_t EXCHANGE_RETRY_COUNT
Attempts per command before reporting failure.
static constexpr uint8_t CMD_EXECUTE
Set position/open/close/stop — requires authentication.
static constexpr uint8_t CMD_PRIVATE_RESP
Response to 0x00 and 0x03 (contains position data).
const char * device_capability_class_name(DeviceType type)
Get a human‑readable name for a capability class.
static constexpr uint8_t RESULT_LIMITATION_BY_USER
Parameter limited by a remote control.
static constexpr uint8_t RESULT_COMMAND_COMPLETED_OK
No errors detected.
static constexpr uint32_t FREQ_CH2
Channel 2: 868.95 MHz (1W and 2W, TX channel).
static constexpr uint8_t CMD_CHALLENGE_REQ
Device sends 6-byte random challenge.
static constexpr uint8_t CMD_STATUS_UPDATE_RESP
Acknowledge status update.
static constexpr uint8_t RESULT_WRONG_POSITION
Node reports wrong position.
static constexpr uint8_t DEVICE_NAME_WRITE_CHAR_LIMIT
Reference write limit before the trailing null.
static constexpr uint8_t RESULT_COMMAND_INCOMPATIBLE_TO_MOVEMENT
Command cannot move the node that way.
DeviceNameValidationError encode_device_name_payload(const std::string &name, uint8_t payload[DEVICE_NAME_WRITE_PAYLOAD_SIZE], std::string &normalized_name)
Validate and encode a user-supplied UTF-8 device name into the fixed Latin-1 write payload.
static constexpr uint8_t RESULT_PRODUCT_NOT_OPERATIONAL
Node is not currently operational.
static constexpr uint8_t CMD_SET_NAME
Set device name (authenticated).
static constexpr uint8_t CMD_SET_CONFIG1_RESP
Config response.
std::string node_id_to_string(const uint8_t id[NODE_ID_SIZE])
Format a 3‑byte node ID as a 6‑character uppercase hex string.
static constexpr uint8_t CMD_DISCOVER_CONFIRM
Confirm discovery to device.
std::string decode_device_name_payload(const uint8_t *data, uint8_t len)
Decode a device-name payload from IO-homecontrol's Latin-1 wire format into UTF-8.
static constexpr uint8_t POS_FAVORITE
Move to favorite/"My" position.
static constexpr uint8_t STATUS_EXPECTED
Byte 1 bit 7: device will send auto status update.
uint8_t decode_packed_device_subtype(uint8_t type_subtype)
Decode a protocol-packed device subtype from the second metadata byte.
static constexpr uint8_t BROADCAST_DISCOVER[NODE_ID_SIZE]
Broadcast address for device discovery (0x00003B).
static constexpr uint8_t CMD_DISCOVER_RESP
Device responds with its ID and type.
static constexpr uint8_t RESULT_POWER_CONSUMPTION_TOO_LOW
Node power consumption is too low.
static constexpr uint8_t RESULT_FILTER_MAINTENANCE_NEEDED
Filter needs maintenance.
static constexpr uint8_t RESULT_WRONG_LOAD_CONNECTED
Wrong load connected to node.
static constexpr uint8_t STATUS_TILT_SELECTOR
Extended status payload marker for tilt-capable devices.
bool device_supports_status_requests(DeviceType type)
Does this device type support status request commands (0x03)?
static constexpr uint8_t LBT_RETRY_DELAY_MS
Backoff between LBT checks (≥ 5ms per ETSI).
static constexpr uint16_t SHORT_PREAMBLE
8 bytes for response/continuation frames
static constexpr uint8_t RESULT_LIMITATION_BY_SAAC
Parameter limited by a standalone automatic controller.
static constexpr uint8_t CMD_PRIVATE
Get device status — no authentication needed.
static constexpr uint8_t DEVICE_SUBTYPE_MASK
static constexpr uint8_t RESULT_LIMITATION_BY_TIMER
Parameter limited by a timer.
static constexpr uint8_t CTRL0_LENGTH_MASK
Bits [4:0]: frame length - 1.
bool has_reached_target_position(float target, float position)
Has the device reached its target within tolerance?
static constexpr uint8_t AES_KEY_SIZE
AES-128 key size.
DeviceCapabilityClass
High‑level capability class derived from DeviceType.
@ CLIMATE
Climate device (heating/cooling).
@ SWITCH
Binary on/off switch.
@ COVER
Position‑controlled cover (shutter/blind/awning).
static constexpr int32_t RESPONSE_WAIT_MS
Wait for response to non-start frame.
static constexpr uint8_t CMD_GET_INFO2_RESP
Device type/model response.
static constexpr uint8_t RESULT_PRIORITY_LEVEL_LOCKED
Node is locked on this priority level.
static constexpr uint8_t POS_STOP
Position values in the IO protocol.
static constexpr uint8_t DEVICE_TYPE_LOW_BITS_SHIFT
static constexpr uint8_t IV_PADDING
Padding byte used in IV construction.
static constexpr uint8_t CMD_CHALLENGE_RESP
Controller responds with HMAC proof.
bool is_limitation_result(uint8_t result)
Check whether a result code represents an environmental or control limitation.
static constexpr uint8_t CMD_GET_INFO2
Request device type/model info.
static constexpr uint8_t RESULT_UNKNOWN_STATUS_REPLY
Device returned an unknown status reply.
static constexpr uint16_t LONG_PREAMBLE
Preamble is a sequence of 0xAA bytes that precedes every frame.
static constexpr uint8_t RESULT_LIMITS_NOT_SET
Device limits are not set.
void 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.
static constexpr uint8_t RESULT_NODE_LOCKED
Node is locked.
static constexpr int32_t RESPONSE_AUTH_WAIT_MS
Wait for final response after challenge response.
static constexpr uint8_t CTRL1_LOW_POWER
Control byte 1 (CTRL1) bit definitions.
const char * device_name_validation_error_description(DeviceNameValidationError error)
Return a human-readable explanation for a device-name validation result.
static constexpr uint16_t CRC_POLYNOMIAL_REVERSED
Reversed CRC-CCITT polynomial used by IO-homecontrol.
static constexpr uint8_t RESULT_NO_CONTACT
No communication to node.
bool device_supports_tilt(DeviceType type)
Does this device type support tilt (slat angle) control?
static constexpr uint8_t STATUS_STOPPED
Status byte flags in CMD_PRIVATE_RESP and CMD_STATUS_UPDATE.
static constexpr int32_t RESPONSE_CHANNEL_WAIT_MS
Per-channel dwell while waiting for an exchange response.
static constexpr uint8_t RESULT_BLOCKED
Node blocked by an object.
static constexpr uint8_t RESULT_INFORMATION_CODE
Information-only code with unknown semantics.
bool hex_to_bytes(const std::string &hex, uint8_t *out, uint8_t len)
Convert a hex string (e.g., "123ABC") to a byte array.
static constexpr int16_t LBT_RSSI_THRESHOLD_DBM
Listen-before-talk (LBT) parameters for ETSI EN 300 220 compliance.
static constexpr uint8_t RESULT_LIMITATION_BY_LOCAL_USER
Parameter limited by local button.
static constexpr uint8_t IV_SIZE
Initialization vector size for AES.
uint8_t serialize(const IoFrame &f, uint8_t *buf, uint8_t buf_size)
Serialize a parsed frame into a wire buffer (without CRC).
static constexpr uint8_t RESULT_TARGET_NOT_REACHABLE
Requested target not reachable.
static constexpr uint8_t RESULT_IP_NOT_SET
Intermediate position is not set.
void set_src(IoFrame &f, const uint8_t id[NODE_ID_SIZE])
Set source node ID.
static constexpr uint16_t SX1262_AUTH_RESPONSE_PREAMBLE
SX1262-specific preamble for the outbound 0x3D challenge response.
static constexpr uint8_t RESULT_LIMITATION_BY_SCD
Parameter limited by a security actuator.
static constexpr int32_t RESPONSE_START_WAIT_MS
Wait for response to start frame (longer).
Runtime state of a paired IO‑Homecontrol device.
float target
Target position the device is moving toward.
float tilt
Current tilt: 0=closed, 100=open, or UNKNOWN_POSITION.
uint32_t status_poll_interval_ms
Configured follow-up poll interval while a state change is expected.
uint32_t next_update
millis() timestamp when we should poll for status next.
uint32_t last_status
millis() timestamp of last received status.
char name[DEVICE_NAME_BUFFER_SIZE]
Cached UTF-8 device name decoded from Latin-1 wire payloads.
uint8_t status_poll_failures
Consecutive background status-poll failures without a valid reply.
uint8_t auth_poll_failures
Consecutive background poll failures that reached 0x3C auth challenge.
bool inverted
True if open/close positions are swapped (e.g., horizontal awning).
float position
Current position: 0=open, 100=closed, or UNKNOWN_POSITION.
uint8_t subtype
Device subtype (manufacturer‑specific).
uint8_t node_id[NODE_ID_SIZE]
Device's 3‑byte radio address.
bool single_follow_up_poll_pending
True when one legacy settle poll should still be scheduled.
DeviceType type
Device type (shutter, awning, etc.).
bool is_stopped
True if device is not moving.
uint32_t poll_deadline
Hard stop for bounded follow-up polling after a command or remote activity.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).
uint8_t data[FRAME_MAX_DATA_SIZE]
Command parameters (0–23 bytes).
uint8_t ctrl0
Control byte 0: flags + length.
uint8_t src[NODE_ID_SIZE]
Source node ID (3 bytes).
uint8_t dst[NODE_ID_SIZE]
Destination node ID (3 bytes).
uint8_t data_len
Actual length of data.
uint8_t ctrl1
Control byte 1: low power, beacon, etc.