23#include "esphome/core/helpers.h"
37constexpr size_t ENROLLMENT_CLASS_HEX_BUFFER_SIZE = 8;
43constexpr uint8_t BLOCKING_WARNING_THRESHOLD_CS = 250;
47uint32_t poll_jitter_random() {
return random_uint32(); }
80 this->warn_if_blocking_over_ = BLOCKING_WARNING_THRESHOLD_CS;
81#ifdef IOHOME_UNSAFE_LOG_KEY_MATERIAL
85 ESP_LOGE(
detail::TAG,
"########################################");
86 ESP_LOGE(
detail::TAG,
"IOHOME_UNSAFE_LOG_KEY_MATERIAL IS ENABLED -- FRAME LOGS EXPOSE YOUR SYSTEM KEY");
87 ESP_LOGE(
detail::TAG,
"This build is NOT safe to run normally or share logs from. Rebuild without this");
88 ESP_LOGE(
detail::TAG,
"flag as soon as you are done capturing.");
89 ESP_LOGE(
detail::TAG,
"########################################");
95 this->mark_failed(LOG_STR(
"Invalid node_id or system_key configuration"));
109 const char *chip_name_for_log =
nullptr;
111 if (this->
radio_ ==
nullptr) {
113 "' (a required pin is missing, the type is unrecognized, or allocation failed)";
115 this->mark_failed(LOG_STR(
"Radio driver setup failed (see 'Radio setup failed' in the config dump)"));
119#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
123 this->run_lr1121_boot_time_bootloader_read_();
130 driver_reason !=
nullptr ? driver_reason :
"driver init failed without a recorded cause";
133#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
137 this->cache_lr1121_flash_verdict_();
140 this->mark_failed(LOG_STR(
"Radio hardware initialization failed (see 'Radio setup failed' in the config dump)"));
144#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
145 this->cache_lr1121_flash_verdict_();
166 *chip_name_out =
"LR1121";
168 ESP_LOGE(
detail::TAG,
"LR1121 requires busy_pin and dio1_pin (dio1_pin carries the chip's DIO9 IRQ line)");
171 auto *radio =
new (std::nothrow)
173 if (radio ==
nullptr)
174 ESP_LOGE(
detail::TAG,
"Failed to allocate LR1121 radio driver");
179 *chip_name_out =
"SX1262";
181 ESP_LOGE(
detail::TAG,
"SX1262 requires busy_pin and dio1_pin");
184 auto *radio =
new (std::nothrow)
187 if (radio ==
nullptr)
188 ESP_LOGE(
detail::TAG,
"Failed to allocate SX1262 radio driver");
193 *chip_name_out =
"SX1276";
198 auto *radio =
new (std::nothrow)
200 if (radio ==
nullptr)
201 ESP_LOGE(
detail::TAG,
"Failed to allocate SX1276 radio driver");
205 *chip_name_out =
"unknown";
218 if (this->
radio_ ==
nullptr)
245 if (param ==
nullptr) {
246 ESP_LOGW(
detail::TAG,
"Unknown tuning number parameter: %s", name.c_str());
262 if (param ==
nullptr) {
263 ESP_LOGW(
detail::TAG,
"Unknown tuning select parameter: %s", name.c_str());
280 if (param ==
nullptr) {
281 ESP_LOGW(
detail::TAG,
"Unknown tuning number parameter: %s", name.c_str());
295 if (param ==
nullptr) {
296 ESP_LOGW(
detail::TAG,
"Unknown tuning select parameter: %s", name.c_str());
325 request, response, freq,
362 uint32_t interval_ms) {
379 bool device_moving) {
380 uint32_t
const now = millis();
384 ESP_LOGD(
TAG,
"Status poll miss for moving device %s skipped (%u of %u): next poll in %" PRIu32
" ms",
385 device_id.c_str(), this->poll_policy_.get_moving_poll_misses(device_id), MOVING_POLL_MISSES_SKIPPED,
387 }
else if (backoff_ms > 0) {
389 "Background status poll backoff for device %s: delay=%" PRIu32
390 " ms auth_like=%s status_failures=%u auth_failures=%u",
392 this->poll_policy_.get_auth_poll_failures(device_id));
420 ESP_LOGE(
TAG,
"Radio stopped responding: %s; reboot the board", reason !=
nullptr ? reason :
"no recorded cause");
421 this->status_set_warning(
"radio stopped responding");
423 for (
const auto &entry : this->
registry_)
457#ifdef IOHOME_LOCK_CHANNEL_HZ
532 ESP_LOGD(
TAG,
"No exchange for %" PRIu32
" ms after linked-remote activity: reading %zu linked device(s)",
537 for (
const std::string &device_id : devices) {
562 ESP_LOGD(
TAG,
"Device %s: no status reported for a refresh interval (%" PRIu32
" s): reading it", due->c_str(),
563 this->status_refresh_policy_.get_interval(*due) / 1000);
578 this->tuning_.normal_start_preamble_from_yaml ?
"set in YAML" :
"from the radio driver");
582 : (this->tuning_.pairing_discovery_low_power ?
"wake-up preamble, discovery is low-power"
583 :
"follows the start preamble"));
586#ifdef IOHOME_UNSAFE_LOG_KEY_MATERIAL
589 ESP_LOGE(
detail::TAG,
" IOHOME_UNSAFE_LOG_KEY_MATERIAL IS ENABLED -- FRAME LOGS EXPOSE YOUR SYSTEM KEY");
590 ESP_LOGE(
detail::TAG,
" Not safe to share logs from: rebuild without this flag as soon as you are done capturing.");
596 LOG_PIN(
" RST Pin: ", this->
rst_pin_);
607 ESP_LOGCONFIG(
detail::TAG,
" Low-power wake belief: %s",
613 for (
const auto &device_id : devices)
614 ESP_LOGCONFIG(
"home_io_control",
" - remote %s -> device %s", remote_id.c_str(), device_id.c_str());
620 if (this->
radio_ !=
nullptr) {
626 ESP_LOGE(
detail::TAG,
" Radio failed after setup: %s", reason !=
nullptr ? reason :
"no recorded cause");
632#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
633 this->dump_lr1121_firmware_update_debug_();
652 detail::TAG,
" - %s: node %s%s, class 0x%02X, acei 0x%02X%s, broadcast %s%s, power %s%s",
653 identity.id.c_str(),
node_id_to_string(identity.node_id).c_str(), identity.node_id_derived ?
" (derived)" :
"",
660 ESP_LOGCONFIG(
detail::TAG,
" inverted=%s", oneway_inverted_label(identity));
666 std::array<char, ENROLLMENT_CLASS_HEX_BUFFER_SIZE> byte_hex{};
670 snprintf(byte_hex.data(), byte_hex.size(),
"%02X",
static_cast<unsigned>(c));
671 classes += classes.empty() ?
"0x" :
" 0x";
672 classes += byte_hex.data();
674 ESP_LOGCONFIG(
detail::TAG,
" enroll: VELUX KLI gesture, 0x30 sweep -> %s", classes.c_str());
size_t linked_remote_count() const
std::vector< std::string > all_linked_devices() const
Every device with a linked_remotes entry, by remote id or by class:, once each, sorted.
void notify(const std::string &device_id)
Invoke all registered callbacks for device_id.
IoDevice * get(const std::string &device_id)
Retrieve a registered device by ID.
void for_each_linked_remote(const std::function< void(const std::string &, const std::vector< std::string > &)> &fn) const
Invoke fn(remote_id, device_id_list) for every linked-remote entry.
void add(const std::string &device_id)
Register a device by ID with default metadata (UNKNOWN type, subtype 0, no overrides).
void set_travel_speed(const std::string &device_id, TravelSpeed speed)
Select a device's travel speed.
ListenOutcome listen(const ListenSpec &spec, RadioRxPacket &packet, IoFrame &frame, const ReplyHandler &on_frame)
The one listen primitive every radio wait loop in this project is built on.
void maybe_hop()
Hop only if the minimum dwell has elapsed and no frame is currently arriving on this channel — RadioD...
bool transmit_frame(const IoFrame &frame, uint32_t freq, uint16_t preamble)
Transmit a raw IoFrame with the given preamble length.
bool authenticate_request(const IoFrame &request, uint32_t freq)
Authenticate an inbound device command via 0x3C challenge / 0x3D HMAC.
ExchangeOutcome send_and_receive(const IoFrame &request, IoFrame &response, uint32_t freq, uint8_t max_tries=EXCHANGE_RETRY_COUNT, uint16_t request_preamble_override=0)
Execute an outbound authenticated exchange with retry.
void reset_hop_timestamp()
Reset the hop-timer (called after radio init in hub setup()).
decisions::AttemptPlan plan_read(decisions::ReadKind kind, const IoFrame &request, uint32_t freq, uint16_t request_preamble_override=0, bool state_unknown=false) const
The attempt plan for a read of request's target, with the transmit time this engine would plan for th...
void hop_frequency(uint32_t skip_freq=0)
Advance the receiver one step along the protocol's channel rotation (CH1→CH2→CH3→CH1).
InternalGPIOPin * fem_en_pin_
Front-end module enable.
InternalGPIOPin * fem_pa_pin_
Front-end module PA switch.
void dump_oneway_controllers_config_() const
Emit the 1W controller identities to the config dump — node, class, and the resolved ACEI / broadcast...
void schedule_background_poll_backoff_(const std::string &device_id, bool auth_like, bool device_moving=false)
Apply backoff after a failed background status poll and log the result.
InternalGPIOPin * dio4_pin_
SX1276 DIO4 preamble detect (optional).
void listen_for_key_extraction_peer_()
One idle pass of listening for the key-extraction responder's peer, in place of the generic idle hop ...
InternalGPIOPin * dio1_pin_
SX1262 DIO1 interrupt; also carries the LR1121's DIO9 IRQ line.
virtual void queue_request_device_sun_level(const std::string &device_id)
Queue an async sun level poll; executed in loop() as a background operation.
void dump_config() override
Dump configuration and radio debug info to the log.
void update_tuning_select(const std::string &name, const std::string &value)
Receive a select tuning update from a HA select entity.
InternalGPIOPin * rst_pin_
virtual IoDevice * get_device(const std::string &device_id)
Retrieve a device by ID; returns nullptr if not found.
void note_status_reported_(const std::string &device_id)
The device just reported its status: move its status refresh (if it has one) a whole interval out.
void queue_due_catchup_reads_()
Read every device with linked_remotes once, when a burst of linked-remote activity has been followed ...
virtual void queue_request_device_status(const std::string &device_id)
Queue an async status request; returns immediately, executed in loop().
void update_tuning_number(const std::string &name, float value)
Receive a numeric tuning update from a HA number entity.
PeriodicPollPolicy battery_level_poll_policy_
Schedule of the opt-in battery level poll.
virtual void add_device(const std::string &device_id)
Add a device to the registry by device ID only (undeclared/legacy path).
InternalGPIOPin * vfem_pin_
Front-end module power.
TuningConfig tuning_
Runtime tuning overrides.
virtual void set_device_status_poll_interval(const std::string &device_id, uint32_t poll_interval_ms)
Configure the optional follow-up polling interval for a registered device.
void process_pending_operation_()
Pop next pending operation from the queue and execute it (set position, request status,...
StatusPollPolicy poll_policy_
void hop_frequency_()
Delegate channel hop to ExchangeEngine (which owns last_hop_us_).
float get_tuning_number_value(const std::string &name) const
Current value of a numeric tuning parameter, used to seed a HA number entity on boot.
bool defer_background_poll_() const
Whether loop() should skip dispatching the queue this iteration because the pending work is a backgro...
virtual void set_device_travel_speed(const std::string &device_id, TravelSpeed speed)
Select a device's travel speed at runtime (see IOHomeCoverTravelSpeedSelect and IOHomeCoverSilentSwit...
ExchangeOutcome send_and_receive_(const IoFrame &request, IoFrame &response, uint32_t freq, const decisions::AttemptRequest &attempts=EXCHANGE_RETRY_COUNT)
Main request/response exchange with retry and automatic authentication.
virtual void queue_request_device_limitation(const std::string &device_id)
Queue an async minimum-limitation read for the rain sensor poll; executed in loop() as a background o...
void resolve_start_preamble_default_()
Resolve normal_start_preamble from the driver when YAML did not set it (ADR 0042).
void loop() override
Main loop: process pending operations and drive radio state machine.
OneWayTransmitter oneway_transmitter_
Owns the 1W controller identities, their rolling-sequence counters and the transmit burst.
std::string radio_failure_reason_
Why setup() gave up on the radio, or empty.
void settle_ended_status_tracking_()
Settle every device whose polling window ran out (StatusPollPolicy::pop_ended_device()).
virtual void set_device_rain_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic rain sensor poll (a read of its minimum limitation).
std::string radio_type_
"sx1276", "sx1262", or "lr1121"; required by the YAML schema.
virtual void set_device_status_refresh_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the status refresh at rest: a status read whenever the device has not re...
uint8_t system_key_[AES_KEY_SIZE]
bool key_extraction_awaiting_reply_() const
True while the key-extraction responder is mid-attempt and still within its bounded listen window.
void queue_due_periodic_polls_()
Queue every periodic poll that is due: the sensor polls (rain, sun level, battery level) and the stat...
virtual void queue_request_device_battery_level(const std::string &device_id)
Queue an async battery level poll; executed in loop() as a background operation.
RadioDriver * select_and_construct_radio_(const char **chip_name_out)
Select and construct the radio driver named by the required radio_type config field.
bool transmit_frame_(const IoFrame &frame, uint32_t freq, uint16_t preamble)
Transmit a raw IoFrame on the current frequency with given preamble length.
bool radio_test_mode_
When true, loop() is suspended for loopback testing.
ExchangeEngine exchange_engine_
Owns all authenticated exchange and LBT/hop logic.
const OneWayControllerRegistry & oneway_controllers() const
PeriodicPollPolicy rain_poll_policy_
Schedule of the opt-in rain sensor poll.
bool radio_failure_reported_
Set once loop() has reported a radio that latched a failure after setup, so the report (an error line...
virtual void set_device_sun_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic sun level poll (a subscription to EVENT_LOCAL_SENSOR,...
InternalGPIOPin * dio0_pin_
SX1276 DIO0 interrupt.
std::vector< OneWayCommandReportFn > oneway_report_callbacks_
Subscribers to the per-command 1W report; one per "Last 1W Command" sensor.
void notify_device_update_(const std::string &id)
Fire all registered device update callbacks for the given device ID.
std::string system_key_str_
std::string get_tuning_select_value(const std::string &name) const
Current option string of a select tuning parameter, used to seed a HA select entity on boot.
void setup() override
Initialize hardware (radio and device registry).
KeyExtractionResponder key_extraction_
Device-role responder for the "Recover System Key" feature (key_extraction_responder....
uint8_t node_id_[NODE_ID_SIZE]
uint8_t tcxo_voltage_
SX1262/LR1121 TCXO voltage setting (default 1.8 V).
void process_received_packet_(const RadioRxPacket &packet)
Parse a received frame, merge supported device state or metadata, and notify callbacks.
bool authenticate_request_(const IoFrame &request, uint32_t freq)
Handle an inbound authenticated command from a device (status updates, etc.).
InternalGPIOPin * busy_pin_
SX1262/LR1121 BUSY pin.
void register_management_actions_()
Register hub-level Home Assistant actions; called from setup().
void apply_tuning_to_radio_()
Apply the current tuning configuration to the active radio driver.
FemProfile fem_profile_
Which FEM part fem_pa_pin_ belongs to, if any.
PeriodicPollPolicy status_refresh_policy_
Schedule of the opt-in status refresh at rest.
PeriodicPollPolicy sun_poll_policy_
Schedule of the opt-in sun level poll.
virtual void set_device_battery_level_poll_interval(const std::string &device_id, uint32_t interval_ms)
Opt a registered device into the periodic battery level poll (a subscription to EVENT_BATTERY_LEVEL_C...
void setup()
Open each registered identity's persistent sequence counter.
void set_command_report_callback(OneWayCommandReportFn callback)
Register the callback that receives a report after every command attempt.
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 periodic_poll_jittered_...
void restart_interval(const std::string &device_id, uint32_t now, uint32_t random)
The device has just given what the poll asks for without being polled: schedule its next poll periodi...
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 periodic_poll_first_delay_ms(random) after now.
Abstract radio driver for IO-Homecontrol.
virtual void dump_front_end()
Optional board front-end-module (external PA/LNA) summary emitted from dump_config,...
uint32_t get_current_freq() const
Get the current RF frequency.
virtual uint16_t default_start_preamble() const
Default preamble for a directed start frame, when the user has not set normal_start_preamble in YAML.
virtual void change_frequency(uint32_t freq_hz)=0
Change the carrier frequency using fast hop (no standby transition needed).
const char * failure_reason() const
Short, human-readable reason the driver latched is_failed, or nullptr if it has not.
virtual bool run_idle_scan()
Let the radio scan the hop channels by itself while the hub is idle.
virtual bool is_failed() const
Returns true if the radio failed to initialize or encountered a fatal error.
virtual bool init()=0
Initialize the radio hardware. Returns true on success.
virtual void apply_tuning(const TuningConfig &tuning)
Apply runtime tuning parameters to the driver.
virtual void dump_debug()
Optional chip-specific diagnostics emitted from dump_config.
virtual bool check_for_packet(RadioRxPacket &packet)=0
Non-blocking check for a received packet.
RadioLR1121(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *irq_pin, InternalGPIOPin *busy_pin, uint8_t tx_power, uint8_t tcxo_voltage_code)
RadioSX1262(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio1_pin, InternalGPIOPin *busy_pin, uint8_t tx_power, uint8_t tcxo_voltage, InternalGPIOPin *fem_en_pin=nullptr, InternalGPIOPin *vfem_pin=nullptr, InternalGPIOPin *fem_pa_pin=nullptr, FemProfile fem_profile=FemProfile::NONE)
RadioSX1276(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio0_pin, InternalGPIOPin *dio4_pin, uint8_t tx_power, uint8_t pa_pin)
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 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.
uint8_t get_moving_poll_misses(const std::string &device_id) const
Consecutive failed polls of a moving device skipped so far.
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 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 ...
std::optional< std::string > pop_due_device(uint32_t now)
Return and consume the first device with a poll overdue.
Helpers shared only by the hub's own implementation files (hub_*.cpp).
constexpr const char * TAG
Shared log tag for hub-level messages.
static constexpr const char * TAG
OneWayPowerClass effective_power_class(const OneWayControllerIdentity &identity)
The burst shape this identity actually transmits with.
bool effective_inverted(const OneWayControllerIdentity &identity)
Whether this identity's OPEN/CLOSE/position values are mirrored on the wire.
static constexpr uint32_t KEY_EXTRACTION_SCAN_SLICE_MS
DeviceType
IO-Homecontrol node types.
@ UNKNOWN
Unknown/unspecified device.
@ ACCEPT
This is the frame the caller was waiting for — stop listening, return ACCEPTED.
std::array< DeviceType, 3 > effective_enrollment_classes(const OneWayControllerIdentity &identity)
The device classes this identity's 0x30 enrollment sweep will actually target.
uint8_t effective_execute_acei(const OneWayControllerIdentity &identity)
The ACEI byte a given identity will put on air for a 1W EXECUTE frame.
ExchangeOutcome
Authenticated exchange engine — outbound and inbound protocol flows.
std::string tuning_config_full_snapshot(const TuningConfig &cfg)
Format the current tuning configuration as a full one-line snapshot.
@ ROTATE_ALL_CHANNELS
CH1->CH2->CH3->CH1.
const TuningSelectParam * find_tuning_select(const std::string &name)
Look up a select tuning parameter by name; returns nullptr if unknown.
std::string tuning_update_log_line(const std::string &name, const std::string &value)
Format a single tuning update for the log.
std::string node_id_to_string(const uint8_t id[NODE_ID_SIZE])
Format a 3‑byte node ID as a 6‑character uppercase hex string.
const char * oneway_power_class_name(OneWayPowerClass power_class)
Human-readable name for a OneWayPowerClass, as it appears in the boot log.
ListenOutcome
How one call to ExchangeEngine::listen() ended.
@ ACCEPTED
The handler returned ReplyDisposition::ACCEPT for some received frame.
const TuningNumberParam * find_tuning_number(const std::string &name)
Look up a numeric tuning parameter by name; returns nullptr if unknown.
uint16_t effective_discovery_preamble(const TuningConfig &cfg)
The preamble length (bytes) of the pairing discovery broadcast (0x28, 0x2E).
bool has_invert_override(const OneWayControllerIdentity &identity)
Whether this identity's inversion comes from an explicit invert_position: rather than the kind.
bool has_power_class_override(const OneWayControllerIdentity &identity)
Whether this identity's burst shape comes from an explicit low_power: rather than the profile.
TravelSpeed
The speed a cover's position moves ask the motor for (ADR 0065).
OneWayWireProfile resolve_oneway_wire_profile(uint8_t manufacturer)
Resolve an identity's 1W wire profile from its manufacturer byte.
bool has_execute_acei_override(const OneWayControllerIdentity &identity)
Whether this identity's ACEI comes from an explicit execute_acei: rather than the profile.
bool hex_to_bytes(const std::string &hex, uint8_t *out, uint8_t len)
Convert a hex string (e.g., "123ABC") to a byte array.
static const char *const TAG
LR1121 radio driver for IO-Homecontrol.
SX1262 radio driver for IO-Homecontrol.
SX1276 radio driver for IO-Homecontrol.
YAML-declared device metadata for registration; defaults match an undeclared device.
Runtime state of a paired IO‑Homecontrol device.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).
uint8_t ctrl1
Control byte 1: low power, beacon, etc.
How one listen window is to be spent — everything ExchangeEngine::listen() needs; everything else is ...
uint32_t window_ms
Total time budget for this listen, in milliseconds.
uint32_t linger_dwell_ms
Length of the preamble/sync extension, in milliseconds.
ListenPolicy policy
Which channels this listen covers.
bool linger_on_preamble
Extend the listen instead of hopping while the chip reports a preamble or sync word,...
What a 1W command attempt did — the only feedback this feature can ever produce.
One configured 1W controller identity.
Vendor-divergent 1W wire settings for a controller identity.
bool profile_is_a_guess
true when manufacturer matched no known 1W wire profile.
EnrollGesture enroll_gesture
Which enrollment gesture this manufacturer's actuators expect.
Raw packet received from the radio.
bool active
True when the YAML tuning: block is present.
uint16_t normal_start_preamble
Preamble for a directed start frame to a non-low-power target.
uint32_t remote_activity_catchup_poll_ms
Read every linked device this long after the last exchange of a burst of linked-remote activity; 0 = ...
uint16_t low_power_wake_preamble
Wake-up preamble (bytes) on a directed start frame to a low_power target believed at rest.
bool pairing_discovery_preamble_set
True when pairing_discovery_preamble was set, from YAML or by a write through the Home Assistant numb...
bool low_power_wake_belief
Order a low_power device's start-frame tries by its wake belief (short preamble first when it is beli...
bool normal_start_preamble_from_yaml
True when normal_start_preamble: appeared in YAML.
One numeric tuning parameter: its wire name plus accessors over TuningConfig.
void(*) set(TuningConfig &, float)
Write a new value (narrowed to the field type).
bool applies_to_radio
True if changes must be re-applied to the radio.
float(*) get(const TuningConfig &)
Read the current value as a float.
One select tuning parameter: its wire name plus string accessors over TuningConfig.
bool(*) set(TuningConfig &, const std::string &)
Parse/apply an option; false if unparseable.
std::string(*) get(const TuningConfig &)
Read the current option string.
bool applies_to_radio
True if changes must be re-applied to the radio.
What a caller asks of one exchange's attempts: a plain cap on tries (today's shape),...
bool state_unknown
True for a read whose evidence about the receiver may be stale (with_state_unknown()).
bool wake_preamble_first
True for the read at a moving cover's predicted end of travel (with_wake_preamble_first()).
ReadKind kind
What the read is for; only read when planned.
bool planned
True: build the plan for kind instead of using a count.
uint8_t max_tries
Cap on attempts; ignored once kind is set.
Runtime tuning configuration for pairing and radio diagnostics.
Table-driven registry of runtime tuning parameters.