Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
proto_timing.h
Go to the documentation of this file.
1#pragma once
2
3/// @file proto_timing.h
4/// @brief Physical-layer radio and timing parameters for the IO-Homecontrol protocol.
5/// @ingroup hioc_protocol
6
7#include <cstdint>
8
9namespace esphome {
10namespace home_io_control {
11
12// ============================================================================
13// Physical Layer — Radio Parameters
14// ============================================================================
15
16/// The protocol uses 3 frequency channels in the 868 MHz ISM band.
17/// IO-Homecontrol uses 3 channels in the 868 MHz SRD band. In 1W (one-way) mode,
18/// only CH2 is used. In 2W (two-way) mode, the controller hops across all three
19/// channels every ~2.7ms when idle. Commands are sent on CH2; responses may arrive
20/// on any channel within the exchange wait window.
21static constexpr uint32_t FREQ_CH1 = 868250000; ///< Channel 1: 868.25 MHz (2W only)
22static constexpr uint32_t FREQ_CH2 = 868950000; ///< Channel 2: 868.95 MHz (1W and 2W, TX channel)
23static constexpr uint32_t FREQ_CH3 = 869850000; ///< Channel 3: 869.85 MHz (2W only)
24
25/// Preamble is a sequence of 0xAA bytes that precedes every frame.
26/// The first frame in an exchange uses a long preamble (1024 bytes = 8192 bits)
27/// so the receiver has time to detect it while hopping. Subsequent frames in the
28/// same exchange use a short preamble (8 bytes) since both sides are already
29/// on the same channel. Solar-powered devices need the long preamble to wake up.
30static constexpr uint16_t LONG_PREAMBLE = 1024; ///< 1024 bytes for initial/start frames
31static constexpr uint16_t SHORT_PREAMBLE = 8; ///< 8 bytes for response/continuation frames
32// Chip-specific defaults (response preamble, post-TX settle, per-chip discovery hop slices
33// for SX1262 and LR1121) live beside their TuningConfig fields in tuning_config.h; the
34// SX1262/LR1121 exchange dwell constants live in radio_sx1262.h / radio_lr1121.h respectively.
35// Kept out of the generic protocol layer per the radio-timing layering cleanup — this header
36// holds only chip-neutral protocol values.
37
38/// Timing constants for frequency hopping and response waiting.
39static constexpr int32_t HOP_TIME_US = 2700; ///< Time per channel when hopping (2.7ms)
40static constexpr int32_t RESPONSE_CHANNEL_WAIT_MS = 50; ///< Per-channel dwell while waiting for an exchange response
41static constexpr int32_t RESPONSE_WAIT_MS = 500; ///< Wait for response to non-start frame
42
43/// Wait for a response to a start frame — the first frame of an exchange, and the one a sleeping
44/// device has just been woken by.
45///
46/// This was 300 ms, *shorter* than the non-start budget above despite its own comment promising
47/// "longer". That inversion is backwards for the case it covers: a start frame is preceded by a
48/// 1024-byte (213 ms) wake-up preamble precisely because the target may have been asleep, and a
49/// device that has just woken is the slowest it will ever be to answer.
50///
51/// Field captures of a Somfy RS100 solar actuator (2026-08-14, third-party listener, three
52/// controllers on one network) measured its request→reply latency at 29 ms, 781 ms, 1548 ms,
53/// 1945 ms, 2469 ms and 3052 ms — the same device, minutes apart. A Somfy Oximo 40 on the same
54/// network answered in ~23 ms every time, day or night, and is *also* solar: reply latency is a
55/// per-model behaviour, not something the power source predicts, so there is no device class this
56/// budget can safely be tuned for. Against a 300 ms budget the RS100 was reachable only in its
57/// fastest state, which is why it answered intermittently and grew worse as the day went on.
58/// tests/corpus/captures/issues/field_rs100_pairing_key_transfer_timeout.yaml shows the same
59/// device class at 1020 ms and 1639 ms, and @ref LR1121_EXCHANGE_RESPONSE_WAIT_SLICE_MS documents
60/// a Somfy awning replying at 287 ms against the old 300 ms budget — margin that thin was already
61/// known to be a problem on a *fast* device.
62///
63/// 1000 ms restores the documented intent and covers the bulk of the observed spread without
64/// unbounded loop blocking (see ADR 0013 — the exchange blocks the ESPHome loop, and a failed
65/// exchange costs EXCHANGE_RETRY_COUNT of these). Devices slower still are reachable by raising
66/// `exchange_start_response_wait_ms` from YAML rather than by rebuilding.
67static constexpr int32_t RESPONSE_START_WAIT_MS = 1000;
68
69static constexpr int32_t RESPONSE_AUTH_WAIT_MS =
70 RESPONSE_WAIT_MS; ///< Wait for final response after challenge response
71static constexpr int32_t EXCHANGE_RETRY_DELAY_MS = 250; ///< Gap between retries within one HA command
72static constexpr uint8_t EXCHANGE_RETRY_COUNT = 3; ///< Attempts per command before reporting failure
73
74/// Listen-before-talk (LBT) parameters for ETSI EN 300 220 compliance.
75/// Before transmitting, the radio checks that the channel RSSI is below the
76/// threshold. If the channel is busy, TX is deferred by LBT_RETRY_DELAY_MS
77/// up to LBT_MAX_RETRIES times.
78static constexpr int16_t LBT_RSSI_THRESHOLD_DBM = -90; ///< Channel-free threshold (ETSI: ≤ -90 dBm)
79static constexpr uint8_t LBT_MAX_RETRIES = 5; ///< Max carrier-sense attempts before TX anyway
80static constexpr uint8_t LBT_RETRY_DELAY_MS = 5; ///< Backoff between LBT checks (≥ 5ms per ETSI)
81
82/// Canonical defaults for the chip-neutral runtime-tunable pairing/discovery parameters.
83///
84/// These are the single source of truth for the diagnostics tuning layer: `TuningConfig`
85/// initializes its fields from them, and the ESPHome YAML schema falls back to them when a
86/// key is omitted. Adjust a value here and both the compiled default and the documented
87/// YAML default follow. Chip-specific tuning defaults live in tuning_config.h instead.
88/// See @ref hioc_tuning.
89static constexpr uint16_t PAIRING_DISCOVERY_WAIT_MS = 2000; ///< Wait window after sending each discovery command.
90static constexpr uint16_t PAIRING_DISCOVERY_INITIAL_DWELL_MS = 300; ///< Dwell on CH2 before discovery hopping begins.
91static constexpr uint8_t PAIRING_KEY_EXCHANGE_RETRIES = 3; ///< Retries for the authenticated key-exchange phase.
92
93} // namespace home_io_control
94} // namespace esphome
static constexpr uint8_t PAIRING_KEY_EXCHANGE_RETRIES
Retries for the authenticated key-exchange phase.
static constexpr uint8_t LBT_MAX_RETRIES
Max carrier-sense attempts before TX anyway.
static constexpr uint32_t FREQ_CH1
The protocol uses 3 frequency channels in the 868 MHz ISM band.
static constexpr uint32_t FREQ_CH3
Channel 3: 869.85 MHz (2W only).
static constexpr int32_t HOP_TIME_US
Timing constants for frequency hopping and response waiting.
static constexpr int32_t EXCHANGE_RETRY_DELAY_MS
Gap between retries within one HA command.
static constexpr uint8_t EXCHANGE_RETRY_COUNT
Attempts per command before reporting failure.
static constexpr uint32_t FREQ_CH2
Channel 2: 868.95 MHz (1W and 2W, TX channel).
static constexpr uint16_t PAIRING_DISCOVERY_WAIT_MS
Canonical defaults for the chip-neutral runtime-tunable pairing/discovery parameters.
static constexpr uint8_t LBT_RETRY_DELAY_MS
Backoff between LBT checks (≥ 5ms per ETSI).
static constexpr uint16_t SHORT_PREAMBLE
8 bytes for response/continuation frames
static constexpr int32_t RESPONSE_WAIT_MS
Wait for response to non-start frame.
static constexpr uint16_t LONG_PREAMBLE
Preamble is a sequence of 0xAA bytes that precedes every frame.
static constexpr int32_t RESPONSE_AUTH_WAIT_MS
Wait for final response after challenge response.
static constexpr int32_t RESPONSE_CHANNEL_WAIT_MS
Per-channel dwell while waiting for an exchange response.
static constexpr int16_t LBT_RSSI_THRESHOLD_DBM
Listen-before-talk (LBT) parameters for ETSI EN 300 220 compliance.
static constexpr uint16_t PAIRING_DISCOVERY_INITIAL_DWELL_MS
Dwell on CH2 before discovery hopping begins.
static constexpr int32_t RESPONSE_START_WAIT_MS
Wait for a response to a start frame — the first frame of an exchange, and the one a sleeping device ...