Add default config if not there (#43321)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
0cf3736162
commit
b3be708db6
75 changed files with 432 additions and 21 deletions
|
@ -166,7 +166,8 @@ async def async_setup(hass, config):
|
|||
# To register the automation blueprints
|
||||
async_get_blueprints(hass)
|
||||
|
||||
await _async_process_config(hass, config, component)
|
||||
if not await _async_process_config(hass, config, component):
|
||||
await async_get_blueprints(hass).async_populate()
|
||||
|
||||
async def trigger_service_handler(entity, service_call):
|
||||
"""Handle automation triggers."""
|
||||
|
@ -487,12 +488,13 @@ async def _async_process_config(
|
|||
hass: HomeAssistant,
|
||||
config: Dict[str, Any],
|
||||
component: EntityComponent,
|
||||
) -> None:
|
||||
) -> bool:
|
||||
"""Process config and add automations.
|
||||
|
||||
This method is a coroutine.
|
||||
Returns if blueprints were used.
|
||||
"""
|
||||
entities = []
|
||||
blueprints_used = False
|
||||
|
||||
for config_key in extract_domain_configs(config, DOMAIN):
|
||||
conf: List[Union[Dict[str, Any], blueprint.BlueprintInputs]] = config[ # type: ignore
|
||||
|
@ -501,6 +503,7 @@ async def _async_process_config(
|
|||
|
||||
for list_no, config_block in enumerate(conf):
|
||||
if isinstance(config_block, blueprint.BlueprintInputs): # type: ignore
|
||||
blueprints_used = True
|
||||
blueprint_inputs = config_block
|
||||
|
||||
try:
|
||||
|
@ -562,6 +565,8 @@ async def _async_process_config(
|
|||
if entities:
|
||||
await component.async_add_entities(entities)
|
||||
|
||||
return blueprints_used
|
||||
|
||||
|
||||
async def _async_process_if(hass, config, p_config):
|
||||
"""Process if checks."""
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
blueprint:
|
||||
name: Motion-activated Light
|
||||
domain: automation
|
||||
source_url: https://github.com/home-assistant/core/blob/dev/homeassistant/components/automation/blueprints/motion_light.yaml
|
||||
input:
|
||||
motion_entity:
|
||||
name: Motion Sensor
|
||||
selector:
|
||||
entity:
|
||||
domain: binary_sensor
|
||||
device_class: motion
|
||||
light_entity:
|
||||
name: Light
|
||||
selector:
|
||||
entity:
|
||||
domain: light
|
||||
|
||||
# If motion is detected within the 120s delay,
|
||||
# we restart the script.
|
||||
mode: restart
|
||||
max_exceeded: silent
|
||||
|
||||
trigger:
|
||||
platform: state
|
||||
entity_id: !placeholder motion_entity
|
||||
from: "off"
|
||||
to: "on"
|
||||
|
||||
action:
|
||||
- service: homeassistant.turn_on
|
||||
entity_id: !placeholder light_entity
|
||||
- wait_for_trigger:
|
||||
platform: state
|
||||
entity_id: !placeholder motion_entity
|
||||
from: "on"
|
||||
to: "off"
|
||||
- delay: 120
|
||||
- service: homeassistant.turn_off
|
||||
entity_id: !placeholder light_entity
|
|
@ -0,0 +1,34 @@
|
|||
blueprint:
|
||||
name: Send notification when a person leaves a zone
|
||||
domain: automation
|
||||
source_url: https://github.com/home-assistant/core/blob/dev/homeassistant/components/automation/blueprints/notify_leaving_zone.yaml
|
||||
input:
|
||||
person_entity:
|
||||
name: Person
|
||||
selector:
|
||||
entity:
|
||||
domain: person
|
||||
zone_entity:
|
||||
name: Zone
|
||||
selector:
|
||||
entity:
|
||||
domain: zone
|
||||
notify_service:
|
||||
name: The notify service to use
|
||||
|
||||
trigger:
|
||||
platform: state
|
||||
entity_id: !placeholder person_entity
|
||||
|
||||
variables:
|
||||
zone_entity: !placeholder zone_entity
|
||||
zone_state: "{{ states[zone_entity].name }}"
|
||||
|
||||
condition:
|
||||
condition: template
|
||||
value_template: "{{ trigger.from_state.state == zone_state and trigger.to_state.state != zone_state }}"
|
||||
|
||||
action:
|
||||
- service: !placeholder notify_service
|
||||
data:
|
||||
message: "{{ trigger.to_state.name }} has left {{ zone_state }}"
|
|
@ -2,14 +2,16 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import pathlib
|
||||
import shutil
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from pkg_resources import parse_version
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from homeassistant import loader
|
||||
from homeassistant.const import CONF_DOMAIN, CONF_NAME, CONF_PATH, __version__
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import placeholder
|
||||
from homeassistant.util import yaml
|
||||
|
@ -169,6 +171,11 @@ class DomainBlueprints:
|
|||
|
||||
hass.data.setdefault(DOMAIN, {})[domain] = self
|
||||
|
||||
@property
|
||||
def blueprint_folder(self) -> pathlib.Path:
|
||||
"""Return the blueprint folder."""
|
||||
return pathlib.Path(self.hass.config.path(BLUEPRINT_FOLDER, self.domain))
|
||||
|
||||
@callback
|
||||
def async_reset_cache(self) -> None:
|
||||
"""Reset the blueprint cache."""
|
||||
|
@ -177,9 +184,7 @@ class DomainBlueprints:
|
|||
def _load_blueprint(self, blueprint_path) -> Blueprint:
|
||||
"""Load a blueprint."""
|
||||
try:
|
||||
blueprint_data = yaml.load_yaml(
|
||||
self.hass.config.path(BLUEPRINT_FOLDER, self.domain, blueprint_path)
|
||||
)
|
||||
blueprint_data = yaml.load_yaml(self.blueprint_folder / blueprint_path)
|
||||
except (HomeAssistantError, FileNotFoundError) as err:
|
||||
raise FailedToLoad(self.domain, blueprint_path, err) from err
|
||||
|
||||
|
@ -257,10 +262,7 @@ class DomainBlueprints:
|
|||
|
||||
async def async_remove_blueprint(self, blueprint_path: str) -> None:
|
||||
"""Remove a blueprint file."""
|
||||
path = pathlib.Path(
|
||||
self.hass.config.path(BLUEPRINT_FOLDER, self.domain, blueprint_path)
|
||||
)
|
||||
|
||||
path = self.blueprint_folder / blueprint_path
|
||||
await self.hass.async_add_executor_job(path.unlink)
|
||||
self._blueprints[blueprint_path] = None
|
||||
|
||||
|
@ -288,3 +290,18 @@ class DomainBlueprints:
|
|||
)
|
||||
|
||||
self._blueprints[blueprint_path] = blueprint
|
||||
|
||||
async def async_populate(self) -> None:
|
||||
"""Create folder if it doesn't exist and populate with examples."""
|
||||
integration = await loader.async_get_integration(self.hass, self.domain)
|
||||
|
||||
def populate():
|
||||
if self.blueprint_folder.exists():
|
||||
return
|
||||
|
||||
shutil.copytree(
|
||||
integration.file_path / BLUEPRINT_FOLDER,
|
||||
self.blueprint_folder / HA_DOMAIN,
|
||||
)
|
||||
|
||||
await self.hass.async_add_executor_job(populate)
|
||||
|
|
|
@ -63,6 +63,7 @@ BLUEPRINT_SCHEMA = vol.Schema(
|
|||
vol.Required(CONF_BLUEPRINT): vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): str,
|
||||
vol.Optional(CONF_DESCRIPTION): str,
|
||||
vol.Required(CONF_DOMAIN): str,
|
||||
vol.Optional(CONF_SOURCE_URL): cv.url,
|
||||
vol.Optional(CONF_HOMEASSISTANT): {
|
||||
|
|
|
@ -453,18 +453,12 @@ def async_template(
|
|||
) -> bool:
|
||||
"""Test if template condition matches."""
|
||||
try:
|
||||
value = value_template.async_render(variables)
|
||||
value: str = value_template.async_render(variables, parse_result=False)
|
||||
except TemplateError as ex:
|
||||
_LOGGER.error("Error during template condition: %s", ex)
|
||||
return False
|
||||
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
|
||||
if isinstance(value, str):
|
||||
return value.lower() == "true"
|
||||
|
||||
return False
|
||||
return value.lower() == "true"
|
||||
|
||||
|
||||
def async_template_from_config(
|
||||
|
|
|
@ -23,6 +23,10 @@ def validate_selector(config: Any) -> Dict:
|
|||
if selector_class is None:
|
||||
raise vol.Invalid(f"Unknown selector type {selector_type} found")
|
||||
|
||||
# Seletors can be empty
|
||||
if config[selector_type] is None:
|
||||
return {selector_type: {}}
|
||||
|
||||
return {
|
||||
selector_type: cast(Dict, selector_class.CONFIG_SCHEMA(config[selector_type]))
|
||||
}
|
||||
|
@ -44,6 +48,8 @@ class EntitySelector(Selector):
|
|||
vol.Optional("integration"): str,
|
||||
# Domain the entity belongs to
|
||||
vol.Optional("domain"): str,
|
||||
# Device class of the entity
|
||||
vol.Optional("device_class"): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ from io import StringIO
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
@ -704,6 +705,9 @@ def patch_yaml_files(files_dict, endswith=True):
|
|||
def mock_open_f(fname, **_):
|
||||
"""Mock open() in the yaml module, used by load_yaml."""
|
||||
# Return the mocked file on full match
|
||||
if isinstance(fname, pathlib.Path):
|
||||
fname = str(fname)
|
||||
|
||||
if fname in files_dict:
|
||||
_LOGGER.debug("patch_yaml_files match %s", fname)
|
||||
res = StringIO(files_dict[fname])
|
||||
|
|
|
@ -23,6 +23,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -22,6 +22,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -22,6 +22,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -13,6 +13,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
3
tests/components/automation/conftest.py
Normal file
3
tests/components/automation/conftest.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""Conftest for automation tests."""
|
||||
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
185
tests/components/automation/test_blueprint.py
Normal file
185
tests/components/automation/test_blueprint.py
Normal file
|
@ -0,0 +1,185 @@
|
|||
"""Test built-in blueprints."""
|
||||
import asyncio
|
||||
import contextlib
|
||||
from datetime import timedelta
|
||||
import pathlib
|
||||
|
||||
from homeassistant.components import automation
|
||||
from homeassistant.components.blueprint import models
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util, yaml
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.common import async_fire_time_changed, async_mock_service
|
||||
|
||||
BUILTIN_BLUEPRINT_FOLDER = pathlib.Path(automation.__file__).parent / "blueprints"
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def patch_blueprint(blueprint_path: str, data_path):
|
||||
"""Patch blueprint loading from a different source."""
|
||||
orig_load = models.DomainBlueprints._load_blueprint
|
||||
|
||||
@callback
|
||||
def mock_load_blueprint(self, path):
|
||||
if path != blueprint_path:
|
||||
assert False, f"Unexpected blueprint {path}"
|
||||
return orig_load(self, path)
|
||||
|
||||
return models.Blueprint(
|
||||
yaml.load_yaml(data_path), expected_domain=self.domain, path=path
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.blueprint.models.DomainBlueprints._load_blueprint",
|
||||
mock_load_blueprint,
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_notify_leaving_zone(hass):
|
||||
"""Test notifying leaving a zone blueprint."""
|
||||
|
||||
def set_person_state(state, extra={}):
|
||||
hass.states.async_set(
|
||||
"person.test_person", state, {"friendly_name": "Paulus", **extra}
|
||||
)
|
||||
|
||||
set_person_state("School")
|
||||
|
||||
assert await async_setup_component(
|
||||
hass, "zone", {"zone": {"name": "School", "latitude": 1, "longitude": 2}}
|
||||
)
|
||||
|
||||
with patch_blueprint(
|
||||
"notify_leaving_zone.yaml",
|
||||
BUILTIN_BLUEPRINT_FOLDER / "notify_leaving_zone.yaml",
|
||||
):
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"automation",
|
||||
{
|
||||
"automation": {
|
||||
"use_blueprint": {
|
||||
"path": "notify_leaving_zone.yaml",
|
||||
"input": {
|
||||
"person_entity": "person.test_person",
|
||||
"zone_entity": "zone.school",
|
||||
"notify_service": "notify.test_service",
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
calls = async_mock_service(hass, "notify", "test_service")
|
||||
|
||||
# Leaving zone to no zone
|
||||
set_person_state("not_home")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["message"] == "Paulus has left School"
|
||||
|
||||
# Should not increase when we go to another zone
|
||||
set_person_state("bla")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
|
||||
# Should not increase when we go into the zone
|
||||
set_person_state("School")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
|
||||
# Should not increase when we move in the zone
|
||||
set_person_state("School", {"extra_key": "triggers change with same state"})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
|
||||
# Should increase when leaving zone for another zone
|
||||
set_person_state("Just Outside School")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 2
|
||||
|
||||
|
||||
async def test_motion_light(hass):
|
||||
"""Test motion light blueprint."""
|
||||
hass.states.async_set("binary_sensor.kitchen", "off")
|
||||
|
||||
with patch_blueprint(
|
||||
"motion_light.yaml",
|
||||
BUILTIN_BLUEPRINT_FOLDER / "motion_light.yaml",
|
||||
):
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"automation",
|
||||
{
|
||||
"automation": {
|
||||
"use_blueprint": {
|
||||
"path": "motion_light.yaml",
|
||||
"input": {
|
||||
"light_entity": "light.kitchen",
|
||||
"motion_entity": "binary_sensor.kitchen",
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
turn_on_calls = async_mock_service(hass, "homeassistant", "turn_on")
|
||||
turn_off_calls = async_mock_service(hass, "homeassistant", "turn_off")
|
||||
|
||||
# Turn on motion
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
# Can't block till done because delay is active
|
||||
# So wait 5 event loop iterations to process script
|
||||
for _ in range(5):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_on_calls) == 1
|
||||
|
||||
# Test light doesn't turn off if motion stays
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200))
|
||||
|
||||
for _ in range(5):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_off_calls) == 0
|
||||
|
||||
# Test light turns off off 120s after last motion
|
||||
hass.states.async_set("binary_sensor.kitchen", "off")
|
||||
|
||||
for _ in range(5):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=120))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(turn_off_calls) == 1
|
||||
|
||||
# Test restarting the script
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
|
||||
for _ in range(5):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_on_calls) == 2
|
||||
assert len(turn_off_calls) == 1
|
||||
|
||||
hass.states.async_set("binary_sensor.kitchen", "off")
|
||||
|
||||
for _ in range(5):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
|
||||
for _ in range(15):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_on_calls) == 3
|
||||
assert len(turn_off_calls) == 1
|
|
@ -20,6 +20,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -20,6 +20,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
14
tests/components/blueprint/conftest.py
Normal file
14
tests/components/blueprint/conftest.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""Blueprints conftest."""
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.async_mock import patch
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def stub_blueprint_populate():
|
||||
"""Stub copying the blueprint automations to the config folder."""
|
||||
with patch(
|
||||
"homeassistant.components.blueprint.models.DomainBlueprints.async_populate"
|
||||
):
|
||||
yield
|
28
tests/components/blueprint/test_default_blueprints.py
Normal file
28
tests/components/blueprint/test_default_blueprints.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
"""Test default blueprints."""
|
||||
import importlib
|
||||
import logging
|
||||
import pathlib
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.blueprint import models
|
||||
from homeassistant.components.blueprint.const import BLUEPRINT_FOLDER
|
||||
from homeassistant.util import yaml
|
||||
|
||||
DOMAINS = ["automation"]
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("domain", DOMAINS)
|
||||
def test_default_blueprints(domain: str):
|
||||
"""Validate a folder of blueprints."""
|
||||
integration = importlib.import_module(f"homeassistant.components.{domain}")
|
||||
blueprint_folder = pathlib.Path(integration.__file__).parent / BLUEPRINT_FOLDER
|
||||
items = list(blueprint_folder.glob("*"))
|
||||
assert len(items) > 0, "Folder cannot be empty"
|
||||
|
||||
for fil in items:
|
||||
LOGGER.info("Processing %s", fil)
|
||||
assert fil.name.endswith(".yaml")
|
||||
data = yaml.load_yaml(fil)
|
||||
models.Blueprint(data, expected_domain=domain)
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -5,6 +5,7 @@ from homeassistant.bootstrap import async_setup_component
|
|||
from homeassistant.components import config
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
async def test_get_device_config(hass, hass_client):
|
||||
|
|
|
@ -4,6 +4,7 @@ import pytest
|
|||
from homeassistant.components.config import device_registry
|
||||
|
||||
from tests.common import mock_device_registry
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -22,6 +22,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -22,6 +22,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from homeassistant.const import (
|
|||
from .test_gateway import DECONZ_WEB_REQUEST, setup_deconz_integration
|
||||
|
||||
from tests.common import assert_lists_same, async_get_device_automations
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
SENSORS = {
|
||||
"1": {
|
||||
|
|
|
@ -4,6 +4,7 @@ import pytest
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
|
@ -13,6 +13,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
AWAY_LATITUDE = 32.881011
|
||||
AWAY_LONGITUDE = -117.234758
|
||||
|
|
|
@ -14,6 +14,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -7,6 +7,7 @@ from homeassistant.core import Context
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import async_mock_service, mock_component
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
3
tests/components/homeassistant/triggers/conftest.py
Normal file
3
tests/components/homeassistant/triggers/conftest.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""Conftest for HA triggers."""
|
||||
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
|
@ -12,6 +12,7 @@ from tests.common import (
|
|||
async_get_device_automations,
|
||||
async_mock_service,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
from tests.components.homekit_controller.common import setup_test_component
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
async_mock_service,
|
||||
mock_device_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
REMOTES_RESPONSE = {"7": HUE_TAP_REMOTE_1, "8": HUE_DIMMER_REMOTE_1}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -17,6 +17,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -20,6 +20,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -21,6 +21,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -11,6 +11,7 @@ import homeassistant.components.automation as automation
|
|||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import async_fire_time_changed, async_mock_service
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -15,6 +15,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -21,6 +21,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -7,6 +7,7 @@ from homeassistant.setup import async_setup_component
|
|||
|
||||
from tests.async_mock import ANY
|
||||
from tests.common import async_fire_mqtt_message, async_mock_service, mock_component
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -3,6 +3,7 @@ from homeassistant.components import search
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
async def test_search(hass):
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
from tests.testing_config.custom_components.test.sensor import DEVICE_CLASSES
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
from tests.testing_config.custom_components.test.sensor import DEVICE_CLASSES
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import homeassistant.util.dt as dt_util
|
|||
|
||||
from tests.async_mock import patch
|
||||
from tests.common import async_fire_time_changed, async_mock_service, mock_component
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
ORIG_TIME_ZONE = dt_util.DEFAULT_TIME_ZONE
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -8,6 +8,7 @@ from homeassistant.components.tag.const import DOMAIN, TAG_ID
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import async_mock_service
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -18,6 +18,7 @@ from tests.common import (
|
|||
async_fire_mqtt_message,
|
||||
async_get_device_automations,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
async def test_get_triggers(hass, device_reg, entity_reg, mqtt_mock, setup_tasmota):
|
||||
|
|
|
@ -17,6 +17,7 @@ from tests.common import (
|
|||
async_mock_service,
|
||||
mock_component,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -14,6 +14,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -14,6 +14,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -14,6 +14,7 @@ from tests.common import (
|
|||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -5,6 +5,7 @@ from homeassistant.core import callback
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
|
@ -16,6 +16,7 @@ from homeassistant.helpers.device_registry import async_get_registry
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import async_mock_service, mock_coro
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
SHORT_PRESS = "remote_button_short_press"
|
||||
COMMAND = "command"
|
||||
|
|
|
@ -19,6 +19,7 @@ from tests.common import (
|
|||
async_get_device_automations,
|
||||
async_mock_service,
|
||||
)
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
ON = 1
|
||||
OFF = 0
|
||||
|
|
|
@ -7,6 +7,7 @@ from homeassistant.core import Context
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import async_mock_service, mock_component
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -165,4 +165,4 @@ action:
|
|||
}
|
||||
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
|
||||
res = await async_check_ha_config_file(hass)
|
||||
assert len(res["automation"]) == 1
|
||||
assert len(res.get("automation", [])) == 1
|
||||
|
|
|
@ -6,7 +6,25 @@ from homeassistant.helpers import selector
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema", ({}, {"non_existing": {}}, {"device": {}, "entity": {}})
|
||||
"schema",
|
||||
(
|
||||
{"device": None},
|
||||
{"entity": None},
|
||||
),
|
||||
)
|
||||
def test_valid_base_schema(schema):
|
||||
"""Test base schema validation."""
|
||||
selector.validate_selector(schema)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"schema",
|
||||
(
|
||||
{},
|
||||
{"non_existing": {}},
|
||||
# Two keys
|
||||
{"device": {}, "entity": {}},
|
||||
),
|
||||
)
|
||||
def test_invalid_base_schema(schema):
|
||||
"""Test base schema validation."""
|
||||
|
|
Loading…
Add table
Reference in a new issue