Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
platform_lr1121_controls.h
Go to the documentation of this file.
1#pragma once
2
3/// @file platform_lr1121_controls.h
4/// @brief Hub-level LR1121 firmware-update entities: the transceiver-flash button and the
5/// bootloader-rewrite arming switch.
6/// @ingroup hioc_platforms
7///
8/// Both are hub-level, not device-bound — there is no `io_device_id` to bind to, they target the
9/// hub's own radio (created from the `home_io_control:` block for the shared reason, see
10/// HubBoundEntity in platform_entity_base.h). They are created dynamically from the presence of
11/// `home_io_control.lr1121_firmware_update:` (the button, behind IOHOME_LR1121_FIRMWARE_UPDATE)
12/// and its `bootloader:` sub-block (the switch, behind IOHOME_LR1121_BOOTLOADER_UPDATE); see
13/// `__init__.py`'s `_create_lr1121_firmware_update()` / `_create_lr1121_bootloader_update()`.
14/// The bootloader define is only ever added from inside the firmware-update path, so it implies
15/// IOHOME_LR1121_FIRMWARE_UPDATE and the two guards nest.
16
17// IOHOME_LR1121_FIRMWARE_UPDATE / IOHOME_LR1121_BOOTLOADER_UPDATE are only visible after
18// something pulls in esphome/core/defines.h (via hub_core.h's own #include "esphome/core/hal.h")
19// — these #includes must run before the #ifdef check, not after (see
20// radio_lr1121_firmware_updater.h for the fuller explanation of why this ordering matters and how
21// it stayed invisible in host unit tests).
22#include "esphome/components/button/button.h"
23#include "esphome/components/switch/switch.h"
24#include "hub_core.h"
26
27#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
28
29namespace esphome {
30namespace home_io_control {
31
32/// @brief Hub-level button entity: press dispatches to
33/// IOHomeControlComponent::trigger_lr1121_firmware_update().
34///
35/// See lr1121_firmware_update_controller.cpp for what a press actually does — every rejection path
36/// is a cached-verdict log, not a fresh bootloader entry. Once a press does proceed, ADR 0020's
37/// invariant applies: every exit after a bootloader excursion reboots the ESP32.
38/// @ingroup hioc_platforms
39class IOHomeLr1121FirmwareUpdateButton : public button::Button, public Component, public HubBoundEntity {
40 public:
41 void dump_config() override {}
42
43 protected:
44 /// @brief When pressed, hand off to the hub — see lr1121_firmware_update_controller.cpp for the
45 /// full guard/decision/flash sequence.
46 void press_action() override { this->parent_->trigger_lr1121_firmware_update(); }
47};
48
49#ifdef IOHOME_LR1121_BOOTLOADER_UPDATE
50
51/// @brief Hub-level switch entity: ON permits the next flash-button press to run the three-stage
52/// bootloader-rewrite sequence (when the cached verdict is AVAILABLE); OFF (the default, and the
53/// restore-on-boot state -- `ALWAYS_OFF`) refuses it. No auto-off timer: see ADR 0021 for why the
54/// window is already self-limiting.
55///
56/// This is a *permission*, not the two-press "armed" confirmation used elsewhere in this
57/// component (`lr1121_flash_confirmation_armed_`) -- see ADR 0021 for why an arming switch
58/// (visible in Home Assistant, so "is this armed?" is answerable by looking) was chosen over
59/// another invisible two-press window for the one operation in this component with no undo. It
60/// can only convert a cached `BootloaderUpgradePath::AVAILABLE` verdict into "run the three-stage
61/// sequence"; it never affects any other verdict or guard (see
62/// IOHomeControlComponent::set_bootloader_rewrite_allowed()).
63/// @ingroup hioc_platforms
64class IOHomeLr1121BootloaderRewriteSwitch : public switch_::Switch, public Component, public HubBoundEntity {
65 public:
66 /// @brief Publish the initial OFF state.
67 ///
68 /// Unlike the arming switches, this switch has no auto-off timer, so the hub never changes the
69 /// permission on its own and there is no state to push back -- but an entity that has never
70 /// published reads as *unknown* in Home Assistant, and a safety control whose whole
71 /// justification is "is this armed? answerable by looking" (ADR 0021) must not render blank.
72 /// Publishing false also makes the configured ALWAYS_OFF restore behaviour observable rather
73 /// than merely implied. Publishing does not call write_state(), so this never touches the hub.
74 void setup() override;
75
76 /// @brief Dump configuration to the log.
77 void dump_config() override;
78
79 /// @brief Get setup priority so the parent hub is available first.
80 /// @return setup_priority::DATA.
81 [[nodiscard]] float get_setup_priority() const override { return setup_priority::DATA; }
82
83 protected:
84 /// @brief Forward the toggle to the hub as a permission -- see
85 /// IOHomeControlComponent::set_bootloader_rewrite_allowed().
86 /// @param state Desired switch state.
87 void write_state(bool state) override;
88};
89
90#endif // IOHOME_LR1121_BOOTLOADER_UPDATE
91
92} // namespace home_io_control
93} // namespace esphome
94
95#endif // IOHOME_LR1121_FIRMWARE_UPDATE
Mixin for entities bound to the hub itself rather than to one device.
IO-Homecontrol ESPHome component — protocol controller.
IOHomeLr1121BootloaderRewriteSwitch
Definition __init__.py:197
IOHomeLr1121FirmwareUpdateButton
Definition __init__.py:157
Shared device-binding mixins for IO-Homecontrol entity platforms.