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

The main IO-Homecontrol component. More...

#include <hub_core.h>

Inheritance diagram for esphome::home_io_control::IOHomeControlComponent:
Collaboration diagram for esphome::home_io_control::IOHomeControlComponent:

Classes

struct  PendingOperation
 A single queued operation to be processed in loop(). More...
struct  ExchangeDebugInfo
 Debug snapshot of the last exchange attempt. More...

Public Member Functions

void setup () override
 Initialize hardware (radio and device registry).
void loop () override
 Main loop: process pending operations and drive radio state machine.
void dump_config () override
 Dump configuration and radio debug info to the log.
float get_setup_priority () const override
 Get setup priority (HARDWARE to initialize early).
void spi_enable () override
 Enable the SPI bus.
void spi_disable () override
 Disable the SPI bus.
uint8_t spi_transfer (uint8_t data) override
 Transfer one byte full‑duplex.
void spi_write (uint8_t data) override
 Write one byte (MOSI only).
uint8_t spi_read () override
 Read one byte (MISO only).
void set_rst_pin (InternalGPIOPin *pin)
 Set the radio reset pin.
void set_dio0_pin (InternalGPIOPin *pin)
 Set the DIO0 interrupt pin (SX1276).
void set_dio4_pin (InternalGPIOPin *pin)
 Set the DIO4 preamble‑detect pin (SX1276, optional).
void set_dio1_pin (InternalGPIOPin *pin)
 Set the DIO1 interrupt pin (SX1262).
void set_busy_pin (InternalGPIOPin *pin)
 Set the BUSY pin (SX1262).
void set_fem_en_pin (InternalGPIOPin *pin)
 Set the front‑end module enable pin.
void set_vfem_pin (InternalGPIOPin *pin)
 Set the VFEM power pin.
void set_fem_pa_pin (InternalGPIOPin *pin)
 Set the FEM PA switch pin.
void set_node_id (const std::string &id)
 Set the controller's node ID (hex string).
void set_system_key (const std::string &key)
 Set the system key (hex string).
void set_tx_power (uint8_t power)
 Set transmit power (dBm).
void set_pa_pin (uint8_t pa_pin)
 Set PA boost pin configuration.
void set_radio_type (const std::string &type)
 Set radio type ("sx1276" or "sx1262"); empty string means auto‑detect.
void set_tcxo_voltage (uint8_t voltage)
 Set TCXO voltage for SX1262 (1.8V / 3.3V).
void add_linked_remote (const std::string &remote_id, const std::string &device_id)
 Declare that a remote (identified by its node ID) controls a registered device.
virtual void add_device (const std::string &device_id)
 Add a device to the registry by device ID only (legacy/delegating overload).
virtual void add_device (const std::string &device_id, DeviceType type, uint8_t subtype, bool inverted)
 Add a device to the registry with full metadata from YAML.
virtual IoDeviceget_device (const std::string &device_id)
 Retrieve a device by ID; returns nullptr if not found.
virtual void register_device_callback (DeviceUpdateCallback cb)
 Register a callback invoked when any device updates.
virtual void set_device_status_poll_interval (const std::string &device_id, uint32_t poll_interval_ms)
 Configure the optional follow-up polling interval for a registered device.
virtual bool set_device_position (const std::string &device_id, uint8_t position)
 Send a position command to a device.
virtual bool set_device_tilt (const std::string &device_id, uint8_t tilt_percent)
 Send a tilt command to a tilt‑capable cover.
virtual bool request_device_status (const std::string &device_id)
 Request current status from a device.
virtual bool discover_and_pair ()
 Discover and pair a device that is in pairing mode.
virtual bool set_light_state (const std::string &device_id, bool on)
 Semantic binary helper for light entities.
virtual bool set_switch_state (const std::string &device_id, bool on)
 Semantic binary helper for switch entities.
virtual void queue_set_device_position (const std::string &device_id, uint8_t position)
 Queue an async position update; returns immediately, executed in loop().
virtual void queue_set_device_tilt (const std::string &device_id, uint8_t tilt_percent)
 Queue an async tilt update; returns immediately, executed in loop().
virtual void queue_request_device_status (const std::string &device_id)
 Queue an async status request; returns immediately, executed in loop().
virtual void queue_discover_and_pair ()
 Queue a pairing operation; executed in loop() when radio idle.
virtual void queue_set_light_state (const std::string &device_id, bool on)
 Async form of set_light_state() that keeps radio work serialized on the main loop.
virtual void queue_set_switch_state (const std::string &device_id, bool on)
 Async form of set_switch_state() that keeps radio work serialized on the main loop.
Public Member Functions inherited from esphome::home_io_control::SpiAccess
virtual ~SpiAccess ()=default

Protected Types

enum class  PendingOperationType : uint8_t {
  SET_POSITION , SET_TILT , SET_LIGHT_STATE , SET_SWITCH_STATE ,
  REQUEST_STATUS , DISCOVER_AND_PAIR
}
 Type of queued pending operation for the main loop. More...

Protected Member Functions

bool transmit_frame_ (const IoFrame &frame, uint32_t freq, uint16_t preamble)
 Transmit a raw IoFrame on the current frequency with given preamble length.
bool send_and_receive_ (const IoFrame &request, IoFrame &response, uint32_t freq)
 Main request/response exchange with retry and automatic authentication.
bool authenticate_request_ (const IoFrame &request, uint32_t freq)
 Handle an inbound authenticated command from a device (status updates, etc.).
void process_received_packet_ (const RadioRxPacket &packet)
 Parse received packet, update device state if it's a status frame, and notify covers.
