mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Add modern style template lock (#144756)
* Add modern style lock * add tests * Add tests and address comments * Update homeassistant/components/template/lock.py --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
fd09476b28
commit
ea046f32be
@ -17,6 +17,7 @@ from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
|
|||||||
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
|
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
|
||||||
from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
|
from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
|
||||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||||
|
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
|
||||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||||
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN
|
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
@ -50,6 +51,7 @@ from . import (
|
|||||||
fan as fan_platform,
|
fan as fan_platform,
|
||||||
image as image_platform,
|
image as image_platform,
|
||||||
light as light_platform,
|
light as light_platform,
|
||||||
|
lock as lock_platform,
|
||||||
number as number_platform,
|
number as number_platform,
|
||||||
select as select_platform,
|
select as select_platform,
|
||||||
sensor as sensor_platform,
|
sensor as sensor_platform,
|
||||||
@ -124,6 +126,9 @@ CONFIG_SECTION_SCHEMA = vol.All(
|
|||||||
vol.Optional(LIGHT_DOMAIN): vol.All(
|
vol.Optional(LIGHT_DOMAIN): vol.All(
|
||||||
cv.ensure_list, [light_platform.LIGHT_SCHEMA]
|
cv.ensure_list, [light_platform.LIGHT_SCHEMA]
|
||||||
),
|
),
|
||||||
|
vol.Optional(LOCK_DOMAIN): vol.All(
|
||||||
|
cv.ensure_list, [lock_platform.LOCK_SCHEMA]
|
||||||
|
),
|
||||||
vol.Optional(WEATHER_DOMAIN): vol.All(
|
vol.Optional(WEATHER_DOMAIN): vol.All(
|
||||||
cv.ensure_list, [weather_platform.WEATHER_SCHEMA]
|
cv.ensure_list, [weather_platform.WEATHER_SCHEMA]
|
||||||
),
|
),
|
||||||
@ -139,7 +144,7 @@ CONFIG_SECTION_SCHEMA = vol.All(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ensure_domains_do_not_have_trigger_or_action(
|
ensure_domains_do_not_have_trigger_or_action(
|
||||||
BUTTON_DOMAIN, COVER_DOMAIN, FAN_DOMAIN
|
BUTTON_DOMAIN, COVER_DOMAIN, FAN_DOMAIN, LOCK_DOMAIN
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from homeassistant.const import (
|
|||||||
ATTR_CODE,
|
ATTR_CODE,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_OPTIMISTIC,
|
CONF_OPTIMISTIC,
|
||||||
|
CONF_STATE,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
)
|
)
|
||||||
@ -25,14 +26,18 @@ from homeassistant.helpers import config_validation as cv
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import CONF_PICTURE, DOMAIN
|
||||||
from .template_entity import (
|
from .template_entity import (
|
||||||
|
LEGACY_FIELDS as TEMPLATE_ENTITY_LEGACY_FIELDS,
|
||||||
|
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA,
|
||||||
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY,
|
TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY,
|
||||||
|
TEMPLATE_ENTITY_ICON_SCHEMA,
|
||||||
TemplateEntity,
|
TemplateEntity,
|
||||||
rewrite_common_legacy_to_modern_conf,
|
rewrite_common_legacy_to_modern_conf,
|
||||||
)
|
)
|
||||||
|
|
||||||
CONF_CODE_FORMAT_TEMPLATE = "code_format_template"
|
CONF_CODE_FORMAT_TEMPLATE = "code_format_template"
|
||||||
|
CONF_CODE_FORMAT = "code_format"
|
||||||
CONF_LOCK = "lock"
|
CONF_LOCK = "lock"
|
||||||
CONF_UNLOCK = "unlock"
|
CONF_UNLOCK = "unlock"
|
||||||
CONF_OPEN = "open"
|
CONF_OPEN = "open"
|
||||||
@ -40,26 +45,69 @@ CONF_OPEN = "open"
|
|||||||
DEFAULT_NAME = "Template Lock"
|
DEFAULT_NAME = "Template Lock"
|
||||||
DEFAULT_OPTIMISTIC = False
|
DEFAULT_OPTIMISTIC = False
|
||||||
|
|
||||||
|
LEGACY_FIELDS = TEMPLATE_ENTITY_LEGACY_FIELDS | {
|
||||||
|
CONF_CODE_FORMAT_TEMPLATE: CONF_CODE_FORMAT,
|
||||||
|
CONF_VALUE_TEMPLATE: CONF_STATE,
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_SCHEMA = vol.All(
|
||||||
|
vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(CONF_CODE_FORMAT): cv.template,
|
||||||
|
vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_NAME): cv.template,
|
||||||
|
vol.Optional(CONF_OPEN): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||||
|
vol.Optional(CONF_PICTURE): cv.template,
|
||||||
|
vol.Required(CONF_STATE): cv.template,
|
||||||
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
|
vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA.schema)
|
||||||
|
.extend(TEMPLATE_ENTITY_ICON_SCHEMA.schema),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = LOCK_PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = LOCK_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_NAME): cv.string,
|
|
||||||
vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA,
|
|
||||||
vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA,
|
|
||||||
vol.Optional(CONF_OPEN): cv.SCRIPT_SCHEMA,
|
|
||||||
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
|
|
||||||
vol.Optional(CONF_CODE_FORMAT_TEMPLATE): cv.template,
|
vol.Optional(CONF_CODE_FORMAT_TEMPLATE): cv.template,
|
||||||
|
vol.Required(CONF_LOCK): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
|
vol.Optional(CONF_OPEN): cv.SCRIPT_SCHEMA,
|
||||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
|
vol.Required(CONF_UNLOCK): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
}
|
}
|
||||||
).extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY.schema)
|
).extend(TEMPLATE_ENTITY_AVAILABILITY_SCHEMA_LEGACY.schema)
|
||||||
|
|
||||||
|
|
||||||
async def _async_create_entities(
|
@callback
|
||||||
hass: HomeAssistant, config: dict[str, Any]
|
def _async_create_template_tracking_entities(
|
||||||
) -> list[TemplateLock]:
|
async_add_entities: AddEntitiesCallback,
|
||||||
"""Create the Template lock."""
|
hass: HomeAssistant,
|
||||||
config = rewrite_common_legacy_to_modern_conf(hass, config)
|
definitions: list[dict],
|
||||||
return [TemplateLock(hass, config, config.get(CONF_UNIQUE_ID))]
|
unique_id_prefix: str | None,
|
||||||
|
) -> None:
|
||||||
|
"""Create the template fans."""
|
||||||
|
fans = []
|
||||||
|
|
||||||
|
for entity_conf in definitions:
|
||||||
|
unique_id = entity_conf.get(CONF_UNIQUE_ID)
|
||||||
|
|
||||||
|
if unique_id and unique_id_prefix:
|
||||||
|
unique_id = f"{unique_id_prefix}-{unique_id}"
|
||||||
|
|
||||||
|
fans.append(
|
||||||
|
TemplateLock(
|
||||||
|
hass,
|
||||||
|
entity_conf,
|
||||||
|
unique_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(fans)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
@ -68,8 +116,22 @@ async def async_setup_platform(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the template lock."""
|
"""Set up the template fans."""
|
||||||
async_add_entities(await _async_create_entities(hass, config))
|
if discovery_info is None:
|
||||||
|
_async_create_template_tracking_entities(
|
||||||
|
async_add_entities,
|
||||||
|
hass,
|
||||||
|
[rewrite_common_legacy_to_modern_conf(hass, config, LEGACY_FIELDS)],
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
_async_create_template_tracking_entities(
|
||||||
|
async_add_entities,
|
||||||
|
hass,
|
||||||
|
discovery_info["entities"],
|
||||||
|
discovery_info["unique_id"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TemplateLock(TemplateEntity, LockEntity):
|
class TemplateLock(TemplateEntity, LockEntity):
|
||||||
@ -92,7 +154,7 @@ class TemplateLock(TemplateEntity, LockEntity):
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert name is not None
|
assert name is not None
|
||||||
|
|
||||||
self._state_template = config.get(CONF_VALUE_TEMPLATE)
|
self._state_template = config.get(CONF_STATE)
|
||||||
for action_id, supported_feature in (
|
for action_id, supported_feature in (
|
||||||
(CONF_LOCK, 0),
|
(CONF_LOCK, 0),
|
||||||
(CONF_UNLOCK, 0),
|
(CONF_UNLOCK, 0),
|
||||||
@ -102,7 +164,7 @@ class TemplateLock(TemplateEntity, LockEntity):
|
|||||||
if (action_config := config.get(action_id)) is not None:
|
if (action_config := config.get(action_id)) is not None:
|
||||||
self.add_script(action_id, action_config, name, DOMAIN)
|
self.add_script(action_id, action_config, name, DOMAIN)
|
||||||
self._attr_supported_features |= supported_feature
|
self._attr_supported_features |= supported_feature
|
||||||
self._code_format_template = config.get(CONF_CODE_FORMAT_TEMPLATE)
|
self._code_format_template = config.get(CONF_CODE_FORMAT)
|
||||||
self._code_format: str | None = None
|
self._code_format: str | None = None
|
||||||
self._code_format_template_error: TemplateError | None = None
|
self._code_format_template_error: TemplateError | None = None
|
||||||
self._optimistic = config.get(CONF_OPTIMISTIC)
|
self._optimistic = config.get(CONF_OPTIMISTIC)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user