|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Classes | |
| struct | ResponderContext |
| Context for one key-extraction arm cycle. More... | |
Enumerations | |
| enum class | ResponderState : uint8_t { DISARMED , ARMED_IDLE , SENT_DISCOVER_RESP , SENT_CONFIRM_ACK , SENT_CHALLENGE , EXTRACTED } |
| State machine for the device-role key-extraction responder. More... | |
Functions | |
| const char * | responder_stage_name (ResponderState state) |
| Get a short, log/telemetry-friendly name for a responder state. | |
| bool | on_discover_request (ResponderContext &ctx) |
| Decide how to react to an inbound CMD_DISCOVER_REQ (0x28) while armed. | |
| bool | on_discover_confirm (ResponderContext &ctx) |
| Decide how to react to an inbound CMD_DISCOVER_CONFIRM (0x2C) addressed to our throwaway ID. | |
| bool | on_key_init (ResponderContext &ctx, const uint8_t challenge[HMAC_SIZE], const uint8_t hub_node_id[NODE_ID_SIZE]) |
| Decide how to react to an inbound CMD_KEY_INIT (0x31) addressed to our throwaway ID. | |
| bool | on_key_transfer (ResponderContext &ctx, const uint8_t transfer_payload[AES_KEY_SIZE]) |
| Decide how to react to an inbound CMD_KEY_TRANSFER (0x32) while armed. | |
|
strong |
State machine for the device-role key-extraction responder.
Definition at line 29 of file pairing_responder.h.
| bool esphome::home_io_control::pairing_responder::on_discover_confirm | ( | ResponderContext & | ctx | ) |
Decide how to react to an inbound CMD_DISCOVER_CONFIRM (0x2C) addressed to our throwaway ID.
A hub sends 0x2C directly to a device it just discovered and, in general, will not proceed to the key exchange until that device answers with CMD_DISCOVER_CONFIRM_ACK (0x2D) — the step between discovery and key-init in a real pairing (tests/corpus/captures/velux_kux100/pairing_full.yaml, and this project's own responder answering a real hub's 0x2C in tests/corpus/captures/issues/issue_45_velux_kig300_key_extraction_success.yaml — the fixed, successful retest of issue_45_velux_kig300_key_extraction_stall.yaml's stalled session, where that same hub's 0x2C previously went unanswered). Hub strictness varies: some retry 0x2C indefinitely without it, others eventually send 0x31 anyway, which is why on_key_init() also accepts a key-init straight from SENT_DISCOVER_RESP.
Valid from SENT_DISCOVER_RESP (first confirm) and SENT_CONFIRM_ACK (a hub retry after missing our 0x2D — resend the same bare ack, nothing is regenerated). No-op from any other state: like on_discover_request(), an early-phase frame must never pull an exchange already past this point back down.
| ctx | Responder context (mutated: state only). |
Definition at line 40 of file pairing_responder.cpp.
| bool esphome::home_io_control::pairing_responder::on_discover_request | ( | ResponderContext & | ctx | ) |
Decide how to react to an inbound CMD_DISCOVER_REQ (0x28) while armed.
Valid from ARMED_IDLE (first response — replies using the throwaway ID/advertised type already stored in ctx by the caller at arm time) and SENT_DISCOVER_RESP (a hub retry — resend the same values without regenerating anything). No-op from any later state: a discovery request must never re-arm or restart an exchange already past this phase. That silence is what a real device does too — in tests/corpus/captures/velux_kux100/pairing_full.yaml the hub re-broadcasts 0x28 right after the confirm-ack and the device pointedly does not answer, before the hub moves on to the key exchange. A second, independent hub does the same thing in tests/corpus/captures/issues/issue_45_velux_kig300_key_extraction_success.yaml (re-broadcast omitted from that capture's frame list as redundant, per its own notes).
| ctx | Responder context (mutated: state only). |
Definition at line 33 of file pairing_responder.cpp.
| bool esphome::home_io_control::pairing_responder::on_key_init | ( | ResponderContext & | ctx, |
| const uint8_t | challenge[HMAC_SIZE], | ||
| const uint8_t | hub_node_id[NODE_ID_SIZE] ) |
Decide how to react to an inbound CMD_KEY_INIT (0x31) addressed to our throwaway ID.
Valid from SENT_DISCOVER_RESP and SENT_CONFIRM_ACK (first key-init: stores challenge and hub_node_id, then advances — accepted from both because not every hub waits for our 0x2D, see on_discover_confirm()) and SENT_CHALLENGE (a hub retry after missing our 0x3C — challenge is discarded and the previously-stored one is reused instead, since the hub's eventual 0x32 must be decrypted with the exact challenge bytes it actually received; SX1262's slow TX→RX turnaround makes this retry path the expected common case, not an edge case). No-op from any other state.
| ctx | Responder context (mutated: state, and on the first call challenge/hub_node_id). |
| challenge | Caller-generated 6 random bytes (crypto::generate_challenge()); only consumed on the first 0x31 of an attempt. |
| hub_node_id | The inbound frame's src (the foreign hub's real node ID). |
challenge directly — they may differ on a retry). Definition at line 47 of file pairing_responder.cpp.
| bool esphome::home_io_control::pairing_responder::on_key_transfer | ( | ResponderContext & | ctx, |
| const uint8_t | transfer_payload[AES_KEY_SIZE] ) |
Decide how to react to an inbound CMD_KEY_TRANSFER (0x32) while armed.
Valid only from SENT_CHALLENGE. Recovers the system key from transfer_payload using ctx.challenge via recover_system_key_from_transfer() (proto_commands.h) and, on success, transitions to EXTRACTED. No-op (state unchanged) from any other state, or if decoding fails.
| ctx | Responder context (mutated: state, and on success recovered_key). |
| transfer_payload | 16-byte CMD_KEY_TRANSFER payload (frame.data). |
Definition at line 61 of file pairing_responder.cpp.
| const char * esphome::home_io_control::pairing_responder::responder_stage_name | ( | ResponderState | state | ) |
Get a short, log/telemetry-friendly name for a responder state.
| state | Responder state. |
Definition at line 15 of file pairing_responder.cpp.