void update_device_status_ (const IoFrame &frame)
 Extract position/status info from a status or status-update frame and merge into device record.
void schedule_status_poll_ (const std::string &device_id, uint32_t delay_ms)
 Schedule a delayed status poll for a registered device using the Component timeout API.
void begin_status_poll_tracking_ (const std::string &device_id, uint32_t initial_delay_ms)
 Begin bounded follow-up polling for a device after a command or overheard remote activity.
bool execute_request_and_update_ (const std::string &device_id, const IoFrame &request, bool warn_on_no_response, uint32_t retry_after_fail_ms=0)
 Shared request/response helper for high-level operations.
void notify_device_update_ (const std::string &id)
 Fire all registered device update callbacks for the given device ID.
void process_pending_operation_ ()
 Pop next pending operation from the queue and execute it (set position, request status, discover).
bool transmit_request_ (const IoFrame &request, uint32_t freq, uint16_t preamble, exchange::OutboundExchangeContext &ctx)
 Wrap transmit_frame_ and mark context failed on error.
decisions::ExchangeFirstResponseDisposition wait_for_first_response_ (const IoFrame &request, exchange::OutboundExchangeContext &ctx)
 Wait loop for the first response packet; classifies via decisions::classify_exchange_first_response.
bool handle_authentication_ (const IoFrame &request, uint32_t freq, exchange::OutboundExchangeContext &ctx)
 Perform challenge-response (TX auth response) after a 0x3C is received.
decisions::ExchangeFinalResponseDisposition wait_for_final_response_ (const IoFrame &request, exchange::OutboundExchangeContext &ctx)
 Wait loop for the final authenticated response; uses is_valid_final_response().
decisions::PairingDiscoveryDisposition wait_for_discovery_response_ (uint32_t timeout_ms, RadioRxPacket &packet, IoFrame &response_frame)
 Wait for a discovery response (0x29) during pairing.
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) from target device during pairing key exchange.
decisions::PairingDiscoveryDisposition run_discovery_phase_ (pairing::PairingContext &context)
 Phase 1: broadcast discovery (0x28) 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 finalize device configuration.
void reset_exchange_debug_ (uint8_t request_cmd)
void record_exchange_debug_ (const char *stage, uint8_t tries, bool saw_challenge)
void log_exchange_debug_ (const char *device_id) const
void hop_frequency_ ()
 Hop to the next channel in the 3‑channel sequence: CH1 → CH2 → CH3 → CH1.

Static Protected Member Functions

static void parse_device_from_discovery (const IoFrame &frame, IoDevice &device, std::string &device_id)
 Parse a discovery response frame into device metadata and ID.

Protected Attributes

RadioDriverradio_ {nullptr}
InternalGPIOPin * rst_pin_ {nullptr}
InternalGPIOPin * dio0_pin_ {nullptr}
 SX1276 DIO0 interrupt.
InternalGPIOPin * dio4_pin_ {nullptr}
 SX1276 DIO4 preamble detect (optional).
InternalGPIOPin * dio1_pin_ {nullptr}
 SX1262 DIO1 interrupt.
InternalGPIOPin * busy_pin_ {nullptr}
 SX1262 BUSY pin.
InternalGPIOPin * fem_en_pin_ {nullptr}
 Front-end module enable.
InternalGPIOPin * vfem_pin_ {nullptr}
 Front-end module power.
InternalGPIOPin * fem_pa_pin_ {nullptr}
 Front-end module PA switch.
std::string node_id_str_
std::string system_key_str_
std::string radio_type_
 "sx1276", "sx1262", or "" (auto-detect)
uint8_t node_id_ [NODE_ID_SIZE] {}
uint8_t system_key_ [AES_KEY_SIZE] {}
uint8_t tx_power_ {DEFAULT_TX_POWER_DBM}
uint8_t pa_pin_ {DEFAULT_PA_PIN_PA_BOOST}
uint8_t tcxo_voltage_ {DEFAULT_TCXO_VOLTAGE_SETTING_1P8V}
 SX1262 TCXO voltage setting (default 1.8 V).
bool initialized_ {false}
bool busy_ {false}
uint32_t last_hop_us_ {0}
ExchangeDebugInfo last_exchange_debug_ {}
std::map< std::string, IoDevicedevices_
std::vector< DeviceUpdateCallbackcallbacks_
std::deque< PendingOperationpending_operations_
std::map< std::string, std::vector< std::string > > linked_remotes_
 Maps remote node IDs to lists of device IDs they control.

Detailed Description

The main IO-Homecontrol component.

Manages the protocol layer and delegates radio operations to a RadioDriver instance.

Inherits SPIDevice so that ESPHome's Python codegen can configure SPI pins. Implements SpiAccess to provide the radio driver with SPI bus access.

Definition at line 57 of file hub_core.h.

Member Enumeration Documentation

◆ PendingOperationType

Type of queued pending operation for the main loop.

Enumerator
SET_POSITION 

Queue a set_device_position call (position 0–100 or special values).

SET_TILT 

Queue a set_device_tilt call (tilt percentage 0–100).

SET_LIGHT_STATE 

Queue a set_light_state call (binary on/off).

SET_SWITCH_STATE 

Queue a set_switch_state call (binary on/off).

REQUEST_STATUS 

Queue a request_device_status call (poll for current position).

DISCOVER_AND_PAIR 

Queue a discover_and_pair call (starts 3‑phase pairing flow).

Definition at line 315 of file hub_core.h.

Member Function Documentation

