|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Encapsulates hub-level management operations exposed as Home Assistant actions. More...
#include <management_actions.h>
Public Member Functions | |
| ManagementActions (const uint8_t *node_id, const uint8_t *system_key, const TuningConfig *tuning, ExchangeEngine &engine, DeviceRegistry ®istry, const bool *initialized, IOHomeControlComponent *hub) | |
| Construct with all required collaborators. | |
| ManagementActions (const ManagementActions &)=delete | |
| Non-copyable — stores references and pointers into hub member addresses. | |
| ManagementActions & | operator= (const ManagementActions &)=delete |
| void | register_actions () |
| Register all management actions (rename, identify, force-open, ...) with ESPHome's native API server. | |
| void | api_rename_device (const std::string &device_id, const std::string &new_name) |
| Native API callback: rename a device and publish the result as a HA event. | |
| ManagementActionResult | rename_device (const std::string &device_id, const std::string &new_name) |
| Rename a registered device and verify the result by reading the name back. | |
| void | api_identify_device (const std::string &device_id) |
| Native API callback: trigger a device's physical identify and publish the result as a HA event. | |
| ManagementActionResult | identify_device (const std::string &device_id) |
| Trigger a registered device's physical identify (brief jog/flash). | |
| void | api_force_open_device (const std::string &device_id) |
| Native API callback: force-open a device and publish the result as a HA event. | |
| ManagementActionResult | force_open_device (const std::string &device_id) |
| Move a registered cover device to fully open at elevated priority, intended to bypass wind/rain soft locks. | |
| void | api_scan_paired_devices () |
| Native API callback: run a roll-call scan and publish the result as a HA event. | |
| ManagementActionResult | scan_paired_devices () |
| Broadcast a roll-call and report every device that answers. | |
| void | publish_result (const ManagementActionResult &result) |
| Publish a management result as one or more structured log lines (one call per line of result.message, see log_multiline_result() in the .cpp) and a Home Assistant event. | |
Encapsulates hub-level management operations exposed as Home Assistant actions.
ManagementActions is constructed once by IOHomeControlComponent. It stores pointers and references into hub members; it is non-copyable for the same reason as ExchangeEngine.
Definition at line 52 of file management_actions.h.
| esphome::home_io_control::ManagementActions::ManagementActions | ( | const uint8_t * | node_id, |
| const uint8_t * | system_key, | ||
| const TuningConfig * | tuning, | ||
| ExchangeEngine & | engine, | ||
| DeviceRegistry & | registry, | ||
| const bool * | initialized, | ||
| IOHomeControlComponent * | hub ) |
Construct with all required collaborators.
| node_id | Controller 3-byte node ID, owned by the hub. |
| system_key | Controller 16-byte AES system key, owned by the hub. Only scan_paired_devices() uses this — it builds a self-authenticating CMD_DISCOVER_SPE_REQ itself, unlike rename/identify/force-open, which authenticate through ExchangeEngine's challenge-response. |
| tuning | Runtime tuning config, owned by the hub. Only scan_paired_devices() uses this — it reuses pairing_discovery_wait_ms as the listen window for each of its own per-channel attempts. |
| engine | Shared exchange engine for radio transactions. |
| registry | Device registry for device lookups. |
| initialized | Pointer to the hub's initialized flag. |
| hub | Hub pointer for ESPHome API calls and public hub methods. |
Definition at line 226 of file management_actions.cpp.
|
delete |
Non-copyable — stores references and pointers into hub member addresses.
| void esphome::home_io_control::ManagementActions::api_force_open_device | ( | const std::string & | device_id | ) |
Native API callback: force-open a device and publish the result as a HA event.
Definition at line 433 of file management_actions.cpp.
| void esphome::home_io_control::ManagementActions::api_identify_device | ( | const std::string & | device_id | ) |
Native API callback: trigger a device's physical identify and publish the result as a HA event.
Definition at line 391 of file management_actions.cpp.
| void esphome::home_io_control::ManagementActions::api_rename_device | ( | const std::string & | device_id, |
| const std::string & | new_name ) |
Native API callback: rename a device and publish the result as a HA event.
Definition at line 294 of file management_actions.cpp.
| void esphome::home_io_control::ManagementActions::api_scan_paired_devices | ( | ) |
Native API callback: run a roll-call scan and publish the result as a HA event.
Definition at line 457 of file management_actions.cpp.
| ManagementActionResult esphome::home_io_control::ManagementActions::force_open_device | ( | const std::string & | device_id | ) |
Move a registered cover device to fully open at elevated priority, intended to bypass wind/rain soft locks.
Safety-sensitive: this deliberately requires an explicit device_id (a hub-level action, not a permanent per-device button) because it can override legitimate environmental protection. Queues the command onto the hub's normal cover-command dispatch path (IOHomeControlComponent::queue_device_command()), which already owns capability gating, poll tracking, and backoff — this method does not talk to the radio directly. The result therefore only confirms that the command was queued; the actual movement outcome arrives later via the device's normal cover-state/polling pipeline, so verified is always false.
| device_id | Target device ID (hex string, case-insensitive). |
Definition at line 437 of file management_actions.cpp.
| ManagementActionResult esphome::home_io_control::ManagementActions::identify_device | ( | const std::string & | device_id | ) |
Trigger a registered device's physical identify (brief jog/flash).
Deliberately performs no device-type gating beyond "is it registered on this hub" — identify exists precisely to let a user work out what an unknown registry entry physically is, so restricting it to specific device types would defeat the purpose. A CMD_ERROR_RESP reply is treated as a successful trigger (not a failure): per the protocol, devices may answer an identify request that way and still perform the jog.
| device_id | Target device ID (hex string, case-insensitive). |
Definition at line 395 of file management_actions.cpp.
|
delete |
| void esphome::home_io_control::ManagementActions::publish_result | ( | const ManagementActionResult & | result | ) |
Publish a management result as one or more structured log lines (one call per line of result.message, see log_multiline_result() in the .cpp) and a Home Assistant event.
Definition at line 298 of file management_actions.cpp.
| void esphome::home_io_control::ManagementActions::register_actions | ( | ) |
Register all management actions (rename, identify, force-open, ...) with ESPHome's native API server.
Definition at line 237 of file management_actions.cpp.
| ManagementActionResult esphome::home_io_control::ManagementActions::rename_device | ( | const std::string & | device_id, |
| const std::string & | new_name ) |
Rename a registered device and verify the result by reading the name back.
| device_id | Target device ID (hex string, case-insensitive). |
| new_name | Requested UTF-8 device name. |
Definition at line 329 of file management_actions.cpp.
| ManagementActionResult esphome::home_io_control::ManagementActions::scan_paired_devices | ( | ) |
Broadcast a roll-call and report every device that answers.
Not a discovery mechanism for new devices: only devices that already hold this hub's system key answer a CMD_DISCOVER_SPE_REQ (the 0x2A payload is self-authenticating — 6 random bytes plus a 6-byte HMAC over the command byte, computed with system_key_), so a device that has never paired with this hub stays silent. See tests/corpus/captures/somfy_awning/discover_spe_paired_rollcall.yaml for a captured exchange. Never writes DeviceRegistry — every responder is only looked up, never registered; an unknown responder usually means a device paired earlier whose YAML config was never saved, not an intruder. result.device_id stays empty (there is no single target) and verified stays false (nothing here is read back). success is true whenever the broadcast went out, including with zero replies — "nothing answered" is a valid result, not a failure. result.message carries the full multi-line report: a header line (devices detected, how many known vs. unknown), then a Known: section followed by an Unknown: section (either omitted if empty) — known responders get a summary line each, unknown responders additionally get a lead-in sentence and a ready-to-paste YAML block. Devices are grouped by known/unknown rather than left in arrival order, since the two groups need different follow-up and interleaving them made an unknown responder easy to miss between known ones. At most SCAN_MAX_REPLIES distinct responders are reported; if more answer, the report says so explicitly rather than quietly listing a subset.
Transmits the request once per channel (CH2, then CH1, then CH3), each with its own full pairing_discovery_wait_ms listen window, merging distinct responders across attempts — a paired device only hears the broadcast if it happens to be awake on the channel the hub transmits on at that instant, and real hardware testing found that single-channel duty-cycling paired devices are not reliably caught by a one-shot broadcast. A responder that answers more than one attempt still appears exactly once. Each attempt is a single transmit followed by its own window, never back-to-back transmits, so it does not reintroduce the different failure mode a 3-channel-burst transmit caused elsewhere: firing three long-preamble transmits back-to-back with no listening in between blew through the tight per-try response wait windows and broke exchanges in both directions (see IOHomeControlComponent::broadcast_key_extraction_reply_()'s doc comment).
This still blocks the caller for the full three-window duration (roughly 3 × pairing_discovery_wait_ms, ~6 s at the 2000 ms default) and therefore trips ESPHome's "operation took a long time" warning on every invocation. That warning uses a per-component ratchet (Component::should_warn_of_blocking()): it starts at 50 ms and, each time it fires, raises its own threshold to the observed duration plus a margin — but the threshold is stored in centiseconds in a uint8_t, so it saturates at 2550 ms. Anything that blocks longer than that can never ratchet out of warning range.
Accepting that is a deliberate tradeoff (confirmed on real hardware 2026-08-10). A shorter fixed window (500 ms/attempt, ~2.4 s total) was tried: it would have gone quiet after one warning, since 2.4 s sits under the 2550 ms cap — but it also caused real, correctly-decoded replies from registered devices to arrive after the window had already closed, where the passive path drops them (hub_status.cpp's unhandled_cmd catch-all). Losing devices from the report is worse than a recurring log line, so the long window won. Getting both would require restructuring this action to run across multiple scheduled loop() ticks so no single blocking unit approaches 2550 ms — not done here.
Definition at line 541 of file management_actions.cpp.