|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Authenticated exchange engine — outbound and inbound protocol flows. More...
#include <exchange_engine.h>
Classes | |
| struct | DebugInfo |
| Snapshot of the last exchange attempt for diagnostics. More... | |
Public Types | |
| using | BroadcastReplyHandler = std::function<void(const IoFrame &frame, int16_t rssi_dbm)> |
| Invoked for each matching broadcast reply, as it arrives. | |
Public Member Functions | |
| ExchangeEngine (RadioDriver **radio_ptr, const uint8_t *node_id, const uint8_t *system_key, const TuningConfig *tuning) | |
| Construct the engine with double-pointer indirection into the hub's RadioDriver pointer and direct pointers to the node/key byte arrays and the tuning config. | |
| ExchangeEngine (const ExchangeEngine &)=delete | |
| ExchangeEngine & | operator= (const ExchangeEngine &)=delete |
| bool | send_and_receive (const IoFrame &request, IoFrame &response, uint32_t freq) |
| Execute an outbound authenticated exchange with retry. | |
| bool | authenticate_request (const IoFrame &request, uint32_t freq) |
| Authenticate an inbound device command via 0x3C challenge / 0x3D HMAC. | |
| uint8_t | collect_broadcast_responses (const IoFrame &request, uint32_t freq, uint8_t expected_cmd, uint32_t window_ms, const BroadcastReplyHandler &on_reply) |
| Transmit request once and hand every matching broadcast reply to on_reply within window_ms. | |
| bool | transmit_frame (const IoFrame &frame, uint32_t freq, uint16_t preamble) |
| Transmit a raw IoFrame with LBT and the given preamble length. | |
| void | hop_frequency () |
| Advance to the next IO-Homecontrol channel (CH1→CH2→CH3→CH1). | |
| void | maybe_hop () |
| Unconditionally hop only if the minimum dwell has elapsed. | |
| void | reset_hop_timestamp () |
| Reset the hop-timer (called after radio init in hub setup()). | |
| void | set_pairing_telemetry (PairingTelemetry *telemetry) |
| Attach a telemetry recorder so transmit_frame()'s LBT loop records defer events. | |
| void | reset_debug (uint8_t request_cmd) |
| Clear the debug snapshot and record the upcoming request command. | |
| void | record_debug (const char *stage, uint8_t tries, bool saw_challenge) |
| Update the debug snapshot with the current stage and radio capture. | |
| void | log_debug (const char *device_id) const |
| Log the debug snapshot as a WARN-level structured line. | |
| const DebugInfo & | get_debug () const |
| Read-only access to the current debug snapshot. | |
Authenticated exchange engine — outbound and inbound protocol flows.
All timing constants (retry count/delay, response windows) come from proto_timing.h; per-chip dwell overrides are queried from the RadioDriver.
Definition at line 42 of file exchange_engine.h.
| using esphome::home_io_control::ExchangeEngine::BroadcastReplyHandler = std::function<void(const IoFrame &frame, int16_t rssi_dbm)> |
Invoked for each matching broadcast reply, as it arrives.
| frame | Parsed reply frame (responder's address is frame.src). |
| rssi_dbm | RSSI of this reply. |
Definition at line 79 of file exchange_engine.h.
| esphome::home_io_control::ExchangeEngine::ExchangeEngine | ( | RadioDriver ** | radio_ptr, |
| const uint8_t * | node_id, | ||
| const uint8_t * | system_key, | ||
| const TuningConfig * | tuning ) |
Construct the engine with double-pointer indirection into the hub's RadioDriver pointer and direct pointers to the node/key byte arrays and the tuning config.
Pointers must remain valid for the lifetime of the engine (guaranteed because hub owns all referenced members).
| radio_ptr | Address of the hub's RadioDriver *radio_ member. |
| node_id | Pointer to the hub's node_id_[NODE_ID_SIZE] array. |
| system_key | Pointer to the hub's system_key_[AES_KEY_SIZE] array. |
| tuning | Pointer to the hub's TuningConfig tuning_ member. |
Definition at line 32 of file exchange_engine.cpp.
|
delete |
| bool esphome::home_io_control::ExchangeEngine::authenticate_request | ( | const IoFrame & | request, |
| uint32_t | freq ) |
Authenticate an inbound device command via 0x3C challenge / 0x3D HMAC.
| request | The received inbound frame (e.g., CMD_STATUS_UPDATE). |
| freq | RF channel the frame arrived on. |
Definition at line 408 of file exchange_engine.cpp.
| uint8_t esphome::home_io_control::ExchangeEngine::collect_broadcast_responses | ( | const IoFrame & | request, |
| uint32_t | freq, | ||
| uint8_t | expected_cmd, | ||
| uint32_t | window_ms, | ||
| const BroadcastReplyHandler & | on_reply ) |
Transmit request once and hand every matching broadcast reply to on_reply within window_ms.
Unlike send_and_receive(), this neither retries the transmit nor performs any authentication — a broadcast roll-call has no per-transaction proof, so replies are informational only (see the caller's protocol notes). Every candidate packet is parsed and checked against expected_cmd and node_id_ (as the frame's destination); anything that fails parse(), carries a different cmd, or is not addressed to us is ignored without ending collection. Silence on a slice hops to the next channel, exactly like wait_for_first_response_(), so replies arriving on any of the three channels are caught.
This method stores nothing and imposes no capacity: it neither buffers replies nor deduplicates them, so the same responder answering twice within one window invokes on_reply twice. Storage, deduplication, and any capacity limit belong to the caller, which knows how little of each reply it actually needs to keep — see ManagementActions::scan_paired_devices(), which decodes each frame on arrival into a compact record rather than retaining whole frames. Collection always runs to the deadline.
| request | Frame to transmit once (cmd + endpoints already filled). |
| freq | RF channel frequency (Hz) for the initial transmit. |
| expected_cmd | Command byte a reply must carry to be considered. |
| window_ms | How long to listen after the transmit, in milliseconds. The caller owns this budget explicitly (rather than this method reading tuning_->pairing_discovery_wait_ms itself) because a caller that transmits more than once needs to divide one total time budget across several calls — see ManagementActions::scan_paired_devices(). |
| on_reply | Invoked once per matching reply, before the next packet is awaited, so the handler must be cheap and must not block. Keep captures to a few pointers: small callables avoid std::function's heap fallback on the implementations this project builds against. |
Definition at line 365 of file exchange_engine.cpp.
|
inlinenodiscard |
Read-only access to the current debug snapshot.
Definition at line 178 of file exchange_engine.h.
| void esphome::home_io_control::ExchangeEngine::hop_frequency | ( | ) |
Advance to the next IO-Homecontrol channel (CH1→CH2→CH3→CH1).
Respects the protocol-defined minimum dwell time (HOP_TIME_US).
Definition at line 79 of file exchange_engine.cpp.
| void esphome::home_io_control::ExchangeEngine::log_debug | ( | const char * | device_id | ) | const |
Log the debug snapshot as a WARN-level structured line.
| device_id | Human-readable device identifier for the log line. |
Definition at line 62 of file exchange_engine.cpp.
| void esphome::home_io_control::ExchangeEngine::maybe_hop | ( | ) |
Unconditionally hop only if the minimum dwell has elapsed.
Called from the hub's loop() to honour passive channel scanning.
Definition at line 98 of file exchange_engine.cpp.
|
delete |
| void esphome::home_io_control::ExchangeEngine::record_debug | ( | const char * | stage, |
| uint8_t | tries, | ||
| bool | saw_challenge ) |
Update the debug snapshot with the current stage and radio capture.
Definition at line 45 of file exchange_engine.cpp.
| void esphome::home_io_control::ExchangeEngine::reset_debug | ( | uint8_t | request_cmd | ) |
Clear the debug snapshot and record the upcoming request command.
Definition at line 40 of file exchange_engine.cpp.
| void esphome::home_io_control::ExchangeEngine::reset_hop_timestamp | ( | ) |
Reset the hop-timer (called after radio init in hub setup()).
Definition at line 77 of file exchange_engine.cpp.
| bool esphome::home_io_control::ExchangeEngine::send_and_receive | ( | const IoFrame & | request, |
| IoFrame & | response, | ||
| uint32_t | freq ) |
Execute an outbound authenticated exchange with retry.
| request | Frame to transmit (cmd + endpoints already filled). |
| response | Populated on success. |
| freq | RF channel frequency (Hz). |
Definition at line 203 of file exchange_engine.cpp.
|
inline |
Attach a telemetry recorder so transmit_frame()'s LBT loop records defer events.
Set by PairingEngine for the duration of a discover_and_pair() attempt only — nullptr (the default) for every non-pairing exchange, which is the common case and stays a no-op.
| telemetry | Non-owning pointer, or nullptr to detach. |
Definition at line 144 of file exchange_engine.h.
| bool esphome::home_io_control::ExchangeEngine::transmit_frame | ( | const IoFrame & | frame, |
| uint32_t | freq, | ||
| uint16_t | preamble ) |
Transmit a raw IoFrame with LBT and the given preamble length.
| frame | Frame to transmit. |
| freq | RF frequency in Hz. |
| preamble | Preamble length (LONG_PREAMBLE or SHORT_PREAMBLE). |
Definition at line 107 of file exchange_engine.cpp.