◆ add_device() [1/2]

void esphome::home_io_control::IOHomeControlComponent::add_device ( const std::string & device_id)
virtual

Add a device to the registry by device ID only (legacy/delegating overload).

Type, subtype, and inverted default to UNKNOWN / 0 / false; use the 4-arg overload when type/subtype/inverted come from YAML declarations.

Parameters
device_idHexadecimal node ID string.

Definition at line 237 of file hub_core.cpp.

Here is the call graph for this function:

◆ add_device() [2/2]

void esphome::home_io_control::IOHomeControlComponent::add_device ( const std::string & device_id,
DeviceType type,
uint8_t subtype,
bool inverted )
virtual

Add a device to the registry with full metadata from YAML.

Parameters
device_idHexadecimal node ID string.
typeDevice type from YAML declaration (UNKNOWN if not specified).
subtypeDevice subtype from YAML declaration.
invertedPosition inversion flag from YAML declaration.

Definition at line 241 of file hub_core.cpp.

Here is the call graph for this function:

◆ add_linked_remote()

void esphome::home_io_control::IOHomeControlComponent::add_linked_remote ( const std::string & remote_id,
const std::string & device_id )
inline

Declare that a remote (identified by its node ID) controls a registered device.

When activity from this remote is overheard, a status poll is scheduled for the device. This is needed for 1W remotes whose destination address differs from the device's 2W ID.

Parameters
remote_idNode ID of the remote control.
device_idNode ID of the device it controls.

Definition at line 123 of file hub_core.h.

◆ authenticate_request_()

bool esphome::home_io_control::IOHomeControlComponent::authenticate_request_ ( const IoFrame & request,
uint32_t freq )
protected

Handle an inbound authenticated command from a device (status updates, etc.).

Parameters
requestInbound authenticated request (e.g., CMD_STATUS_UPDATE).
freqRF frequency the packet arrived on.
Returns
true if authentication succeeded; false otherwise.

Definition at line 331 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ begin_status_poll_tracking_()

void esphome::home_io_control::IOHomeControlComponent::begin_status_poll_tracking_ ( const std::string & device_id,
uint32_t initial_delay_ms )
protected

Begin bounded follow-up polling for a device after a command or overheard remote activity.

Parameters
device_idID of the device to poll.
initial_delay_msDelay before the first follow-up poll.

Definition at line 153 of file hub_status.cpp.

Here is the call graph for this function:

◆ discover_and_pair()

bool esphome::home_io_control::IOHomeControlComponent::discover_and_pair ( )
virtual

Discover and pair a device that is in pairing mode.

Pairing orchestrator — high‑level three‑phase flow.

Returns
true if pairing completed successfully; false otherwise.

Phase 1: Discovery (run_discovery_phase_) finds a device in pairing mode. Phase 2: Key exchange (run_key_exchange_phase_) performs authenticated key establishment using the challenge‑response protocol. Phase 3: Finalization (finalize_pairing_configuration_) sends SetConfig1.

On success the device is added to the current runtime registry and either a valid YAML snippet or a follow-up guidance message is printed in the logs. Any phase failure aborts early, logging an appropriate warning.

Returns
true if pairing completed; false otherwise.

Definition at line 346 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ dump_config()

void esphome::home_io_control::IOHomeControlComponent::dump_config ( )
override

Dump configuration and radio debug info to the log.

Definition at line 305 of file hub_core.cpp.

◆ execute_request_and_update_()

bool esphome::home_io_control::IOHomeControlComponent::execute_request_and_update_ ( const std::string & device_id,
const IoFrame & request,
bool warn_on_no_response,
uint32_t retry_after_fail_ms = 0 )
protected

Shared request/response helper for high-level operations.

Parameters
device_idTarget device ID.
requestOutbound request frame.
warn_on_no_responseIf true, logs a warning when no response is received.
retry_after_fail_msIf non-zero, schedules next status poll after this delay on failure.
Returns
true if device acknowledged; false otherwise.

Definition at line 58 of file hub_operations.cpp.

Here is the call graph for this function:

◆ finalize_pairing_configuration_()

bool esphome::home_io_control::IOHomeControlComponent::finalize_pairing_configuration_ ( pairing::PairingContext & context)
protected

Phase 3: send SetConfig1 (0x6F) to finalize device configuration.

Execute Phase 3: finalize pairing configuration on the device.

Parameters
contextPairing context with device information.
Returns
true (pairing proceeds regardless of set‑config outcome).

Sends a SetConfig1 command (0x6F) using the authenticated exchange path. This step is optional in the sense that the command may be skipped if create_set_config1() returns false, but the pairing itself is already complete at this point. The function always returns true to avoid aborting a successfully paired device.

Definition at line 328 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ get_device()

IoDevice * esphome::home_io_control::IOHomeControlComponent::get_device ( const std::string & device_id)
virtual

Retrieve a device by ID; returns nullptr if not found.

Parameters
device_idHexadecimal node ID.
Returns
Pointer to IoDevice, or nullptr.

Definition at line 256 of file hub_core.cpp.

◆ get_setup_priority()

float esphome::home_io_control::IOHomeControlComponent::get_setup_priority ( ) const
inlinenodiscardoverride

Get setup priority (HARDWARE to initialize early).

Returns
setup_priority::HARDWARE.

Definition at line 70 of file hub_core.h.

◆ handle_authentication_()

bool esphome::home_io_control::IOHomeControlComponent::handle_authentication_ ( const IoFrame & request,
uint32_t freq,
exchange::OutboundExchangeContext & ctx )
protected

