|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Classes | |
| struct | OneWayDedupState |
| Key fields of the last processed 1W frame, used to collapse a remote's repeat burst. More... | |
| struct | TargetEvidence |
| What the hub knows about the device an exchange is addressed to, as the exchange engine sees it. More... | |
| struct | RainLimitationInput |
| What one decoded status reply said, plus what the hub had predicted. More... | |
Enumerations | |
| enum class | ExchangeFirstResponseDisposition : uint8_t { IGNORE_UNRELATED , COMPLETE_DIRECT , REQUIRE_AUTH } |
| Disposition for the first response in an authenticated exchange. More... | |
| enum class | ExchangeFinalResponseDisposition : uint8_t { IGNORE_UNRELATED , ACCEPT } |
| Disposition for the final response after authentication. More... | |
| enum class | PairingDiscoveryDisposition : uint8_t { NO_RESPONSE , INVALID , ACCEPT } |
| Disposition during pairing discovery phase. More... | |
| enum class | PairingKeyChallengeDisposition : uint8_t { IGNORE , ACCEPT } |
| Disposition during pairing key-challenge phase. More... | |
| enum class | PairingDiscoverConfirmDisposition : uint8_t { IGNORE , ACK , ERROR } |
| Disposition for a candidate reply to a discovery-confirm request (0x2C). More... | |
| enum class | PairingKeyConfirmDisposition : uint8_t { IGNORE , CONFIRM , CHALLENGE , REFUSE } |
| Disposition for a candidate reply to the key-transfer (0x32) confirm wait — the slow-turnaround path's expanded classification of PairingKeyChallengeDisposition's device challenge to also cover a direct confirm or an explicit refusal. More... | |
| enum class | WakeBelief : uint8_t { ASLEEP , AWAKE } |
| Whether a low-power receiver is believed to be travelling right now, judged from what this hub has seen of it. More... | |
| enum class | RainLimitationRule : uint8_t { NONE = 0 , RAIN_ORIGINATOR , CLAMPED_COMMAND } |
| Which evidence path labelled a device as limited by rain. More... | |
Functions | |
| bool | is_exchange_internal_command (uint8_t cmd) |
| Returns true for commands that are internal to an exchange handshake and carry no useful information for a passive observer (challenge request/response). | |
| bool | frame_matches_nodes (const IoFrame &frame, const uint8_t expected_src[NODE_ID_SIZE], const uint8_t expected_dst[NODE_ID_SIZE]) |
| Check if two frames have identical src/dst node IDs. | |
| bool | frame_matches_exchange_endpoints (const IoFrame &request, const IoFrame &candidate) |
| Check if candidate frame endpoints are the reverse of the request (dst==request.src, src==request.dst). | |
| ExchangeFirstResponseDisposition | classify_exchange_first_response (const IoFrame &request, const IoFrame &candidate) |
| Decide how to handle the first response packet in an authenticated exchange. | |
| ExchangeFinalResponseDisposition | classify_exchange_final_response (const IoFrame &request, const IoFrame &candidate) |
| Decide if a candidate frame is an acceptable final response after authentication. | |
| bool | is_repeatable_execute (const IoFrame &request) |
| True for a CMD_EXECUTE that has the same effect sent twice as sent once. | |
| bool | retry_after_unconfirmed_accept_is_safe (const IoFrame &request, bool target_confirms_execute, uint8_t unconfirmed_tries) |
| Whether an authenticated-but-unanswered request may be sent again. | |
| PairingDiscoveryDisposition | classify_pairing_discovery_response (const IoFrame &candidate, const uint8_t controller_id[NODE_ID_SIZE]) |
| Decide if a frame is a valid discovery response (0x29) during pairing. | |
| PairingKeyChallengeDisposition | classify_pairing_key_challenge (const IoFrame &candidate, const uint8_t device_id[NODE_ID_SIZE], const uint8_t controller_id[NODE_ID_SIZE]) |
| Decide if a frame is a valid key-challenge (0x3C) during pairing key exchange. | |
| PairingDiscoverConfirmDisposition | classify_pairing_discover_confirm_reply (const IoFrame &candidate, const uint8_t device_id[NODE_ID_SIZE], const uint8_t controller_id[NODE_ID_SIZE]) |
| Decide how to handle a candidate reply to a discovery-confirm request (0x2C) during pairing. | |
| PairingKeyConfirmDisposition | classify_pairing_key_confirm_reply (const IoFrame &request, const IoFrame &candidate) |
| Decide how to handle a candidate reply to the key-transfer (0x32) confirm wait (wait_for_key_confirm_(), slow-turnaround chips only). | |
| bool | discover_confirm_try_rotates (uint8_t try_index) |
| Whether discover-confirm try try_index (1-based) should rotate channels rather than hold the request channel. | |
| bool | is_duplicate_1w_frame (const OneWayDedupState &last, const OneWayDedupState &incoming, uint32_t window_ms) |
| Decide whether an incoming 1W frame repeats the previous one inside the burst window. | |
| bool | defer_background_poll_for_1w_activity (bool next_op_is_background, uint32_t first_1w_activity_ms, uint32_t last_1w_activity_ms, uint32_t now, uint32_t quiet_ms, uint32_t max_defer_ms) |
| Decide whether to hold back a queued background poll because a 1W remote is still transmitting. | |
| uint8_t | scheduled_poll_max_tries (uint8_t status_poll_failures, uint8_t auth_poll_failures, bool settles_a_stop=false) |
| Transmit-attempt budget for a scheduler-owned status poll, by backoff-ladder position. | |
| TargetEvidence | target_evidence (const IoDevice &dev) |
| Build the exchange engine's view of a device record. | |
| bool | is_stop_request (const IoFrame &request) |
| True for a CMD_EXECUTE whose main byte is POS_STOP. | |
| WakeBelief | wake_belief (const TargetEvidence &evidence, uint32_t now, bool is_stop) |
| Judge whether a low-power receiver is travelling. | |
| uint16_t | low_power_try_preamble (WakeBelief belief, uint8_t try_index, uint16_t short_preamble, uint16_t wake_preamble) |
| Start-preamble length for one try of a directed exchange to a low-power receiver. | |
| const char * | wake_belief_name (WakeBelief belief) |
| Lowercase name of a belief for log lines. | |
| bool | is_one_way_pairing_gesture (bool oneway, const uint8_t dst[NODE_ID_SIZE], uint8_t cmd) |
| True if a frame's shape matches a 1W remote's pairing gesture (issue #27/#65): CTRL0 1W bit set, addressed to the 1W broadcast address (0x00003F), with one of the three command bytes observed in the field capture — 0x20 (WRITE_PRIVATE), 0x39 (1W remove), or 0x2E (alternate discovery, 1W-flagged). | |
| bool | oneway_burst_started_fresh (uint32_t last_1w_activity_ms, uint32_t now, uint32_t quiet_ms) |
| Whether a 1W frame arriving at now starts a new burst rather than extending the current one — true if no frame has been seen yet, or the gap since the last one reached quiet_ms (the previous burst already released any deferred poll). | |
| uint32_t | remote_poll_timer_id (const uint8_t node_id[NODE_ID_SIZE]) |
| Numeric set_timeout() id for a device's remote-activity poll timer (hub_status.cpp's schedule_status_poll_()). | |
| uint32_t | heating_poll_timer_id (const uint8_t node_id[NODE_ID_SIZE]) |
| Numeric set_timeout() id for a heater's regular-cadence poll timer (IOHomeControlComponent::schedule_heating_poll_()). | |
| bool | pairing_node_has_heater_at_next_address (DeviceType type, uint8_t manufacturer) |
| Does a pairing node that answered discovery this way control a heater at the next address? | |
| bool | next_node_id (const uint8_t node[NODE_ID_SIZE], uint8_t next[NODE_ID_SIZE]) |
| The node address one above node, as a 24-bit number (B6BDFB -> B6BDFC). | |
| RainLimitationRule | rain_limitation_rule (const RainLimitationInput &in) |
| Decide which rain-limitation evidence, if any, a status reply provides. | |
| bool | is_rain_limited (const RainLimitationInput &in) |
| True when rain_limitation_rule() finds evidence of a rain limitation. | |
| const char * | rain_limitation_rule_name (RainLimitationRule rule) |
| Name of a rain-limitation rule for log lines. | |
| RainSensorState | rain_state_from_minimum_limit (uint16_t value_raw) |
| Rain state from the raw value of a minimum-limitation reply. | |
| RainSensorState | rain_state_from_limitation_reply (const LimitationStatus &status) |
| Rain state from a decoded limitation reply: the one place that knows which reply fields decide. | |
Variables | |
| constexpr uint32_t | REMOTE_POLL_TIMER_ID_TAG = 0x01000000 |
| Namespace tag for remote_poll_timer_id() below: the node address occupies the low 24 bits, and this is OR-ed in above them. | |
| constexpr uint32_t | HEATING_POLL_TIMER_ID_TAG = 0x02000000 |
| Namespace tag for heating_poll_timer_id(): the same node-address scheme under its own bit, so a heater's regular-cadence timer and a remote-activity poll timer for the same device never replace one another. | |
| static constexpr uint8_t | RAIN_MINIMUM_LIMIT_PERCENT = 89 |
| A window with a wired rain sensor limits its own opening while it rains. | |
| static constexpr uint16_t | POSITION_FULL_PERCENT = 100 |
| Percent value of a fully limited position, the divisor of the raw position coding. | |
| static constexpr uint16_t | POSITION_RAW_PER_PERCENT = STATUS_POS_MAX / POSITION_FULL_PERCENT |
| Raw position units per percent (512). | |
| static constexpr uint16_t | RAIN_MINIMUM_LIMIT_RAW = POSITION_RAW_PER_PERCENT * RAIN_MINIMUM_LIMIT_PERCENT |
| RAIN_MINIMUM_LIMIT_PERCENT in the raw position coding (0xB200). | |
|
strong |
Disposition for the final response after authentication.
| Enumerator | |
|---|---|
| IGNORE_UNRELATED | Frame doesn't match endpoints — ignore. |
| ACCEPT | Frame matches expected response — exchange succeeds. |
Definition at line 34 of file hub_decisions.h.
|
strong |
Disposition for the first response in an authenticated exchange.
Definition at line 27 of file hub_decisions.h.
|
strong |
Disposition for a candidate reply to a discovery-confirm request (0x2C).
Definition at line 53 of file hub_decisions.h.
|
strong |
Disposition during pairing discovery phase.
| Enumerator | |
|---|---|
| NO_RESPONSE | No packets received on the channel within timeout. |
| INVALID | Packets seen but none were valid discovery (0x29) frames. |
| ACCEPT | Valid discovery response received. |
Definition at line 40 of file hub_decisions.h.
|
strong |
Disposition during pairing key-challenge phase.
| Enumerator | |
|---|---|
| IGNORE | Not a valid challenge (wrong cmd, length, or sender). |
| ACCEPT | Valid 0x3C challenge from target device. |
Definition at line 47 of file hub_decisions.h.
|
strong |
Disposition for a candidate reply to the key-transfer (0x32) confirm wait — the slow-turnaround path's expanded classification of PairingKeyChallengeDisposition's device challenge to also cover a direct confirm or an explicit refusal.
| Enumerator | |
|---|---|
| IGNORE | Not from/to the expected endpoints — keep waiting. |
| CONFIRM | CMD_KEY_CONFIRM (0x33) — the device accepted the key. |
| CHALLENGE | A fresh CMD_CHALLENGE_REQ (0x3C) — the device may challenge the key transfer before confirming it; answered via ExchangeEngine::answer_challenge(). |
| REFUSE | Anything else (including CMD_ERROR_RESP) — an explicit or implicit refusal; ends the whole wait, not just the current try. |
Definition at line 63 of file hub_decisions.h.
|
strong |
Which evidence path labelled a device as limited by rain.
Definition at line 575 of file hub_decisions.h.
|
strong |
Whether a low-power receiver is believed to be travelling right now, judged from what this hub has seen of it.
Orders the tries of a directed exchange: a moving receiver hears the short start preamble and ignores the long wake-up one, a resting one needs the long one.
Having merely heard from the device recently is deliberately not a reason to lead short: a resting VELUX SSL solar roller shutter ignored the short preamble on every try in field logs, including tries sent 34 ms after it had answered (ADR 0040, amendment).
| Enumerator | |
|---|---|
| ASLEEP | Not known to be moving — lead with the wake-up preamble. |
| AWAKE | Moving, or about to be stopped — the short preamble is the one it hears. |
Definition at line 391 of file hub_decisions.h.
|
inline |
Decide if a candidate frame is an acceptable final response after authentication.
Only endpoint matching is checked here; command validity is encoded in the disposition mapping by the caller.
| request | Original outbound request frame. |
| candidate | Parsed IoFrame from the device. |
Definition at line 125 of file hub_decisions.h.
|
inline |
Decide how to handle the first response packet in an authenticated exchange.
Used by wait_for_first_response_() to determine whether the exchange:
| request | Original outbound request frame. |
| candidate | Parsed IoFrame from the device. |
Definition at line 106 of file hub_decisions.h.
|
inline |
Decide how to handle a candidate reply to a discovery-confirm request (0x2C) during pairing.
A non-matching or unrecognised frame is IGNORE, keeping the listen open rather than ending it: the discover-confirm step never fails a pairing attempt (see run_discover_confirm_step_()'s doc) — this classification only decides whether to keep listening or stop early.
| candidate | Parsed IoFrame. |
| device_id | Node ID of the device being paired (expected sender). |
| controller_id | Node ID of this controller (expected destination). |
Definition at line 224 of file hub_decisions.h.
|
inline |
Decide if a frame is a valid discovery response (0x29) during pairing.
Only the destination is checked, not the source: the discovery request goes out to a shared broadcast address, so a response arriving during the same window may be a device answering a different controller's concurrent discovery rather than ours — real hardware addresses its response back to the requesting controller's own node ID, so checking that is both possible and sufficient to reject it. The source can't be checked here — the device's node ID is exactly what discovery exists to learn, so there is nothing yet to compare it to.
| candidate | Parsed IoFrame. |
| controller_id | Node ID of this controller (expected destination). |
Definition at line 183 of file hub_decisions.h.
|
inline |
Decide if a frame is a valid key-challenge (0x3C) during pairing key exchange.
The challenge must:
| candidate | Parsed IoFrame. |
| device_id | Node ID of the device being paired (expected sender). |
| controller_id | Node ID of this controller (expected destination). |
Definition at line 202 of file hub_decisions.h.
|
inline |
Decide how to handle a candidate reply to the key-transfer (0x32) confirm wait (wait_for_key_confirm_(), slow-turnaround chips only).
| request | The outbound CMD_KEY_TRANSFER (0x32) this reply answers. |
| candidate | Parsed IoFrame from the device. |
Definition at line 244 of file hub_decisions.h.
|
inline |
Decide whether to hold back a queued background poll because a 1W remote is still transmitting.
The radio is half-duplex and an authenticated exchange blocks for 1–3 s, during which no frame can be received at all. A press on a linked remote schedules a status poll, so without this gate the hub's own poll can start on top of the burst that triggered it and go deaf to the rest of it.
Only background polls are deferred. A user command must never wait on a remote the user may not even own — 1W broadcasts carry no ownership marker, so the activity could be a neighbour's.
The hold re-arms on every 1W frame received while it is already active, so a real burst from one remote (~160 ms, well under quiet_ms) never gets cut short mid-transmission. Left unchecked that re-arming has no cap: sustained sub-quiet_ms 1W traffic from any source — including a neighbour's, since these broadcasts carry no ownership marker — would hold background polls back indefinitely. max_defer_ms bounds that: once that much time has passed since the burst started (not the most recent frame), the poll is let through regardless of ongoing traffic. The gate only ever delays a poll, never drops one — it stays queued and fires as soon as it is no longer deferred.
| next_op_is_background | True if the queue front is a background poll (OperationQueue::is_background_op()). |
| first_1w_activity_ms | millis() of the first frame in the current 1W burst; 0 if none seen since boot. |
| last_1w_activity_ms | millis() of the most recent 1W frame; 0 if none seen since boot. |
| now | Current millis(). |
| quiet_ms | How long after 1W activity to hold background polls back. |
| max_defer_ms | Hard cap on total defer time, measured from first_1w_activity_ms. |
Definition at line 342 of file hub_decisions.h.
|
inlinenodiscard |
Whether discover-confirm try try_index (1-based) should rotate channels rather than hold the request channel.
Tries 1 and 3 hold: a 0x2D is a unicast reply to a unicast 0x2C, and every other unicast pairing wait in this project holds the request channel on that same expectation (see listen_for_key_confirm_()'s own reasoning), and every 0x2D a Somfy Izymo dimmer sent came back on the request channel. But the one real VELUX-system sample on record (from a hopping monitor, a weak source) logged a 0x2D on a different channel than its own 0x2C, so the middle try hedges by rotating instead, until a VELUX device's reply channel is measured. See ADR 0039 for why this is not simply one fixed policy for every try, unlike every other listen in this project (ADR 0028).
| try_index | 1-based try number (1..PAIRING_DISCOVER_CONFIRM_TRIES). |
Definition at line 269 of file hub_decisions.h.
|
inline |
Check if candidate frame endpoints are the reverse of the request (dst==request.src, src==request.dst).
Definition at line 90 of file hub_decisions.h.
|
inline |
Check if two frames have identical src/dst node IDs.
Definition at line 83 of file hub_decisions.h.
|
inline |
Numeric set_timeout() id for a heater's regular-cadence poll timer (IOHomeControlComponent::schedule_heating_poll_()).
Same keying as remote_poll_timer_id(), in the HEATING_POLL_TIMER_ID_TAG namespace, so a poll that a linked remote triggers cannot cancel it.
| node_id | 3-byte device node address. |
Definition at line 532 of file hub_decisions.h.
|
inline |
Decide whether an incoming 1W frame repeats the previous one inside the burst window.
| last | State recorded for the previously processed 1W frame. |
| incoming | Candidate frame's key fields, with timestamp set to now. |
| window_ms | Burst-suppression window. |
Definition at line 304 of file hub_decisions.h.
|
inline |
Returns true for commands that are internal to an exchange handshake and carry no useful information for a passive observer (challenge request/response).
These frames appear in every authenticated exchange between other controllers and devices on the network, but contain only ephemeral cryptographic data.
Definition at line 78 of file hub_decisions.h.
|
inline |
True if a frame's shape matches a 1W remote's pairing gesture (issue #27/#65): CTRL0 1W bit set, addressed to the 1W broadcast address (0x00003F), with one of the three command bytes observed in the field capture — 0x20 (WRITE_PRIVATE), 0x39 (1W remove), or 0x2E (alternate discovery, 1W-flagged).
Shared between PairingAdvisor (classifying recorded telemetry events, pairing_advisor.cpp) and the hub's normal passive RX path (hub_status.cpp), which remembers a recent sighting so a PROG press completed just before "Discover & Pair" is pressed isn't invisible to the advisor purely because of when the discovery telemetry window happened to open — see PairingTelemetry::record_recent_one_way_sighting().
| oneway | CTRL0 1W-protocol bit. |
| dst | Frame destination node ID. |
| cmd | Frame command byte. |
Definition at line 478 of file hub_decisions.h.
|
inlinenodiscard |
True when rain_limitation_rule() finds evidence of a rain limitation.
Definition at line 611 of file hub_decisions.h.
|
inlinenodiscard |
True for a CMD_EXECUTE that has the same effect sent twice as sent once.
Every EXECUTE this hub sends names an absolute target (a position, open/close, STOP, a tilt angle, a light level) except the stored-position selector POS_FAVORITE, used by favourite and vent: on a Somfy motor "My" while moving means stop, so a second copy can undo what the first one started.
| request | Outbound request frame. |
Definition at line 136 of file hub_decisions.h.
|
inlinenodiscard |
True for a CMD_EXECUTE whose main byte is POS_STOP.
A STOP is only ever sent to a receiver that is (believed) moving, so it is treated as awake whatever the stamps say.
| request | Outbound request frame. |
Definition at line 418 of file hub_decisions.h.
|
inlinenodiscard |
Start-preamble length for one try of a directed exchange to a low-power receiver.
The plans (short = short_preamble, wake = wake_preamble): AWAKE short/wake/wake, ASLEEP wake on every try. A moving receiver answers the first short try; when it does not, it has most likely come to rest, where only the wake-up preamble reaches it, so every later try uses that one. A single-try exchange (most scheduler-owned status polls) sends only try 1's preamble; its backoff ladder, and the evidence a silent AWAKE exchange spends (ExchangeEngine::set_wake_evidence_spent_handler()), cover a wrong belief there.
| belief | See wake_belief(). |
| try_index | 1-based try number, clamped to [1, EXCHANGE_RETRY_COUNT]. |
| short_preamble | Preamble for a receiver known to be moving (normal_start_preamble). |
| wake_preamble | Wake-up preamble for a resting receiver (low_power_wake_preamble). |
Definition at line 447 of file hub_decisions.h.
|
inline |
The node address one above node, as a 24-bit number (B6BDFB -> B6BDFC).
A carry into the higher bytes (xxxxFF) is computed as plain arithmetic; no radiator with such an address has been seen, so whether the device counts the same way is unconfirmed.
| node | Address to count from. | |
| [out] | next | The next address; untouched when false is returned. |
Definition at line 559 of file hub_decisions.h.
|
inlinenodiscard |
Whether a 1W frame arriving at now starts a new burst rather than extending the current one — true if no frame has been seen yet, or the gap since the last one reached quiet_ms (the previous burst already released any deferred poll).
Callers use this to decide whether to reset a burst's start-time tracking; see defer_background_poll_for_1w_activity() for why the burst start (not just the latest frame) needs its own timestamp.
| last_1w_activity_ms | millis() of the most recent 1W frame before this one; 0 if none seen since boot. |
| now | Current millis() (this frame's arrival time). |
| quiet_ms | Gap after which a previous burst is considered over. |
Definition at line 496 of file hub_decisions.h.
|
inline |
Does a pairing node that answered discovery this way control a heater at the next address?
An Atlantic radiator in its display's pairing mode answers discovery as a remote controller (node type 1023), hands over its key, and is controlled at the next node address up: three AGILIA IO radiators follow this (issue #165, tests/corpus/captures/pairing/atlantic_agilia_pairing_key_pull_heater_rollcall.yaml). The heater answers a roll-call only now and then, so the pairing asks that address directly first.
| type | Node type the pairing node answered discovery with. |
| manufacturer | Manufacturer byte of that discovery reply (0 when the reply carried none). |
Definition at line 548 of file hub_decisions.h.
|
inlinenodiscard |
Decide which rain-limitation evidence, if any, a status reply provides.
A rain limitation is an inference from observations, never a prediction (ADR 0030 keeps predictions apart): windows clamp an open to their ventilation position without sending CMD_ERROR_RESP / RESULT_LIMITATION_BY_RAIN, so the only evidence is what the device reports in its ordinary status replies. Rule order matters: the originator rule is the direct evidence and wins; the clamp rule only applies while earlier rain evidence is still fresh.
| in | What the reply said and what had been predicted. |
Definition at line 601 of file hub_decisions.h.
|
inlinenodiscard |
Name of a rain-limitation rule for log lines.
Definition at line 616 of file hub_decisions.h.
|
inlinenodiscard |
Rain state from a decoded limitation reply: the one place that knows which reply fields decide.
Only the main parameter's value counts; originator and remaining time do not.
| status | A decoded CMD_LIMITATION_STATUS_RESP payload. |
Definition at line 657 of file hub_decisions.h.
|
inlinenodiscard |
Rain state from the raw value of a minimum-limitation reply.
| value_raw | Big-endian raw value in position coding (LimitationStatus::value_raw). |
Definition at line 647 of file hub_decisions.h.
|
inline |
Numeric set_timeout() id for a device's remote-activity poll timer (hub_status.cpp's schedule_status_poll_()).
Keyed by the device's node address rather than a name, because Component::set_timeout(const char *name, ...) stores the caller's pointer, not a copy of the string (its header documents this: static lifetime required, use the numeric-id overload for a dynamically-built name) — see schedule_status_poll_()'s own comment for why a per-device name can't satisfy that here. A node address is unique per device, so this id is collision-free by construction.
| node_id | 3-byte device node address. |
Definition at line 522 of file hub_decisions.h.
|
inlinenodiscard |
Whether an authenticated-but-unanswered request may be sent again.
Every request except CMD_EXECUTE is idempotent (status polls, name reads, management actions, config writes) and keeps its full retry budget when the device authenticates but never closes the exchange.
CMD_EXECUTE moves something, and a missing closing reply means two different things depending on the device. Some devices never close an EXECUTE exchange within the response window and report through a later status update instead; for them silence is normal and a re-send only repeats a command already being carried out. For a device that normally does close it, silence can mean our challenge answer never arrived and the command was not carried out at all (a STOP that left an awning moving). So an EXECUTE is sent again only to a device known to confirm, only when repeating it is harmless (is_repeatable_execute()), and at most UNCONFIRMED_EXECUTE_MAX_RESENDS times per exchange.
| request | Outbound request frame. |
| target_confirms_execute | The target has closed an EXECUTE exchange with a reply before (TargetEvidence::confirms_execute). |
| unconfirmed_tries | Tries of this exchange that ended accepted without a closing reply, including the one just ended (1-based). |
Definition at line 161 of file hub_decisions.h.
|
inline |
Transmit-attempt budget for a scheduler-owned status poll, by backoff-ladder position.
See SCHEDULED_POLL_MAX_TRIES and SCHEDULED_POLL_RETRY_GRACE_FIRST_FAILURE (proto_timing.h) for why the full budget belongs to a middle band of the ladder rather than to its start or its tail.
The two counters are mutually exclusive by construction — StatusPollPolicy::on_exchange_failed() zeroes one while incrementing the other — so an auth-shaped streak reads status_poll_failures as 0 and would otherwise fall into the band's own "fresh window" case. It is rejected first, deliberately, so the predicate stays correct even if that exclusivity is ever relaxed.
The settle poll after an accepted STOP (settles_a_stop) gets the full budget whatever the counters say: see STOP_SETTLE_POLL_TRIES (proto_timing.h).
| status_poll_failures | Consecutive silent failures already recorded for this device. |
| auth_poll_failures | Consecutive challenge-seen failures already recorded. |
| settles_a_stop | True for the first poll after an accepted STOP (StatusPollPolicy::take_stop_settle()). |
Definition at line 370 of file hub_decisions.h.
|
inlinenodiscard |
Build the exchange engine's view of a device record.
| dev | Device record to read. |
Definition at line 411 of file hub_decisions.h.
|
inlinenodiscard |
Judge whether a low-power receiver is travelling.
AWAKE for a STOP request or while moving evidence is younger than LOW_POWER_MAX_TRAVEL_MS; ASLEEP otherwise. A zero stamp means never and is never recent. Ages use unsigned subtraction, so millis() wrap-around is safe.
| evidence | Stamps for the target device. |
| now | Current millis(). |
| is_stop | True when the request being sent is a STOP (see is_stop_request()). |
Definition at line 429 of file hub_decisions.h.
|
inlinenodiscard |
Lowercase name of a belief for log lines.
Definition at line 456 of file hub_decisions.h.
|
constexpr |
Namespace tag for heating_poll_timer_id(): the same node-address scheme under its own bit, so a heater's regular-cadence timer and a remote-activity poll timer for the same device never replace one another.
Definition at line 509 of file hub_decisions.h.
|
staticconstexpr |
Percent value of a fully limited position, the divisor of the raw position coding.
Definition at line 635 of file hub_decisions.h.
|
staticconstexpr |
Raw position units per percent (512).
Definition at line 637 of file hub_decisions.h.
|
staticconstexpr |
A window with a wired rain sensor limits its own opening while it rains.
Home Assistant's VELUX integration reads that limit and calls it rain from this minimum limit upward (observed values 89, 91, 93 and 100 %).
Definition at line 633 of file hub_decisions.h.
|
staticconstexpr |
RAIN_MINIMUM_LIMIT_PERCENT in the raw position coding (0xB200).
Definition at line 641 of file hub_decisions.h.
|
constexpr |
Namespace tag for remote_poll_timer_id() below: the node address occupies the low 24 bits, and this is OR-ed in above them.
Each numeric-id timer caller has its own tag (see HEATING_POLL_TIMER_ID_TAG), so two timers for the same device never replace one another and an id says which caller it belongs to.
Definition at line 504 of file hub_decisions.h.