|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Owns and drives all three phases of the IO-Homecontrol device pairing flow. More...
#include <pairing_engine.h>
Public Member Functions | |
| PairingEngine (RadioDriver **radio_ptr, const uint8_t *node_id, const uint8_t *system_key, const TuningConfig *tuning, ExchangeEngine &engine, DeviceRegistry ®istry, PairingTelemetry &telemetry) | |
| Construct the engine with all required collaborators. | |
| PairingEngine (const PairingEngine &)=delete | |
| Non-copyable — stores double-pointer and references into hub member addresses. | |
| PairingEngine & | operator= (const PairingEngine &)=delete |
| bool | discover_and_pair () |
| Discover and pair a device currently in pairing mode (three-phase orchestrator). | |
Static Public Member Functions | |
| static void | parse_device_from_discovery (const IoFrame &frame, IoDevice &device, std::string &device_id) |
| Extract node ID, device type, and subtype from a CMD_DISCOVER_RESP frame. | |
Protected Member Functions | |
| decisions::PairingDiscoveryDisposition | run_discovery_phase_ (pairing::PairingContext &context) |
| Phase 1: broadcast discovery command(s) and wait for a device response (0x29). | |
| bool | run_key_exchange_phase_ (pairing::PairingContext &context) |
| Phase 2: authenticated key exchange (0x31 → 0x3C → 0x32 → 0x33). | |
| bool | finalize_pairing_configuration_ (pairing::PairingContext &context) |
| Phase 3: send SetConfig1 (0x6F) to enable automatic status updates; best-effort. | |
| decisions::PairingDiscoveryDisposition | wait_for_discovery_response_ (uint32_t timeout_ms, RadioRxPacket &packet, IoFrame &response_frame) |
| Wait for a discovery response (0x29) within timeout_ms with per-chip frequency hopping. | |
| bool | wait_for_key_challenge_ (uint32_t timeout_ms, RadioRxPacket &packet, IoFrame &challenge_frame, const uint8_t device_node_id[NODE_ID_SIZE]) |
| Wait for a key-challenge (0x3C) or direct key-confirm (0x33) from the target device. | |
| bool | wait_for_key_confirm_ (pairing::PairingContext &context) |
| Transmit the 0x32 key transfer and wait for the 0x33 key confirm with retry. | |
Owns and drives all three phases of the IO-Homecontrol device pairing flow.
Constructed once by IOHomeControlComponent; collaborators (radio, exchange engine, device registry) are injected as pointers/references so the engine never outlives them.
Definition at line 60 of file pairing_engine.h.
| esphome::home_io_control::PairingEngine::PairingEngine | ( | RadioDriver ** | radio_ptr, |
| const uint8_t * | node_id, | ||
| const uint8_t * | system_key, | ||
| const TuningConfig * | tuning, | ||
| ExchangeEngine & | engine, | ||
| DeviceRegistry & | registry, | ||
| PairingTelemetry & | telemetry ) |
Construct the engine with all required collaborators.
| radio_ptr | Double pointer into the hub's radio_ member — survives driver replacement in tests. |
| node_id | Controller 3-byte node ID buffer, owned by the hub. |
| system_key | 16-byte AES system key buffer, owned by the hub. |
| tuning | Tuning configuration, owned by the hub. |
| engine | Shared exchange engine for transmit/receive operations. |
| registry | Device registry where paired devices are permanently registered. |
| telemetry | Per-attempt telemetry recorder, owned by the hub. |
Definition at line 53 of file pairing_engine.cpp.
|
delete |
Non-copyable — stores double-pointer and references into hub member addresses.
| bool esphome::home_io_control::PairingEngine::discover_and_pair | ( | ) |
Discover and pair a device currently in pairing mode (three-phase orchestrator).
Pairing orchestrator — high-level three-phase flow.
Phase 1: run_discovery_phase_() finds a device in pairing mode. Phase 2: run_key_exchange_phase_() performs authenticated key establishment. Phase 3: finalize_pairing_configuration_() sends SetConfig1 (best-effort).
On success the device is added to the registry and a YAML snippet is printed to the log. The hub's thin wrapper manages the busy_ flag before and after this call.
Definition at line 412 of file pairing_engine.cpp.
|
protected |
Phase 3: send SetConfig1 (0x6F) to enable automatic status updates; best-effort.
Phase 3: send SetConfig1 (0x6F) to enable automatic status updates. Best-effort.
Pairing always proceeds regardless of the outcome — the return value is informational only, used to distinguish PairingOutcome::PAIRED from PairingOutcome::CONFIG_FAILED in telemetry; it never causes discover_and_pair() to report failure.
| context | Pairing context with device information from phases 1 and 2. |
Definition at line 396 of file pairing_engine.cpp.
|
delete |
|
static |
Extract node ID, device type, and subtype from a CMD_DISCOVER_RESP frame.
Parse a discovery response frame into device metadata and ID.
Decodes node ID, device type, subtype, and the extended fields (manufacturer, backbone, Multi Information Byte) via decode_discovery_response(), then emits pairing's diagnostic log lines for whichever extended fields the payload actually included. The inversion flag is derived from the type via default_inverted_for_type().
Definition at line 223 of file pairing_engine.cpp.
|
protected |
Phase 1: broadcast discovery command(s) and wait for a device response (0x29).
| context | Pairing context updated on success. |
Sends each configured discovery command in order, waiting up to pairing_discovery_wait_ms for a valid response after each TX. Retries up to PAIRING_DISCOVERY_MAX_ATTEMPTS times per command.
Definition at line 260 of file pairing_engine.cpp.
|
protected |
Phase 2: authenticated key exchange (0x31 → 0x3C → 0x32 → 0x33).
| context | Pairing context populated by run_discovery_phase_(). |
Steps:
Step 4 depends on the driver's TX→RX turnaround: fast-turnaround radios await the 0x33 through the standard send_and_receive() exchange; slow-turnaround radios use the dedicated wait_for_key_confirm_() path with a key-init re-trigger, because the 0x33 would otherwise arrive while the receiver is still settling (see RadioDriver::has_fast_tx_rx_turnaround()).
Definition at line 327 of file pairing_engine.cpp.
|
protected |
Wait for a discovery response (0x29) within timeout_ms with per-chip frequency hopping.
Wait for a valid discovery response (0x29) within timeout_ms.
| timeout_ms | Maximum wait window. |
| packet | Output: raw RadioRxPacket of the accepted discovery frame. |
| response_frame | Output: parsed IoFrame of the accepted discovery frame. |
Listens with per-chip frequency hopping between slices. Distinguishes between NO_RESPONSE (no packets at all) and INVALID (packets seen but none valid).
Frequency hopping: hops between the 3 IO-homecontrol channels after each slice. The slice length comes from RadioDriver::discovery_hop_slice_ms() — chips that retune slowly need a much longer dwell than fast-hopping chips. When preamble or sync detection fires, the dwell extends by PREAMBLE_DWELL_MS so the incoming frame can complete without interruption.
Definition at line 76 of file pairing_engine.cpp.
|
protected |
Wait for a key-challenge (0x3C) or direct key-confirm (0x33) from the target device.
Wait for a key-challenge (0x3C) or direct key-confirm (0x33) from target device.
| timeout_ms | Maximum wait window. |
| packet | Output: raw RadioRxPacket of the accepted frame. |
| challenge_frame | Output: parsed IoFrame. |
| device_node_id | Expected source node ID (devices paired to). |
During key exchange the device typically responds to 0x31 with a random 6-byte challenge (0x3C). Some devices skip the challenge and send 0x33 directly — indicating immediate key acceptance (observed mostly when the controller's TX→RX turnaround is slow enough that the 0x3C is missed). Both are accepted.
Definition at line 129 of file pairing_engine.cpp.
|
protected |
Transmit the 0x32 key transfer and wait for the 0x33 key confirm with retry.
Transmit the 0x32 key transfer and wait for 0x33 key confirm (with retry).
Uses a dedicated wait loop with frequency hopping and the driver's response_preamble() (drivers whose TX waveform needs more lock-on margin return a longer preamble). Retries up to EXCHANGE_RETRY_COUNT times on timeout.
Definition at line 165 of file pairing_engine.cpp.