Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
proto_commands.h File Reference

Command builders for the IO‑Homecontrol protocol. More...

#include "proto_codecs.h"
#include "proto_constants.h"
#include "proto_device_model.h"
#include "proto_frame.h"
Include dependency graph for proto_commands.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Namespaces

namespace  esphome
namespace  esphome::home_io_control

Functions

bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::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 "fully open" value, sent at elevated ACEI priority (see EXECUTE_ACEI_FORCE_OPEN).
bool esphome::home_io_control::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.
bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::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).
bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::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 esphome::home_io_control::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 esphome::home_io_control::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 esphome::home_io_control::create_get_name (IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
 Build a get-name request (0x50).
bool esphome::home_io_control::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 esphome::home_io_control::create_identify (IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power)
 Build an authenticated device-identify request (0x1E).
bool esphome::home_io_control::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 behind every heating/climate function.
bool esphome::home_io_control::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 esphome::home_io_control::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 esphome::home_io_control::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 both the tilt block (selector STATUS_TILT_SELECTOR) and the field-observed selector 0x80 (tests/corpus/captures/probe/multi_somfy_probe_extended_private_both_selectors.yaml), which this codebase has never decoded.
bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::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).
bool esphome::home_io_control::create_discover (IoFrame &f, const uint8_t *own)
 Build a discovery broadcast (0x28).
bool esphome::home_io_control::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.
bool esphome::home_io_control::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.
bool esphome::home_io_control::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 responder.
bool esphome::home_io_control::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.
bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::create_challenge_req (IoFrame &f, const uint8_t *dst, const uint8_t *src)
 Build a challenge request (0x3C) containing 6 random bytes.
bool esphome::home_io_control::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 esphome::home_io_control::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.
bool esphome::home_io_control::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.
bool esphome::home_io_control::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.
bool esphome::home_io_control::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 responder answering a hub-issued 0x3C challenging our own 0x37.
bool esphome::home_io_control::create_status_update_resp (IoFrame &f, const uint8_t *own, const uint8_t *dst)
 Build a status-update acknowledgment (0x72).
bool esphome::home_io_control::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 controlled by any remote (not just us).

Detailed Description

Command builders for the IO‑Homecontrol protocol.

This module provides builder functions that populate IoFrame structures for the various commands used in discovery, pairing, control, and status operations. All builders follow the same pattern: fill an IoFrame with CTRL0/CTRL1 flags, addresses, command ID, and optional payload.

Position encoding:

  • IO protocol position values: 0 = fully open, 100 = fully closed, for a non-inverted device — but this is per-device, not a universal wire constant: IoDevice::inverted devices (e.g. horizontal awnings) have it backwards (0 = fully closed, 100 = fully open). Never hardcode "0 = open" in caller code without checking inversion first.
  • Use create_execute_position() for numeric positions (0–100).
  • Use create_execute_command() for named commands: CoverCommand::STOP, CoverCommand::FAVORITE, CoverCommand::VENT.
  • Use create_force_open() for CoverCommand::FORCE_OPEN — it takes the target "fully open" position explicitly rather than assuming 0
  • The Home Assistant layer maps HA's 1.0=open/0.0=closed to the IO scale via ha_position = 1.0 - (io_position / 100.0), or the inverted form for IoDevice::inverted devices; see platform_cover.h.

Low‑power flag and preamble handling:

  • CTRL1_LOW_POWER is a per‑device property on the command path. Every device‑addressed builder on that path takes an explicit low_power argument, set from the target's YAML‑declared low_power class (default false: an always‑listening receiver). Battery/solar devices that duty‑cycle their receiver get the flag; mains devices do not, matching a reference hub's own traffic. The pairing and device‑role builders (create_key_init, create_key_transfer, create_set_config1, create_status_update_resp) keep a fixed value instead — see ADR 0029's out‑of‑scope note.
  • The preamble follows the flag. For a start frame the exchange engine uses LONG_PREAMBLE (1024 bytes) when CTRL1_LOW_POWER is set — the wake‑up burst for a sleeping receiver — and the runtime‑tunable normal_start_preamble otherwise; follow‑up frames use the driver's response_preamble() (exchange_engine.cpp). The flag and the preamble can never disagree because both derive from the same per‑device property.

Definition in file proto_commands.h.