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

Functions

uint8_t round_percent (float fraction)
 Convert a 0.0-1.0 HA fraction (position, tilt, or brightness) to a 0-100 IO percent.
bool is_binary_entity_position (uint8_t position)
 Is the given position value an on/off binary encoding?
bool known_device_matches_entity_class (const IoDevice &dev, DeviceCapabilityClass expected)
 Does the device's type match the expected HA entity class?
bool known_device_supports_status_requests (const IoDevice &dev)
 Does the device support status requests?
bool known_device_accepts_execute_position (const IoDevice &dev, uint8_t position)
 Can this device accept an execute (position) command?
bool known_device_accepts_execute_tilt (const IoDevice &dev)
 Can this device accept a tilt command?
void log_rejected_operation (const std::string &device_id, const IoDevice &dev, const char *operation, const char *expected)
 Log a rejected operation with capability mismatch details.
void log_component_capture (const RadioDriver *radio, const char *stage, const uint8_t *buf, uint8_t len, const IoFrame *frame=nullptr)
 Log a frame at the "io_capture" tag with structured fields.
void log_frame_issue (IOHomeControlComponent *component, const char *direction, const char *reason, const IoFrame &frame, uint8_t len)
 Log a frame‑level issue (unregistered endpoints, unsupported commands).
void log_1w_remote_frame (const OneWayFrameInfo &info, const std::vector< std::string > *linked_devices=nullptr)
 Log an already-decoded 1W remote frame at DEBUG level.
bool is_exposed_sender (const std::vector< std::string > &exposed_senders, const std::string &sender_id)
 Whether a 1W sender is on the exposed_senders allowlist for the sender HA event.
std::string format_name_and_hex (const char *name, uint8_t value)
 Format a name/value pair as "name(0xXX)", e.g. "execute(0x00)".
std::string describe_learned_device_type (DeviceType type)
 Build the YAML line to add once a device's type is learned at runtime.
std::map< std::string, std::string > build_sender_event_data (const OneWayFrameInfo &info, bool linked)
 Build the Home Assistant event data map for a decoded 1W sender frame.
void normalize_stopped_state (IoDevice &dev)
 Normalize stopped state: some devices briefly report stopped before target/current converge.
void update_link_health (IoDevice &dev, RadioDriver *radio)
 Update per-device link-health stats from the radio's last capture.
void record_exchange_timeout (IoDevice &dev, uint8_t tries)
 Record that an outbound exchange to this device timed out (no valid response).
void log_status_update (const std::string &id, const IoDevice &dev, const char *suffix="")
 Log a concise status‑update line used by inbound handlers.
void log_command_result (const std::string &id, uint8_t result, uint8_t request_cmd=0, bool include_request_cmd=false)
 Log a decoded CMD_ERROR_RESP result with optional request-command context.
void record_command_result (IoDevice &dev, const std::string &id, uint8_t result, uint8_t request_cmd=0, bool include_request_cmd=false)
 Store a decoded CMD_ERROR_RESP result on the device and log it.
void clear_command_result (IoDevice &dev)
 Clear a previously recorded CMD_ERROR_RESP result, if any.

Variables

constexpr const char * TAG = "home_io_control"
 Shared log tag for hub-level messages.
constexpr uint32_t ONEWAY_DEDUP_WINDOW_MS = 2000
 Suppress a repeated 1W log/poll for the same remote and the same intent within this window.
constexpr float BINARY_ENTITY_ON_POSITION_THRESHOLD
 Shared 0-100 cutoff: values below this mean binary "on".
