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# Shared by the cover platform (2W display inversion) and the 1W controller identity (wire
83# mirroring of OPEN/CLOSE/position). Defined here because platform modules and hub modules both
84# import from this leaf, and the yaml-emitter sync check resolves hub key constants from it.
85CONF_INVERT_POSITION = "invert_position"
86# Injected at schema time, never user-supplied: the generated buttons' IDs and the identity's
87# diagnostic sensor ID (ADR 0009).
88CONF_BUTTON_IDS = "button_ids"
89CONF_LAST_COMMAND_SENSOR_ID = "last_command_sensor_id"
90# Only present when enrollment: true (ADR 0009 -- an ID created late in to_code() is silently
91# dropped at runtime).
92CONF_ENROLL_BUTTON_ID = "_enroll_button_id"
93CONF_DIAGNOSTIC_PROBES = "diagnostic_probes"
94CONF_LR1121_FIRMWARE_UPDATE = "lr1121_firmware_update"
95CONF_LR1121_BOOTLOADER = "bootloader"
96CONF_CHECKSUM_MD5 = "checksum_md5"
97CONF_TARGET_VERSION = "target_version"
98MIN_STATUS_POLL_INTERVAL_MS = 500
99MIN_RAIN_SENSOR_POLL_INTERVAL_MS = 60000
100MIN_SUN_LEVEL_POLL_INTERVAL_MS = 60000
101MIN_BATTERY_LEVEL_POLL_INTERVAL_MS = 60000
102MIN_STATUS_REFRESH_INTERVAL_MS = 60000
103
104# Internal config key for the "Accept Foreign Pairing" companion switch ID (injected by
105# post-validator, same pattern as tuning.py's companion entity IDs — ESPHome 2026.x sizes the
106# runtime component vector from IDs known at the end of schema validation, so a companion
107# entity created only in to_code() would silently drop; see tuning.py::_inject_tuning_companion_ids
108# for the fuller rationale).
109CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID = "_accept_foreign_pairing_switch_id"
110# Internal config key for the "Recover 1W Controller Key" companion switch ID (injected by
111# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
112CONF_RECOVER_ONEWAY_KEY_SWITCH_ID = "_recover_oneway_key_switch_id"
113# Internal config key for the "Flash LR1121 Radio Firmware" companion button ID (injected by
114# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
115CONF_LR1121_FIRMWARE_UPDATE_BUTTON_ID = "_lr1121_firmware_update_button_id"
116# Internal config key for the "Scan Paired Devices" companion button ID (injected by
117# post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
118CONF_SCAN_PAIRED_DEVICES_BUTTON_ID = "_scan_paired_devices_button_id"
119# Internal config key for the "Discover & Pair" button ID (injected by post-validator; same
120# rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
121CONF_DISCOVER_AND_PAIR_BUTTON_ID = "_discover_and_pair_button_id"
122# Internal config key for the "Last Pairing Result" companion sensor ID that ships with the button
123# above (injected by the same post-validator, gated on the same flag).
124CONF_DISCOVER_AND_PAIR_RESULT_SENSOR_ID = "_discover_and_pair_result_sensor_id"
125# Internal config key for the "Last Device Event" diagnostic sensor ID (injected by post-validator,
126# gated on `diagnostic_probes: true`; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above).
127CONF_DEVICE_EVENT_SENSOR_ID = "_device_event_sensor_id"
128# Internal config key for the "Allow LR1121 Bootloader Rewrite (Irreversible)" companion switch ID
129# (injected by post-validator; same rationale as CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID above --
130# only present when lr1121_firmware_update.bootloader: is configured).
131CONF_LR1121_BOOTLOADER_SWITCH_ID = "_lr1121_bootloader_switch_id"
132
133home_io_control_ns = cg.esphome_ns.namespace("home_io_control")
134IOHomeControlComponent = home_io_control_ns.class_(
135 "IOHomeControlComponent", cg.Component, spi.SPIDevice
136)
137# Hub-level "Recover System Key" switch (key extraction, key_extraction_responder.cpp /
138# platform_hub_controls.h). Deliberately NOT exposed via a `switch:` platform entry: earlier
139# revisions dispatched on the presence/absence of `io_device_id` within switch.py, which meant an
140# ordinary device-bound switch missing `io_device_id` by mistake would silently become this
141# security-sensitive switch instead of failing validation. Gating it behind this boolean (created
142# dynamically, like the `tuning:` UI controls) makes that class of mistake structurally
143# impossible: there is no shared schema for the two to be confused under.
144IOHomeAcceptForeignPairingSwitch = home_io_control_ns.class_(
145 "IOHomeAcceptForeignPairingSwitch", switch_component.Switch, cg.Component
146)
147# Hub-level "Recover 1W Controller Key" switch (key adoption, oneway_key_adoption.cpp /
148# platform_hub_controls.h). Same dynamically-created, hub-bound shape and rationale as the switch
149# above. Independent of accept_foreign_pairing — the two arm different listeners (2W pairing
150# responder vs. 1W add-controller broadcast).
151IOHomeRecoverOneWayKeySwitch = home_io_control_ns.class_(
152 "IOHomeRecoverOneWayKeySwitch", switch_component.Switch, cg.Component
153)
154# Hub-level "Flash LR1121 Radio Firmware" button (lr1121_firmware_update_controller.cpp /
155# platform_lr1121_controls.h). Same "created dynamically from a home_io_control: sub-block, not a
156# device-bound platform entry" shape as the switch above — there is no `io_device_id` to bind this
157# to, it targets the hub's own radio.
158IOHomeLr1121FirmwareUpdateButton = home_io_control_ns.class_(
159 "IOHomeLr1121FirmwareUpdateButton", button_component.Button, cg.Component
160)
161# Hub-level "Scan Paired Devices" button (management_actions.cpp / platform_hub_controls.h). An
162# additional trigger for the already-registered `scan_paired_devices` native API action, which is
163# unchanged. Same "created dynamically from the home_io_control: block" shape as the entities
164# above -- there is no `io_device_id` to bind a roll-call to.
165IOHomeScanPairedDevicesButton = home_io_control_ns.class_(
166 "IOHomeScanPairedDevicesButton", button_component.Button, cg.Component
167)
168# Hub-level "Discover & Pair" button and its companion "Last Pairing Result" diagnostic sensor
169# (platform_hub_controls.h). Created from `home_io_control.discover_and_pair_button: true`, the
170# same shape as the entity above.
171IOHomeDiscoverButton = home_io_control_ns.class_(
172 "IOHomeDiscoverButton", button_component.Button, cg.Component
173)
174IOHomePairingResultTextSensor = home_io_control_ns.class_(
175 "IOHomePairingResultTextSensor", text_sensor_component.TextSensor, cg.Component
176)
177# Hub-level diagnostic text sensor showing the last recorded device event (platform_hub_controls.h).
178IOHomeDeviceEventTextSensor = home_io_control_ns.class_(
179 "IOHomeDeviceEventTextSensor", text_sensor_component.TextSensor, cg.Component
180)
181# Generated 1W command buttons and their per-identity diagnostic sensor
182# (platform_oneway_entities.h). Created from the `oneway_controllers:` block, never a `button:`
183# entry, for the same reason as the switch above.
184IOHomeOneWayCommandButton = home_io_control_ns.class_(
185 "IOHomeOneWayCommandButton", button_component.Button, cg.Component
186)
187IOHomeOneWayLastCommandTextSensor = home_io_control_ns.class_(
188 "IOHomeOneWayLastCommandTextSensor", text_sensor_component.TextSensor, cg.Component
189)
190# Generated 1W enrollment button (platform_oneway_entities.h), one per identity with
191# `enrollment: true`. Same "created from the hub block, never a `button:` entry" reasoning as
192# IOHomeOneWayCommandButton above -- see that class's comment.
193IOHomeOneWayEnrollButton = home_io_control_ns.class_(
194 "IOHomeOneWayEnrollButton", button_component.Button, cg.Component
195)
196OneWayButtonAction = home_io_control_ns.enum("OneWayButtonAction", is_class=True)
197
198
199# Hub-level "Allow LR1121 Bootloader Rewrite (Irreversible)" arming switch
200# (lr1121_firmware_update_controller.cpp / platform_lr1121_controls.h). Same dynamically-created,
201# hub-bound shape as the two entities above; created only when lr1121_firmware_update.bootloader:
202# is configured (see _create_lr1121_bootloader_update()).
203IOHomeLr1121BootloaderRewriteSwitch = home_io_control_ns.class_(
204 "IOHomeLr1121BootloaderRewriteSwitch", switch_component.Switch, cg.Component
205)