Perform challenge-response (TX auth response) after a 0x3C is received.

Handle device authentication challenge (0x3C → 0x3D exchange).

Parameters
requestOriginal request frame (needed for HMAC derivation).
freqRF channel frequency (same channel used for the request).
ctxExchange context holding the challenge frame and state.
Returns
true if challenge response was sent successfully; false otherwise.

When the first response is a challenge request (0x3C), this helper builds the HMAC challenge response using create_challenge_resp() and transmits it with the SX1262‑specific longer preamble. The exchange context is updated with the BUILD_AUTH_RESPONSE and TX_AUTH_RESPONSE states.

Definition at line 268 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ hop_frequency_()

void esphome::home_io_control::IOHomeControlComponent::hop_frequency_ ( )
protected

Hop to the next channel in the 3‑channel sequence: CH1 → CH2 → CH3 → CH1.

Called periodically by the main loop when idle to maintain synchronization with the protocol's ~2.7 ms hopping schedule. Devices also hop, so the controller must hop even while waiting for a response; the next transmit will use whatever channel is current.

Definition at line 169 of file hub_core.cpp.

◆ log_exchange_debug_()

void esphome::home_io_control::IOHomeControlComponent::log_exchange_debug_ ( const char * device_id) const
protected

Definition at line 58 of file hub_core.cpp.

◆ loop()

void esphome::home_io_control::IOHomeControlComponent::loop ( )
override

Main loop: process pending operations and drive radio state machine.

Definition at line 263 of file hub_core.cpp.

Here is the call graph for this function:

◆ notify_device_update_()

void esphome::home_io_control::IOHomeControlComponent::notify_device_update_ ( const std::string & id)
protected

Fire all registered device update callbacks for the given device ID.

Parameters
idDevice ID that updated.

Definition at line 220 of file hub_core.cpp.

◆ parse_device_from_discovery()

void esphome::home_io_control::IOHomeControlComponent::parse_device_from_discovery ( const IoFrame & frame,
IoDevice & device,
std::string & device_id )
staticprotected

Parse a discovery response frame into device metadata and ID.

Parameters
frameParsed discovery response.
deviceOutput: populated IoDevice (node_id, type, subtype, inverted, position/target/stopped).
device_idOutput: hex string representation of node ID.

Extracts node ID, device type, and subtype from a CMD_DISCOVER_RESP frame. The two-byte payload uses the shared packed device metadata layout defined in proto_frame.h. The inversion flag is derived from the type via default_inverted_for_type().

Definition at line 236 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ process_pending_operation_()

void esphome::home_io_control::IOHomeControlComponent::process_pending_operation_ ( )
protected

Pop next pending operation from the queue and execute it (set position, request status, discover).

Definition at line 302 of file hub_operations.cpp.

Here is the call graph for this function:

◆ process_received_packet_()

void esphome::home_io_control::IOHomeControlComponent::process_received_packet_ ( const RadioRxPacket & packet)
protected

Parse received packet, update device state if it's a status frame, and notify covers.

Parameters
packetRaw radio packet containing a parsed IoFrame.

Definition at line 231 of file hub_status.cpp.

Here is the call graph for this function:

◆ queue_discover_and_pair()

void esphome::home_io_control::IOHomeControlComponent::queue_discover_and_pair ( )
virtual

Queue a pairing operation; executed in loop() when radio idle.

Definition at line 266 of file hub_operations.cpp.

◆ queue_request_device_status()

void esphome::home_io_control::IOHomeControlComponent::queue_request_device_status ( const std::string & device_id)
virtual

Queue an async status request; returns immediately, executed in loop().

Parameters
device_idTarget device ID.

Definition at line 249 of file hub_operations.cpp.

Here is the call graph for this function:

◆ queue_set_device_position()

void esphome::home_io_control::IOHomeControlComponent::queue_set_device_position ( const std::string & device_id,
uint8_t position )
virtual

Queue an async position update; returns immediately, executed in loop().

Parameters
device_idTarget device ID.
positionDesired position.

Definition at line 231 of file hub_operations.cpp.

Here is the call graph for this function:

◆ queue_set_device_tilt()

void esphome::home_io_control::IOHomeControlComponent::queue_set_device_tilt ( const std::string & device_id,
uint8_t tilt_percent )
virtual

Queue an async tilt update; returns immediately, executed in loop().

Parameters
device_idTarget device ID.
tilt_percentDesired tilt.

Definition at line 240 of file hub_operations.cpp.

Here is the call graph for this function:

◆ queue_set_light_state()

void esphome::home_io_control::IOHomeControlComponent::queue_set_light_state ( const std::string & device_id,
bool on )
virtual

Async form of set_light_state() that keeps radio work serialized on the main loop.

Parameters
device_idTarget device ID.
onDesired on/off state.

Definition at line 276 of file hub_operations.cpp.

Here is the call graph for this function:

◆ queue_set_switch_state()

void esphome::home_io_control::IOHomeControlComponent::queue_set_switch_state ( const std::string & device_id,
bool on )
virtual

Async form of set_switch_state() that keeps radio work serialized on the main loop.

Parameters
device_idTarget device ID.
onDesired on/off state.

Definition at line 289 of file hub_operations.cpp.

Here is the call graph for this function:

◆ record_exchange_debug_()

void esphome::home_io_control::IOHomeControlComponent::record_exchange_debug_ ( const char * stage,
uint8_t tries,
bool saw_challenge )
protected

Definition at line 41 of file hub_core.cpp.

◆ register_device_callback()

