171[[nodiscard]]
inline uint32_t
settle_delay_ms(uint32_t interval_ms, uint32_t remaining_delay_ms,
bool cap_for_stop) {
173 if (remaining_delay_ms != 0)
174 delay = std::min(delay, remaining_delay_ms);
242 void set_interval(
const std::string &device_id, uint32_t interval_ms);
244 [[nodiscard]] uint32_t
get_interval(
const std::string &device_id)
const;
250 void begin_tracking(
const std::string &device_id, uint32_t initial_delay_ms, uint32_t now);
252 void clear(
const std::string &device_id);
279 void on_trusted_report(
const std::string &device_id, std::optional<uint16_t> remaining_s, uint32_t now);
293 [[nodiscard]] uint32_t
get_next_update(
const std::string &device_id)
const;
307 uint32_t
on_exchange_failed(
const std::string &device_id,
bool auth_like, uint32_t now,
bool device_moving =
false);
342 [[nodiscard]]
bool is_tracking_active(
const std::string &device_id, uint32_t now)
const;
352 [[nodiscard]] std::optional<std::string>
pop_due_device(uint32_t now);
371 uint8_t cmd, uint32_t now, uint32_t last_status_ms);
406 std::map<std::string, PollTracking> tracking_;
407 bool catchup_burst_open_{
false};
408 uint32_t catchup_due_ms_{0};
409 std::set<std::string> state_unknown_;
410 std::map<std::string, ForeignTraffic> foreign_;
411 std::vector<std::string> ended_;
414 void note_ended_(
const std::string &device_id);
417 static uint32_t retry_delay_ms(uint8_t consecutive_failures,
bool auth_like);
Per-hub poll scheduling and failure-backoff policy.
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 re...
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.
bool take_settling_read(const std::string &device_id)
Consume the marks (none short-circuits another) for the poll being dispatched.
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_exchange_ended(uint32_t now, uint32_t delay_ms)
An exchange ended at now.
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.
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).
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 ...
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).
uint32_t get_next_update(const std::string &device_id) const
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.
uint32_t get_interval(const std::string &device_id) const
Return the configured interval (0 when not set or unconfigured).
void clear_failure_streaks(const std::string &device_id)
Reset failure streaks (and skipped moving misses) after a successful exchange response.
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.
void on_linked_remote_activity()
A linked remote was heard: open a burst, or keep the open one.
void set_next_update(const std::string &device_id, uint32_t abs_time)
Schedule the next poll at an absolute millis() timestamp.
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.
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.
uint8_t get_moving_poll_misses(const std::string &device_id) const
Consecutive failed polls of a moving device skipped so far.
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.
uint8_t get_status_poll_failures(const std::string &device_id) const
bool take_due_catchup(uint32_t now)
True once when the open burst's catch-up is due at now.
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.
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 ...
uint8_t get_auth_poll_failures(const std::string &device_id) const
uint32_t get_poll_deadline(const std::string &device_id) const
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.
std::optional< std::string > pop_ended_device()
Return and consume a device whose polling window ended without the device being reported at rest: the...
void clear(const std::string &device_id)
Stop all polling for a device and reset failure counts. Preserves interval_ms.
bool is_remote_poll_pending(const std::string &device_id, uint32_t now) const
True while a poll armed by foreign traffic is pending.
uint32_t get_settle_update(const std::string &device_id) const
The planned predicted-end read's timestamp (0 = none).
std::optional< std::string > pop_due_device(uint32_t now)
Return and consume the first device with a poll overdue.
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).
@ OPEN
Position 0 (fully open).
static constexpr uint32_t STATUS_RETRY_AFTER_FAIL_STEP4_MS
Fourth retry after a silent failure.
static constexpr uint32_t ONEWAY_QUIET_PERIOD_MS
Hold queued background polls back for this long after any 1W frame, so a poll the hub itself schedule...
static constexpr uint32_t FOREIGN_READ_RESYNC_MS
How long a device's authenticated status or this hub's own read-triggered poll keeps a further overhe...
static constexpr uint32_t FOREIGN_CHALLENGE_AFTER_REQUEST_MS
A device challenges a request 2.5-3.3 ms after it; 100 ms is far above that and far below the next re...
ForeignFrameKind
What an overheard frame of another controller is.
@ REQUEST_TO_DEVICE
Another controller's command to a registered device.
@ DEVICE_CHALLENGE_TO_OTHER
A registered device's challenge (0x3C) addressed to another controller.
static constexpr uint32_t STATUS_AUTH_RETRY_AFTER_FAIL_MAX_MS
Steady-state after repeated auth failures.
static constexpr uint32_t ONEWAY_POLL_DEFER_CAP_MS
Hard cap on how long sustained 1W traffic may hold a background poll back in total,...
static constexpr uint32_t DEFAULT_SETTLE_POLL_DELAY_MS
Default follow-up settle-poll delay used while a device may still be moving, when no explicit poll in...
static constexpr uint32_t PREDICTED_END_MARGIN_MS
static constexpr uint32_t STATUS_RETRY_AFTER_FAIL_STEP3_MS
Third retry after a silent failure.
static constexpr uint32_t FROZEN_COUNT_BACKOFF_FIRST_MS
Delay after the first frozen report.
static constexpr uint32_t FROZEN_COUNT_BACKOFF_SECOND_MS
Delay after the second.
static constexpr uint32_t MAX_TRACKED_STATUS_POLL_WINDOW_MS
Hard stop for bounded follow-up polling after a command, remote activity or the first moving report,...
static constexpr uint32_t PREDICTED_END_DROPS_PROGRESS_WITHIN_MS
A progress read due within this long before the predicted-end read is dropped: the settling read foll...
static constexpr uint32_t HEATING_POST_WRITE_POLL_DELAY_MS
Delay of the extra heater poll after a register write the heater acknowledged.
static constexpr uint8_t PREDICTED_END_STALE_REPORTS
Reports in a row whose remaining time did not fall below the previous one before the count is taken a...
static constexpr uint32_t STATUS_RETRY_AFTER_FAIL_MS
First retry after a silent failure.
static constexpr uint32_t STATUS_RETRY_AFTER_FAIL_MAX_MS
Steady-state backoff after many silent failures.
static constexpr uint32_t FROZEN_COUNT_BACKOFF_MAX_MS
Delay after the third and every later one.
static constexpr uint32_t STATUS_AUTH_RETRY_AFTER_FAIL_STEP3_MS
Third retry.
uint32_t settle_delay_ms(uint32_t interval_ms, uint32_t remaining_delay_ms, bool cap_for_stop)
Resolve the follow-up settle-poll delay while a device may still be moving.
static constexpr uint32_t INITIAL_STATUS_REQUEST_DELAY_MS
Delay before the first post-boot status request from an entity.
static constexpr uint32_t STATUS_AUTH_RETRY_AFTER_FAIL_STEP2_MS
Second retry.
static constexpr uint32_t STATUS_AUTH_RETRY_AFTER_FAIL_MS
First retry after a challenge-seen failure.
static constexpr uint32_t STOP_SETTLE_POLL_CAP_MS
Upper bound on the settle-poll delay after a STOP command.
MovingReportAction
What the hub does with a status report that reads as moving.
@ FOLLOW
A window is open: schedule the next poll as usual.
@ END
The window ran out: it is closed and reported ended; no further poll.
static constexpr uint8_t MOVING_POLL_MISSES_SKIPPED
Consecutive failed polls of a moving device that are skipped rather than backed off.
static constexpr uint32_t STATUS_RETRY_AFTER_FAIL_STEP2_MS
Second retry after a silent failure.
static constexpr uint32_t HEATING_POLL_DEFAULT_INTERVAL_MS
Interval between regular polls of a heater (its status_poll_interval overrides it).
ForeignAction
What the hub does about an overheard foreign frame.
@ PUSH_PENDING
A poll armed by foreign traffic is pending: move its timer out, change nothing else.
@ ARM
Schedule a poll REMOTE_ACTIVITY_STATUS_POLL_DELAY_MS from now and begin tracking.
Physical-layer radio and timing parameters for the IO-Homecontrol protocol.
Per-device bookkeeping of overheard foreign traffic.
std::string last_request_from
Controller that sent it (frame source); empty = none heard.
uint32_t last_request_ms
When it was heard; 0 = never.
uint32_t pending_due_ms
When the armed poll is due; 0 = none pending.
uint8_t last_request_cmd
Command of the last request heard to this device.
uint32_t last_read_poll_ms
When a read last armed a poll; 0 = never.
Per-device poll scheduling state.
uint8_t auth_poll_failures
Consecutive background poll failures that saw a 0x3C challenge.
uint32_t settle_update
Absolute millis() timestamp of the predicted-end read; 0 = none planned.
bool confirm_stopped
The next poll confirms a stop off target (a settling read, see decisions::StoppedReport::SETTLING).
bool stop_settle
The next poll reads where an accepted STOP left the device (a settling read).
uint8_t status_poll_failures
Consecutive background poll failures (silent — no reply).
uint32_t poll_deadline
Hard stop for bounded follow-up polling.
uint8_t stale_reports
Reports in a row whose remaining time did not fall.
bool predicted_end_read
The next poll is the predicted-end read (a settling read).
std::optional< uint16_t > last_remaining_s
Remaining time of the last report that was aimed at (> 2 s).
uint32_t interval_ms
Configured follow-up poll interval (0 = no configured cadence; delays fall back to remaining time / d...
uint8_t moving_poll_misses
Consecutive failed polls of a moving device skipped so far (see MOVING_POLL_MISSES_SKIPPED); not coun...
uint32_t next_update
Absolute millis() timestamp for the next poll; 0 = idle.