Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
hub_exchange.h
Go to the documentation of this file.
1#pragma once
2
3/// @file hub_exchange.h
4/// @brief Internal exchange-state model for hub-owned authenticated non‑pairing flows.
5///
6/// This module defines the state machines and context structures used for
7/// outbound authenticated exchanges (controller → device) and inbound authentication
8/// (device → controller). These are the building blocks that power commands like
9/// set_position, request_status, and handling unsolicited status‑update frames.
10///
11/// Exchange lifecycle (outbound):
12/// 1. Controller sends a command with START flag (e.g., CMD_EXECUTE, CMD_PRIVATE).
13/// 2. Device may challenge with CMD_CHALLENGE_REQ (0x3C) if it requires auth.
14/// 3. Controller computes HMAC and responds with CMD_CHALLENGE_RESP (0x3D).
15/// 4. Device finally sends the response frame (e.g., CMD_PRIVATE_RESP with position).
16///
17/// Inbound authentication (device-initiated):
18/// Device sends a command that requires verification (e.g., CMD_STATUS_UPDATE).
19/// Controller challenges with 0x3C, device proves knowledge of system key with 0x3D,
20/// controller acknowledges with CMD_STATUS_UPDATE_RESP (0x72).
21///
22/// Both paths rely on the HMAC construction defined in proto_crypto.h which uses
23/// AES-128-ECB to encrypt an IV derived from the original frame bytes and a
24/// 6-byte random challenge.
25
26#include "proto_frame.h"
27#include "radio_interface.h"
28#include <cstdint>
29#include <string>
30
31namespace esphome {
32namespace home_io_control {
33
34namespace exchange {
35
36/// @brief State machine for an outbound authenticated exchange (non‑pairing).
37enum class OutboundExchangeState : uint8_t {
38 IDLE, ///< No active exchange; idle state.
39 TX_REQUEST, ///< Request frame transmitted; awaiting first response from device.
40 WAIT_FIRST_RESPONSE, ///< Listening for first response. This may be a challenge (0x3C) or the final response.
41 BUILD_AUTH_RESPONSE, ///< Building the 0x3D challenge response after receiving 0x3C.
42 TX_AUTH_RESPONSE, ///< Auth response (0x3D) transmitted; awaiting device's final reply.
43 WAIT_FINAL_RESPONSE, ///< Listening for the authenticated final response (e.g., status frame).
44 SUCCESS, ///< Exchange completed successfully; device acknowledged.
45 FAILED, ///< Exchange failed (timeout, retries exhausted, or radio error).
46};
47
48/// @brief State machine for inbound authentication (device‑initiated commands).
49enum class InboundAuthState : uint8_t {
50 IDLE, ///< No inbound authentication in progress.
51 TX_CHALLENGE, ///< Challenge (0x3C) sent to device; awaiting 0x3D response.
52 WAIT_CHALLENGE_RESPONSE, ///< Timer running; waiting for device's HMAC proof (0x3D).
53 VERIFIED, ///< Device successfully authenticated; command is trusted.
54 FAILED, ///< Authentication failed (timeout or HMAC mismatch).
55};
56
57/// @brief Context carried across one outbound authenticated exchange.
59 OutboundExchangeState state{OutboundExchangeState::IDLE}; ///< Current state machine state.
60 uint8_t try_index{0}; ///< Current retry attempt (1‑based within EXCHANGE_RETRY_COUNT).
61 bool saw_challenge{false}; ///< True if a 0x3C challenge was received during this exchange.
62 uint32_t exchange_start_ms{0}; ///< Timestamp when the exchange attempt began (millis).
63 uint32_t wait_ms{0}; ///< Current timeout window for the active wait (ms).
64 uint32_t first_response_ms{0}; ///< Timestamp when the first valid response arrived (for RTT/timing).
65 IoFrame rx{}; ///< Most recent candidate frame received during the exchange.
66};
67
68/// @brief Context for a single inbound authentication (device‑initiated command).
70 InboundAuthState state{InboundAuthState::IDLE}; ///< Current authentication state.
71 IoFrame challenge{}; ///< The 0x3C challenge frame we sent (needed to verify 0x3D response).
72};
73
74} // namespace exchange
75
76} // namespace home_io_control
77} // namespace esphome
InboundAuthState
State machine for inbound authentication (device‑initiated commands).
@ WAIT_CHALLENGE_RESPONSE
Timer running; waiting for device's HMAC proof (0x3D).
@ VERIFIED
Device successfully authenticated; command is trusted.
@ TX_CHALLENGE
Challenge (0x3C) sent to device; awaiting 0x3D response.
@ IDLE
No inbound authentication in progress.
OutboundExchangeState
State machine for an outbound authenticated exchange (non‑pairing).
@ TX_REQUEST
Request frame transmitted; awaiting first response from device.
@ TX_AUTH_RESPONSE
Auth response (0x3D) transmitted; awaiting device's final reply.
@ BUILD_AUTH_RESPONSE
Building the 0x3D challenge response after receiving 0x3C.
@ FAILED
Exchange failed (timeout, retries exhausted, or radio error).
@ SUCCESS
Exchange completed successfully; device acknowledged.
@ WAIT_FIRST_RESPONSE
Listening for first response. This may be a challenge (0x3C) or the final response.
@ WAIT_FINAL_RESPONSE
Listening for the authenticated final response (e.g., status frame).
IO-Homecontrol 2W protocol definitions.
Radio abstraction layer for IO-Homecontrol.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).
Context for a single inbound authentication (device‑initiated command).
IoFrame challenge
The 0x3C challenge frame we sent (needed to verify 0x3D response).
InboundAuthState state
Current authentication state.
Context carried across one outbound authenticated exchange.
uint32_t first_response_ms
Timestamp when the first valid response arrived (for RTT/timing).
uint8_t try_index
Current retry attempt (1‑based within EXCHANGE_RETRY_COUNT).
IoFrame rx
Most recent candidate frame received during the exchange.
uint32_t exchange_start_ms
Timestamp when the exchange attempt began (millis).
uint32_t wait_ms
Current timeout window for the active wait (ms).
OutboundExchangeState state
Current state machine state.
bool saw_challenge
True if a 0x3C challenge was received during this exchange.