constexpr const char * ONEWAY_SENDER_EVENT = "esphome.home_io_control_sender_event"
 Home Assistant event fired when a decoded 1W frame carries a command intent from an exposed sender (a physical remote button press, or a wind/rain sensor's triggered command).
constexpr size_t NAME_AND_HEX_BUFFER_SIZE = 40
 Buffer size for format_name_and_hex(): longest command name plus "(0xXX)" and a margin.
constexpr size_t LEARNED_DEVICE_TYPE_HEX_BUFFER_SIZE = 24
 Buffer size for describe_learned_device_type()'s hex fallback: "io_device_type: 0xXX" plus margin.

Function Documentation

◆ build_sender_event_data()

std::map< std::string, std::string > esphome::home_io_control::detail::build_sender_event_data ( const OneWayFrameInfo & info,
bool linked )
inline

Build the Home Assistant event data map for a decoded 1W sender frame.

Only meaningful when info.has_intent is true (the caller gates emission on that); the intent field is only populated by decode_1w_frame() in that case.

Parameters
infoAlready-decoded 1W frame info (see decode_1w_frame()).
linkedTrue if this sender is linked to at least one registered device.
Returns
Event data map ready for fire_homeassistant_event().

Definition at line 277 of file hub_internal.h.

Here is the call graph for this function:

◆ clear_command_result()

void esphome::home_io_control::detail::clear_command_result ( IoDevice & dev)
inline

Clear a previously recorded CMD_ERROR_RESP result, if any.

A stale limitation reason (e.g. a rain lockout from an hour ago) is worse than none once the device has since replied normally, so every successful status/command reply for a device clears it. Called from the CMD_PRIVATE_RESP and CMD_STATUS_UPDATE branches of update_device_status_() — not from CMD_GET_NAME_RESP/CMD_GET_INFO2_RESP, which are metadata lookups unrelated to whether the device's last movement command succeeded. Like record_command_result(), does not notify subscribers itself — both existing call sites clear before their own notify_device_update_() call, which is what actually publishes this change.

Parameters
devDevice to clear.

Definition at line 411 of file hub_internal.h.

◆ describe_learned_device_type()

std::string esphome::home_io_control::detail::describe_learned_device_type ( DeviceType type)
inline

Build the YAML line to add once a device's type is learned at runtime.

Logged when io_device_type was left unset in YAML and an INFO2 response just resolved it for the first time this boot (ADR 0018: nothing persists, so this repeats on every reboot until the user copies the line in). Reuses yaml_device_type_name() so the exact syntax always matches what the pairing snippet and the Python schema accept.

Parameters
typeThe now-known device type. Must not be DeviceType::UNKNOWN.
Returns
The YAML line to add, e.g. io_device_type: "venetian_blind" or io_device_type: 0x11.

Definition at line 261 of file hub_internal.h.

Here is the call graph for this function:

◆ format_name_and_hex()

std::string esphome::home_io_control::detail::format_name_and_hex ( const char * name,
uint8_t value )
inline

Format a name/value pair as "name(0xXX)", e.g. "execute(0x00)".

Definition at line 244 of file hub_internal.h.

◆ is_binary_entity_position()

bool esphome::home_io_control::detail::is_binary_entity_position ( uint8_t position)
inline

Is the given position value an on/off binary encoding?

Parameters
positionPosition value to test.
Returns
true if position equals BINARY_ENTITY_ON_POSITION or BINARY_ENTITY_OFF_POSITION.

Definition at line 64 of file hub_internal.h.

◆ is_exposed_sender()

bool esphome::home_io_control::detail::is_exposed_sender ( const std::vector< std::string > & exposed_senders,
const std::string & sender_id )
inline

Whether a 1W sender is on the exposed_senders allowlist for the sender HA event.

"Sender" covers both remotes and wind/rain sensors — they use the identical 1W broadcast mechanism and differ only in the originator byte inside the payload, not in addressing. Overheard 1W traffic is always DEBUG-logged regardless of this check (see log_1w_remote_frame()); this only gates whether the event reaches Home Assistant. Deliberately separate from linked_devices — a sender can be event-enabled without controlling any registered device (e.g. to trigger an HA automation with no matching cover/light/switch), or vice versa.

Parameters
exposed_sendersConfigured allowlist (exposed_senders YAML key, empty by default).
sender_idNode ID of the 1W sender that sent the frame.
Returns
true if the sender is in the allowlist.

Definition at line 236 of file hub_internal.h.

◆ known_device_accepts_execute_position()

bool esphome::home_io_control::detail::known_device_accepts_execute_position ( const IoDevice & dev,
uint8_t position )
inline

Can this device accept an execute (position) command?

Checks capability and, for unknown types, allows binary positions for light/switch.

Parameters
devIoDevice to check.
positionPosition value being sent.
Returns
true if operation is appropriate for this device type.

Definition at line 90 of file hub_internal.h.

Here is the call graph for this function:

◆ known_device_accepts_execute_tilt()

bool esphome::home_io_control::detail::known_device_accepts_execute_tilt ( const IoDevice & dev)
inline

Can this device accept a tilt command?

Parameters
devIoDevice to check.
Returns
true only if device type is known to support tilt.

Definition at line 108 of file hub_internal.h.

Here is the call graph for this function:

◆ known_device_matches_entity_class()

bool esphome::home_io_control::detail::known_device_matches_entity_class ( const IoDevice & dev,
DeviceCapabilityClass expected )
inline

Does the device's type match the expected HA entity class?

UNKNOWN devices always match to keep imported/discovered devices working.

Parameters
devIoDevice to check.
expectedDesired capability class (COVER, LIGHT, SWITCH, etc.).
Returns
true if device type matches or is UNKNOWN.

Definition at line 73 of file hub_internal.h.

Here is the call graph for this function:

◆ known_device_supports_status_requests()

bool esphome::home_io_control::detail::known_device_supports_status_requests ( const IoDevice & dev)
inline

Does the device support status requests?

UNKNOWN devices pass through.

Parameters
devIoDevice to check.
Returns
true if device type supports status requests or is UNKNOWN.

Definition at line 81 of file hub_internal.h.

Here is the call graph for this function:

◆ log_1w_remote_frame()

void esphome::home_io_control::detail::log_1w_remote_frame ( const OneWayFrameInfo & info,
const std::vector< std::string > * linked_devices = nullptr )
inline

Log an already-decoded 1W remote frame at DEBUG level.

Formats a concise DEBUG log line showing remote ID, target type, command intent, and priority. When the remote is linked to devices, appends the linked device IDs. Takes the already-decoded OneWayFrameInfo so callers that also build a HA event (see build_sender_event_data()) decode the frame once, not twice.

Parameters
infoAlready-decoded 1W frame info (see decode_1w_frame()).
linked_devicesOptional pointer to device IDs this remote is linked to.

Definition at line 191 of file hub_internal.h.

Here is the call graph for this function:

◆ log_command_result()

void esphome::home_io_control::detail::log_command_result ( const std::string & id,
uint8_t result,
uint8_t request_cmd = 0,
bool include_request_cmd = false )
inline

Log a decoded CMD_ERROR_RESP result with optional request-command context.

Parameters
idDevice ID.
resultResult byte from CMD_ERROR_RESP data[0].
request_cmdOriginal outbound request command when known.
include_request_cmdTrue to include request_cmd in the log line.

Definition at line 370 of file hub_internal.h.

Here is the call graph for this function:

◆ log_component_capture()

void esphome::home_io_control::detail::log_component_capture ( const RadioDriver * radio,
const char * stage,
const uint8_t * buf,
uint8_t len,
const IoFrame * frame = nullptr )
inline

Log a frame at the "io_capture" tag with structured fields.

Used for protocol‑level debugging (phases: component, tx, rx, parse_ok/parse_fail).

Parameters
radioRadio driver instance (provides chip name and capture).
stageString label for the current phase.
bufRaw bytes being logged.
lenLength of buf.
frameOptional parsed IoFrame for decoded fields (cmd, src, dst).

Definition at line 135 of file hub_internal.h.

Here is the call graph for this function:

◆ log_frame_issue()

void esphome::home_io_control::detail::log_frame_issue ( IOHomeControlComponent * component,
const char * direction,
const char * reason,
const IoFrame & frame,
uint8_t len )
inline

Log a frame‑level issue (unregistered endpoints, unsupported commands).

Parameters
componentPointer to the component (for device lookup).
direction"tx" or "rx".
reasonShort issue label (e.g., "unregistered_device").
frameParsed frame.
lenSerialized length.

Definition at line 161 of file hub_internal.h.

Here is the call graph for this function:

◆ log_rejected_operation()

void esphome::home_io_control::detail::log_rejected_operation ( const std::string & device_id,
const IoDevice & dev,
const char * operation,
const char * expected )
inline

Log a rejected operation with capability mismatch details.

Parameters
device_idDevice ID string.
devIoDevice that rejected the command.
operationHuman‑readable operation name (e.g., "set position").
expectedExpected capability class or profile name.

Definition at line 121 of file hub_internal.h.

Here is the call graph for this function:

◆ log_status_update()

void esphome::home_io_control::detail::log_status_update ( const std::string & id,
const IoDevice & dev,
const char * suffix = "" )
inline

Log a concise status‑update line used by inbound handlers.

Parameters
idDevice ID.
devCurrent device state.
suffixOptional suffix added after the state string (e.g., " (status update)").

Definition at line 360 of file hub_internal.h.

Here is the call graph for this function:

◆ normalize_stopped_state()

void esphome::home_io_control::detail::normalize_stopped_state ( IoDevice & dev)
inline

Normalize stopped state: some devices briefly report stopped before target/current converge.

Parameters
devDevice record to update (may clear is_stopped if positions differ).

Definition at line 296 of file hub_internal.h.

Here is the call graph for this function:

◆ record_command_result()

void esphome::home_io_control::detail::record_command_result ( IoDevice & dev,
const std::string & id,
uint8_t result,
uint8_t request_cmd = 0,
bool include_request_cmd = false )
inline

Store a decoded CMD_ERROR_RESP result on the device and log it.

Single place both CMD_ERROR_RESP call sites (the unsolicited status path and the reply to our own EXECUTE) route through, so the store-and-log policy cannot drift between them. Does not notify subscribers itself — callers already call notify_device_update_() once per handled frame; call it after this.

Parameters
devDevice that returned the result.
idDevice ID (for the log line).
resultResult byte from CMD_ERROR_RESP data[0].
request_cmdOriginal outbound request command when known.
include_request_cmdTrue to include request_cmd context in the log line.

Definition at line 394 of file hub_internal.h.

Here is the call graph for this function:

◆ record_exchange_timeout()

void esphome::home_io_control::detail::record_exchange_timeout ( IoDevice & dev,
uint8_t tries )
inline

Record that an outbound exchange to this device timed out (no valid response).

Called once per failed exchange from execute_request_and_update_()'s "no valid response" branch — the single place every device-directed exchange already reads ExchangeEngine::DebugInfo. Both counters saturate at UINT16_MAX instead of wrapping, matching PairingTelemetry's counters.

Parameters
devDevice the failed exchange was addressed to.
triesNumber of attempts the failed exchange made (DebugInfo::tries, 1-based).

Definition at line 349 of file hub_internal.h.

◆ round_percent()

uint8_t esphome::home_io_control::detail::round_percent ( float fraction)
inline

Convert a 0.0-1.0 HA fraction (position, tilt, or brightness) to a 0-100 IO percent.

Rounds rather than truncates: HA quantizes call values to 0-255 before they ever reach us, so its "50%" is 128/255=0.50196, not exactly 0.5 — a truncating cast compounds that quantization into a consistent ~1% bias, caught on real hardware in both platform_cover.cpp (position and tilt) and platform_light.cpp (brightness). Callers apply their own invert/complement logic (e.g. 1.0F - fraction) before calling this; it only owns the rounding.

Parameters
fractionValue in [0.0, 1.0].
Returns
Rounded 0-100 percent.

Definition at line 55 of file hub_internal.h.

◆ update_link_health()

void esphome::home_io_control::detail::update_link_health ( IoDevice & dev,
RadioDriver * radio )
inline

Update per-device link-health stats from the radio's last capture.

Called for every frame whose src is a registered device, regardless of command type or whether that command's own payload was well-formed — any such frame is real evidence the device is reachable and at this signal strength. The two call sites cover both ways such a frame arrives: update_device_status_() (inbound status path) and execute_request_and_update_()'s explicit-refusal branch (a CMD_ERROR_RESP reply to our own request, which returns before reaching the status path). Always stamps last_seen_ms; only touches the RSSI fields when radio is non-null and its last capture is valid (real drivers always populate a valid capture before a frame is handed off, but tests calling this path directly without a radio, or without exercising RX through it, must not crash or fabricate an RSSI).

Parameters
devDevice that sent the frame.
radioRadio driver to read the last capture from; may be nullptr.

Definition at line 319 of file hub_internal.h.

Here is the call graph for this function:

Variable Documentation

◆ BINARY_ENTITY_ON_POSITION_THRESHOLD

float esphome::home_io_control::detail::BINARY_ENTITY_ON_POSITION_THRESHOLD
inlineconstexpr
Initial value:
=
50.0F

Shared 0-100 cutoff: values below this mean binary "on".

Definition at line 39 of file hub_internal.h.

◆ LEARNED_DEVICE_TYPE_HEX_BUFFER_SIZE

size_t esphome::home_io_control::detail::LEARNED_DEVICE_TYPE_HEX_BUFFER_SIZE = 24
inlineconstexpr

Buffer size for describe_learned_device_type()'s hex fallback: "io_device_type: 0xXX" plus margin.

Definition at line 251 of file hub_internal.h.

◆ NAME_AND_HEX_BUFFER_SIZE

size_t esphome::home_io_control::detail::NAME_AND_HEX_BUFFER_SIZE = 40
inlineconstexpr

Buffer size for format_name_and_hex(): longest command name plus "(0xXX)" and a margin.

Definition at line 241 of file hub_internal.h.

◆ ONEWAY_DEDUP_WINDOW_MS

uint32_t esphome::home_io_control::detail::ONEWAY_DEDUP_WINDOW_MS = 2000
inlineconstexpr

Suppress a repeated 1W log/poll for the same remote and the same intent within this window.

Wide on purpose: it collapses both the 4×/40ms reliability burst and a held button into one logical press. A different intent from the same remote (a stop after a move) is not a duplicate and passes through immediately — see decisions::is_duplicate_1w_frame().

Definition at line 38 of file hub_internal.h.

◆ ONEWAY_SENDER_EVENT

const char* esphome::home_io_control::detail::ONEWAY_SENDER_EVENT = "esphome.home_io_control_sender_event"
inlineconstexpr

Home Assistant event fired when a decoded 1W frame carries a command intent from an exposed sender (a physical remote button press, or a wind/rain sensor's triggered command).

Definition at line 222 of file hub_internal.h.

◆ TAG

const char* esphome::home_io_control::detail::TAG = "home_io_control"
inlineconstexpr

Shared log tag for hub-level messages.

Definition at line 33 of file hub_internal.h.