virtual void esphome::home_io_control::IOHomeControlComponent::register_device_callback ( DeviceUpdateCallback cb)
inlinevirtual

Register a callback invoked when any device updates.

Parameters
cbCallable with signature void(const std::string&, const IoDevice&).

Definition at line 145 of file hub_core.h.

◆ request_device_status()

bool esphome::home_io_control::IOHomeControlComponent::request_device_status ( const std::string & device_id)
virtual

Request current status from a device.

Parameters
device_idTarget device ID.
Returns
true if status frame was received and processed.

Definition at line 177 of file hub_operations.cpp.

Here is the call graph for this function:

◆ reset_exchange_debug_()

void esphome::home_io_control::IOHomeControlComponent::reset_exchange_debug_ ( uint8_t request_cmd)
protected

Definition at line 36 of file hub_core.cpp.

◆ run_discovery_phase_()

decisions::PairingDiscoveryDisposition esphome::home_io_control::IOHomeControlComponent::run_discovery_phase_ ( pairing::PairingContext & context)
protected

Phase 1: broadcast discovery (0x28) and wait for a device response (0x29).

Execute Phase 1: discover a pairable device on channel 2.

Parameters
contextPairing context modified on success.
Returns
PairingDiscoveryDisposition: ACCEPT, NO_RESPONSE, or INVALID.

Transmits a discovery broadcast (0x28) and waits up to the configured discovery timeout for a valid discovery response (0x29). On success the response is parsed into context.device and context.device_id and the function returns ACCEPT. On failure returns NO_RESPONSE (no packets) or INVALID (packets seen but none were valid discovery frames).

Definition at line 261 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ run_key_exchange_phase_()

bool esphome::home_io_control::IOHomeControlComponent::run_key_exchange_phase_ ( pairing::PairingContext & context)
protected

Phase 2: authenticated key exchange (0x31 → 0x3C → 0x32 → 0x33).

Execute Phase 2: perform authenticated key exchange with the discovered device.

Parameters
contextPairing context populated by run_discovery_phase_().
Returns
true if key exchange completes successfully; false otherwise.

Performs the full four‑step key exchange:

  1. TX_KEY_INIT — send key‑init frame (0x31) to device
  2. WAIT_KEY_CHALLENGE — wait for device's challenge (0x3C)
  3. TX_KEY_TRANSFER — send challenge response + our key share (0x32)
  4. WAIT_KEY_CONFIRM — wait for device's key‑confirm (0x33) using the normal authenticated exchange (send_and_receive_) to inherit retry logic.

Each step updates the pairing state for observability. Any failure returns false immediately; the orchestrator will clean up and abort pairing.

Definition at line 290 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ schedule_status_poll_()

void esphome::home_io_control::IOHomeControlComponent::schedule_status_poll_ ( const std::string & device_id,
uint32_t delay_ms )
protected

Schedule a delayed status poll for a registered device using the Component timeout API.

Parameters
device_idID of the device to poll.
delay_msDelay in milliseconds before polling.
Note
Uses ESPHome's set_timeout() mechanism; the callback executes in loop(). A zero delay schedules immediately on the next loop iteration.

Definition at line 165 of file hub_status.cpp.

◆ send_and_receive_()

bool esphome::home_io_control::IOHomeControlComponent::send_and_receive_ ( const IoFrame & request,
IoFrame & response,
uint32_t freq )
protected

Main request/response exchange with retry and automatic authentication.

Parameters
requestOutbound request IoFrame.
responseOutput: received response IoFrame.
freqRF frequency in Hz.
Returns
true if exchange succeeded; false otherwise.

Definition at line 143 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ set_busy_pin()

void esphome::home_io_control::IOHomeControlComponent::set_busy_pin ( InternalGPIOPin * pin)
inline

Set the BUSY pin (SX1262).

Definition at line 98 of file hub_core.h.

◆ set_device_position()

bool esphome::home_io_control::IOHomeControlComponent::set_device_position ( const std::string & device_id,
uint8_t position )
virtual

Send a position command to a device.

Parameters
device_idTarget device ID.
positionDesired position (0–100, or POS_STOP/POS_FAVORITE).
Returns
true if device acknowledged; false on timeout or radio error.

Definition at line 95 of file hub_operations.cpp.

Here is the call graph for this function:

◆ set_device_status_poll_interval()

void esphome::home_io_control::IOHomeControlComponent::set_device_status_poll_interval ( const std::string & device_id,
uint32_t poll_interval_ms )
virtual

Configure the optional follow-up polling interval for a registered device.

Parameters
device_idTarget device ID.
poll_interval_msPoll interval in milliseconds; zero keeps the legacy one-shot settle poll only.

Definition at line 230 of file hub_core.cpp.

Here is the call graph for this function:

◆ set_device_tilt()

bool esphome::home_io_control::IOHomeControlComponent::set_device_tilt ( const std::string & device_id,
uint8_t tilt_percent )
virtual

Send a tilt command to a tilt‑capable cover.

Parameters
device_idTarget device ID.
tilt_percentDesired tilt (0–100).
Returns
true if device acknowledged; false otherwise.

Definition at line 146 of file hub_operations.cpp.

Here is the call graph for this function:

◆ set_dio0_pin()

void esphome::home_io_control::IOHomeControlComponent::set_dio0_pin ( InternalGPIOPin * pin)
inline

Set the DIO0 interrupt pin (SX1276).

Definition at line 92 of file hub_core.h.

◆ set_dio1_pin()

void esphome::home_io_control::IOHomeControlComponent::set_dio1_pin ( InternalGPIOPin * pin)
inline

