mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Support async validation of device trigger (#27333)
This commit is contained in:
parent
3194dd3456
commit
fdf4f398a7
@ -7,9 +7,6 @@ from typing import Any, Awaitable, Callable
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.device_automation.exceptions import (
|
|
||||||
InvalidDeviceAutomationConfig,
|
|
||||||
)
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_NAME,
|
ATTR_NAME,
|
||||||
@ -476,10 +473,7 @@ async def _async_process_trigger(hass, config, trigger_configs, name, action):
|
|||||||
for conf in trigger_configs:
|
for conf in trigger_configs:
|
||||||
platform = importlib.import_module(".{}".format(conf[CONF_PLATFORM]), __name__)
|
platform = importlib.import_module(".{}".format(conf[CONF_PLATFORM]), __name__)
|
||||||
|
|
||||||
try:
|
remove = await platform.async_attach_trigger(hass, conf, action, info)
|
||||||
remove = await platform.async_attach_trigger(hass, conf, action, info)
|
|
||||||
except InvalidDeviceAutomationConfig:
|
|
||||||
remove = False
|
|
||||||
|
|
||||||
if not remove:
|
if not remove:
|
||||||
_LOGGER.error("Error setting up trigger %s", name)
|
_LOGGER.error("Error setting up trigger %s", name)
|
||||||
|
@ -4,6 +4,9 @@ import importlib
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.device_automation.exceptions import (
|
||||||
|
InvalidDeviceAutomationConfig,
|
||||||
|
)
|
||||||
from homeassistant.const import CONF_PLATFORM
|
from homeassistant.const import CONF_PLATFORM
|
||||||
from homeassistant.config import async_log_exception, config_without_domain
|
from homeassistant.config import async_log_exception, config_without_domain
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
@ -52,7 +55,12 @@ async def _try_async_validate_config_item(hass, config, full_config=None):
|
|||||||
"""Validate config item."""
|
"""Validate config item."""
|
||||||
try:
|
try:
|
||||||
config = await async_validate_config_item(hass, config, full_config)
|
config = await async_validate_config_item(hass, config, full_config)
|
||||||
except (vol.Invalid, HomeAssistantError, IntegrationNotFound) as ex:
|
except (
|
||||||
|
vol.Invalid,
|
||||||
|
HomeAssistantError,
|
||||||
|
IntegrationNotFound,
|
||||||
|
InvalidDeviceAutomationConfig,
|
||||||
|
) as ex:
|
||||||
async_log_exception(ex, DOMAIN, full_config or config, hass)
|
async_log_exception(ex, DOMAIN, full_config or config, hass)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -18,6 +18,9 @@ async def async_validate_trigger_config(hass, config):
|
|||||||
platform = await async_get_device_automation_platform(
|
platform = await async_get_device_automation_platform(
|
||||||
hass, config[CONF_DOMAIN], "trigger"
|
hass, config[CONF_DOMAIN], "trigger"
|
||||||
)
|
)
|
||||||
|
if hasattr(platform, "async_validate_trigger_config"):
|
||||||
|
return await getattr(platform, "async_validate_trigger_config")(hass, config)
|
||||||
|
|
||||||
return platform.TRIGGER_SCHEMA(config)
|
return platform.TRIGGER_SCHEMA(config)
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,8 +204,10 @@ def _get_deconz_event_from_device_id(hass, device_id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def async_attach_trigger(hass, config, action, automation_info):
|
async def async_validate_trigger_config(hass, config):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Validate config."""
|
||||||
|
config = TRIGGER_SCHEMA(config)
|
||||||
|
|
||||||
device_registry = await hass.helpers.device_registry.async_get_registry()
|
device_registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
device = device_registry.async_get(config[CONF_DEVICE_ID])
|
device = device_registry.async_get(config[CONF_DEVICE_ID])
|
||||||
|
|
||||||
@ -214,6 +216,16 @@ async def async_attach_trigger(hass, config, action, automation_info):
|
|||||||
if device.model not in REMOTES or trigger not in REMOTES[device.model]:
|
if device.model not in REMOTES or trigger not in REMOTES[device.model]:
|
||||||
raise InvalidDeviceAutomationConfig
|
raise InvalidDeviceAutomationConfig
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
async def async_attach_trigger(hass, config, action, automation_info):
|
||||||
|
"""Listen for state changes based on configuration."""
|
||||||
|
device_registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
device = device_registry.async_get(config[CONF_DEVICE_ID])
|
||||||
|
|
||||||
|
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||||
|
|
||||||
trigger = REMOTES[device.model][trigger]
|
trigger = REMOTES[device.model][trigger]
|
||||||
|
|
||||||
deconz_event = _get_deconz_event_from_device_id(hass, device.id)
|
deconz_event = _get_deconz_event_from_device_id(hass, device.id)
|
||||||
|
@ -21,8 +21,10 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_attach_trigger(hass, config, action, automation_info):
|
async def async_validate_trigger_config(hass, config):
|
||||||
"""Listen for state changes based on configuration."""
|
"""Validate config."""
|
||||||
|
config = TRIGGER_SCHEMA(config)
|
||||||
|
|
||||||
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||||
zha_device = await async_get_zha_device(hass, config[CONF_DEVICE_ID])
|
zha_device = await async_get_zha_device(hass, config[CONF_DEVICE_ID])
|
||||||
|
|
||||||
@ -32,6 +34,14 @@ async def async_attach_trigger(hass, config, action, automation_info):
|
|||||||
):
|
):
|
||||||
raise InvalidDeviceAutomationConfig
|
raise InvalidDeviceAutomationConfig
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
async def async_attach_trigger(hass, config, action, automation_info):
|
||||||
|
"""Listen for state changes based on configuration."""
|
||||||
|
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||||
|
zha_device = await async_get_zha_device(hass, config[CONF_DEVICE_ID])
|
||||||
|
|
||||||
trigger = zha_device.device_automation_triggers[trigger]
|
trigger = zha_device.device_automation_triggers[trigger]
|
||||||
|
|
||||||
event_config = {
|
event_config = {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
"""ZHA device automation trigger tests."""
|
"""ZHA device automation trigger tests."""
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import homeassistant.components.automation as automation
|
import homeassistant.components.automation as automation
|
||||||
@ -197,7 +195,7 @@ async def test_if_fires_on_event(hass, config_entry, zha_gateway, calls):
|
|||||||
assert calls[0].data["message"] == "service called"
|
assert calls[0].data["message"] == "service called"
|
||||||
|
|
||||||
|
|
||||||
async def test_exception_no_triggers(hass, config_entry, zha_gateway, calls):
|
async def test_exception_no_triggers(hass, config_entry, zha_gateway, calls, caplog):
|
||||||
"""Test for exception on event triggers firing."""
|
"""Test for exception on event triggers firing."""
|
||||||
from zigpy.zcl.clusters.general import OnOff, Basic
|
from zigpy.zcl.clusters.general import OnOff, Basic
|
||||||
|
|
||||||
@ -219,33 +217,32 @@ async def test_exception_no_triggers(hass, config_entry, zha_gateway, calls):
|
|||||||
ha_device_registry = await async_get_registry(hass)
|
ha_device_registry = await async_get_registry(hass)
|
||||||
reg_device = ha_device_registry.async_get_device({("zha", ieee_address)}, set())
|
reg_device = ha_device_registry.async_get_device({("zha", ieee_address)}, set())
|
||||||
|
|
||||||
with patch("logging.Logger.error") as mock:
|
await async_setup_component(
|
||||||
await async_setup_component(
|
hass,
|
||||||
hass,
|
automation.DOMAIN,
|
||||||
automation.DOMAIN,
|
{
|
||||||
{
|
automation.DOMAIN: [
|
||||||
automation.DOMAIN: [
|
{
|
||||||
{
|
"trigger": {
|
||||||
"trigger": {
|
"device_id": reg_device.id,
|
||||||
"device_id": reg_device.id,
|
"domain": "zha",
|
||||||
"domain": "zha",
|
"platform": "device",
|
||||||
"platform": "device",
|
"type": "junk",
|
||||||
"type": "junk",
|
"subtype": "junk",
|
||||||
"subtype": "junk",
|
},
|
||||||
},
|
"action": {
|
||||||
"action": {
|
"service": "test.automation",
|
||||||
"service": "test.automation",
|
"data": {"message": "service called"},
|
||||||
"data": {"message": "service called"},
|
},
|
||||||
},
|
}
|
||||||
}
|
]
|
||||||
]
|
},
|
||||||
},
|
)
|
||||||
)
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
assert "Invalid config for [automation]" in caplog.text
|
||||||
mock.assert_called_with("Error setting up trigger %s", "automation 0")
|
|
||||||
|
|
||||||
|
|
||||||
async def test_exception_bad_trigger(hass, config_entry, zha_gateway, calls):
|
async def test_exception_bad_trigger(hass, config_entry, zha_gateway, calls, caplog):
|
||||||
"""Test for exception on event triggers firing."""
|
"""Test for exception on event triggers firing."""
|
||||||
from zigpy.zcl.clusters.general import OnOff, Basic
|
from zigpy.zcl.clusters.general import OnOff, Basic
|
||||||
|
|
||||||
@ -275,27 +272,26 @@ async def test_exception_bad_trigger(hass, config_entry, zha_gateway, calls):
|
|||||||
ha_device_registry = await async_get_registry(hass)
|
ha_device_registry = await async_get_registry(hass)
|
||||||
reg_device = ha_device_registry.async_get_device({("zha", ieee_address)}, set())
|
reg_device = ha_device_registry.async_get_device({("zha", ieee_address)}, set())
|
||||||
|
|
||||||
with patch("logging.Logger.error") as mock:
|
await async_setup_component(
|
||||||
await async_setup_component(
|
hass,
|
||||||
hass,
|
automation.DOMAIN,
|
||||||
automation.DOMAIN,
|
{
|
||||||
{
|
automation.DOMAIN: [
|
||||||
automation.DOMAIN: [
|
{
|
||||||
{
|
"trigger": {
|
||||||
"trigger": {
|
"device_id": reg_device.id,
|
||||||
"device_id": reg_device.id,
|
"domain": "zha",
|
||||||
"domain": "zha",
|
"platform": "device",
|
||||||
"platform": "device",
|
"type": "junk",
|
||||||
"type": "junk",
|
"subtype": "junk",
|
||||||
"subtype": "junk",
|
},
|
||||||
},
|
"action": {
|
||||||
"action": {
|
"service": "test.automation",
|
||||||
"service": "test.automation",
|
"data": {"message": "service called"},
|
||||||
"data": {"message": "service called"},
|
},
|
||||||
},
|
}
|
||||||
}
|
]
|
||||||
]
|
},
|
||||||
},
|
)
|
||||||
)
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
assert "Invalid config for [automation]" in caplog.text
|
||||||
mock.assert_called_with("Error setting up trigger %s", "automation 0")
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user