|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Per-hub poll scheduling and failure-backoff policy. More...
#include <status_poll_policy.h>
Public Member Functions | |
| void | set_interval (const std::string &device_id, uint32_t interval_ms) |
| Set the configured follow-up poll interval (ms; 0 = legacy one-shot settle only). | |
| uint32_t | get_interval (const std::string &device_id) const |
| Return the configured interval (0 when not set or unconfigured). | |
| void | begin_tracking (const std::string &device_id, uint32_t initial_delay_ms, uint32_t now) |
| Begin bounded follow-up polling after a command or remote activity. | |
| void | clear (const std::string &device_id) |
| Stop all polling for a device and reset failure counts. Preserves interval_ms. | |
| MovingReportAction | on_moving_report (const std::string &device_id, uint32_t now, bool may_open) |
| Decide what a status report that reads as moving means for the follow-up window. | |
| void | on_trusted_report (const std::string &device_id, std::optional< uint16_t > remaining_s, uint32_t now) |
| Aim or re-aim the predicted-end read from a trusted status report of a moving device. | |
| uint32_t | frozen_count_delay_ms (const std::string &device_id) const |
| How long the next progress read waits when the device's remaining time has stopped falling. | |
| uint32_t | get_settle_update (const std::string &device_id) const |
| The planned predicted-end read's timestamp (0 = none). | |
| void | set_next_update (const std::string &device_id, uint32_t abs_time) |
| Schedule the next poll at an absolute millis() timestamp. | |
| uint32_t | get_next_update (const std::string &device_id) const |
| uint32_t | on_exchange_failed (const std::string &device_id, bool auth_like, uint32_t now, bool device_moving=false) |
| Record a failed background poll; apply backoff or clear tracking if the window expired. | |
| void | clear_failure_streaks (const std::string &device_id) |
| Reset failure streaks (and skipped moving misses) after a successful exchange response. | |
| uint8_t | get_status_poll_failures (const std::string &device_id) const |
| uint8_t | get_auth_poll_failures (const std::string &device_id) const |
| uint8_t | get_moving_poll_misses (const std::string &device_id) const |
| Consecutive failed polls of a moving device skipped so far. | |
| uint32_t | get_poll_deadline (const std::string &device_id) const |
| void | mark_stop_settle (const std::string &device_id) |
| Mark the device's next poll as the one reading where an accepted STOP left it, so it is a settling read (decisions::ReadKind::SETTLING). | |
| bool | take_stop_settle (const std::string &device_id) |
| Consume the mark set by mark_stop_settle(): true once, for the first poll dispatched after it. | |
| void | set_confirm_stopped (const std::string &device_id, bool needed) |
| Mark (or unmark) the device's next poll as the one confirming a stop off target, so it is a settling read too. | |
| bool | take_confirm_stopped (const std::string &device_id) |
| Consume the mark set by set_confirm_stopped(): true once, for the first poll dispatched after it. | |
| bool | is_predicted_end_read (const std::string &device_id) const |
| True when the next poll is the predicted-end read (the mark take_settling_read() consumes). | |
| bool | take_settling_read (const std::string &device_id) |
| Consume the marks (none short-circuits another) for the poll being dispatched. | |
| bool | is_tracking_active (const std::string &device_id, uint32_t now) const |
| True when the device has an active bounded polling window (deadline set and not expired). | |
| std::optional< std::string > | pop_due_device (uint32_t now) |
| Return and consume the first device with a poll overdue. | |
| ForeignAction | on_foreign_frame (const std::string &device_id, ForeignFrameKind kind, const std::string &controller, uint8_t cmd, uint32_t now, uint32_t last_status_ms) |
| Decide what an overheard frame of another controller means for this device. | |
| void | on_remote_poll_ran (const std::string &device_id) |
| The poll armed by foreign traffic ran (or was dropped): nothing is pending any more. | |
| bool | is_remote_poll_pending (const std::string &device_id, uint32_t now) const |
| True while a poll armed by foreign traffic is pending. | |
| std::optional< std::string > | pop_ended_device () |
| Return and consume a device whose polling window ended without the device being reported at rest: the window expired with a poll still pending (pop_due_device()), or the failure ladder no longer fits in it (on_exchange_failed()). | |
| void | on_linked_remote_activity () |
| A linked remote was heard: open a burst, or keep the open one. | |
| void | on_exchange_ended (uint32_t now, uint32_t delay_ms) |
An exchange ended at now. | |
| bool | take_due_catchup (uint32_t now) |
True once when the open burst's catch-up is due at now. | |
| void | mark_state_unknown (const std::string &device_id) |
| Mark the device's next status read as a catch-up read: a press the hub missed may have set it moving since its last report, so the read treats its state as unknown (decisions::AttemptRequest::with_state_unknown()). | |
| bool | take_state_unknown (const std::string &device_id) |
| Consume the mark set by mark_state_unknown(): true once, for the status read dispatched after it. | |
Per-hub poll scheduling and failure-backoff policy.
Maintains a PollTracking entry per device; all hub poll bookkeeping lives here and nowhere else. Callers inject 'now' timestamps so the class is fully testable without a hardware clock.
Definition at line 238 of file status_poll_policy.h.
| void esphome::home_io_control::StatusPollPolicy::begin_tracking | ( | const std::string & | device_id, |
| uint32_t | initial_delay_ms, | ||
| uint32_t | now ) |
Begin bounded follow-up polling after a command or remote activity.
Sets a deadline regardless of whether a configured interval exists; interval-0 devices use remaining-time or default settle delays computed at response time.
Definition at line 39 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::clear | ( | const std::string & | device_id | ) |
Stop all polling for a device and reset failure counts. Preserves interval_ms.
Definition at line 52 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::clear_failure_streaks | ( | const std::string & | device_id | ) |
Reset failure streaks (and skipped moving misses) after a successful exchange response.
Definition at line 201 of file status_poll_policy.cpp.
|
nodiscard |
How long the next progress read waits when the device's remaining time has stopped falling.
Zero while the count falls or none is known. From the PREDICTED_END_STALE_REPORTS-th report in a row whose count did not fall: FROZEN_COUNT_BACKOFF_FIRST_MS, then FROZEN_COUNT_BACKOFF_SECOND_MS, then FROZEN_COUNT_BACKOFF_MAX_MS for every further one. A caller whose own cadence is longer keeps it.
| device_id | Device whose last trusted report was passed to on_trusted_report(). |
Definition at line 113 of file status_poll_policy.cpp.
|
nodiscard |
Definition at line 262 of file status_poll_policy.cpp.
|
nodiscard |
Return the configured interval (0 when not set or unconfigured).
Definition at line 34 of file status_poll_policy.cpp.
|
nodiscard |
Consecutive failed polls of a moving device skipped so far.
Definition at line 267 of file status_poll_policy.cpp.
|
nodiscard |
Definition at line 136 of file status_poll_policy.cpp.
|
nodiscard |
Definition at line 141 of file status_poll_policy.cpp.
|
nodiscard |
The planned predicted-end read's timestamp (0 = none).
Definition at line 127 of file status_poll_policy.cpp.
|
nodiscard |
Definition at line 257 of file status_poll_policy.cpp.
|
nodiscard |
True when the next poll is the predicted-end read (the mark take_settling_read() consumes).
Definition at line 240 of file status_poll_policy.cpp.
|
nodiscard |
True while a poll armed by foreign traffic is pending.
A pending poll whose signal was lost expires by itself once now is more than REMOTE_ACTIVITY_STATUS_POLL_DELAY_MS past its due time.
Definition at line 277 of file status_poll_policy.cpp.
|
nodiscard |
True when the device has an active bounded polling window (deadline set and not expired).
Definition at line 146 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::mark_state_unknown | ( | const std::string & | device_id | ) |
Mark the device's next status read as a catch-up read: a press the hub missed may have set it moving since its last report, so the read treats its state as unknown (decisions::AttemptRequest::with_state_unknown()).
Needs no tracked device; begin_tracking() and clear() drop the mark, since heard activity or a report is news again.
Definition at line 388 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::mark_stop_settle | ( | const std::string & | device_id | ) |
Mark the device's next poll as the one reading where an accepted STOP left it, so it is a settling read (decisions::ReadKind::SETTLING).
Only a tracked device can be marked; begin_tracking() and clear() drop the mark, so a newer command or remote activity never inherits it.
Definition at line 210 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::on_exchange_ended | ( | uint32_t | now, |
| uint32_t | delay_ms ) |
An exchange ended at now.
While a burst is open its catch-up becomes due delay_ms after now, later or earlier than before; a delay_ms of 0 (the catch-up is switched off) closes the burst instead. No-op without an open burst.
Definition at line 377 of file status_poll_policy.cpp.
| uint32_t esphome::home_io_control::StatusPollPolicy::on_exchange_failed | ( | const std::string & | device_id, |
| bool | auth_like, | ||
| uint32_t | now, | ||
| bool | device_moving = false ) |
Record a failed background poll; apply backoff or clear tracking if the window expired.
When device_moving is true, no failure streak is running and fewer than MOVING_POLL_MISSES_SKIPPED misses in a row have been skipped, the miss is skipped instead: the next poll keeps the normal cadence (settle_delay_ms() without a remaining time, at most STATUS_RETRY_AFTER_FAIL_MS) and the failure streaks are left alone.
| device_id | Device whose poll failed. |
| auth_like | True when the failed exchange saw a 0x3C challenge. |
| now | Current millis(). |
| device_moving | True when a single-try poll of a device believed travelling failed. |
Definition at line 154 of file status_poll_policy.cpp.
| ForeignAction esphome::home_io_control::StatusPollPolicy::on_foreign_frame | ( | const std::string & | device_id, |
| ForeignFrameKind | kind, | ||
| const std::string & | controller, | ||
| uint8_t | cmd, | ||
| uint32_t | now, | ||
| uint32_t | last_status_ms ) |
Decide what an overheard frame of another controller means for this device.
Order: a pending foreign-armed poll answers first (PUSH_PENDING for any frame, timer pushed out); a request that writes ARMs; any other request ARMs only when neither last_status_ms nor the last read-triggered poll is younger than FOREIGN_READ_RESYNC_MS (0 = never, so the first read polls); a challenge is IGNOREd when the last request heard from the same controller was within FOREIGN_CHALLENGE_AFTER_REQUEST_MS and not a write, otherwise it ARMs. Every request updates the last-request record; a challenge does not. ARM and PUSH_PENDING set the pending due time; an ARM from a read stamps the read-poll time.
| device_id | Registered device the frame concerns. |
| kind | Request to the device, or the device's challenge to another controller. |
| controller | The other controller: the request's source, or the challenge's destination. |
| cmd | Command of the frame. |
| now | Current millis(). |
| last_status_ms | millis() of the device's last authenticated status; 0 = never. |
Definition at line 293 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::on_linked_remote_activity | ( | ) |
A linked remote was heard: open a burst, or keep the open one.
Only the exchanges that end while it is open set its due time (on_exchange_ended()), so a burst during which the hub never used the radio never comes due.
Definition at line 375 of file status_poll_policy.cpp.
| MovingReportAction esphome::home_io_control::StatusPollPolicy::on_moving_report | ( | const std::string & | device_id, |
| uint32_t | now, | ||
| bool | may_open ) |
Decide what a status report that reads as moving means for the follow-up window.
An open window is followed and its deadline stays: a later report never extends it. A window whose deadline has passed is closed and reported ended (see pop_ended_device()); the report that finds it expired does not reopen it, so a poll the hub scheduled itself cannot chain windows. Without a window, the report opens one at now when may_open allows it.
| device_id | Device the report belongs to. |
| now | Current millis(). |
| may_open | True when this kind of device may start tracking from a report alone. |
Definition at line 69 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::on_remote_poll_ran | ( | const std::string & | device_id | ) |
The poll armed by foreign traffic ran (or was dropped): nothing is pending any more.
Definition at line 287 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::on_trusted_report | ( | const std::string & | device_id, |
| std::optional< uint16_t > | remaining_s, | ||
| uint32_t | now ) |
Aim or re-aim the predicted-end read from a trusted status report of a moving device.
A remaining time, whatever its size (0 included), plans the read at now + remaining time + PREDICTED_END_MARGIN_MS, replacing an earlier aim; an aim past the end of the follow-up window is not planned. A count that did not fall since the last aimed report counts as stale; after PREDICTED_END_STALE_REPORTS in a row the read is given up and only progress reads remain (a falling count aims again). No count (remaining_s empty) drops the aim: a report that stopped, or a device that sends none. A report also withdraws a predicted-end read already popped but not yet sent, since it replaces the prediction that called for it.
The poll that confirms a stop off target is never predicted: its report passes no count, and its delay stays the default one (see decisions::classify_stopped_report()).
| device_id | Device the report belongs to; tracked devices only. |
| remaining_s | Usable remaining travel time in seconds, empty when there is none. |
| now | Current millis(). |
Definition at line 84 of file status_poll_policy.cpp.
|
nodiscard |
Return and consume the first device with a poll overdue.
A device's predicted-end read (on_trusted_report()) wins over its progress read: when it is due, the device is returned with its predicted-end mark set (take_settling_read()) and a progress read due too is dropped. A progress read due while the predicted-end read follows within PREDICTED_END_DROPS_PROGRESS_WITHIN_MS is dropped as well; the predicted-end read stays planned. Clears expired tracking entries as a side effect. Returns nullopt if nothing is due.
Definition at line 336 of file status_poll_policy.cpp.
|
nodiscard |
Return and consume a device whose polling window ended without the device being reported at rest: the window expired with a poll still pending (pop_due_device()), or the failure ladder no longer fits in it (on_exchange_failed()).
An explicit clear() — a stopped report, a failed build — is not "ran out" and is never returned. Returns nullopt when there is none.
Definition at line 367 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::set_confirm_stopped | ( | const std::string & | device_id, |
| bool | needed ) |
Mark (or unmark) the device's next poll as the one confirming a stop off target, so it is a settling read too.
Every trusted status report sets it from its own verdict, so a report that no longer needs confirming (moving again, or at rest) drops a mark an earlier one left. Only a tracked device can be marked; begin_tracking() and clear() drop the mark as for the STOP mark.
| device_id | Device whose next poll is meant. |
| needed | True when the latest report stopped off target for the first time. |
Definition at line 225 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::set_interval | ( | const std::string & | device_id, |
| uint32_t | interval_ms ) |
Set the configured follow-up poll interval (ms; 0 = legacy one-shot settle only).
Definition at line 30 of file status_poll_policy.cpp.
| void esphome::home_io_control::StatusPollPolicy::set_next_update | ( | const std::string & | device_id, |
| uint32_t | abs_time ) |
Schedule the next poll at an absolute millis() timestamp.
Definition at line 132 of file status_poll_policy.cpp.
|
nodiscard |
Consume the mark set by set_confirm_stopped(): true once, for the first poll dispatched after it.
Definition at line 231 of file status_poll_policy.cpp.
|
nodiscard |
True once when the open burst's catch-up is due at now.
The burst is closed first, so the catch-up's own reads, which are exchanges too, do not reopen it. Wrap-safe across a millis() rollover.
Definition at line 392 of file status_poll_policy.cpp.
|
nodiscard |
Consume the marks (none short-circuits another) for the poll being dispatched.
Definition at line 245 of file status_poll_policy.cpp.
|
nodiscard |
Consume the mark set by mark_state_unknown(): true once, for the status read dispatched after it.
Definition at line 390 of file status_poll_policy.cpp.
|
nodiscard |
Consume the mark set by mark_stop_settle(): true once, for the first poll dispatched after it.
Definition at line 216 of file status_poll_policy.cpp.