43IOHomeClimate = home_io_control_ns.class_(
"IOHomeClimate", climate.Climate, cg.Component)
69 """Declare the heater companion IDs during validation (ESPHome 2026.x StaticVector sizing)."""
71 base = companion_id_base(config, CONF_ID)
72 config[CONF_WINDOW_SENSOR_ID] = ID(
73 f
"{base}_window_sensor", is_declaration=
True, type=IOHomeWindowBinarySensor
75 config[CONF_WINDOW_DETECTION_SWITCH_ID] = ID(
76 f
"{base}_window_detection_switch",
78 type=IOHomeOpenWindowDetectionSwitch,
80 return inject_companion_sensor_ids(config, CONF_ID)
111 if CONF_MIN_TEMPERATURE
not in config
and CONF_MAX_TEMPERATURE
not in config:
113 if config.get(CONF_DEVICE_TYPE) != DEVICE_TYPE_OPTIONS[
"heating_temperature_interface"]:
115 "min_temperature and max_temperature apply to io_device_type: heating_temperature_interface "
116 "only: a heat pump uses a fixed range, and every other device has no temperature range"
118 low, high = TEMPERATURE_RANGE_BOUNDS_C
119 for key
in (CONF_MIN_TEMPERATURE, CONF_MAX_TEMPERATURE):
120 if key
in config
and not low <= config[key] <= high:
122 f
"{key} must be between {low:g} and {high:g} degrees Celsius",
125 minimum = config.get(CONF_MIN_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[0])
126 maximum = config.get(CONF_MAX_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[1])
127 if minimum >= maximum:
129 f
"min_temperature ({minimum:g}) must be below max_temperature ({maximum:g}): they are the "
130 "range the device encodes its temperature over, not the range of the card"
152 var = cg.new_Pvariable(config[CONF_ID])
153 await cg.register_component(var, config)
154 await climate.register_climate(var, config)
156 parent = await cg.get_variable(config[CONF_HOME_IO_CONTROL_ID])
157 await wire_device_binding(var, parent, config)
158 await create_companion_sensors(config, parent)
160 if CONF_MIN_TEMPERATURE
in config
or CONF_MAX_TEMPERATURE
in config:
162 var.set_temperature_range(
163 config.get(CONF_MIN_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[0]),
164 config.get(CONF_MAX_TEMPERATURE, DEFAULT_TEMPERATURE_RANGE_C[1]),
168 if CONF_WINDOW_SENSOR_ID
in config:
169 window_config = binary_sensor.binary_sensor_schema(
170 IOHomeWindowBinarySensor, device_class=DEVICE_CLASS_WINDOW
171 ).extend(cv.COMPONENT_SCHEMA)(
172 inherit_esphome_device(
174 CONF_ID: config[CONF_WINDOW_SENSOR_ID],
175 CONF_NAME: companion_entity_name(config,
"Window"),
180 window_sensor = await binary_sensor.new_binary_sensor(window_config)
181 await cg.register_component(window_sensor, window_config)
182 cg.add(window_sensor.set_parent(parent))
183 cg.add(window_sensor.set_device_id(config[CONF_IO_DEVICE_ID]))
185 if CONF_WINDOW_DETECTION_SWITCH_ID
in config:
187 detection_config = switch.switch_schema(
188 IOHomeOpenWindowDetectionSwitch,
189 default_restore_mode=
"DISABLED",
190 entity_category=ENTITY_CATEGORY_CONFIG,
191 ).extend(cv.COMPONENT_SCHEMA)(
192 inherit_esphome_device(
194 CONF_ID: config[CONF_WINDOW_DETECTION_SWITCH_ID],
195 CONF_NAME: companion_entity_name(config,
"Open Window Detection"),
196 CONF_DISABLED_BY_DEFAULT:
True,
201 detection_switch = await switch.new_switch(detection_config)
202 await cg.register_component(detection_switch, detection_config)
203 cg.add(detection_switch.set_parent(parent))
204 cg.add(detection_switch.set_device_id(config[CONF_IO_DEVICE_ID]))