32uint32_t apply_status_poll_failure_backoff(
IoDevice &dev,
bool auth_like_failure) {
33 if (auth_like_failure) {
34 dev.status_poll_failures = 0;
35 if (dev.auth_poll_failures < UINT8_MAX)
36 dev.auth_poll_failures++;
40 dev.auth_poll_failures = 0;
41 if (dev.status_poll_failures < UINT8_MAX)
42 dev.status_poll_failures++;
48void clear_status_poll_failure_backoff(
IoDevice &dev) {
49 dev.status_poll_failures = 0;
50 dev.auth_poll_failures = 0;
59 bool warn_on_no_response, uint32_t retry_after_fail_ms) {
62 if (retry_after_fail_ms != 0) {
63 if (
auto *dev = this->
get_device(device_id); dev !=
nullptr) {
65 const uint32_t backoff_ms = apply_status_poll_failure_backoff(*dev, auth_like_failure);
66 uint32_t
const now = millis();
68 dev->next_update = now + backoff_ms;
70 "Background status poll backoff for device %s: delay=%u ms auth_like=%s status_failures=%u "
72 device_id.c_str(), backoff_ms, YESNO(auth_like_failure), dev->status_poll_failures,
73 dev->auth_poll_failures);
80 if (warn_on_no_response) {
81 ESP_LOGW(
detail::TAG,
"No response from device %s", device_id.c_str());
86 if (retry_after_fail_ms != 0) {
87 if (
auto *dev = this->
get_device(device_id); dev !=
nullptr)
88 clear_status_poll_failure_backoff(*dev);
100 const char *action =
"set position";
114 device_id, *dev, action,
122 dev->single_follow_up_poll_pending = dev->status_poll_interval_ms == 0;
126 ESP_LOGI(
detail::TAG,
"Sending %s to device %s (profile=%s)", action, device_id.c_str(),
141 if (position !=
POS_STOP && dev->status_poll_interval_ms != 0 && dev->next_update == 0)
156 dev->single_follow_up_poll_pending = dev->status_poll_interval_ms == 0;
159 ESP_LOGI(
detail::TAG,
"Sending tilt=%u%% to device %s (profile=%s)", tilt_percent, device_id.c_str(),
172 if (dev->status_poll_interval_ms != 0 && dev->next_update == 0)
195 uint32_t
const retry_after_fail_ms =
311 switch (operation.
type) {
virtual bool set_device_tilt(const std::string &device_id, uint8_t tilt_percent)
Send a tilt command to a tilt‑capable cover.
bool send_and_receive_(const IoFrame &request, IoFrame &response, uint32_t freq)
Main request/response exchange with retry and automatic authentication.
virtual bool set_switch_state(const std::string &device_id, bool on)
Semantic binary helper for switch entities.
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().
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.
virtual IoDevice * get_device(const std::string &device_id)
Retrieve a device by ID; returns nullptr if not found.
virtual void queue_request_device_status(const std::string &device_id)
Queue an async status request; returns immediately, executed in loop().
void process_pending_operation_()
Pop next pending operation from the queue and execute it (set position, request status,...
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.
@ 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).
@ DISCOVER_AND_PAIR
Queue a discover_and_pair call (starts 3‑phase pairing flow).
@ REQUEST_STATUS
Queue a request_device_status call (poll for current position).
@ SET_POSITION
Queue a set_device_position call (position 0–100 or special values).
void log_exchange_debug_(const char *device_id) const
ExchangeDebugInfo last_exchange_debug_
std::deque< PendingOperation > pending_operations_
virtual bool discover_and_pair()
Discover and pair a device that is in pairing mode.
void update_device_status_(const IoFrame &frame)
Extract position/status info from a status or status-update frame and merge into device record.
virtual bool set_light_state(const std::string &device_id, bool on)
Semantic binary helper for light entities.
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_device_position(const std::string &device_id, uint8_t position)
Queue an async position update; returns immediately, executed in 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.
virtual bool set_device_position(const std::string &device_id, uint8_t position)
Send a position command to a device.
uint8_t node_id_[NODE_ID_SIZE]
virtual void queue_discover_and_pair()
Queue a pairing operation; executed in loop() when radio idle.
virtual bool request_device_status(const std::string &device_id)
Request current status from a device.
Internal helpers shared by the hub implementation .cpp files.
bool known_device_accepts_execute_tilt(const IoDevice &dev)
Can this device accept a tilt command?
bool known_device_matches_entity_class(const IoDevice &dev, DeviceCapabilityClass expected)
Does the device's type match the expected HA entity class?
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.
bool known_device_accepts_execute_position(const IoDevice &dev, uint8_t position)
Can this device accept an execute (position) command?
constexpr uint32_t STATUS_RETRY_AFTER_FAIL_MS
First retry after a silent status-poll failure.
constexpr const char * TAG
Shared log tag for hub-level messages.
bool known_device_supports_status_requests(const IoDevice &dev)
Does the device support status requests?
constexpr uint8_t BINARY_ENTITY_ON_POSITION
constexpr uint8_t BINARY_ENTITY_OFF_POSITION
bool is_binary_entity_position(uint8_t position)
Is the given position value an on/off binary encoding?
uint32_t status_poll_retry_delay_ms(uint8_t consecutive_failures, bool auth_like_failure)
Compute the next background status-poll retry delay after a failed exchange.
void clear_status_poll_tracking(IoDevice &dev)
Clear all bounded follow-up polling state for a device.
bool status_poll_tracking_active(const IoDevice &dev, uint32_t now)
Check whether a device remains inside its bounded follow-up polling window.
const char * device_operation_profile_name(DeviceType type)
Human‑readable operation profile name for a device type.
bool create_get_status(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a get-status request (0x03). The device responds with its current position.
bool create_execute(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t position)
Build an execute command (0x00) to control a device.
bool create_execute_tilt(IoFrame &f, const uint8_t *own, const uint8_t *dst, bool low_power, uint8_t tilt_percent)
Build a tilt execute command (0x00) for devices that support slat angle control.
static constexpr uint32_t FREQ_CH2
Channel 2: 868.95 MHz (1W and 2W, TX channel).
@ SWITCH
Binary on/off switch.
@ COVER
Position‑controlled cover (shutter/blind/awning).
@ LIGHT
Binary on/off light.
static constexpr uint8_t POS_STOP
Position values in the IO protocol.
bool create_get_status_tilt(IoFrame &f, const uint8_t *own, const uint8_t *dst)
Build a tilt-aware get-status request (0x03) that returns the extended 16-byte tilt payload.
bool device_supports_tilt(DeviceType type)
Does this device type support tilt (slat angle) control?
Command builders for the IO‑Homecontrol protocol.
A single queued operation to be processed in loop().
std::string device_id
Target device ID (hex string, e.g., "123ABC").
PendingOperationType type
Operation type (determines which queue handler to invoke).
uint8_t position
Position/tilt value (0–100) or binary state (ON=0, OFF=100 for lights/switches).
Runtime state of a paired IO‑Homecontrol device.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).