Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
hub_decisions.h File Reference

Pure transition helpers for hub-owned exchange and pairing frame decisions. More...

#include "proto_codecs.h"
#include "proto_constants.h"
#include "proto_device_model.h"
#include "proto_frame.h"
#include "proto_timing.h"
#include "tuning_config.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
Include dependency graph for hub_decisions.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  esphome::home_io_control::decisions::OneWayDedupState
 Key fields of the last processed 1W frame, used to collapse a remote's repeat burst. More...
struct  esphome::home_io_control::decisions::AttemptPlan
 How one exchange spends its attempts. Handed to ExchangeEngine::send_and_receive(). More...
struct  esphome::home_io_control::decisions::AttemptRequest
 What a caller asks of one exchange's attempts: a plain cap on tries (today's shape), or a read kind whose plan the engine builds for the request (ExchangeEngine::plan_read()). More...
struct  esphome::home_io_control::decisions::TargetEvidence
 What the hub knows about the device an exchange is addressed to, as the exchange engine sees it. More...
struct  esphome::home_io_control::decisions::RainLimitationInput
 What one decoded status reply said, plus what the hub had predicted. More...
struct  esphome::home_io_control::decisions::StoppedReportInput
 One decoded status report, plus what the hub remembers and whether it will poll again. More...

Namespaces

namespace  esphome
namespace  esphome::home_io_control
namespace  esphome::home_io_control::decisions

Enumerations

enum class  esphome::home_io_control::decisions::ExchangeFirstResponseDisposition : uint8_t { esphome::home_io_control::decisions::IGNORE_UNRELATED , esphome::home_io_control::decisions::COMPLETE_DIRECT , esphome::home_io_control::decisions::REQUIRE_AUTH }
 Disposition for the first response in an authenticated exchange. More...
enum class  esphome::home_io_control::decisions::ExchangeFinalResponseDisposition : uint8_t { esphome::home_io_control::decisions::IGNORE_UNRELATED , esphome::home_io_control::decisions::ACCEPT }
 Disposition for the final response after authentication. More...
enum class  esphome::home_io_control::decisions::PairingDiscoveryDisposition : uint8_t { esphome::home_io_control::decisions::NO_RESPONSE , esphome::home_io_control::decisions::INVALID , esphome::home_io_control::decisions::ACCEPT }
 Disposition during pairing discovery phase. More...
enum class  esphome::home_io_control::decisions::PairingKeyChallengeDisposition : uint8_t { esphome::home_io_control::decisions::IGNORE , esphome::home_io_control::decisions::ACCEPT }
 Disposition during pairing key-challenge phase. More...
enum class  esphome::home_io_control::decisions::PairingDiscoverConfirmDisposition : uint8_t { esphome::home_io_control::decisions::IGNORE , esphome::home_io_control::decisions::ACK , esphome::home_io_control::decisions::ERROR }
 Disposition for a candidate reply to a discovery-confirm request (0x2C). More...
