100 """Declare the heater companion IDs during validation (ESPHome 2026.x StaticVector sizing)."""
102 base = companion_id_base(config, CONF_ID)
103 config[CONF_WINDOW_SENSOR_ID] = ID(
104 f
"{base}_window_sensor", is_declaration=
True, type=IOHomeWindowBinarySensor
106 config[CONF_WINDOW_DETECTION_SWITCH_ID] = ID(
107 f
"{base}_window_detection_switch",
109 type=IOHomeOpenWindowDetectionSwitch,
111 return inject_companion_sensor_ids(config, CONF_ID)
124 if CONF_MIN_TEMPERATURE
not in config
and CONF_MAX_TEMPERATURE
not in config:
126 if config.get(CONF_DEVICE_TYPE) != DEVICE_TYPE_OPTIONS[
"heating_temperature_interface"]:
128 "min_temperature and max_temperature apply to io_device_type: heating_temperature_interface "
129 "only: a heat pump uses a fixed range, and every other device has no temperature range"
131 low, high = TEMPERATURE_RANGE_BOUNDS_C
132 for key
in (CONF_MIN_TEMPERATURE, CONF_MAX_TEMPERATURE):
133 if key
in config
and not low <= config[key] <= high:
135 f
"{key} must be between {low:g} and {high:g} degrees Celsius",
138 minimum = config.get(CONF_MIN_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[0])
139 maximum = config.get(CONF_MAX_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[1])
140 if minimum >= maximum:
142 f
"min_temperature ({minimum:g}) must be below max_temperature ({maximum:g}): they are the "
143 "range the device encodes its temperature over, not the range of the card"
174 var = cg.new_Pvariable(config[CONF_ID])
175 await cg.register_component(var, config)
176 await climate.register_climate(var, config)
178 parent = await cg.get_variable(config[CONF_HOME_IO_CONTROL_ID])
179 await wire_device_binding(var, parent, config)
180 await create_companion_sensors(config, parent)
182 if CONF_MIN_TEMPERATURE
in config
or CONF_MAX_TEMPERATURE
in config:
184 var.set_temperature_range(
185 config.get(CONF_MIN_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[0]),
186 config.get(CONF_MAX_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[1]),
190 if CONF_WINDOW_SENSOR_ID
in config:
191 window_config = binary_sensor.binary_sensor_schema(
192 IOHomeWindowBinarySensor, device_class=DEVICE_CLASS_WINDOW
193 ).extend(cv.COMPONENT_SCHEMA)(
194 inherit_esphome_device(
196 CONF_ID: config[CONF_WINDOW_SENSOR_ID],
197 CONF_NAME: companion_entity_name(config,
"Window"),
202 window_sensor = await binary_sensor.new_binary_sensor(window_config)
203 await cg.register_component(window_sensor, window_config)
204 cg.add(window_sensor.set_parent(parent))
205 cg.add(window_sensor.set_device_id(config[CONF_IO_DEVICE_ID]))
207 if CONF_WINDOW_DETECTION_SWITCH_ID
in config:
209 detection_config = switch.switch_schema(
210 IOHomeOpenWindowDetectionSwitch,
211 default_restore_mode=
"DISABLED",
212 entity_category=ENTITY_CATEGORY_CONFIG,
213 ).extend(cv.COMPONENT_SCHEMA)(
214 inherit_esphome_device(
216 CONF_ID: config[CONF_WINDOW_DETECTION_SWITCH_ID],
217 CONF_NAME: companion_entity_name(config,
"Open Window Detection"),
218 CONF_DISABLED_BY_DEFAULT:
True,
223 detection_switch = await switch.new_switch(detection_config)
224 await cg.register_component(detection_switch, detection_config)
225 cg.add(detection_switch.set_parent(parent))
226 cg.add(detection_switch.set_device_id(config[CONF_IO_DEVICE_ID]))
228 if CONF_NIGHT_LIGHT
in config:
229 night_light_config = config[CONF_NIGHT_LIGHT]
230 if CONF_DEVICE_ID
not in night_light_config:
231 inherit_esphome_device(night_light_config, config)
232 night_light = cg.new_Pvariable(night_light_config[CONF_OUTPUT_ID])
233 await cg.register_component(night_light, night_light_config)
234 await light.register_light(night_light, night_light_config)
235 cg.add(night_light.set_parent(parent))
236 cg.add(night_light.set_device_id(config[CONF_IO_DEVICE_ID]))