Set the DIO1 interrupt pin (SX1262).

Definition at line 96 of file hub_core.h.

◆ set_dio4_pin()

void esphome::home_io_control::IOHomeControlComponent::set_dio4_pin ( InternalGPIOPin * pin)
inline

Set the DIO4 preamble‑detect pin (SX1276, optional).

Definition at line 94 of file hub_core.h.

◆ set_fem_en_pin()

void esphome::home_io_control::IOHomeControlComponent::set_fem_en_pin ( InternalGPIOPin * pin)
inline

Set the front‑end module enable pin.

Definition at line 100 of file hub_core.h.

◆ set_fem_pa_pin()

void esphome::home_io_control::IOHomeControlComponent::set_fem_pa_pin ( InternalGPIOPin * pin)
inline

Set the FEM PA switch pin.

Definition at line 104 of file hub_core.h.

◆ set_light_state()

bool esphome::home_io_control::IOHomeControlComponent::set_light_state ( const std::string & device_id,
bool on )
virtual

Semantic binary helper for light entities.

Internally mapped to the shared execute path.

Parameters
device_idTarget device ID.
onDesired on/off state.
Returns
true if device acknowledged.

Definition at line 200 of file hub_operations.cpp.

Here is the call graph for this function:

◆ set_node_id()

void esphome::home_io_control::IOHomeControlComponent::set_node_id ( const std::string & id)
inline

Set the controller's node ID (hex string).

Definition at line 106 of file hub_core.h.

◆ set_pa_pin()

void esphome::home_io_control::IOHomeControlComponent::set_pa_pin ( uint8_t pa_pin)
inline

Set PA boost pin configuration.

Definition at line 112 of file hub_core.h.

◆ set_radio_type()

void esphome::home_io_control::IOHomeControlComponent::set_radio_type ( const std::string & type)
inline

Set radio type ("sx1276" or "sx1262"); empty string means auto‑detect.

Definition at line 114 of file hub_core.h.

◆ set_rst_pin()

void esphome::home_io_control::IOHomeControlComponent::set_rst_pin ( InternalGPIOPin * pin)
inline

Set the radio reset pin.

Definition at line 90 of file hub_core.h.

◆ set_switch_state()

bool esphome::home_io_control::IOHomeControlComponent::set_switch_state ( const std::string & device_id,
bool on )
virtual

Semantic binary helper for switch entities.

Internally mapped to the shared execute path.

Parameters
device_idTarget device ID.
onDesired on/off state.
Returns
true if device acknowledged.

Definition at line 216 of file hub_operations.cpp.

Here is the call graph for this function:

◆ set_system_key()

void esphome::home_io_control::IOHomeControlComponent::set_system_key ( const std::string & key)
inline

Set the system key (hex string).

Definition at line 108 of file hub_core.h.

◆ set_tcxo_voltage()

void esphome::home_io_control::IOHomeControlComponent::set_tcxo_voltage ( uint8_t voltage)
inline

Set TCXO voltage for SX1262 (1.8V / 3.3V).

Definition at line 116 of file hub_core.h.

◆ set_tx_power()

void esphome::home_io_control::IOHomeControlComponent::set_tx_power ( uint8_t power)
inline

Set transmit power (dBm).

Definition at line 110 of file hub_core.h.

◆ set_vfem_pin()

void esphome::home_io_control::IOHomeControlComponent::set_vfem_pin ( InternalGPIOPin * pin)
inline

Set the VFEM power pin.

Definition at line 102 of file hub_core.h.

◆ setup()

void esphome::home_io_control::IOHomeControlComponent::setup ( )
override

Initialize hardware (radio and device registry).

Initialize the IO‑Homecontrol component and radio hardware.

This is the main setup entry point called by ESPHome during startup. The sequence:

  1. Parse node_id and system_key from hex strings (fails early if malformed).
  2. Initialize the SPI bus via spi_setup().
  3. Auto‑detect or explicitly select the radio chip:
    • If radio_type is "sx1276" or "sx1262", select that driver.
    • If empty (default), attempt to read SX1276 version register (0x42 = 0x12). If the read fails or returns wrong version, fall back to SX1262.
  4. Allocate the appropriate RadioDriver (SX1276 needs DIO0; SX1262 needs BUSY+DIO1).
  5. Call radio_->init() which performs chip reset, calibration, and register configuration.
  6. Enter normal loop() operation with radio in RX mode.
Note
Blocking operations in setup() temporarily raise the ESPHome WDT threshold to 250 ms (warn_if_blocking_over_) because radio init can exceed the default 30–50 ms budget.

Definition at line 87 of file hub_core.cpp.

Here is the call graph for this function:

◆ spi_disable()

void esphome::home_io_control::IOHomeControlComponent::spi_disable ( )
inlineoverridevirtual

Disable the SPI bus.

Implements esphome::home_io_control::SpiAccess.

Definition at line 76 of file hub_core.h.

◆ spi_enable()

void esphome::home_io_control::IOHomeControlComponent::spi_enable ( )
inlineoverridevirtual

Enable the SPI bus.

Implements esphome::home_io_control::SpiAccess.

Definition at line 74 of file hub_core.h.

◆ spi_read()

uint8_t esphome::home_io_control::IOHomeControlComponent::spi_read ( )
inlineoverridevirtual

Read one byte (MISO only).

Returns
Received byte.

Implements esphome::home_io_control::SpiAccess.

Definition at line 86 of file hub_core.h.

◆ spi_transfer()