enum class  esphome::home_io_control::decisions::PairingKeyConfirmDisposition : uint8_t { esphome::home_io_control::decisions::IGNORE , esphome::home_io_control::decisions::CONFIRM , esphome::home_io_control::decisions::CHALLENGE , esphome::home_io_control::decisions::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  esphome::home_io_control::decisions::ReadKind : uint8_t { esphome::home_io_control::decisions::PROGRESS , esphome::home_io_control::decisions::SETTLING , esphome::home_io_control::decisions::COMMAND }
 What a request is for, which decides how its attempts are spent. More...
enum class  esphome::home_io_control::decisions::WakeBelief : uint8_t { esphome::home_io_control::decisions::ASLEEP , esphome::home_io_control::decisions::AWAKE , esphome::home_io_control::decisions::UNKNOWN }
 Whether a low-power receiver is believed to be travelling right now, judged from what this hub has seen of it. More...
enum class  esphome::home_io_control::decisions::HeaterModelHint : uint8_t { esphome::home_io_control::decisions::NONE , esphome::home_io_control::decisions::LOOKS_LIKE_RADIATOR , esphome::home_io_control::decisions::LOOKS_LIKE_TOWEL_DRYER }
 What the model check suggests about a heater's declared io_model:. More...
enum class  esphome::home_io_control::decisions::RainLimitationRule : uint8_t { esphome::home_io_control::decisions::NONE = 0 , esphome::home_io_control::decisions::RAIN_ORIGINATOR , esphome::home_io_control::decisions::CLAMPED_COMMAND }
 Which evidence path labelled a device as limited by rain. More...
enum class  esphome::home_io_control::decisions::StoppedReport : uint8_t {
  esphome::home_io_control::decisions::MOVING , esphome::home_io_control::decisions::STOPPED , esphome::home_io_control::decisions::STOPPED_CONFIRMED , esphome::home_io_control::decisions::STOPPED_UNCONFIRMABLE ,
  esphome::home_io_control::decisions::SETTLING
}
 What the hub makes of one status report's movement state. More...

Functions

bool esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::is_device_event_report (const IoFrame &frame)
 Returns true for a frame that reports a device event rather than a status: a CMD_SET_CONFIG1_RESP, or a well-formed CMD_STATUS_UPDATE whose event is not EVENT_STATUS_CHANGE (a subscribed sensor report, see decode_status_update_event()).
bool esphome::home_io_control::decisions::is_subscription_answer (const IoFrame &request, const IoFrame &response)
 Returns true when response is the answer to the subscription request: the request is a CMD_SUBSCRIBE_EVENT with the subscribe action, and the response a well-formed CMD_STATUS_UPDATE carrying the same event, from the device the request went to.
bool esphome::home_io_control::decisions::overheard_command_writes (uint8_t cmd)
 Returns true for the commands that write to a device: an execute, a mode activation or a private register write.
bool esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::classify_exchange_first_response (const IoFrame &request, const IoFrame &candidate)
 Decide how to handle the first response packet in an authenticated exchange.
ExchangeFinalResponseDisposition esphome::home_io_control::decisions::classify_exchange_final_response (const IoFrame &request, const IoFrame &candidate)
 Decide if a candidate frame is an acceptable final response after authentication.
bool esphome::home_io_control::decisions::is_repeatable_execute (const IoFrame &request)
 True for a CMD_EXECUTE that has the same effect sent twice as sent once.
bool esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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.
bool esphome::home_io_control::decisions::scheduled_poll_in_retry_band (uint8_t status_poll_failures, uint8_t auth_poll_failures)
 True when a scheduler-owned status poll sits in the middle band of the backoff ladder.
uint8_t esphome::home_io_control::decisions::scheduled_poll_max_tries (uint8_t status_poll_failures, uint8_t auth_poll_failures)
 Transmit-attempt budget for a scheduler-owned status poll of a heater, by ladder position.
uint32_t esphome::home_io_control::decisions::short_lead_cost_ms (uint32_t short_tx_ms)
 What the short lead attempt costs the exchange: its transmission, its brief listen and the attempt overhead (the same terms attempt_fits() counts for any attempt).
bool esphome::home_io_control::decisions::attempt_fits (uint32_t elapsed_ms, uint32_t gap_ms, uint32_t tx_ms, uint32_t window_ms, uint32_t auth_tail_ms, uint32_t budget_ms)
 The attempt budget rule: an attempt starts only if the whole attempt, up to the end of the last wait it can make, ends inside budget_ms.
uint8_t esphome::home_io_control::decisions::attempts_that_fit (uint32_t budget_ms, uint32_t attempt_tx_ms, uint32_t early_window_ms, uint32_t last_window_ms, uint8_t cap)
 How many attempts to a silent target fit the budget when none waits a gap, capped at cap.
AttemptPlan esphome::home_io_control::decisions::attempt_plan_for_tries (uint8_t max_tries, uint16_t window_ms)
 The plan for a caller that names only a number of attempts: that many (at least one, at most EXCHANGE_RETRY_COUNT), the default gap, and window_ms.
AttemptPlan esphome::home_io_control::decisions::attempt_plan (ReadKind kind, bool low_power, const TuningConfig &tuning, uint32_t attempt_tx_ms, uint16_t last_window_ms=0, std::optional< uint32_t > short_lead_tx_ms=std::nullopt)
 The attempt plan for a request, from what it is for and who it asks.
bool esphome::home_io_control::decisions::is_repeat_safe_command (const IoFrame &request)
 Whether a request may be sent again to a device that said nothing, without a second action.
ReadKind esphome::home_io_control::decisions::scheduled_poll_read_kind (uint8_t status_poll_failures, uint8_t auth_poll_failures, bool settles_a_position)
 What a cover's status poll is for, from where it sits and what it settles.
TargetEvidence esphome::home_io_control::decisions::target_evidence (const IoDevice &dev)
 Build the exchange engine's view of a device record.
bool esphome::home_io_control::decisions::moving_until_holds (const TargetEvidence &evidence, uint32_t now)
 True while the remaining time the receiver last reported has not run out: by its own account it is still travelling, so a silent exchange is not evidence that it has come to rest.
bool esphome::home_io_control::decisions::is_stop_request (const IoFrame &request)
 True for a CMD_EXECUTE whose main byte is POS_STOP.
WakeBelief esphome::home_io_control::decisions::wake_belief (const TargetEvidence &evidence, uint32_t now, bool is_stop, bool is_status_read=false, bool state_unknown=false)
 Judge whether a low-power receiver is travelling.
uint16_t esphome::home_io_control::decisions::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 * esphome::home_io_control::decisions::wake_belief_name (WakeBelief belief)
 Lowercase name of a belief for log lines.
bool esphome::home_io_control::decisions::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).
std::array< uint32_t, 3 > esphome::home_io_control::decisions::status_update_ack_channel_order (uint32_t receive_freq_hz)
 The order in which a 0x72 status-update acknowledgement is sent on the three channels: the channel the 0x71 exchange ran on first, then the other two in their usual CH1, CH2, CH3 order.
