Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
rain_poll_policy.cpp
Go to the documentation of this file.
1/// @file rain_poll_policy.cpp
2/// @brief Rain sensor poll schedule implementation.
3/// @ingroup hioc_hub
4
5#include "rain_poll_policy.h"
6
7#include <algorithm>
8
9namespace esphome {
10namespace home_io_control {
11
12namespace {
13
14/// True when @p deadline has been reached at @p now, correct across the millis() rollover.
15bool reached(uint32_t now, uint32_t deadline) { return static_cast<int32_t>(now - deadline) >= 0; }
16
17} // namespace
18
19void RainPollPolicy::set_interval(const std::string &device_id, uint32_t interval_ms, uint32_t now, uint32_t random) {
20 if (interval_ms == 0) {
21 entries_.erase(device_id);
22 return;
23 }
24 Entry &e = entries_[device_id];
25 e.interval_ms = interval_ms;
26 e.next_poll = now + rain_poll_first_delay_ms(random);
27 e.failures = 0;
28}
29
30uint32_t RainPollPolicy::get_interval(const std::string &device_id) const {
31 const auto it = entries_.find(device_id);
32 return it != entries_.end() ? it->second.interval_ms : 0;
33}
34
35bool RainPollPolicy::has_due(uint32_t now) const {
36 return std::any_of(entries_.begin(), entries_.end(),
37 [now](const auto &entry) { return reached(now, entry.second.next_poll); });
38}
39
40std::optional<std::string> RainPollPolicy::pop_due_device(uint32_t now, uint32_t random) {
41 for (auto &[device_id, e] : entries_) {
42 if (!reached(now, e.next_poll))
43 continue;
44 e.next_poll = now + rain_poll_jittered_interval_ms(e.interval_ms, random);
45 return device_id;
46 }
47 return std::nullopt;
48}
49
50void RainPollPolicy::defer(const std::string &device_id, uint32_t delay_ms, uint32_t now) {
51 const auto it = entries_.find(device_id);
52 if (it == entries_.end())
53 return;
54 const uint32_t retry_at = now + delay_ms;
55 if (reached(it->second.next_poll, retry_at)) // next_poll is at or after retry_at: pull it earlier
56 it->second.next_poll = retry_at;
57}
58
59bool RainPollPolicy::on_poll_failed(const std::string &device_id) {
60 const auto it = entries_.find(device_id);
61 if (it == entries_.end())
62 return false;
63 if (it->second.failures < UINT8_MAX)
64 it->second.failures++;
65 return it->second.failures >= RAIN_POLL_FAILURES_BEFORE_UNKNOWN;
66}
67
68void RainPollPolicy::on_poll_succeeded(const std::string &device_id) {
69 const auto it = entries_.find(device_id);
70 if (it != entries_.end())
71 it->second.failures = 0;
72}
73
74bool RainPollPolicy::first_error_reply(const std::string &device_id) {
75 const auto it = entries_.find(device_id);
76 if (it == entries_.end() || it->second.error_reported)
77 return false;
78 it->second.error_reported = true;
79 return true;
80}
81
82uint8_t RainPollPolicy::get_failures(const std::string &device_id) const {
83 const auto it = entries_.find(device_id);
84 return it != entries_.end() ? it->second.failures : 0;
85}
86
87uint32_t RainPollPolicy::get_next_poll(const std::string &device_id) const {
88 const auto it = entries_.find(device_id);
89 return it != entries_.end() ? it->second.next_poll : 0;
90}
91
92} // namespace home_io_control
93} // namespace esphome
uint8_t get_failures(const std::string &device_id) const
Consecutive unanswered polls (0 for an unscheduled device).
bool has_due(uint32_t now) const
True when any device's poll is due at now.
void set_interval(const std::string &device_id, uint32_t interval_ms, uint32_t now, uint32_t random)
Set the poll interval and schedule the first poll at rain_poll_first_delay_ms(random) after now.
std::optional< std::string > pop_due_device(uint32_t now, uint32_t random)
Return one device whose poll is due and immediately schedule its next poll at rain_poll_jittered_inte...
uint32_t get_interval(const std::string &device_id) const
Return the configured interval (0 when the device is not scheduled).
void defer(const std::string &device_id, uint32_t delay_ms, uint32_t now)
Pull the device's next poll forward to delay_ms after now. Never pushes it later.
bool first_error_reply(const std::string &device_id)
True the first time it is called for a device that answered the limitation read with an error reply,...
void on_poll_succeeded(const std::string &device_id)
Clear the unanswered-poll count.
bool on_poll_failed(const std::string &device_id)
Count one unanswered poll (saturating).
uint32_t get_next_poll(const std::string &device_id) const
Absolute millis() time of the device's next poll (0 for an unscheduled device).
uint32_t rain_poll_first_delay_ms(uint32_t random)
Delay of a device's first poll after its interval is set.
uint32_t rain_poll_jittered_interval_ms(uint32_t interval_ms, uint32_t random)
One poll interval moved by a uniform offset of up to RAIN_POLL_JITTER_PERCENT either way.
Schedule and failure bookkeeping for the opt-in rain sensor poll.