Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
hub_names.py
Go to the documentation of this file.
1## @file
2## @brief Shared vocabulary of the Home IO Control codegen: YAML keys and generated C++ handles.
3## @ingroup hioc_codegen
4##
5## The ``CONF_*`` keys of the ``home_io_control:`` block and its ``oneway_controllers:`` /
6## ``lr1121_firmware_update:`` sub-blocks (tuning.py keeps the ``tuning:`` keys), the
7## ``home_io_control`` C++ namespace, and the class/enum handles of the hub and of the
8## hub-level entities it generates. The other codegen modules import from here; this
9## module imports none of them.
10
11import esphome.codegen as cg
12from esphome.components import spi
13# Aliased: this package has its own switch.py/button.py platform submodules, so the real ESPHome
14# components are always imported under names that cannot be mistaken for them. In the package's
15# __init__.py an unaliased `switch`/`button` would even be overwritten: __init__.py's namespace IS
16# the package object, the slot ESPHome's loader binds `esphome.components.home_io_control.switch`
17# into when it imports our platform file, so whichever import ran last would silently win.
18from esphome.components import button as button_component
19from esphome.components import switch as switch_component
20from esphome.components import text_sensor as text_sensor_component
21
22
23CONF_HOME_IO_CONTROL_ID = "home_io_control_id"
24CONF_RST_PIN = "rst_pin"
25CONF_DIO0_PIN = "dio0_pin"
26CONF_DIO4_PIN = "dio4_pin"
27CONF_DIO1_PIN = "dio1_pin"
28CONF_BUSY_PIN = "busy_pin"
29CONF_NODE_ID = "node_id"
30CONF_SYSTEM_KEY = "system_key"
31CONF_TX_POWER = "tx_power"
32CONF_PA_PIN = "pa_pin"
33CONF_RADIO_TYPE = "radio_type"
34CONF_FEM_EN_PIN = "fem_en_pin"
35CONF_VFEM_PIN = "vfem_pin"
36CONF_FEM_PA_PIN = "fem_pa_pin"
37# Which RF front-end part fem_pa_pin (and, for the parts that have one, fem_en_pin) is wired to
38# (ADR 0035) -- selects the driver's per-transmission switching behaviour and which pins that
39# behaviour requires; never supplies a pin number itself. See FEM_REQUIRED_PINS in hub_validators.py.
40# ("Part", not "chip" -- see FEM_PROFILES' own comment there for why.)
41CONF_FEM = "fem"
42CONF_TCXO_VOLTAGE = "tcxo_voltage"
43CONF_EXPOSED_SENDERS = "exposed_senders"
44CONF_ACCEPT_FOREIGN_PAIRING = "accept_foreign_pairing"
45CONF_RECOVER_ONEWAY_KEY = "recover_oneway_key"
46CONF_SCAN_PAIRED_DEVICES_BUTTON = "scan_paired_devices_button"
47CONF_DISCOVER_AND_PAIR_BUTTON = "discover_and_pair_button"
48CONF_ONEWAY_CONTROLLERS = "oneway_controllers"
49# Internal marker recording that an identity's node_id was derived rather than configured, so
50# validation errors and the boot log can say which it was.
51CONF_NODE_ID_DERIVED = "_node_id_derived"
52CONF_MANUFACTURER = "manufacturer"
53# Same YAML key as platform_common.py's CONF_DEVICE_TYPE, spelled here rather than imported:
54# platform_common imports from this package, whose modules import this one, so the dependency
55# cannot run the other way.
56CONF_IO_DEVICE_TYPE = "io_device_type"
57CONF_INITIAL_SEQUENCE = "initial_sequence"
58CONF_COMMANDS = "commands"
59# Per-identity 1W wire overrides (ADR 0031). execute_acei: overrides the manufacturer-derived
60# ACEI byte for CMD_EXECUTE; execute_broadcast: all|typed picks the all-devices (00 00 3F) vs
61# typed-class destination — a handheld-remote-vs-class-bound axis, not a vendor axis.
62CONF_EXECUTE_ACEI = "execute_acei"
63CONF_EXECUTE_BROADCAST = "execute_broadcast"
64# The build flag for this identity's "Enroll 1W Controller" button. Presence/absence is the whole
65# gate -- adding or removing this line and reflashing is the enrollment feature's entire
66# lifecycle, same shape as accept_foreign_pairing/recover_oneway_key.
67CONF_ENROLLMENT = "enrollment"
68# Whether the "Enroll 1W Controller" button's 0x30 carries a trailing MAC. Only meaningful with
69# enrollment: true -- see ONEWAY_CONTROLLER_SCHEMA's own comment and create_1w_add_controller()'s
70# @warning (proto_commands.h) for why real hardware disagrees on this byte.
71CONF_ENROLLMENT_WITH_MAC = "enrollment_with_mac"
72# Override for the device classes a VELUX enrollment 0x30 sweep targets. Unset -> the manufacturer
73# profile's list (velux: {roller_shutter, vertical_exterior_awning, dual_roller_shutter}). Ignored by the somfy gesture.
74# See resolve_oneway_wire_profile() / effective_enrollment_classes() (oneway_controller.h), ADR 0032.
75CONF_ENROLLMENT_CLASSES = "enrollment_classes"
76# Same YAML key as platform_common.py's per-device 2W low_power (ADR 0029), tri-state here: unset
77# keeps every 1W burst in the legacy shape (LONG_PREAMBLE on every copy, CTRL1 0x00); `false`/`true`
78# opt an identity into the ADR 0038 shapes instead. One definition, shared: platform_common.py
79# imports this constant rather than keeping its own copy. See ONEWAY_CONTROLLER_SCHEMA's own
80# comment on this key for the full tri-state semantics, and ADR 0038.
81CONF_LOW_POWER = "low_power"
82# Injected at schema time, never user-supplied: the generated buttons' IDs and the identity's
83# diagnostic sensor ID (ADR 0009).
84CONF_BUTTON_IDS = "button_ids"
85CONF_LAST_COMMAND_SENSOR_ID = "last_command_sensor_id"
86# Only present when enrollment: true (ADR 0009 -- an ID created late in to_code() is silently
87# dropped at runtime).
88CONF_ENROLL_BUTTON_ID = "_enroll_button_id"
89CONF_DIAGNOSTIC_PROBES = "diagnostic_probes"
90CONF_LR1121_FIRMWARE_UPDATE = "lr1121_firmware_update"
91CONF_LR1121_BOOTLOADER = "bootloader"
92CONF_CHECKSUM_MD5 = "checksum_md5"
93CONF_TARGET_VERSION = "target_version"
94MIN_STATUS_POLL_INTERVAL_MS = 500
95MIN_RAIN_SENSOR_POLL_INTERVAL_MS = 60000
96
97# Internal config key for the "Accept Foreign Pairing" companion switch ID (injected by
98# post-validator, same pattern as tuning.py's companion entity IDs — ESPHome 2026.x sizes the
99# runtime component vector from IDs known at the end of schema validation, so a companion
100# entity created only in to_code() would silently drop; see tuning.py::_inject_tuning_companion_ids
101# for the fuller rationale).
102CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID = "_accept_foreign_pairing_switch_id"
103# Internal config key for the "Recover 1W Controller Key" companion switch ID (injected by
104# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
105CONF_RECOVER_ONEWAY_KEY_SWITCH_ID = "_recover_oneway_key_switch_id"
106# Internal config key for the "Flash LR1121 Radio Firmware" companion button ID (injected by
107# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
108CONF_LR1121_FIRMWARE_UPDATE_BUTTON_ID = "_lr1121_firmware_update_button_id"
109# Internal config key for the "Scan Paired Devices" companion button ID (injected by
110# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
111CONF_SCAN_PAIRED_DEVICES_BUTTON_ID = "_scan_paired_devices_button_id"
112# Internal config key for the "Discover & Pair" button ID (injected by post-validator; same
113# rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
114CONF_DISCOVER_AND_PAIR_BUTTON_ID = "_discover_and_pair_button_id"
115# Internal config key for the "Last Pairing Result" companion sensor ID that ships with the button
116# above (injected by the same post-validator, gated on the same flag). Deliberately NOT shared
117# with button.py's identically-purposed CONF_PAIRING_RESULT_SENSOR_ID: during the deprecation
118# window (see button.py) both exist, keying different config dicts -- the hub block here, vs. a
119# legacy button: entry there.
120CONF_DISCOVER_AND_PAIR_RESULT_SENSOR_ID = "_discover_and_pair_result_sensor_id"
121# Internal config key for the "Allow LR1121 Bootloader Rewrite (Irreversible)" companion switch ID
122# (injected by post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above --
123# only present when lr1121_firmware_update.bootloader: is configured).
124CONF_LR1121_BOOTLOADER_SWITCH_ID = "_lr1121_bootloader_switch_id"
125
126home_io_control_ns = cg.esphome_ns.namespace("home_io_control")
127IOHomeControlComponent = home_io_control_ns.class_(
128 "IOHomeControlComponent", cg.Component, spi.SPIDevice
129)
130# Hub-level "Recover System Key" switch (key extraction, key_extraction_responder.cpp /
131# platform_hub_controls.h). Deliberately NOT exposed via a `switch:` platform entry: earlier
132# revisions dispatched on the presence/absence of `io_device_id` within switch.py, which meant an
133# ordinary device-bound switch missing `io_device_id` by mistake would silently become this
134# security-sensitive switch instead of failing validation. Gating it behind this boolean (created
135# dynamically, like the `tuning:` UI controls) makes that class of mistake structurally
136# impossible: there is no shared schema for the two to be confused under.
137IOHomeAcceptForeignPairingSwitch = home_io_control_ns.class_(
138 "IOHomeAcceptForeignPairingSwitch", switch_component.Switch, cg.Component
139)
140# Hub-level "Recover 1W Controller Key" switch (key adoption, oneway_key_adoption.cpp /
141# platform_hub_controls.h). Same dynamically-created, hub-bound shape and rationale as the switch
142# above. Independent of accept_foreign_pairing — the two arm different listeners (2W pairing
143# responder vs. 1W add-controller broadcast).
144IOHomeRecoverOneWayKeySwitch = home_io_control_ns.class_(
145 "IOHomeRecoverOneWayKeySwitch", switch_component.Switch, cg.Component
146)
147# Hub-level "Flash LR1121 Radio Firmware" button (lr1121_firmware_update_controller.cpp /
148# platform_lr1121_controls.h). Same "created dynamically from a home_io_control: sub-block, not a
149# device-bound platform entry" shape as the switch above — there is no `io_device_id` to bind this
150# to, it targets the hub's own radio.
151IOHomeLr1121FirmwareUpdateButton = home_io_control_ns.class_(
152 "IOHomeLr1121FirmwareUpdateButton", button_component.Button, cg.Component
153)
154# Hub-level "Scan Paired Devices" button (management_actions.cpp / platform_hub_controls.h). An
155# additional trigger for the already-registered `scan_paired_devices` native API action, which is
156# unchanged. Same "created dynamically from the home_io_control: block" shape as the entities
157# above -- there is no `io_device_id` to bind a roll-call to.
158IOHomeScanPairedDevicesButton = home_io_control_ns.class_(
159 "IOHomeScanPairedDevicesButton", button_component.Button, cg.Component
160)
161# Hub-level "Discover & Pair" button and its companion "Last Pairing Result" diagnostic sensor
162# (platform_hub_controls.h). Created from `home_io_control.discover_and_pair_button: true`, the
163# same shape as the entity above. Declared here (rather than in button.py, which historically owned
164# both) because the deprecated `button:` platform (button.py) also still instantiates them for the
165# duration of its deprecation window and imports both names from the package.
166IOHomeDiscoverButton = home_io_control_ns.class_(
167 "IOHomeDiscoverButton", button_component.Button, cg.Component
168)
169IOHomePairingResultTextSensor = home_io_control_ns.class_(
170 "IOHomePairingResultTextSensor", text_sensor_component.TextSensor, cg.Component
171)
172# Generated 1W command buttons and their per-identity diagnostic sensor
173# (platform_oneway_entities.h). Created from the `oneway_controllers:` block, never a `button:`
174# entry, for the same reason as the switch above.
175IOHomeOneWayCommandButton = home_io_control_ns.class_(
176 "IOHomeOneWayCommandButton", button_component.Button, cg.Component
177)
178IOHomeOneWayLastCommandTextSensor = home_io_control_ns.class_(
179 "IOHomeOneWayLastCommandTextSensor", text_sensor_component.TextSensor, cg.Component
180)
181# Generated 1W enrollment button (platform_oneway_entities.h), one per identity with
182# `enrollment: true`. Same "created from the hub block, never a `button:` entry" reasoning as
183# IOHomeOneWayCommandButton above -- see that class's comment.
184IOHomeOneWayEnrollButton = home_io_control_ns.class_(
185 "IOHomeOneWayEnrollButton", button_component.Button, cg.Component
186)
187OneWayButtonAction = home_io_control_ns.enum("OneWayButtonAction", is_class=True)
188
189
190# Hub-level "Allow LR1121 Bootloader Rewrite (Irreversible)" arming switch
191# (lr1121_firmware_update_controller.cpp / platform_lr1121_controls.h). Same dynamically-created,
192# hub-bound shape as the two entities above; created only when lr1121_firmware_update.bootloader:
193# is configured (see _create_lr1121_bootloader_update()).
194IOHomeLr1121BootloaderRewriteSwitch = home_io_control_ns.class_(
195 "IOHomeLr1121BootloaderRewriteSwitch", switch_component.Switch, cg.Component
196)