bool esphome::home_io_control::decisions::frame_issue_is_warning (bool dst_registered, bool dst_is_us)
 Whether a frame issue (a frame the hub did not act on) is logged at WARN rather than DEBUG.
bool esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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_()).
HeaterModelHint esphome::home_io_control::decisions::classify_heater_model_hint (DeviceModel declared, bool towel_mode_has_value)
 Compare a heater's declared model with whether it answered the towel-dryer mode register (0x0136) with a value.
std::string esphome::home_io_control::decisions::format_heater_model_name (const uint8_t *bytes, size_t len)
 Render a heater's model-name register (0x0119, ASCII) for a log line.
bool esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::rain_limitation_rule (const RainLimitationInput &in)
 Decide which rain-limitation evidence, if any, a status reply provides.
bool esphome::home_io_control::decisions::is_rain_limited (const RainLimitationInput &in)
 True when rain_limitation_rule() finds evidence of a rain limitation.
const char * esphome::home_io_control::decisions::rain_limitation_rule_name (RainLimitationRule rule)
 Name of a rain-limitation rule for log lines.
RainSensorState esphome::home_io_control::decisions::rain_state_from_minimum_limit (uint16_t value_raw)
 Rain state from the raw value of a minimum-limitation reply.
RainSensorState esphome::home_io_control::decisions::rain_state_from_limitation_reply (const LimitationStatus &status)
 Rain state from a decoded limitation reply: the one place that knows which reply fields decide.
bool esphome::home_io_control::decisions::is_executing (ExecutionState state)
 True when a device in this state is moving or about to: waiting for its turn (2), waiting for power (3) or executing (4).
bool esphome::home_io_control::decisions::reads_stopped_by_status_byte (uint8_t status_byte)
 Does byte 0 of a status reply say the device is at rest?
StoppedReport esphome::home_io_control::decisions::classify_stopped_report (const StoppedReportInput &in)
 Decide whether a "stopped" report means at rest.
bool esphome::home_io_control::decisions::stopped_report_at_rest (StoppedReport report)
 True when a verdict means the device is at rest.
bool esphome::home_io_control::decisions::stopped_report_keeps_candidate (StoppedReport report)
 True when a verdict leaves an off-target report to remember for the next one.

Variables

constexpr uint32_t esphome::home_io_control::decisions::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 esphome::home_io_control::decisions::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.
constexpr uint8_t esphome::home_io_control::decisions::HEATER_MODEL_CHECK_MAX_RUNS = 3
 Runs of the one-off heater model check before the hub gives up on it for this boot.
constexpr uint8_t esphome::home_io_control::decisions::MODEL_NAME_PRINTABLE_FIRST = 0x20
 First and last byte format_heater_model_name() prints as itself: printable ASCII, space to '~'.
constexpr uint8_t esphome::home_io_control::decisions::MODEL_NAME_PRINTABLE_LAST = 0x7E
 See MODEL_NAME_PRINTABLE_FIRST.
static constexpr uint8_t esphome::home_io_control::decisions::RAIN_MINIMUM_LIMIT_PERCENT = 89
 A window with a wired rain sensor limits its own opening while it rains.
static constexpr uint16_t esphome::home_io_control::decisions::POSITION_FULL_PERCENT = 100
 Percent value of a fully limited position, the divisor of the raw position coding.
static constexpr uint16_t esphome::home_io_control::decisions::POSITION_RAW_PER_PERCENT = STATUS_POS_MAX / POSITION_FULL_PERCENT
 Raw position units per percent (512).
static constexpr uint16_t esphome::home_io_control::decisions::RAIN_MINIMUM_LIMIT_RAW = POSITION_RAW_PER_PERCENT * RAIN_MINIMUM_LIMIT_PERCENT
 RAIN_MINIMUM_LIMIT_PERCENT in the raw position coding (0xB200).

Detailed Description

Pure transition helpers for hub-owned exchange and pairing frame decisions.

This header contains inline, testable decision logic: frame classification for exchange and pairing flows, plus shared timing utilities. No state, no side effects — suitable for unit testing without radio hardware.

Definition in file hub_decisions.h.