uint8_t esphome::home_io_control::IOHomeControlComponent::spi_transfer ( uint8_t data)
inlineoverridevirtual

Transfer one byte full‑duplex.

Parameters
dataByte to send.
Returns
Received byte.

Implements esphome::home_io_control::SpiAccess.

Definition at line 80 of file hub_core.h.

◆ spi_write()

void esphome::home_io_control::IOHomeControlComponent::spi_write ( uint8_t data)
inlineoverridevirtual

Write one byte (MOSI only).

Parameters
dataByte to send.

Implements esphome::home_io_control::SpiAccess.

Definition at line 83 of file hub_core.h.

◆ transmit_frame_()

bool esphome::home_io_control::IOHomeControlComponent::transmit_frame_ ( const IoFrame & frame,
uint32_t freq,
uint16_t preamble )
protected

Transmit a raw IoFrame on the current frequency with given preamble length.

Parameters
frameIoFrame to transmit.
freqRF frequency in Hz.
preamblePreamble length in bytes (LONG_PREAMBLE or SHORT_PREAMBLE).

Definition at line 194 of file hub_core.cpp.

Here is the call graph for this function:

◆ transmit_request_()

bool esphome::home_io_control::IOHomeControlComponent::transmit_request_ ( const IoFrame & request,
uint32_t freq,
uint16_t preamble,
exchange::OutboundExchangeContext & ctx )
protected

Wrap transmit_frame_ and mark context failed on error.

Transmit the initial request frame and update exchange context on failure.

Parameters
requestOutbound IoFrame to transmit.
freqRF frequency in Hz.
preamblePreamble length in bytes.
ctxExchange context (state updated on failure).
Returns
true if transmit succeeded; false otherwise.

This helper isolates the one-shot TX operation from the retry loop. It does NOT implement retries itself — the orchestrator (send_and_receive_) calls this repeatedly until success or retry exhaustion. On failure we mark the context state as FAILED and record debug info; success returns true.

Definition at line 213 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ update_device_status_()

void esphome::home_io_control::IOHomeControlComponent::update_device_status_ ( const IoFrame & frame)
protected

Extract position/status info from a status or status-update frame and merge into device record.

Parameters
frameIoFrame containing a status-bearing command (CMD_PRIVATE_RESP or CMD_STATUS_UPDATE).

Definition at line 173 of file hub_status.cpp.

Here is the call graph for this function:

◆ wait_for_discovery_response_()

decisions::PairingDiscoveryDisposition esphome::home_io_control::IOHomeControlComponent::wait_for_discovery_response_ ( uint32_t timeout_ms,
RadioRxPacket & packet,
IoFrame & response_frame )
protected

Wait for a discovery response (0x29) during pairing.

Wait for a valid discovery response (0x29) within the timeout.

Parameters
timeout_msMaximum time to wait in milliseconds.
packetOutput: raw RadioRxPacket of the accepted frame.
response_frameOutput: parsed IoFrame of the accepted frame.
Returns
PairingDiscoveryDisposition: ACCEPT on success; NO_RESPONSE or INVALID otherwise.

Listens for incoming packets and parses them. Frames that parse successfully are passed to decisions::classify_pairing_discovery_response(). Only a frame classified as ACCEPT (CMD_DISCOVER_RESP) returns true. All other frames are ignored until the deadline expires.

The function distinguishes between NO_RESPONSE (no packets seen at all) and INVALID (some packets seen but none were valid discovery responses).

Definition at line 181 of file hub_pairing.cpp.

Here is the call graph for this function:

◆ wait_for_final_response_()

decisions::ExchangeFinalResponseDisposition esphome::home_io_control::IOHomeControlComponent::wait_for_final_response_ ( const IoFrame & request,
exchange::OutboundExchangeContext & ctx )
protected

Wait loop for the final authenticated response; uses is_valid_final_response().

Wait for the final (authenticated) response after challenge has been answered.

Parameters
requestOriginal request frame (used for endpoint matching).
ctxExchange context (receives final rx frame on accept).
Returns
ACCEPT if a matching final response arrives; IGNORE_UNRELATED on timeout.

After sending the 0x3D challenge response, the device will reply with the actual command response (e.g. 0x04 status) signed using the shared system key. This helper loops within RESPONSE_AUTH_WAIT_MS, hopping channels on each slice, parsing and validating that the frame matches the original request endpoints. Non‑matching frames are logged and ignored.

Definition at line 302 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ wait_for_first_response_()

decisions::ExchangeFirstResponseDisposition esphome::home_io_control::IOHomeControlComponent::wait_for_first_response_ ( const IoFrame & request,
exchange::OutboundExchangeContext & ctx )
protected

Wait loop for the first response packet; classifies via decisions::classify_exchange_first_response.

Wait for the first response packet within the configured timeout window.

Parameters
requestOriginal request frame (used for endpoint matching).
ctxExchange context (provides deadline and receives rx frame on accept).
Returns
Disposition indicating next step.

Listens on the current RF channel, hopping to the next channel after each slice if no packet arrives. Parses incoming frames and classifies them via decisions::classify_exchange_first_response():

  • COMPLETE_DIRECT → matching non‑challenge frame (operation complete, no auth)
  • REQUIRE_AUTH → matching 0x3C challenge (device demands authentication)
  • IGNORE_UNRELATED → all others (timeout, wrong endpoints, unparsable)

Definition at line 231 of file hub_exchange.cpp.

Here is the call graph for this function:

◆ wait_for_key_challenge_()

