mirror of
https://github.com/home-assistant/core.git
synced 2025-11-14 13:30:43 +00:00
Improve validation of device automations (#102766)
* Improve validation of device automations * Improve comments * Address review comment
This commit is contained in:
@@ -5,9 +5,9 @@ from typing import cast
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, Platform
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, CONF_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import DeviceAutomationType, async_get_device_automation_platform
|
||||
@@ -55,31 +55,42 @@ async def async_validate_device_automation_config(
|
||||
platform = await async_get_device_automation_platform(
|
||||
hass, validated_config[CONF_DOMAIN], automation_type
|
||||
)
|
||||
|
||||
# Make sure the referenced device and optional entity exist
|
||||
device_registry = dr.async_get(hass)
|
||||
if not (device := device_registry.async_get(validated_config[CONF_DEVICE_ID])):
|
||||
# The device referenced by the device automation does not exist
|
||||
raise InvalidDeviceAutomationConfig(
|
||||
f"Unknown device '{validated_config[CONF_DEVICE_ID]}'"
|
||||
)
|
||||
if entity_id := validated_config.get(CONF_ENTITY_ID):
|
||||
try:
|
||||
er.async_validate_entity_id(er.async_get(hass), entity_id)
|
||||
except vol.Invalid as err:
|
||||
raise InvalidDeviceAutomationConfig(
|
||||
f"Unknown entity '{entity_id}'"
|
||||
) from err
|
||||
|
||||
if not hasattr(platform, DYNAMIC_VALIDATOR[automation_type]):
|
||||
# Pass the unvalidated config to avoid mutating the raw config twice
|
||||
return cast(
|
||||
ConfigType, getattr(platform, STATIC_VALIDATOR[automation_type])(config)
|
||||
)
|
||||
|
||||
# Bypass checks for entity platforms
|
||||
# Devices are not linked to config entries from entity platform domains, skip
|
||||
# the checks below which look for a config entry matching the device automation
|
||||
# domain
|
||||
if (
|
||||
automation_type == DeviceAutomationType.ACTION
|
||||
and validated_config[CONF_DOMAIN] in ENTITY_PLATFORMS
|
||||
):
|
||||
# Pass the unvalidated config to avoid mutating the raw config twice
|
||||
return cast(
|
||||
ConfigType,
|
||||
await getattr(platform, DYNAMIC_VALIDATOR[automation_type])(hass, config),
|
||||
)
|
||||
|
||||
# Only call the dynamic validator if the referenced device exists and the relevant
|
||||
# config entry is loaded
|
||||
registry = dr.async_get(hass)
|
||||
if not (device := registry.async_get(validated_config[CONF_DEVICE_ID])):
|
||||
# The device referenced by the device automation does not exist
|
||||
raise InvalidDeviceAutomationConfig(
|
||||
f"Unknown device '{validated_config[CONF_DEVICE_ID]}'"
|
||||
)
|
||||
|
||||
# Find a config entry with the same domain as the device automation
|
||||
device_config_entry = None
|
||||
for entry_id in device.config_entries:
|
||||
if (
|
||||
@@ -91,7 +102,7 @@ async def async_validate_device_automation_config(
|
||||
break
|
||||
|
||||
if not device_config_entry:
|
||||
# The config entry referenced by the device automation does not exist
|
||||
# There's no config entry with the same domain as the device automation
|
||||
raise InvalidDeviceAutomationConfig(
|
||||
f"Device '{validated_config[CONF_DEVICE_ID]}' has no config entry from "
|
||||
f"domain '{validated_config[CONF_DOMAIN]}'"
|
||||
|
||||
Reference in New Issue
Block a user