Home Assistant Unofficial Reference 2024.12.1
helpers.py
Go to the documentation of this file.
1 """Helpers for device oriented automations."""
2 
3 from __future__ import annotations
4 
5 from typing import cast
6 
7 import voluptuous as vol
8 
9 from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, CONF_ENTITY_ID, Platform
10 from homeassistant.core import HomeAssistant
11 from homeassistant.helpers import device_registry as dr, entity_registry as er
12 from homeassistant.helpers.typing import ConfigType
13 
14 from . import DeviceAutomationType, async_get_device_automation_platform
15 from .exceptions import InvalidDeviceAutomationConfig
16 
17 DYNAMIC_VALIDATOR = {
18  DeviceAutomationType.ACTION: "async_validate_action_config",
19  DeviceAutomationType.CONDITION: "async_validate_condition_config",
20  DeviceAutomationType.TRIGGER: "async_validate_trigger_config",
21 }
22 
23 STATIC_VALIDATOR = {
24  DeviceAutomationType.ACTION: "ACTION_SCHEMA",
25  DeviceAutomationType.CONDITION: "CONDITION_SCHEMA",
26  DeviceAutomationType.TRIGGER: "TRIGGER_SCHEMA",
27 }
28 
29 ENTITY_PLATFORMS = {
30  Platform.ALARM_CONTROL_PANEL.value,
31  Platform.BUTTON.value,
32  Platform.CLIMATE.value,
33  Platform.COVER.value,
34  Platform.FAN.value,
35  Platform.HUMIDIFIER.value,
36  Platform.LIGHT.value,
37  Platform.LOCK.value,
38  Platform.NUMBER.value,
39  Platform.REMOTE.value,
40  Platform.SELECT.value,
41  Platform.SWITCH.value,
42  Platform.TEXT.value,
43  Platform.VACUUM.value,
44  Platform.WATER_HEATER.value,
45 }
46 
47 
49  hass: HomeAssistant,
50  config: ConfigType,
51  automation_schema: vol.Schema,
52  automation_type: DeviceAutomationType,
53 ) -> ConfigType:
54  """Validate config."""
55  validated_config: ConfigType = automation_schema(config)
56  platform = await async_get_device_automation_platform(
57  hass, validated_config[CONF_DOMAIN], automation_type
58  )
59 
60  # Make sure the referenced device and optional entity exist
61  device_registry = dr.async_get(hass)
62  if not (device := device_registry.async_get(validated_config[CONF_DEVICE_ID])):
63  # The device referenced by the device automation does not exist
65  f"Unknown device '{validated_config[CONF_DEVICE_ID]}'"
66  )
67  if entity_id := validated_config.get(CONF_ENTITY_ID):
68  try:
69  er.async_validate_entity_id(er.async_get(hass), entity_id)
70  except vol.Invalid as err:
72  f"Unknown entity '{entity_id}'"
73  ) from err
74 
75  if not hasattr(platform, DYNAMIC_VALIDATOR[automation_type]):
76  # Pass the unvalidated config to avoid mutating the raw config twice
77  return cast(
78  ConfigType, getattr(platform, STATIC_VALIDATOR[automation_type])(config)
79  )
80 
81  # Devices are not linked to config entries from entity platform domains, skip
82  # the checks below which look for a config entry matching the device automation
83  # domain
84  if (
85  automation_type == DeviceAutomationType.ACTION
86  and validated_config[CONF_DOMAIN] in ENTITY_PLATFORMS
87  ):
88  # Pass the unvalidated config to avoid mutating the raw config twice
89  return cast(
90  ConfigType,
91  await getattr(platform, DYNAMIC_VALIDATOR[automation_type])(hass, config),
92  )
93 
94  # Find a config entry with the same domain as the device automation
95  device_config_entry = None
96  for entry_id in device.config_entries:
97  if (
98  not (entry := hass.config_entries.async_get_entry(entry_id))
99  or entry.domain != validated_config[CONF_DOMAIN]
100  ):
101  continue
102  device_config_entry = entry
103  break
104 
105  if not device_config_entry:
106  # There's no config entry with the same domain as the device automation
108  f"Device '{validated_config[CONF_DEVICE_ID]}' has no config entry from "
109  f"domain '{validated_config[CONF_DOMAIN]}'"
110  )
111 
112  if not await hass.config_entries.async_wait_component(device_config_entry):
113  # The component could not be loaded, skip the dynamic validation
114  return validated_config
115 
116  # Pass the unvalidated config to avoid mutating the raw config twice
117  return cast(
118  ConfigType,
119  await getattr(platform, DYNAMIC_VALIDATOR[automation_type])(hass, config),
120  )
ConfigType async_validate_device_automation_config(HomeAssistant hass, ConfigType config, vol.Schema automation_schema, DeviceAutomationType automation_type)
Definition: helpers.py:53
DeviceAutomationTriggerProtocol async_get_device_automation_platform(HomeAssistant hass, str domain, Literal[DeviceAutomationType.TRIGGER] automation_type)
Definition: __init__.py:137