bool esphome::home_io_control::IOHomeControlComponent::wait_for_key_challenge_ ( uint32_t timeout_ms,
RadioRxPacket & packet,
IoFrame & challenge_frame,
const uint8_t device_node_id[NODE_ID_SIZE] )
protected

Wait for a key-challenge (0x3C) from target device during pairing key exchange.

Wait for a valid key‑challenge frame (0x3C from the target device).

Parameters
timeout_msMaximum time to wait in milliseconds.
packetOutput: raw RadioRxPacket of the challenge frame.
challenge_frameOutput: parsed IoFrame containing the challenge.
device_node_idNode ID of the device we are pairing (expected sender).
Returns
true if a valid challenge was received; false on timeout.

During key exchange the device responds to our key‑init with a random 6‑byte challenge. This helper loops until such a frame is received and validated by decisions::classify_pairing_key_challenge() — it must be a 0x3C command, 6 bytes long, and come from the discovered device node ID.

Definition at line 209 of file hub_pairing.cpp.

Here is the call graph for this function:

Member Data Documentation

◆ busy_

bool esphome::home_io_control::IOHomeControlComponent::busy_ {false}
protected

Definition at line 380 of file hub_core.h.

◆ busy_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::busy_pin_ {nullptr}
protected

SX1262 BUSY pin.

Definition at line 363 of file hub_core.h.

◆ callbacks_

std::vector<DeviceUpdateCallback> esphome::home_io_control::IOHomeControlComponent::callbacks_
protected

Definition at line 384 of file hub_core.h.

◆ devices_

std::map<std::string, IoDevice> esphome::home_io_control::IOHomeControlComponent::devices_
protected

Definition at line 383 of file hub_core.h.

◆ dio0_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::dio0_pin_ {nullptr}
protected

SX1276 DIO0 interrupt.

Definition at line 360 of file hub_core.h.

◆ dio1_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::dio1_pin_ {nullptr}
protected

SX1262 DIO1 interrupt.

Definition at line 362 of file hub_core.h.

◆ dio4_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::dio4_pin_ {nullptr}
protected

SX1276 DIO4 preamble detect (optional).

Definition at line 361 of file hub_core.h.

◆ fem_en_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::fem_en_pin_ {nullptr}
protected

Front-end module enable.

Definition at line 364 of file hub_core.h.

◆ fem_pa_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::fem_pa_pin_ {nullptr}
protected

Front-end module PA switch.

Definition at line 366 of file hub_core.h.

◆ initialized_

bool esphome::home_io_control::IOHomeControlComponent::initialized_ {false}
protected

Definition at line 379 of file hub_core.h.

◆ last_exchange_debug_

ExchangeDebugInfo esphome::home_io_control::IOHomeControlComponent::last_exchange_debug_ {}
protected

Definition at line 382 of file hub_core.h.

◆ last_hop_us_

uint32_t esphome::home_io_control::IOHomeControlComponent::last_hop_us_ {0}
protected

Definition at line 381 of file hub_core.h.

◆ linked_remotes_

std::map<std::string, std::vector<std::string> > esphome::home_io_control::IOHomeControlComponent::linked_remotes_
protected

Maps remote node IDs to lists of device IDs they control.

Used to trigger status polls when 1W remote activity is overheard.

Definition at line 388 of file hub_core.h.

◆ node_id_

uint8_t esphome::home_io_control::IOHomeControlComponent::node_id_[NODE_ID_SIZE] {}
protected

Definition at line 372 of file hub_core.h.

◆ node_id_str_

std::string esphome::home_io_control::IOHomeControlComponent::node_id_str_
protected

Definition at line 369 of file hub_core.h.

◆ pa_pin_

uint8_t esphome::home_io_control::IOHomeControlComponent::pa_pin_ {DEFAULT_PA_PIN_PA_BOOST}
protected

Definition at line 375 of file hub_core.h.

◆ pending_operations_

std::deque<PendingOperation> esphome::home_io_control::IOHomeControlComponent::pending_operations_
protected

Definition at line 385 of file hub_core.h.

◆ radio_

RadioDriver* esphome::home_io_control::IOHomeControlComponent::radio_ {nullptr}
protected

Definition at line 356 of file hub_core.h.

◆ radio_type_

std::string esphome::home_io_control::IOHomeControlComponent::radio_type_
protected

"sx1276", "sx1262", or "" (auto-detect)

Definition at line 371 of file hub_core.h.

◆ rst_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::rst_pin_ {nullptr}
protected

Definition at line 359 of file hub_core.h.

◆ system_key_

uint8_t esphome::home_io_control::IOHomeControlComponent::system_key_[AES_KEY_SIZE] {}
protected

Definition at line 373 of file hub_core.h.

◆ system_key_str_

std::string esphome::home_io_control::IOHomeControlComponent::system_key_str_
protected

Definition at line 370 of file hub_core.h.

◆ tcxo_voltage_

uint8_t esphome::home_io_control::IOHomeControlComponent::tcxo_voltage_ {DEFAULT_TCXO_VOLTAGE_SETTING_1P8V}
protected

SX1262 TCXO voltage setting (default 1.8 V).

Definition at line 376 of file hub_core.h.

◆ tx_power_

uint8_t esphome::home_io_control::IOHomeControlComponent::tx_power_ {DEFAULT_TX_POWER_DBM}
protected

Definition at line 374 of file hub_core.h.

◆ vfem_pin_

InternalGPIOPin* esphome::home_io_control::IOHomeControlComponent::vfem_pin_ {nullptr}
protected

Front-end module power.

Definition at line 365 of file hub_core.h.


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