11import esphome.codegen
as cg
12import esphome.config_validation
as cv
14from esphome.components
import button
as button_component
15from esphome.components
import switch
as switch_component
16from esphome.components
import text_sensor
as text_sensor_component
17from esphome.const
import (
20 ENTITY_CATEGORY_CONFIG,
21 ENTITY_CATEGORY_DIAGNOSTIC,
23from esphome.core
import ID
25from .hub_names
import (
26 CONF_ACCEPT_FOREIGN_PAIRING,
27 CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID,
28 CONF_DEVICE_EVENT_SENSOR_ID,
29 CONF_DIAGNOSTIC_PROBES,
30 CONF_DISCOVER_AND_PAIR_BUTTON,
31 CONF_DISCOVER_AND_PAIR_BUTTON_ID,
32 CONF_DISCOVER_AND_PAIR_RESULT_SENSOR_ID,
33 CONF_RECOVER_ONEWAY_KEY,
34 CONF_RECOVER_ONEWAY_KEY_SWITCH_ID,
35 CONF_SCAN_PAIRED_DEVICES_BUTTON,
36 CONF_SCAN_PAIRED_DEVICES_BUTTON_ID,
37 IOHomeAcceptForeignPairingSwitch,
38 IOHomeDeviceEventTextSensor,
40 IOHomePairingResultTextSensor,
41 IOHomeRecoverOneWayKeySwitch,
42 IOHomeScanPairedDevicesButton,
47 """Shared body for the hub-level entities gated by a bare boolean flag in the
48 `home_io_control:` block (accept_foreign_pairing, recover_oneway_key,
49 scan_paired_devices_button, discover_and_pair_button): declare the entity's ID during
50 validation, under the `{hub_id}_{suffix}` name, only when its flag is set. See
51 companion_id_base() in platform_common.py for why this must happen at validation time rather
54 if not config[flag_key]:
56 parent_id = config[CONF_ID]
57 base = parent_id.id
if parent_id.id
else "home_io_control"
58 config[id_key] = ID(f
"{base}_{suffix}", is_declaration=
True, type=cls)
65 flag_key=CONF_ACCEPT_FOREIGN_PAIRING,
66 id_key=CONF_ACCEPT_FOREIGN_PAIRING_SWITCH_ID,
67 suffix=
"accept_foreign_pairing_switch",
68 cls=IOHomeAcceptForeignPairingSwitch,
75 flag_key=CONF_RECOVER_ONEWAY_KEY,
76 id_key=CONF_RECOVER_ONEWAY_KEY_SWITCH_ID,
77 suffix=
"recover_oneway_key_switch",
78 cls=IOHomeRecoverOneWayKeySwitch,
85 flag_key=CONF_SCAN_PAIRED_DEVICES_BUTTON,
86 id_key=CONF_SCAN_PAIRED_DEVICES_BUTTON_ID,
87 suffix=
"scan_paired_devices_button",
88 cls=IOHomeScanPairedDevicesButton,
95 flag_key=CONF_DISCOVER_AND_PAIR_BUTTON,
96 id_key=CONF_DISCOVER_AND_PAIR_BUTTON_ID,
97 suffix=
"discover_and_pair_button",
98 cls=IOHomeDiscoverButton,
103 """Second ID off the same flag: the button always ships with its "Last Pairing Result" sensor,
104 so both IDs are gated on CONF_DISCOVER_AND_PAIR_BUTTON. _inject_hub_entity_id() already no-ops
105 when the flag is false, so no extra guard is needed here.
109 flag_key=CONF_DISCOVER_AND_PAIR_BUTTON,
110 id_key=CONF_DISCOVER_AND_PAIR_RESULT_SENSOR_ID,
111 suffix=
"pairing_result_sensor",
112 cls=IOHomePairingResultTextSensor,
117 """The "Last Device Event" sensor exists only with `diagnostic_probes: true`: it shows what the
118 device-event recorder saw, and that recorder is a diagnostic tool of the probe build.
122 flag_key=CONF_DIAGNOSTIC_PROBES,
123 id_key=CONF_DEVICE_EVENT_SENSOR_ID,
124 suffix=
"device_event_sensor",
125 cls=IOHomeDeviceEventTextSensor,
130 """Create one hub-level entity from its declared ID and a fixed name, bound to the hub.
132 A bare {id, name} dict is run through the platform's entity schema plus COMPONENT_SCHEMA, so
133 it carries the entity/component defaults new_*()/register_component() require, instead of a
134 hand-assembled config dict of its own (tuning.py's _create_number()/_create_select() do the
135 same for the tuning entities).
137 entity_config = schema.extend(cv.COMPONENT_SCHEMA)({CONF_ID: entity_id, CONF_NAME: name})
138 entity = await new_entity(entity_config)
139 await cg.register_component(entity, entity_config)
140 cg.add(entity.set_parent(var))
145 """Create a hub-level arming switch (key extraction or key adoption).
147 ALWAYS_OFF is a security property, not a UX default: every switch built here arms a window
148 (foreign-key extraction or 1W key adoption) that must never come back armed after a reboot.
150 schema = switch_component.switch_schema(
152 default_restore_mode=
"ALWAYS_OFF",
153 entity_category=ENTITY_CATEGORY_CONFIG,
155 await
_create_hub_entity(schema, switch_component.new_switch, config[id_key], name, var)
159 """Create the hub-level "Scan Paired Devices" button.
161 The `scan_paired_devices` native API action is registered independently in C++
162 (ManagementActions::register_actions()) and is unaffected by this key -- the button is an extra
163 trigger onto the same method, not a replacement.
165 schema = button_component.button_schema(IOHomeScanPairedDevicesButton, entity_category=ENTITY_CATEGORY_CONFIG)
167 schema, button_component.new_button, config[CONF_SCAN_PAIRED_DEVICES_BUTTON_ID],
"Scan Paired Devices", var
172 """Create the hub-level "Discover & Pair" button and its "Last Pairing Result" sensor.
174 The two are always created together: the sensor is the only place a pairing attempt's
175 machine-readable outcome ever appears, so a button without it would be a button whose result
178 inherit_esphome_device() is deliberately NOT called: the hub's own config has no `device_id:`
179 slot for these to inherit -- see that function's docstring.
181 button_schema = button_component.button_schema(IOHomeDiscoverButton, entity_category=ENTITY_CATEGORY_CONFIG)
183 button_schema, button_component.new_button, config[CONF_DISCOVER_AND_PAIR_BUTTON_ID],
"Discover & Pair", var
185 sensor_schema = text_sensor_component.text_sensor_schema(
186 IOHomePairingResultTextSensor, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
190 text_sensor_component.new_text_sensor,
191 config[CONF_DISCOVER_AND_PAIR_RESULT_SENSOR_ID],
192 "Last Pairing Result",
198 """Create the hub-level "Last Device Event" diagnostic text sensor.
200 The value is `#<n> t=<uptime s> <SRC> <cmd> <payload hex>`; the counter makes a repeated
201 identical report a new state, which Home Assistant's history needs.
203 sensor_schema = text_sensor_component.text_sensor_schema(
204 IOHomeDeviceEventTextSensor,
205 entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
206 icon=
"mdi:radio-tower",
210 text_sensor_component.new_text_sensor,
211 config[CONF_DEVICE_EVENT_SENSOR_ID],
inject_discover_and_pair_button_id(config)
inject_recover_oneway_key_switch_id(config)
create_scan_paired_devices_button(config, var)
inject_scan_paired_devices_button_id(config)
create_hub_arming_switch(config, var, *, cls, id_key, name)
_inject_hub_entity_id(config, *, flag_key, id_key, suffix, cls)
inject_discover_and_pair_result_sensor_id(config)
create_discover_and_pair_button(config, var)
inject_device_event_sensor_id(config)
inject_accept_foreign_pairing_switch_id(config)
_create_hub_entity(schema, new_entity, entity_id, name, var)
create_device_event_sensor(config, var)