mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 10:16:02 -05:00
Validate template actions: field using async_validate_actions_config (#180018)
This commit is contained in:
@@ -5,9 +5,13 @@ from collections.abc import Coroutine
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from homeassistant import config as conf_util
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_ACTIONS,
|
||||
CONF_DEVICE_ID,
|
||||
CONF_NAME,
|
||||
CONF_TRIGGERS,
|
||||
@@ -19,6 +23,7 @@ from homeassistant.exceptions import ConfigEntryError, HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr, discovery, issue_registry as ir
|
||||
from homeassistant.helpers.helper_integration import async_remove_helper_devices
|
||||
from homeassistant.helpers.reload import async_reload_integration_platforms
|
||||
from homeassistant.helpers.script import async_validate_actions_config
|
||||
from homeassistant.helpers.service import async_register_admin_service
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.loader import async_get_integration
|
||||
@@ -192,6 +197,13 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
||||
return True
|
||||
|
||||
|
||||
def _humanize(err: Exception, data: Any) -> str:
|
||||
"""Humanize vol.Invalid, stringify other exceptions."""
|
||||
if isinstance(err, vol.Invalid):
|
||||
return humanize_error(data, err)
|
||||
return str(err)
|
||||
|
||||
|
||||
async def _process_config(hass: HomeAssistant, hass_config: ConfigType) -> None:
|
||||
"""Process config."""
|
||||
coordinators = hass.data.pop(DATA_COORDINATORS, None)
|
||||
@@ -212,6 +224,24 @@ async def _process_config(hass: HomeAssistant, hass_config: ConfigType) -> None:
|
||||
|
||||
for conf_section in hass_config[DOMAIN]:
|
||||
if CONF_TRIGGERS in conf_section:
|
||||
if actions_config := conf_section.get(CONF_ACTIONS):
|
||||
try:
|
||||
conf_section[CONF_ACTIONS] = await async_validate_actions_config(
|
||||
hass, actions_config
|
||||
)
|
||||
except (vol.Invalid, HomeAssistantError) as err:
|
||||
breadcrumb = "template section"
|
||||
if (unique_id := conf_section.get(CONF_UNIQUE_ID)) is not None:
|
||||
breadcrumb = f"template section with unique_id: {unique_id}"
|
||||
|
||||
_LOGGER.error(
|
||||
"The 'actions' for %s failed to setup: %s",
|
||||
breadcrumb,
|
||||
_humanize(err, actions_config),
|
||||
)
|
||||
|
||||
continue
|
||||
|
||||
coordinator_tasks.append(init_coordinator(hass, conf_section))
|
||||
continue
|
||||
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, StrEnum
|
||||
from itertools import chain
|
||||
from unittest.mock import AsyncMock, Mock
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import template
|
||||
from homeassistant.components.device_automation import toggle_entity
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, State
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
@@ -18,6 +21,7 @@ from tests.common import (
|
||||
MockConfigEntry,
|
||||
assert_setup_component,
|
||||
async_mock_service,
|
||||
mock_platform,
|
||||
mock_restore_cache,
|
||||
mock_restore_cache_with_extra_data,
|
||||
)
|
||||
@@ -70,6 +74,85 @@ def make_test_action(action: str, extra_data: ConfigType | None = None) -> Confi
|
||||
}
|
||||
|
||||
|
||||
def make_mock_device_actions(
|
||||
actions: list[str],
|
||||
platform_setup: TemplatePlatformSetup,
|
||||
device_entry: dr.DeviceEntry,
|
||||
entity_entry: er.RegistryEntry,
|
||||
) -> ConfigType:
|
||||
"""Make actions for device testing."""
|
||||
return {
|
||||
action: [
|
||||
{
|
||||
"action": "test.automation",
|
||||
"data": {
|
||||
"action": "fake_action",
|
||||
"caller": platform_setup.entity_id,
|
||||
},
|
||||
},
|
||||
{
|
||||
"domain": "fake_integration",
|
||||
"type": "turn_on",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": entity_entry.id,
|
||||
"metadata": {"secondary": False},
|
||||
},
|
||||
]
|
||||
for action in actions
|
||||
}
|
||||
|
||||
|
||||
async def setup_mock_devices(
|
||||
hass: HomeAssistant,
|
||||
domain: str,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> tuple[TemplatePlatformSetup, dr.DeviceEntry, er.RegistryEntry]:
|
||||
"""Setup mock devices for testing."""
|
||||
FAKE_DOMAIN = "fake_integration"
|
||||
|
||||
hass.config.components.add(FAKE_DOMAIN)
|
||||
|
||||
async def _async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions."""
|
||||
return await toggle_entity.async_get_actions(hass, device_id, FAKE_DOMAIN)
|
||||
|
||||
mock_platform(
|
||||
hass,
|
||||
f"{FAKE_DOMAIN}.device_action",
|
||||
Mock(
|
||||
ACTION_SCHEMA=toggle_entity.ACTION_SCHEMA.extend(
|
||||
{vol.Required("domain"): FAKE_DOMAIN}
|
||||
),
|
||||
async_get_actions=_async_get_actions,
|
||||
async_call_action_from_config=AsyncMock(),
|
||||
spec=[
|
||||
"ACTION_SCHEMA",
|
||||
"async_get_actions",
|
||||
"async_call_action_from_config",
|
||||
],
|
||||
),
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
"fake_integration", "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
platform_setup = TemplatePlatformSetup(
|
||||
domain, "test_entity", make_test_trigger("sensor.trigger")
|
||||
)
|
||||
return (platform_setup, device_entry, entity_entry)
|
||||
|
||||
|
||||
def assert_action(
|
||||
platform_setup: TemplatePlatformSetup,
|
||||
calls: list[ServiceCall],
|
||||
|
||||
@@ -9,12 +9,27 @@ from homeassistant.components.template.config import (
|
||||
async_validate_config_section,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
)
|
||||
from homeassistant.helpers.discovery import Platform
|
||||
from homeassistant.helpers.script_variables import ScriptVariables
|
||||
from homeassistant.helpers.template import Template
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .conftest import (
|
||||
ConfigurationStyle,
|
||||
TemplatePlatformSetup,
|
||||
assert_action,
|
||||
async_trigger,
|
||||
make_mock_device_actions,
|
||||
setup_entity,
|
||||
setup_mock_devices,
|
||||
)
|
||||
|
||||
from tests.common import assert_platform_setup_creates_issue, assert_setup_component
|
||||
|
||||
|
||||
@@ -443,6 +458,338 @@ async def test_setup_component_bad_config_logs_error(
|
||||
assert expected_error in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("platform", "config"),
|
||||
[
|
||||
(
|
||||
Platform.ALARM_CONTROL_PANEL,
|
||||
{
|
||||
"state": "{{ 'disarmed' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.BINARY_SENSOR,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.COVER,
|
||||
{
|
||||
"state": "{{ 'open' }}",
|
||||
"open_cover": [],
|
||||
"close_cover": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.DEVICE_TRACKER,
|
||||
{
|
||||
"in_zones": "{{ ['zone.home'] }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.EVENT,
|
||||
{
|
||||
"event_type": "{{ 'single' }}",
|
||||
"event_types": "{{ ['single'] }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.FAN,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.IMAGE,
|
||||
{
|
||||
"url": "{{ 'http://www.test.com' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.LIGHT,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.LOCK,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"lock": [],
|
||||
"unlock": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.NUMBER,
|
||||
{
|
||||
"state": "{{ 4 }}",
|
||||
"min": "0",
|
||||
"max": "100",
|
||||
"step": "0.1",
|
||||
"unit_of_measurement": "cm",
|
||||
"set_value": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SELECT,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"options": "{{ ['off', 'on', 'auto'] }}",
|
||||
"select_option": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SENSOR,
|
||||
{
|
||||
"state": "{{ 'yes' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SWITCH,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.UPDATE,
|
||||
{
|
||||
"installed_version": "{{ '1.0' }}",
|
||||
"latest_version": "{{ '2.0' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.VACUUM,
|
||||
{
|
||||
"state": "{{ 'docked' }}",
|
||||
"start": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.WEATHER,
|
||||
{
|
||||
"condition": "{{ 'cloudy' }}",
|
||||
"temperature": "{{ 20 }}",
|
||||
"humidity": "{{ 50 }}",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("extra_section_config", "breadcrumb"),
|
||||
[
|
||||
({}, "template section"),
|
||||
({"unique_id": "foo"}, "template section with unique_id: foo"),
|
||||
],
|
||||
)
|
||||
async def test_trigger_schema_with_invalid_actions(
|
||||
hass: HomeAssistant,
|
||||
platform: Platform,
|
||||
config: ConfigType,
|
||||
extra_section_config: ConfigType,
|
||||
breadcrumb: str,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test trigger schema with invalid actions."""
|
||||
|
||||
await setup_entity(
|
||||
hass,
|
||||
TemplatePlatformSetup(
|
||||
platform,
|
||||
"test_entity",
|
||||
{
|
||||
**extra_section_config,
|
||||
"trigger": [
|
||||
{"trigger": "state", "entity_id": ["sensor.test_state"]},
|
||||
],
|
||||
"action": [
|
||||
{
|
||||
"type": "turn_off",
|
||||
"device_id": "70c5f67ec2f82f9ba128fe6e99eb7dfa",
|
||||
"entity_id": "c7e6f3753cb18937f2147bbbdccdd949",
|
||||
"domain": "light",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
ConfigurationStyle.TRIGGER,
|
||||
1,
|
||||
config,
|
||||
)
|
||||
|
||||
assert len(hass.states.async_entity_ids(platform)) == 0
|
||||
assert (
|
||||
f"The 'actions' for {breadcrumb} failed to setup: Unknown device '70c5f67ec2f82f9ba128fe6e99eb7dfa'"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("platform", "config"),
|
||||
[
|
||||
(
|
||||
Platform.ALARM_CONTROL_PANEL,
|
||||
{
|
||||
"state": "{{ 'disarmed' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.BINARY_SENSOR,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.COVER,
|
||||
{
|
||||
"state": "{{ 'open' }}",
|
||||
"open_cover": [],
|
||||
"close_cover": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.DEVICE_TRACKER,
|
||||
{
|
||||
"in_zones": "{{ ['zone.home'] }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.EVENT,
|
||||
{
|
||||
"event_type": "{{ 'single' }}",
|
||||
"event_types": "{{ ['single'] }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.FAN,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.IMAGE,
|
||||
{
|
||||
"url": "{{ 'http://www.test.com' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.LIGHT,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.LOCK,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"lock": [],
|
||||
"unlock": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.NUMBER,
|
||||
{
|
||||
"state": "{{ 4 }}",
|
||||
"min": "0",
|
||||
"max": "100",
|
||||
"step": "0.1",
|
||||
"unit_of_measurement": "cm",
|
||||
"set_value": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SELECT,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"options": "{{ ['off', 'on', 'auto'] }}",
|
||||
"select_option": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SENSOR,
|
||||
{
|
||||
"state": "{{ 'yes' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.SWITCH,
|
||||
{
|
||||
"state": "{{ 'on' }}",
|
||||
"turn_on": [],
|
||||
"turn_off": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.UPDATE,
|
||||
{
|
||||
"installed_version": "{{ '1.0' }}",
|
||||
"latest_version": "{{ '2.0' }}",
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.VACUUM,
|
||||
{
|
||||
"state": "{{ 'docked' }}",
|
||||
"start": [],
|
||||
},
|
||||
),
|
||||
(
|
||||
Platform.WEATHER,
|
||||
{
|
||||
"condition": "{{ 'cloudy' }}",
|
||||
"temperature": "{{ 20 }}",
|
||||
"humidity": "{{ 50 }}",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_trigger_schema_with_valid_actions(
|
||||
hass: HomeAssistant,
|
||||
platform: Platform,
|
||||
config: ConfigType,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
calls: list,
|
||||
) -> None:
|
||||
"""Test trigger schema with valid actions configurations."""
|
||||
|
||||
platform_setup, device_entry, entity_entry = await setup_mock_devices(
|
||||
hass, platform, device_registry, entity_registry
|
||||
)
|
||||
|
||||
await setup_entity(
|
||||
hass,
|
||||
TemplatePlatformSetup(
|
||||
platform,
|
||||
"test_entity",
|
||||
{
|
||||
"trigger": [
|
||||
{"trigger": "state", "entity_id": ["sensor.test_state"]},
|
||||
],
|
||||
**make_mock_device_actions(
|
||||
["actions"], platform_setup, device_entry, entity_entry
|
||||
),
|
||||
},
|
||||
),
|
||||
ConfigurationStyle.TRIGGER,
|
||||
1,
|
||||
config,
|
||||
)
|
||||
|
||||
await async_trigger(hass, "sensor.test_state", "anything")
|
||||
assert_action(platform_setup, calls, 1, "fake_action")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "expected_root", "expected_entity"),
|
||||
[
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
"""The tests for template helpers."""
|
||||
|
||||
from unittest.mock import AsyncMock, Mock
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.device_automation import toggle_entity
|
||||
from homeassistant.components.template import DOMAIN
|
||||
from homeassistant.components.template.alarm_control_panel import (
|
||||
SCRIPT_FIELDS as ALARM_CONTROL_PANEL_SCRIPT_FIELDS,
|
||||
@@ -42,64 +38,14 @@ from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .conftest import (
|
||||
ConfigurationStyle,
|
||||
TemplatePlatformSetup,
|
||||
assert_action,
|
||||
async_trigger,
|
||||
make_test_trigger,
|
||||
make_mock_device_actions,
|
||||
setup_entity,
|
||||
setup_mock_devices,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry, mock_platform
|
||||
|
||||
|
||||
async def _setup_mock_devices(
|
||||
hass: HomeAssistant,
|
||||
domain: str,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> tuple[TemplatePlatformSetup, dr.DeviceEntry, er.RegistryEntry]:
|
||||
FAKE_DOMAIN = "fake_integration"
|
||||
|
||||
hass.config.components.add(FAKE_DOMAIN)
|
||||
|
||||
async def _async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions."""
|
||||
return await toggle_entity.async_get_actions(hass, device_id, FAKE_DOMAIN)
|
||||
|
||||
mock_platform(
|
||||
hass,
|
||||
f"{FAKE_DOMAIN}.device_action",
|
||||
Mock(
|
||||
ACTION_SCHEMA=toggle_entity.ACTION_SCHEMA.extend(
|
||||
{vol.Required("domain"): FAKE_DOMAIN}
|
||||
),
|
||||
async_get_actions=_async_get_actions,
|
||||
async_call_action_from_config=AsyncMock(),
|
||||
spec=[
|
||||
"ACTION_SCHEMA",
|
||||
"async_get_actions",
|
||||
"async_call_action_from_config",
|
||||
],
|
||||
),
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
"fake_integration", "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
platform_setup = TemplatePlatformSetup(
|
||||
domain, "test_entity", make_test_trigger("sensor.trigger")
|
||||
)
|
||||
return (platform_setup, device_entry, entity_entry)
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def _setup_and_test_yaml_device_action(
|
||||
@@ -114,29 +60,13 @@ async def _setup_and_test_yaml_device_action(
|
||||
calls: list,
|
||||
) -> None:
|
||||
|
||||
platform_setup, device_entry, entity_entry = await _setup_mock_devices(
|
||||
platform_setup, device_entry, entity_entry = await setup_mock_devices(
|
||||
hass, domain, device_registry, entity_registry
|
||||
)
|
||||
|
||||
actions = {
|
||||
action: [
|
||||
{
|
||||
"action": "test.automation",
|
||||
"data": {
|
||||
"action": "fake_action",
|
||||
"caller": platform_setup.entity_id,
|
||||
},
|
||||
},
|
||||
{
|
||||
"domain": "fake_integration",
|
||||
"type": "turn_on",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": entity_entry.id,
|
||||
"metadata": {"secondary": False},
|
||||
},
|
||||
]
|
||||
for action in script_fields
|
||||
}
|
||||
actions = make_mock_device_actions(
|
||||
script_fields, platform_setup, device_entry, entity_entry
|
||||
)
|
||||
|
||||
await setup_entity(hass, platform_setup, style, 1, {**actions, **extra_config})
|
||||
await async_trigger(hass, "sensor.trigger", "anything")
|
||||
@@ -490,29 +420,13 @@ async def test_config_entry_device_actions(
|
||||
) -> None:
|
||||
"""Test device actions in config flow."""
|
||||
|
||||
platform_setup, device_entry, entity_entry = await _setup_mock_devices(
|
||||
platform_setup, device_entry, entity_entry = await setup_mock_devices(
|
||||
hass, domain, device_registry, entity_registry
|
||||
)
|
||||
|
||||
actions = {
|
||||
action: [
|
||||
{
|
||||
"action": "test.automation",
|
||||
"data": {
|
||||
"action": "fake_action",
|
||||
"caller": platform_setup.entity_id,
|
||||
},
|
||||
},
|
||||
{
|
||||
"domain": "fake_integration",
|
||||
"type": "turn_on",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": entity_entry.id,
|
||||
"metadata": {"secondary": False},
|
||||
},
|
||||
]
|
||||
for action in script_fields
|
||||
}
|
||||
actions = make_mock_device_actions(
|
||||
script_fields, platform_setup, device_entry, entity_entry
|
||||
)
|
||||
|
||||
template_config_entry = MockConfigEntry(
|
||||
data={},
|
||||
|
||||
Reference in New Issue
Block a user