21constexpr uint8_t POSITION_PERCENT_MAX = 100;
38constexpr uint8_t EXECUTE_ACEI =
55constexpr uint8_t EXECUTE_ACEI_FORCE_OPEN =
83constexpr uint8_t KEY_EXTRACTION_DISCOVER_RESP_FLAGS = 0xDD;
91constexpr uint16_t KEY_EXTRACTION_DISCOVER_RESP_TIMESTAMP = 0x000E;
101constexpr uint16_t LOW_BYTE_MASK = 0xFF;
103constexpr size_t EXECUTE_PAYLOAD_SIZE = 8;
105constexpr uint8_t EXECUTE_POSITION_LAYOUT_FLAG = 0x80;
107constexpr uint8_t EXECUTE_POSITION_PROFILE = 0x06;
115constexpr uint8_t EXECUTE_PROFILE_SILENT = 0x05;
117constexpr size_t EXECUTE_SPECIAL_PAYLOAD_SIZE = 6;
121constexpr size_t PRIVATE2_LONG_PAYLOAD_SIZE = 6;
126constexpr uint8_t PRIVATE2_EXTENDED_BLOCK_FLAG = 0x80;
128constexpr uint8_t STATUS_UPDATE_ACK_PAYLOAD[] = {0x05, 0x00};
130constexpr uint8_t SET_CONFIG1_STATUS_BROADCAST_PAYLOAD[] = {0xE0, 0x10, 0x0A, 0x08, 0x00};
132constexpr uint8_t IDENTIFY_PARAMETER = 0xFF;
136inline std::array<uint8_t, EXECUTE_PAYLOAD_SIZE> make_position_payload(uint8_t acei, uint8_t position,
137 bool silent =
false) {
140 return {EXECUTE_ORIGINATOR, acei,
static_cast<uint8_t
>(
POSITION_WIRE_SCALE * position), 0x00,
141 EXECUTE_POSITION_LAYOUT_FLAG,
POS_FAVORITE, silent ? EXECUTE_PROFILE_SILENT : EXECUTE_POSITION_PROFILE, 0x00};
149constexpr uint8_t ONEWAY_EXECUTE_PARAMS_SIZE = 6;
155constexpr uint8_t ONEWAY_SEQUENCE_SIZE = 2;
160constexpr uint8_t ONEWAY_EXECUTE_MAC_SPAN_SIZE = 1 + ONEWAY_EXECUTE_PARAMS_SIZE;
163constexpr uint8_t ONEWAY_EXECUTE_SEQUENCE_OFFSET = ONEWAY_EXECUTE_PARAMS_SIZE;
164constexpr uint8_t ONEWAY_EXECUTE_MAC_OFFSET = ONEWAY_EXECUTE_SEQUENCE_OFFSET + ONEWAY_SEQUENCE_SIZE;
167constexpr uint8_t ONEWAY_EXECUTE_PAYLOAD_SIZE = ONEWAY_EXECUTE_MAC_OFFSET +
HMAC_SIZE;
169constexpr uint8_t ONEWAY_EXECUTE_FP1 = 0x00;
170constexpr uint8_t ONEWAY_EXECUTE_FP2 = 0x00;
198 uint16_t sequence,
const uint8_t controller_key[
AES_KEY_SIZE], uint8_t acei,
bool broadcast_all) {
199 uint8_t payload[ONEWAY_EXECUTE_PAYLOAD_SIZE] = {EXECUTE_ORIGINATOR, acei, main0, main1, ONEWAY_EXECUTE_FP1,
205 uint8_t mac_span[ONEWAY_EXECUTE_MAC_SPAN_SIZE];
207 memcpy(&mac_span[1], payload, ONEWAY_EXECUTE_PARAMS_SIZE);
213 &payload[ONEWAY_EXECUTE_MAC_OFFSET]))
216 payload[ONEWAY_EXECUTE_SEQUENCE_OFFSET] =
static_cast<uint8_t
>(sequence >>
BITS_PER_BYTE);
217 payload[ONEWAY_EXECUTE_SEQUENCE_OFFSET + 1] =
static_cast<uint8_t
>(sequence);
232constexpr uint8_t ONEWAY_ADD_ENC_KEY_OFFSET = 0;
233constexpr uint8_t ONEWAY_ADD_MANUFACTURER_OFFSET =
AES_KEY_SIZE;
234constexpr uint8_t ONEWAY_ADD_DATA_OFFSET =
AES_KEY_SIZE + 1;
235constexpr uint8_t ONEWAY_ADD_SEQUENCE_OFFSET =
AES_KEY_SIZE + 2;
236constexpr uint8_t ONEWAY_ADD_PAYLOAD_SIZE =
AES_KEY_SIZE + 4;
239constexpr uint8_t ONEWAY_ADD_DATA_VALUE = 0x01;
242constexpr uint8_t ONEWAY_ADD_MAC_SPAN_SIZE = 1 +
AES_KEY_SIZE;
246constexpr uint8_t ONEWAY_REMOVE_DATA_OFFSET = 0;
247constexpr uint8_t ONEWAY_REMOVE_SEQUENCE_OFFSET = 1;
248constexpr uint8_t ONEWAY_REMOVE_MAC_OFFSET = 3;
249constexpr uint8_t ONEWAY_REMOVE_PAYLOAD_SIZE = 9;
251constexpr uint8_t ONEWAY_REMOVE_DATA_VALUE = 0x00;
254constexpr uint8_t ONEWAY_REMOVE_MAC_SPAN_SIZE = 2;
258bool create_no_payload_request(
IoFrame &f,
const uint8_t *own,
const uint8_t *dst,
bool low_power, uint8_t cmd) {
270 if (position > POSITION_PERCENT_MAX)
275 const auto payload = make_position_payload(EXECUTE_ACEI, position, silent);
287 uint8_t main_byte = 0;
288 uint8_t modifier_byte = 0;
292 modifier_byte = 0x00;
296 modifier_byte = 0x00;
314 const uint8_t extended[EXECUTE_PAYLOAD_SIZE] = {
315 EXECUTE_ORIGINATOR, EXECUTE_ACEI, main_byte, modifier_byte, EXECUTE_POSITION_LAYOUT_FLAG,
319 const uint8_t payload[EXECUTE_SPECIAL_PAYLOAD_SIZE] = {EXECUTE_ORIGINATOR, EXECUTE_ACEI, main_byte,
320 modifier_byte, 0x00, 0x00};
337 const auto payload = make_position_payload(EXECUTE_ACEI_FORCE_OPEN, open_position);
344 uint16_t sequence,
const uint8_t controller_key[
AES_KEY_SIZE], uint8_t acei,
345 bool broadcast_all) {
346 if (position > POSITION_PERCENT_MAX)
348 return build_1w_execute(f, src, target_type,
static_cast<uint8_t
>(
POSITION_WIRE_SCALE * position), 0x00, sequence,
349 controller_key, acei, broadcast_all);
359 uint16_t sequence,
const uint8_t controller_key[
AES_KEY_SIZE], uint8_t acei,
360 bool broadcast_all) {
377 return build_1w_execute(f, src, target_type, main0, main1, sequence, controller_key, acei, broadcast_all);
385 uint16_t sequence,
const uint8_t controller_key[
AES_KEY_SIZE],
bool with_mac) {
386 uint8_t payload[ONEWAY_ADD_PAYLOAD_SIZE] = {0};
393 payload[ONEWAY_ADD_MANUFACTURER_OFFSET] = manufacturer;
394 payload[ONEWAY_ADD_DATA_OFFSET] = ONEWAY_ADD_DATA_VALUE;
395 payload[ONEWAY_ADD_SEQUENCE_OFFSET] =
static_cast<uint8_t
>(sequence >>
BITS_PER_BYTE);
396 payload[ONEWAY_ADD_SEQUENCE_OFFSET + 1] =
static_cast<uint8_t
>(sequence);
403 uint8_t mac_span[ONEWAY_ADD_MAC_SPAN_SIZE];
405 memcpy(&mac_span[1], &payload[ONEWAY_ADD_ENC_KEY_OFFSET],
AES_KEY_SIZE);
413 init_1w_broadcast_frame(f, src, target_type);
432 uint8_t payload[ONEWAY_REMOVE_PAYLOAD_SIZE] = {0};
433 payload[ONEWAY_REMOVE_DATA_OFFSET] = ONEWAY_REMOVE_DATA_VALUE;
434 payload[ONEWAY_REMOVE_SEQUENCE_OFFSET] =
static_cast<uint8_t
>(sequence >>
BITS_PER_BYTE);
435 payload[ONEWAY_REMOVE_SEQUENCE_OFFSET + 1] =
static_cast<uint8_t
>(sequence);
439 uint8_t mac_span[ONEWAY_REMOVE_MAC_SPAN_SIZE] = {
CMD_ONEWAY_REMOVE, payload[ONEWAY_REMOVE_DATA_OFFSET]};
442 if (!
crypto::create_1w_hmac(mac_span,
sizeof(mac_span), sequence, controller_key, &payload[ONEWAY_REMOVE_MAC_OFFSET]))
445 init_1w_broadcast_frame(f, src, target_type);
459 uint8_t d[3] = {function_id, sub_index, 0x00};
469 return create_no_payload_request(f, own, dst, low_power,
CMD_GET_NAME);
480 return create_no_payload_request(f, own, dst, low_power,
CMD_GET_INFO1);
485 return create_no_payload_request(f, own, dst, low_power,
CMD_GET_INFO2);
510 size_t payload_len) {
525 auto const tilt_value =
526 static_cast<uint16_t
>((POSITION_PERCENT_MAX - tilt_percent) *
STATUS_POS_MAX / POSITION_PERCENT_MAX);
527 uint8_t d[EXECUTE_PAYLOAD_SIZE] = {EXECUTE_ORIGINATOR,
533 static_cast<uint8_t
>(tilt_value),
540 uint8_t position, uint8_t tilt_percent) {
541 if (position > POSITION_PERCENT_MAX)
547 auto const tilt_value =
548 static_cast<uint16_t
>((POSITION_PERCENT_MAX - tilt_percent) *
STATUS_POS_MAX / POSITION_PERCENT_MAX);
549 uint8_t d[EXECUTE_PAYLOAD_SIZE] = {EXECUTE_ORIGINATOR,
551 static_cast<uint8_t
>(2 * position),
555 static_cast<uint8_t
>(tilt_value),
569 uint8_t block, uint8_t function_id) {
573 uint8_t d[4] = {function_id, selector, block, 0x00};
599 uint8_t d[PRIVATE2_LONG_PAYLOAD_SIZE] = {
POS_UNKNOWN, 0x00, PRIVATE2_EXTENDED_BLOCK_FLAG,
625 bool payload_enabled, uint8_t payload,
const uint8_t *system_key) {
635 if (system_key ==
nullptr)
668 uint8_t manufacturer_id) {
682 static_cast<uint8_t
>(KEY_EXTRACTION_DISCOVER_RESP_TIMESTAMP >>
BITS_PER_BYTE);
684 static_cast<uint8_t
>(KEY_EXTRACTION_DISCOVER_RESP_TIMESTAMP & LOW_BYTE_MASK);
723 return crypto::crypt_key(&key_init_cmd, 1, challenge, transfer_payload, out_key);
753 const uint8_t challenge[
HMAC_SIZE],
bool start,
bool low_power) {
791 const uint8_t challenge[
HMAC_SIZE],
const IoFrame &origin,
const uint8_t *key,
792 bool end,
bool low_power) {
799 frame_data[0] = origin.
cmd;
810 const IoFrame &origin,
const uint8_t *key) {
840 const uint8_t challenge[
HMAC_SIZE],
const IoFrame &origin,
const uint8_t *key) {
867 sizeof(SET_CONFIG1_STATUS_BROADCAST_PAYLOAD));
void generate_challenge(uint8_t out[HMAC_SIZE])
Generate 6 random bytes for a challenge using the ESP32 hardware RNG.
bool create_hmac(const uint8_t *data, uint8_t len, const uint8_t challenge[HMAC_SIZE], const uint8_t key[AES_KEY_SIZE], uint8_t hmac[HMAC_SIZE])
Create a 6-byte HMAC for authentication (proprietary IO-Homecontrol scheme).
bool crypt_1w_key(const uint8_t node[NODE_ID_SIZE], const uint8_t in[AES_KEY_SIZE], uint8_t out[AES_KEY_SIZE])
Encrypt or decrypt a 1W controller key during add-controller key adoption (CMD 0x30).
bool crypt_key(const uint8_t *data, uint8_t len, const uint8_t challenge[HMAC_SIZE], const uint8_t in[AES_KEY_SIZE], uint8_t out[AES_KEY_SIZE])
Encrypt or decrypt a system key during pairing.
bool create_1w_hmac(const uint8_t *data, uint8_t len, uint16_t sequence, const uint8_t controller_key[AES_KEY_SIZE], uint8_t hmac[HMAC_SIZE])
Create the 6-byte authenticator for a 1W frame.
bool create_force_open(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t open_position)
Build a force-open execute frame (0x00): an ordinary position command to the device's wire-scale "ful...
bool set_cmd(IoFrame &f, uint8_t cmd, const uint8_t *params, uint8_t params_len)
Set command and payload.
bool create_identify(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build an authenticated device-identify request (0x1E).
bool create_get_name(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a get-name request (0x50).
void encode_packed_device_type(DeviceType type, uint8_t subtype, uint8_t &type_msb, uint8_t &type_subtype)
Encode a DeviceType/subtype pair into the two-byte packed metadata format used by discovery responses...
static constexpr uint8_t BITS_PER_BYTE
Number of bits in one protocol byte.
static bool create_device_terminal_ack(IoFrame &f, const uint8_t *own, const uint8_t *dst, uint8_t cmd)
Build a bare device→hub terminal acknowledgement: no payload, END set, START and LOW_POWER clear.
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 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 ...
bool create_get_status(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a get-status request (0x03). The device responds with its current position.
static constexpr uint8_t CMD_KEY_TRANSFER
Send encrypted system key to device.
bool create_set_name(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, const uint8_t payload[DEVICE_NAME_WRITE_PAYLOAD_SIZE])
Build an authenticated set-name request (0x52) using a fixed zero-padded Latin-1 payload.
bool create_write_private(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, const uint8_t *payload, size_t payload_len)
Build a generic CMD_WRITE_PRIVATE (0x20) frame around a caller-supplied payload — the one builder beh...
static constexpr uint8_t CMD_DISCOVER_CONFIRM_ACK
Device acknowledges confirmation.
DeviceType
Device type identifiers reported by IO‑Homecontrol products.
@ UNKNOWN
Unknown/unspecified device.
void encode_broadcast_address(DeviceType type, uint8_t out[NODE_ID_SIZE])
Encode a device type into its typed-broadcast destination address — the exact inverse of broadcast_ta...
static constexpr uint8_t ACEI_LEVEL_USER_DEFAULT
Default remote controller priority.
bool create_private2_read(IoFrame &f, const uint8_t *own, const uint8_t *dst, uint8_t modifier, bool long_form, bool low_power)
Build a CMD_PRIVATE2 (0x0C) request in either of the two field-observed shapes.
static constexpr uint8_t DISCOVERY_RESP_MANUFACTURER_OFFSET
Manufacturer ID at data[5].
static constexpr uint8_t FRAME_MAX_DATA_SIZE
Maximum data bytes after command ID (declared length - header).
static constexpr uint8_t POS_UNKNOWN
Wire value: position unknown / keep current.
static constexpr uint8_t CMD_ADDRESS_RESP
Address assignment response: the device returns its own 3-byte backbone address, byte-identical to th...
bool create_discover_resp(IoFrame &f, const uint8_t *own, const uint8_t *dst, DeviceType type, uint8_t subtype, uint8_t manufacturer_id)
Build a discovery response (0x29) — device side, used only by the key-extraction responder.
CoverCommand
Named device commands for cover-type actuators.
@ FAVORITE
Move to stored favorite/"My" position.
@ STOP
Stop movement immediately.
@ VENT
Move to ventilation position (window-type devices).
bool create_1w_remove_controller(IoFrame &f, const uint8_t src[NODE_ID_SIZE], DeviceType target_type, uint16_t sequence, const uint8_t controller_key[AES_KEY_SIZE])
Build a 1W remove-controller frame (CMD 0x39).
bool create_discovery_request(IoFrame &f, const uint8_t *own, uint8_t command, const uint8_t *dst, bool low_power, bool payload_enabled, uint8_t payload, const uint8_t *system_key)
Build a configurable discovery request command (0x28, 0x2A, or 0x2E).
static bool create_challenge_req_framed(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE], bool start, bool low_power)
Build a challenge request (0x3C) with caller-chosen framing bits.
static constexpr uint8_t CMD_DISCOVER_ALT_REQ
Alternate discovery.
bool recover_system_key_from_transfer(const uint8_t transfer_payload[AES_KEY_SIZE], const uint8_t challenge[HMAC_SIZE], uint8_t out_key[AES_KEY_SIZE])
Recover the system key from a CMD_KEY_TRANSFER payload.
static constexpr uint8_t POSITION_WIRE_SCALE
Scale factor between a 0-100 percent position and its CMD_EXECUTE main-byte wire value.
static constexpr uint8_t CMD_GET_NAME
Request device name.
bool create_get_info1(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a CMD_GET_INFO1 (0x54) request. No payload. See proto_commands.h for the evidence note.
bool create_execute_position_and_tilt(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t position, uint8_t tilt_percent)
Build a combined position-and-tilt execute command (0x00) — setClosureAndOrientation.
bool create_1w_execute_command(IoFrame &f, const uint8_t src[NODE_ID_SIZE], DeviceType target_type, CoverCommand cmd, uint16_t sequence, const uint8_t controller_key[AES_KEY_SIZE], uint8_t acei, bool broadcast_all)
Build a 1W named-command execute frame (CMD 0x00) targeting a device class.
static constexpr uint8_t HMAC_SIZE
Authentication HMAC is 6 bytes (truncated AES output).
static constexpr uint8_t ACEI_EXTENDED_SHIFT
Shift for extended field extraction.
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 CMD_WRITE_PRIVATE
Write private register (climate/heating devices).
bool create_address_resp_device_role(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build an address response (0x37) — device side, used only by the key-extraction responder.
static constexpr uint8_t DISCOVERY_RESP_BACKBONE_OFFSET
Byte offsets within CMD_DISCOVER_RESP (0x29) payload data.
static constexpr uint8_t FRAME_MAX_SIZE
Historical name for FRAME_MAX_DECLARED_SIZE, kept as an alias rather than a second literal so the two...
static constexpr uint8_t DEVICE_NAME_WRITE_PAYLOAD_SIZE
Fixed write payload: 15 visible chars plus trailing null/padding.
bool create_key_confirm(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a key-confirm frame (0x33) — device side, used only by the key-extraction responder.
static constexpr uint8_t CMD_KEY_CONFIRM
Device confirms key was received.
static constexpr uint8_t ACEI_LEVEL_PROTECTION_HUMAN
ACEI priority level values (0–7).
static constexpr uint8_t CMD_KEY_INIT
Initiate key transfer to device.
bool create_execute_tilt(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t tilt_percent)
Build a tilt execute command (0x00) for devices that support slat angle control.
bool create_set_config1(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a set-config command (0x6F) to tell the device to automatically send status updates when contro...
bool create_challenge_resp(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE], const IoFrame &origin, const uint8_t *key)
Build a challenge response (0x3D) proving we know the system key.
void set_dst(IoFrame &f, const uint8_t id[NODE_ID_SIZE])
Set destination node ID.
static constexpr uint8_t POS_VENT_MODIFIER
Modifier byte for the ventilation command.
bool create_key_init(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a key-init request (0x31) to start the pairing key exchange with a discovered device.
bool create_execute_position(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t position, bool silent)
Build a position execute command (0x00) to move a device to a numeric position.
bool create_general_info3(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a CMD_GET_GENERAL_INFO3 (0x58) request.
bool create_get_info2(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a CMD_GET_INFO2 (0x56) request. No payload. See proto_commands.h for the evidence note.
bool create_execute_command(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, CoverCommand cmd, bool silent)
Build a named-command execute frame (0x00) for STOP, FAVORITE, or VENT.
static constexpr uint8_t CMD_ONEWAY_ADD_CONTROLLER
1W "add controller" — a 1W device broadcasts this while its key-copy gesture is active,...
static constexpr uint8_t DISCOVERY_RESP_FLAGS_OFFSET
Flags byte at data[6].
static constexpr uint8_t CMD_DISCOVER_SPE_REQ
Broadcast roll-call answered by every device that already holds this controller's system key,...
static constexpr uint8_t CMD_EXECUTE
Set position/open/close/stop — requires authentication.
static constexpr uint8_t CMD_CHALLENGE_REQ
6-byte random challenge.
static constexpr uint8_t CMD_STATUS_UPDATE_RESP
Acknowledge status update.
bool create_discover_confirm_ack(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a discovery-confirm acknowledgement (0x2D) — device side, used only by the key-extraction respo...
static constexpr uint8_t CMD_SET_NAME
Set device name (authenticated).
bool create_challenge_req_device_role(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE])
Build a device-role challenge request (0x3C) — device side, used only by the key-extraction responder...
static constexpr uint8_t ACEI_LEVEL_SHIFT
Shift for priority level extraction.
static bool create_challenge_resp_framed(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE], const IoFrame &origin, const uint8_t *key, bool end, bool low_power)
Build a challenge response (0x3D) with caller-chosen framing bits.
static constexpr uint8_t CMD_ONEWAY_REMOVE
1W "remove controller" (un-pair a 1W remote from a device); same payload shape as 0x2E.
bool create_discover(IoFrame &f, const uint8_t *own)
Build a discovery broadcast (0x28).
static constexpr uint8_t POS_FAVORITE
Wire value: move to favorite/"My" position.
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 DISCOVERY_RESP_FULL_SIZE
Full discovery response payload size.
static constexpr uint8_t DISCOVERY_RESP_TIMESTAMP_OFFSET
Timestamp starts at data[7] (2 bytes).
bool create_private_function(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t function_id, uint8_t sub_index)
Build a CMD_PRIVATE (0x03) request for an arbitrary function ID.
static constexpr uint8_t STATUS_TILT_SELECTOR
Extended status payload marker for tilt-capable devices.
bool create_get_status_tilt(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
Build a tilt-aware get-status request (0x03) that returns the extended 16-byte tilt payload.
bool create_get_status_extended(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t selector, uint8_t block, uint8_t function_id)
Build an extended CMD_PRIVATE (0x03) request with a selector/block pair — the shape real hubs use for...
static constexpr uint8_t CMD_GET_GENERAL_INFO3
Observed on the wire (tests/corpus/captures/probe/velux_kig300_probe_capability_burst....
static constexpr uint8_t PRIVATE_GET_POSITION_STATUS
CMD_PRIVATE (0x03) function ID for a position-status request — data[0] of the payload.
static constexpr uint8_t CMD_IDENTIFY
Device physical identification / jog — requires authentication.
static constexpr uint8_t CMD_PRIVATE
Get device status — no authentication needed.
static constexpr uint8_t CMD_PRIVATE2
Content otherwise undecoded by the wire parser.
static constexpr uint8_t AES_KEY_SIZE
AES-128 key size.
static constexpr uint8_t POS_STOP
Position values in the IO protocol.
static constexpr uint8_t ORIGINATOR_USER_REMOTE
User sent command from a remote control.
static constexpr uint8_t CMD_CHALLENGE_RESP
HMAC proof answering a 0x3C.
static constexpr uint8_t CMD_GET_INFO2
Request device type/model info.
bool create_challenge_resp_device_role(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE], const IoFrame &origin, const uint8_t *key)
Build a device-role challenge response (0x3D) — device side, used only by the key-extraction responde...
static constexpr uint8_t CMD_GET_INFO1
Request device general info 1.
bool create_1w_execute_position(IoFrame &f, const uint8_t src[NODE_ID_SIZE], DeviceType target_type, uint8_t position, uint16_t sequence, const uint8_t controller_key[AES_KEY_SIZE], uint8_t acei, bool broadcast_all)
Build a 1W position execute frame (CMD 0x00) targeting a device class.
bool create_challenge_req(IoFrame &f, const uint8_t *dst, const uint8_t *src, const uint8_t challenge[HMAC_SIZE])
Build a challenge request (0x3C) using a caller-supplied challenge.
bool create_status_update_resp(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a status-update acknowledgment (0x72).
bool create_1w_add_controller(IoFrame &f, const uint8_t src[NODE_ID_SIZE], DeviceType target_type, uint8_t manufacturer, uint16_t sequence, const uint8_t controller_key[AES_KEY_SIZE], bool with_mac)
Build a 1W add-controller frame (CMD 0x30).
static constexpr uint8_t ACEI_VALID_BIT
ACEI byte bit-field definitions.
bool create_key_transfer(IoFrame &f, IoFrame &old_frame, const uint8_t *dst, const uint8_t *src, const uint8_t key[AES_KEY_SIZE], const uint8_t challenge[HMAC_SIZE])
Build a key-transfer frame (0x32) containing the system key encrypted with the transfer key.
void set_src(IoFrame &f, const uint8_t id[NODE_ID_SIZE])
Set source node ID.
Command builders for the IO‑Homecontrol protocol.
IO-Homecontrol command IDs, result codes and protocol enumerations.
Cryptographic helpers for the IO‑Homecontrol protocol.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).
uint8_t data[FRAME_MAX_DATA_SIZE]
Command parameters (0–23 bytes). Never includes mac.
uint8_t mac[HMAC_SIZE]
Out-of-length authenticator trailer; meaningful only when has_mac.
bool has_mac
True if this frame carries the mac trailer (see struct doc).
uint8_t data_len
Actual length of data.