1 """Support for covers which integrate with other components."""
3 from __future__
import annotations
8 import voluptuous
as vol
13 DEVICE_CLASSES_SCHEMA,
15 PLATFORM_SCHEMA
as COVER_PLATFORM_SCHEMA,
36 from .const
import DOMAIN
37 from .template_entity
import (
38 TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY,
40 rewrite_common_legacy_to_modern_conf,
43 _LOGGER = logging.getLogger(__name__)
46 OPENING_STATE =
"opening"
47 CLOSED_STATE =
"closed"
48 CLOSING_STATE =
"closing"
60 CONF_POSITION_TEMPLATE =
"position_template"
61 CONF_TILT_TEMPLATE =
"tilt_template"
62 OPEN_ACTION =
"open_cover"
63 CLOSE_ACTION =
"close_cover"
64 STOP_ACTION =
"stop_cover"
65 POSITION_ACTION =
"set_cover_position"
66 TILT_ACTION =
"set_cover_tilt_position"
67 CONF_TILT_OPTIMISTIC =
"tilt_optimistic"
69 CONF_OPEN_AND_CLOSE =
"open_or_close"
72 CoverEntityFeature.OPEN_TILT
73 | CoverEntityFeature.CLOSE_TILT
74 | CoverEntityFeature.STOP_TILT
75 | CoverEntityFeature.SET_TILT_POSITION
78 COVER_SCHEMA = vol.All(
79 cv.deprecated(CONF_ENTITY_ID),
82 vol.Inclusive(OPEN_ACTION, CONF_OPEN_AND_CLOSE): cv.SCRIPT_SCHEMA,
83 vol.Inclusive(CLOSE_ACTION, CONF_OPEN_AND_CLOSE): cv.SCRIPT_SCHEMA,
84 vol.Optional(STOP_ACTION): cv.SCRIPT_SCHEMA,
85 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
86 vol.Optional(CONF_POSITION_TEMPLATE): cv.template,
87 vol.Optional(CONF_TILT_TEMPLATE): cv.template,
88 vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
89 vol.Optional(CONF_OPTIMISTIC): cv.boolean,
90 vol.Optional(CONF_TILT_OPTIMISTIC): cv.boolean,
91 vol.Optional(POSITION_ACTION): cv.SCRIPT_SCHEMA,
92 vol.Optional(TILT_ACTION): cv.SCRIPT_SCHEMA,
93 vol.Optional(CONF_FRIENDLY_NAME): cv.string,
94 vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
95 vol.Optional(CONF_UNIQUE_ID): cv.string,
97 ).extend(TEMPLATE_ENTITY_COMMON_SCHEMA_LEGACY.schema),
98 cv.has_at_least_one_key(OPEN_ACTION, POSITION_ACTION),
101 PLATFORM_SCHEMA = COVER_PLATFORM_SCHEMA.extend(
102 {vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA)}
107 """Create the Template cover."""
110 for object_id, entity_config
in config[CONF_COVERS].items():
113 unique_id = entity_config.get(CONF_UNIQUE_ID)
130 async_add_entities: AddEntitiesCallback,
131 discovery_info: DiscoveryInfoType |
None =
None,
133 """Set up the Template cover."""
138 """Representation of a Template cover."""
140 _attr_should_poll =
False
149 """Initialize the Template cover."""
151 hass, config=config, fallback_name=object_id, unique_id=unique_id
154 ENTITY_ID_FORMAT, object_id, hass=hass
157 self.
_template_template = config.get(CONF_VALUE_TEMPLATE)
162 if (open_action := config.get(OPEN_ACTION))
is not None:
165 if (close_action := config.get(CLOSE_ACTION))
is not None:
168 if (stop_action := config.get(STOP_ACTION))
is not None:
171 if (position_action := config.get(POSITION_ACTION))
is not None:
174 if (tilt_action := config.get(TILT_ACTION))
is not None:
176 optimistic = config.get(CONF_OPTIMISTIC)
180 tilt_optimistic = config.get(CONF_TILT_OPTIMISTIC)
187 supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
189 supported_features |= CoverEntityFeature.STOP
191 supported_features |= CoverEntityFeature.SET_POSITION
193 supported_features |= TILT_FEATURES
198 """Set up templates."""
209 none_on_template_error=
True,
217 none_on_template_error=
True,
224 if isinstance(result, TemplateError):
228 state =
str(result).lower()
230 if state
in _VALID_STATES:
232 if state
in (
"true", OPEN_STATE):
237 self.
_is_opening_is_opening = state == OPENING_STATE
238 self.
_is_closing_is_closing = state == CLOSING_STATE
241 "Received invalid cover is_on state: %s for entity %s. Expected: %s",
244 ", ".join(_VALID_STATES),
259 state =
float(result)
260 except ValueError
as err:
265 if state < 0
or state > 100:
268 "Cover position value must be between 0 and 100. Value was: %.2f",
281 state =
float(result)
282 except ValueError
as err:
287 if state < 0
or state > 100:
290 "Tilt value must be between 0 and 100. Value was: %.2f",
298 """Return if the cover is closed."""
306 """Return if the cover is currently opening."""
311 """Return if the cover is currently closing."""
316 """Return current position of cover.
318 None is unknown, 0 is closed, 100 is fully open.
326 """Return current position of cover tilt.
328 None is unknown, 0 is closed, 100 is fully open.
333 """Move the cover up."""
339 run_variables={
"position": 100},
347 """Move the cover down."""
353 run_variables={
"position": 0},
361 """Fire the stop action."""
366 """Set cover position."""
367 self.
_position_position = kwargs[ATTR_POSITION]
370 run_variables={
"position": self.
_position_position},
377 """Tilt the cover open."""
381 run_variables={
"tilt": self.
_tilt_value_tilt_value},
388 """Tilt the cover closed."""
392 run_variables={
"tilt": self.
_tilt_value_tilt_value},
399 """Move the cover tilt to a specific position."""
400 self.
_tilt_value_tilt_value = kwargs[ATTR_TILT_POSITION]
403 run_variables={
"tilt": self.
_tilt_value_tilt_value},
current_cover_tilt_position
None async_open_cover_tilt(self, **Any kwargs)
def _update_position(self, result)
def __init__(self, hass, object_id, config, unique_id)
None async_set_cover_position(self, **Any kwargs)
None async_set_cover_tilt_position(self, **Any kwargs)
def _update_tilt(self, result)
bool|None is_closed(self)
None async_stop_cover(self, **Any kwargs)
None async_open_cover(self, **Any kwargs)
None _async_setup_templates(self)
None async_close_cover_tilt(self, **Any kwargs)
def _update_state(self, result)
None async_close_cover(self, **Any kwargs)
None _update_state(self, str|TemplateError result)
None async_run_script(self, Script script, *_VarsType|None run_variables=None, Context|None context=None)
None add_template_attribute(self, str attribute, Template template, Callable[[Any], Any]|None validator=None, Callable[[Any], None]|None on_update=None, bool none_on_template_error=False)
None async_write_ha_state(self)
def _async_create_entities(hass, config)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
dict[str, Any] rewrite_common_legacy_to_modern_conf(HomeAssistant hass, dict[str, Any] entity_cfg, dict[str, str]|None extra_legacy_fields=None)
str async_generate_entity_id(str entity_id_format, str|None name, Iterable[str]|None current_ids=None, HomeAssistant|None hass=None)