Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
esphome::home_io_control::ExchangeEngine Class Reference

Authenticated exchange engine — outbound and inbound protocol flows. More...

#include <exchange_engine.h>

Collaboration diagram for esphome::home_io_control::ExchangeEngine:

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
ExchangeEngineoperator= (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 DebugInfoget_debug () const
 Read-only access to the current debug snapshot.

Detailed Description

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.

Member Typedef Documentation

◆ BroadcastReplyHandler

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.

Parameters
frameParsed reply frame (responder's address is frame.src).
rssi_dbmRSSI of this reply.

Definition at line 79 of file exchange_engine.h.

Constructor & Destructor Documentation

◆ ExchangeEngine() [1/2]

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).

Parameters
radio_ptrAddress of the hub's RadioDriver *radio_ member.
node_idPointer to the hub's node_id_[NODE_ID_SIZE] array.
system_keyPointer to the hub's system_key_[AES_KEY_SIZE] array.
tuningPointer to the hub's TuningConfig tuning_ member.

Definition at line 32 of file exchange_engine.cpp.

◆ ExchangeEngine() [2/2]

esphome::home_io_control::ExchangeEngine::ExchangeEngine ( const ExchangeEngine & )
delete
Here is the call graph for this function:

Member Function Documentation

◆ authenticate_request()

bool esphome::home_io_control::ExchangeEngine::authenticate_request ( const IoFrame & request,
uint32_t freq )

Authenticate an inbound device command via 0x3C challenge / 0x3D HMAC.

Parameters
requestThe received inbound frame (e.g., CMD_STATUS_UPDATE).
freqRF channel the frame arrived on.
Returns
true if HMAC verified; false on timeout or mismatch.

Definition at line 408 of file exchange_engine.cpp.

Here is the call graph for this function:

◆ collect_broadcast_responses()

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.

Parameters
requestFrame to transmit once (cmd + endpoints already filled).
freqRF channel frequency (Hz) for the initial transmit.
expected_cmdCommand byte a reply must carry to be considered.
window_msHow 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_replyInvoked 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.
Returns
Number of matching replies handed to on_reply (duplicates included).

Definition at line 365 of file exchange_engine.cpp.

Here is the call graph for this function:

◆ get_debug()

const DebugInfo & esphome::home_io_control::ExchangeEngine::get_debug ( ) const
inlinenodiscard

Read-only access to the current debug snapshot.

Definition at line 178 of file exchange_engine.h.

◆ hop_frequency()

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.

Here is the call graph for this function:

◆ log_debug()

void esphome::home_io_control::ExchangeEngine::log_debug ( const char * device_id) const

Log the debug snapshot as a WARN-level structured line.

Parameters
device_idHuman-readable device identifier for the log line.

Definition at line 62 of file exchange_engine.cpp.

Here is the call graph for this function:

◆ maybe_hop()

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.

Here is the call graph for this function:

◆ operator=()

ExchangeEngine & esphome::home_io_control::ExchangeEngine::operator= ( const ExchangeEngine & )
delete
Here is the call graph for this function:

◆ record_debug()

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.

◆ reset_debug()

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.

◆ reset_hop_timestamp()

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.

◆ send_and_receive()

bool esphome::home_io_control::ExchangeEngine::send_and_receive ( const IoFrame & request,
IoFrame & response,
uint32_t freq )

Execute an outbound authenticated exchange with retry.

Parameters
requestFrame to transmit (cmd + endpoints already filled).
responsePopulated on success.
freqRF channel frequency (Hz).
Returns
true if device responded within retry budget; false otherwise.

Definition at line 203 of file exchange_engine.cpp.

Here is the call graph for this function:

◆ set_pairing_telemetry()

void esphome::home_io_control::ExchangeEngine::set_pairing_telemetry ( PairingTelemetry * telemetry)
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.

Parameters
telemetryNon-owning pointer, or nullptr to detach.

Definition at line 144 of file exchange_engine.h.

◆ transmit_frame()

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.

Parameters
frameFrame to transmit.
freqRF frequency in Hz.
preamblePreamble length (LONG_PREAMBLE or SHORT_PREAMBLE).
Returns
true if the radio accepted the packet; false otherwise.

Definition at line 107 of file exchange_engine.cpp.

Here is the call graph for this function:

The documentation for this class was generated from the following files: