9import esphome.codegen
as cg
10import esphome.config_validation
as cv
11from esphome.components
import button, cover
12from esphome.const
import (
13 CONF_DISABLED_BY_DEFAULT,
17from esphome.core
import ID
19from .
import home_io_control_ns
20from .platform_common
import (
22 create_companion_sensors,
23 inject_companion_sensor_ids,
24 platform_schema_extension,
28 CONF_HOME_IO_CONTROL_ID,
31DEPENDENCIES = [
"home_io_control"]
33CONF_INVERT_POSITION =
"invert_position"
34CONF_OPTIMISTIC_STATE =
"optimistic_state"
37CONF_FAVORITE_BUTTON_ID =
"_favorite_button_id"
38CONF_VENT_BUTTON_ID =
"_vent_button_id"
40IOHomeCover = home_io_control_ns.class_(
"IOHomeCover", cover.Cover, cg.Component)
41IOHomeCoverFavoriteButton = home_io_control_ns.class_(
42 "IOHomeCoverFavoriteButton", button.Button, cg.Component
44IOHomeCoverVentButton = home_io_control_ns.class_(
45 "IOHomeCoverVentButton", button.Button, cg.Component
50POSITION_CONTROL_DEVICE_TYPES = {
70 """Check if the given device type value supports 0-100% position control."""
71 return value
in POSITION_CONTROL_DEVICE_TYPES
83 """Check if the given device type value supports the ventilation command."""
84 return value
in VENT_DEVICE_TYPES
88 """Derive the favorite-position button name from the parent cover name."""
89 base_name = config.get(CONF_NAME,
"")
91 return f
"{base_name} Favorite Position"
92 return "Favorite Position"
96 """Derive the ventilation-position button name from the parent cover name."""
97 base_name = config.get(CONF_NAME,
"")
99 return f
"{base_name} Ventilation Position"
100 return "Ventilation Position"
104 """Declare cover companion entity IDs during schema validation for StaticVector sizing.
106 The favorite and ventilation buttons are cover-only and gated on device capability, so
107 their injection stays here. The always-present companion sensor IDs are delegated to the
108 shared helper. See platform_common.companion_id_base() for the StaticVector rationale.
110 base = companion_id_base(config, CONF_ID)
114 config[CONF_DEVICE_TYPE]
116 config[CONF_FAVORITE_BUTTON_ID] = ID(
117 f
"{base}_favorite_button",
119 type=IOHomeCoverFavoriteButton,
124 config[CONF_VENT_BUTTON_ID] = ID(
125 f
"{base}_vent_button",
127 type=IOHomeCoverVentButton,
131 return inject_companion_sensor_ids(config, CONF_ID)
134CONFIG_SCHEMA = cv.All(
135 cover.cover_schema(IOHomeCover)
136 .extend(platform_schema_extension())
137 .extend({cv.Optional(CONF_INVERT_POSITION): cv.boolean})
138 .extend({cv.Optional(CONF_OPTIMISTIC_STATE, default=
True): cv.boolean})
139 .extend(cv.COMPONENT_SCHEMA),
140 _inject_companion_ids,
145 var = await cover.new_cover(config)
146 await cg.register_component(var, config)
148 parent = await cg.get_variable(config[CONF_HOME_IO_CONTROL_ID])
149 await wire_device_binding(var, parent, config)
151 if CONF_INVERT_POSITION
in config:
152 cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
154 cg.add(var.set_optimistic_state(config[CONF_OPTIMISTIC_STATE]))
156 if CONF_FAVORITE_BUTTON_ID
in config:
158 CONF_ID: config[CONF_FAVORITE_BUTTON_ID],
160 CONF_DISABLED_BY_DEFAULT:
False,
162 favorite = await button.new_button(favorite_config)
163 await cg.register_component(favorite, favorite_config)
164 cg.add(favorite.set_parent(parent))
165 cg.add(favorite.set_device_id(config[CONF_DEVICE_ID]))
167 if CONF_VENT_BUTTON_ID
in config:
169 CONF_ID: config[CONF_VENT_BUTTON_ID],
171 CONF_DISABLED_BY_DEFAULT:
False,
173 vent = await button.new_button(vent_config)
174 await cg.register_component(vent, vent_config)
175 cg.add(vent.set_parent(parent))
176 cg.add(vent.set_device_id(config[CONF_DEVICE_ID]))
178 await create_companion_sensors(config, parent)
_inject_companion_ids(config)
device_supports_position_control(value)
device_supports_vent(value)
favorite_button_name(config)