Allow exposing any entity to the default conversation agent (#92398)
* Allow exposing any entity to the default conversation agent * Tweak * Fix race, update tests * Update tests
This commit is contained in:
parent
6a8668effc
commit
0126cfa9d9
30 changed files with 195 additions and 128 deletions
|
@ -1,4 +1,5 @@
|
|||
"""Const for conversation integration."""
|
||||
|
||||
DOMAIN = "conversation"
|
||||
DEFAULT_EXPOSED_ATTRIBUTES = {"device_class"}
|
||||
HOME_ASSISTANT_AGENT = "homeassistant"
|
||||
|
|
|
@ -21,19 +21,21 @@ from homeassistant.components.homeassistant.exposed_entities import (
|
|||
async_listen_entity_updates,
|
||||
async_should_expose,
|
||||
)
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS
|
||||
from homeassistant.const import MATCH_ALL
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
intent,
|
||||
start,
|
||||
template,
|
||||
translation,
|
||||
)
|
||||
from homeassistant.helpers.event import async_track_state_change
|
||||
from homeassistant.util.json import JsonObjectType, json_loads_object
|
||||
|
||||
from .agent import AbstractConversationAgent, ConversationInput, ConversationResult
|
||||
from .const import DOMAIN
|
||||
from .const import DEFAULT_EXPOSED_ATTRIBUTES, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_DEFAULT_ERROR_TEXT = "Sorry, I couldn't understand that"
|
||||
|
@ -81,16 +83,24 @@ def async_setup(hass: core.HomeAssistant) -> None:
|
|||
async_should_expose(hass, DOMAIN, entity_id)
|
||||
|
||||
@core.callback
|
||||
def async_handle_entity_registry_changed(event: core.Event) -> None:
|
||||
"""Set expose flag on newly created entities."""
|
||||
if event.data["action"] == "create":
|
||||
async_should_expose(hass, DOMAIN, event.data["entity_id"])
|
||||
def async_entity_state_listener(
|
||||
changed_entity: str,
|
||||
old_state: core.State | None,
|
||||
new_state: core.State | None,
|
||||
):
|
||||
"""Set expose flag on new entities."""
|
||||
if old_state is not None or new_state is None:
|
||||
return
|
||||
async_should_expose(hass, DOMAIN, changed_entity)
|
||||
|
||||
hass.bus.async_listen(
|
||||
er.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
async_handle_entity_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
@core.callback
|
||||
def async_hass_started(hass: core.HomeAssistant) -> None:
|
||||
"""Set expose flag on all entities."""
|
||||
for state in hass.states.async_all():
|
||||
async_should_expose(hass, DOMAIN, state.entity_id)
|
||||
async_track_state_change(hass, MATCH_ALL, async_entity_state_listener)
|
||||
|
||||
start.async_at_started(hass, async_hass_started)
|
||||
|
||||
|
||||
class DefaultAgent(AbstractConversationAgent):
|
||||
|
@ -130,6 +140,11 @@ class DefaultAgent(AbstractConversationAgent):
|
|||
self._async_handle_entity_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
self.hass.bus.async_listen(
|
||||
core.EVENT_STATE_CHANGED,
|
||||
self._async_handle_state_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
async_listen_entity_updates(
|
||||
self.hass, DOMAIN, self._async_exposed_entities_updated
|
||||
)
|
||||
|
@ -475,12 +490,19 @@ class DefaultAgent(AbstractConversationAgent):
|
|||
@core.callback
|
||||
def _async_handle_entity_registry_changed(self, event: core.Event) -> None:
|
||||
"""Clear names list cache when an entity registry entry has changed."""
|
||||
if event.data["action"] == "update" and not any(
|
||||
if event.data["action"] != "update" or not any(
|
||||
field in event.data["changes"] for field in _ENTITY_REGISTRY_UPDATE_FIELDS
|
||||
):
|
||||
return
|
||||
self._slot_lists = None
|
||||
|
||||
@core.callback
|
||||
def _async_handle_state_changed(self, event: core.Event) -> None:
|
||||
"""Clear names list cache when a state is added or removed from the state machine."""
|
||||
if event.data.get("old_state") and event.data.get("new_state"):
|
||||
return
|
||||
self._slot_lists = None
|
||||
|
||||
@core.callback
|
||||
def _async_exposed_entities_updated(self) -> None:
|
||||
"""Handle updated preferences."""
|
||||
|
@ -493,30 +515,38 @@ class DefaultAgent(AbstractConversationAgent):
|
|||
|
||||
area_ids_with_entities: set[str] = set()
|
||||
entity_registry = er.async_get(self.hass)
|
||||
entities = [
|
||||
entity
|
||||
for entity in entity_registry.entities.values()
|
||||
if async_should_expose(self.hass, DOMAIN, entity.entity_id)
|
||||
states = [
|
||||
state
|
||||
for state in self.hass.states.async_all()
|
||||
if async_should_expose(self.hass, DOMAIN, state.entity_id)
|
||||
]
|
||||
devices = dr.async_get(self.hass)
|
||||
|
||||
# Gather exposed entity names
|
||||
entity_names = []
|
||||
for entity in entities:
|
||||
for state in states:
|
||||
# Checked against "requires_context" and "excludes_context" in hassil
|
||||
context = {"domain": entity.domain}
|
||||
if entity.device_class:
|
||||
context[ATTR_DEVICE_CLASS] = entity.device_class
|
||||
context = {"domain": state.domain}
|
||||
if state.attributes:
|
||||
# Include some attributes
|
||||
for attr in DEFAULT_EXPOSED_ATTRIBUTES:
|
||||
if attr not in state.attributes:
|
||||
continue
|
||||
context[attr] = state.attributes[attr]
|
||||
|
||||
entity = entity_registry.async_get(state.entity_id)
|
||||
|
||||
if not entity:
|
||||
# Default name
|
||||
entity_names.append((state.name, state.name, context))
|
||||
continue
|
||||
|
||||
if entity.aliases:
|
||||
for alias in entity.aliases:
|
||||
entity_names.append((alias, alias, context))
|
||||
|
||||
# Default name
|
||||
name = entity.async_friendly_name(self.hass) or entity.entity_id.replace(
|
||||
"_", " "
|
||||
)
|
||||
entity_names.append((name, name, context))
|
||||
entity_names.append((state.name, state.name, context))
|
||||
|
||||
if entity.area_id:
|
||||
# Expose area too
|
||||
|
|
|
@ -305,7 +305,11 @@ class ExposedEntities:
|
|||
if domain in DEFAULT_EXPOSED_DOMAINS:
|
||||
return True
|
||||
|
||||
device_class = get_device_class(self._hass, entity_id)
|
||||
try:
|
||||
device_class = get_device_class(self._hass, entity_id)
|
||||
except HomeAssistantError:
|
||||
# The entity no longer exists
|
||||
return False
|
||||
if (
|
||||
domain == "binary_sensor"
|
||||
and device_class in DEFAULT_EXPOSED_BINARY_SENSOR_DEVICE_CLASSES
|
||||
|
|
|
@ -307,26 +307,6 @@ class RegistryEntry:
|
|||
|
||||
hass.states.async_set(self.entity_id, STATE_UNAVAILABLE, attrs)
|
||||
|
||||
def async_friendly_name(self, hass: HomeAssistant) -> str | None:
|
||||
"""Return the friendly name.
|
||||
|
||||
If self.name is not None, this returns self.name
|
||||
If has_entity_name is False, self.original_name
|
||||
If has_entity_name is True, this returns device.name + self.original_name
|
||||
"""
|
||||
if not self.has_entity_name or self.name is not None:
|
||||
return self.name or self.original_name
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
if not (device_id := self.device_id) or not (
|
||||
device_entry := device_registry.async_get(device_id)
|
||||
):
|
||||
return self.original_name
|
||||
|
||||
if not (original_name := self.original_name):
|
||||
return device_entry.name_by_user or device_entry.name
|
||||
return f"{device_entry.name_by_user or device_entry.name} {original_name}"
|
||||
|
||||
|
||||
class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
|
||||
"""Store entity registry data."""
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
"""The tests for the Air Quality component."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.air_quality import ATTR_N2O, ATTR_OZONE, ATTR_PM_10
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
|
@ -9,6 +11,12 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
async def test_state(hass: HomeAssistant) -> None:
|
||||
"""Test Air Quality state."""
|
||||
config = {"air_quality": {"platform": "demo"}}
|
||||
|
|
|
@ -39,6 +39,7 @@ def events(hass: HomeAssistant) -> list[Event]:
|
|||
@pytest.fixture
|
||||
async def mock_camera(hass: HomeAssistant) -> None:
|
||||
"""Initialize a demo camera platform."""
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
assert await async_setup_component(
|
||||
hass, "camera", {camera.DOMAIN: {"platform": "demo"}}
|
||||
)
|
||||
|
|
|
@ -1539,6 +1539,7 @@ async def test_automation_restore_last_triggered_with_initial_state(
|
|||
|
||||
async def test_extraction_functions(hass: HomeAssistant) -> None:
|
||||
"""Test extraction functions."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
|
11
tests/components/calendar/conftest.py
Normal file
11
tests/components/calendar/conftest.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
"""Test fixtures for calendar sensor platforms."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
|
@ -1,6 +1,8 @@
|
|||
"""The tests for calendar recorder."""
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.recorder import Recorder
|
||||
from homeassistant.components.recorder.history import get_significant_states
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME
|
||||
|
@ -12,9 +14,15 @@ from tests.common import async_fire_time_changed
|
|||
from tests.components.recorder.common import async_wait_recording_done
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant():
|
||||
"""Override the fixture in calendar.conftest."""
|
||||
|
||||
|
||||
async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant) -> None:
|
||||
"""Test sensor attributes to be excluded."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
|
|
@ -5,11 +5,18 @@ import pytest
|
|||
|
||||
from homeassistant.components import camera
|
||||
from homeassistant.components.camera.const import StreamType
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .common import WEBRTC_ANSWER
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_camera")
|
||||
async def mock_camera_fixture(hass):
|
||||
"""Initialize a demo camera platform."""
|
||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
|||
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import camera
|
||||
from homeassistant.components.recorder import Recorder
|
||||
from homeassistant.components.recorder.history import get_significant_states
|
||||
|
@ -20,9 +22,15 @@ from tests.common import async_fire_time_changed
|
|||
from tests.components.recorder.common import async_wait_recording_done
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant():
|
||||
"""Override the fixture in calendar.conftest."""
|
||||
|
||||
|
||||
async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant) -> None:
|
||||
"""Test camera registered attributes to be excluded."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(
|
||||
hass, camera.DOMAIN, {camera.DOMAIN: {"platform": "demo"}}
|
||||
)
|
||||
|
|
|
@ -91,21 +91,21 @@ async def test_exposed_areas(
|
|||
)
|
||||
device_registry.async_update_device(kitchen_device.id, area_id=area_kitchen.id)
|
||||
|
||||
kitchen_light = entity_registry.async_get_or_create(
|
||||
"light", "demo", "1234", original_name="kitchen light"
|
||||
)
|
||||
kitchen_light = entity_registry.async_get_or_create("light", "demo", "1234")
|
||||
entity_registry.async_update_entity(
|
||||
kitchen_light.entity_id, device_id=kitchen_device.id
|
||||
)
|
||||
hass.states.async_set(kitchen_light.entity_id, "on")
|
||||
|
||||
bedroom_light = entity_registry.async_get_or_create(
|
||||
"light", "demo", "5678", original_name="bedroom light"
|
||||
hass.states.async_set(
|
||||
kitchen_light.entity_id, "on", attributes={ATTR_FRIENDLY_NAME: "kitchen light"}
|
||||
)
|
||||
|
||||
bedroom_light = entity_registry.async_get_or_create("light", "demo", "5678")
|
||||
entity_registry.async_update_entity(
|
||||
bedroom_light.entity_id, area_id=area_bedroom.id
|
||||
)
|
||||
hass.states.async_set(bedroom_light.entity_id, "on")
|
||||
hass.states.async_set(
|
||||
bedroom_light.entity_id, "on", attributes={ATTR_FRIENDLY_NAME: "bedroom light"}
|
||||
)
|
||||
|
||||
# Hide the bedroom light
|
||||
expose_entity(hass, bedroom_light.entity_id, False)
|
||||
|
@ -156,6 +156,8 @@ async def test_expose_flag_automatically_set(
|
|||
|
||||
assert await async_setup_component(hass, "conversation", {})
|
||||
await hass.async_block_till_done()
|
||||
with patch("homeassistant.components.http.start_http_server_and_save_config"):
|
||||
await hass.async_start()
|
||||
|
||||
# After setting up conversation, the expose flag should now be set on all entities
|
||||
assert async_get_assistant_settings(hass, conversation.DOMAIN) == {
|
||||
|
@ -164,10 +166,11 @@ async def test_expose_flag_automatically_set(
|
|||
}
|
||||
|
||||
# New entities will automatically have the expose flag set
|
||||
new_light = entity_registry.async_get_or_create("light", "demo", "2345")
|
||||
new_light = "light.demo_2345"
|
||||
hass.states.async_set(new_light, "test")
|
||||
await hass.async_block_till_done()
|
||||
assert async_get_assistant_settings(hass, conversation.DOMAIN) == {
|
||||
light.entity_id: {"should_expose": True},
|
||||
new_light.entity_id: {"should_expose": True},
|
||||
new_light: {"should_expose": True},
|
||||
test.entity_id: {"should_expose": False},
|
||||
}
|
||||
|
|
|
@ -202,11 +202,7 @@ async def test_http_processing_intent_entity_added_removed(
|
|||
|
||||
# Add an entity
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"5678",
|
||||
suggested_object_id="late",
|
||||
original_name="friendly light",
|
||||
"light", "demo", "5678", suggested_object_id="late"
|
||||
)
|
||||
hass.states.async_set("light.late", "off", {"friendly_name": "friendly light"})
|
||||
|
||||
|
@ -274,7 +270,7 @@ async def test_http_processing_intent_entity_added_removed(
|
|||
}
|
||||
|
||||
# Now delete the entity
|
||||
entity_registry.async_remove("light.late")
|
||||
hass.states.async_remove("light.late")
|
||||
|
||||
client = await hass_client()
|
||||
resp = await client.post(
|
||||
|
@ -313,11 +309,7 @@ async def test_http_processing_intent_alias_added_removed(
|
|||
so that the new alias is available.
|
||||
"""
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen light",
|
||||
"light", "demo", "1234", suggested_object_id="kitchen"
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "off", {"friendly_name": "kitchen light"})
|
||||
|
||||
|
@ -438,7 +430,6 @@ async def test_http_processing_intent_entity_renamed(
|
|||
LIGHT_DOMAIN,
|
||||
{LIGHT_DOMAIN: [{"platform": "test"}]},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
calls = async_mock_service(hass, LIGHT_DOMAIN, "turn_on")
|
||||
client = await hass_client()
|
||||
|
@ -882,20 +873,9 @@ async def test_http_processing_intent_conversion_not_expose_new(
|
|||
@pytest.mark.parametrize("agent_id", AGENT_ID_OPTIONS)
|
||||
@pytest.mark.parametrize("sentence", ("turn on kitchen", "turn kitchen on"))
|
||||
async def test_turn_on_intent(
|
||||
hass: HomeAssistant,
|
||||
init_components,
|
||||
entity_registry: er.EntityRegistry,
|
||||
sentence,
|
||||
agent_id,
|
||||
hass: HomeAssistant, init_components, sentence, agent_id
|
||||
) -> None:
|
||||
"""Test calling the turn on intent."""
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen",
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "off")
|
||||
calls = async_mock_service(hass, LIGHT_DOMAIN, "turn_on")
|
||||
|
||||
|
@ -913,17 +893,8 @@ async def test_turn_on_intent(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("sentence", ("turn off kitchen", "turn kitchen off"))
|
||||
async def test_turn_off_intent(
|
||||
hass: HomeAssistant, init_components, entity_registry: er.EntityRegistry, sentence
|
||||
) -> None:
|
||||
async def test_turn_off_intent(hass: HomeAssistant, init_components, sentence) -> None:
|
||||
"""Test calling the turn on intent."""
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen",
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "on")
|
||||
calls = async_mock_service(hass, LIGHT_DOMAIN, "turn_off")
|
||||
|
||||
|
@ -969,21 +940,11 @@ async def test_http_api_no_match(
|
|||
|
||||
|
||||
async def test_http_api_handle_failure(
|
||||
hass: HomeAssistant,
|
||||
init_components,
|
||||
entity_registry: er.EntityRegistry,
|
||||
hass_client: ClientSessionGenerator,
|
||||
hass: HomeAssistant, init_components, hass_client: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test the HTTP conversation API with an error during handling."""
|
||||
client = await hass_client()
|
||||
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen",
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "off")
|
||||
|
||||
# Raise an error during intent handling
|
||||
|
@ -1020,19 +981,11 @@ async def test_http_api_handle_failure(
|
|||
async def test_http_api_unexpected_failure(
|
||||
hass: HomeAssistant,
|
||||
init_components,
|
||||
entity_registry: er.EntityRegistry,
|
||||
hass_client: ClientSessionGenerator,
|
||||
) -> None:
|
||||
"""Test the HTTP conversation API with an unexpected error during handling."""
|
||||
client = await hass_client()
|
||||
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen",
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "off")
|
||||
|
||||
# Raise an "unexpected" error during intent handling
|
||||
|
@ -1355,17 +1308,8 @@ async def test_prepare_fail(hass: HomeAssistant) -> None:
|
|||
assert not agent._lang_intents.get("not-a-language")
|
||||
|
||||
|
||||
async def test_language_region(
|
||||
hass: HomeAssistant, init_components, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
async def test_language_region(hass: HomeAssistant, init_components) -> None:
|
||||
"""Test calling the turn on intent."""
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="kitchen",
|
||||
original_name="kitchen",
|
||||
)
|
||||
hass.states.async_set("light.kitchen", "off")
|
||||
calls = async_mock_service(hass, LIGHT_DOMAIN, "turn_on")
|
||||
|
||||
|
@ -1414,17 +1358,8 @@ async def test_reload_on_new_component(hass: HomeAssistant) -> None:
|
|||
assert {"light"} == (lang_intents.loaded_components - loaded_components)
|
||||
|
||||
|
||||
async def test_non_default_response(
|
||||
hass: HomeAssistant, init_components, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
async def test_non_default_response(hass: HomeAssistant, init_components) -> None:
|
||||
"""Test intent response that is not the default."""
|
||||
entity_registry.async_get_or_create(
|
||||
"cover",
|
||||
"demo",
|
||||
"1234",
|
||||
suggested_object_id="front_door",
|
||||
original_name="front door",
|
||||
)
|
||||
hass.states.async_set("cover.front_door", "closed")
|
||||
calls = async_mock_service(hass, "cover", SERVICE_OPEN_COVER)
|
||||
|
||||
|
|
|
@ -218,6 +218,7 @@ async def test_discover_platform(
|
|||
mock_demo_setup_scanner, mock_see, hass: HomeAssistant
|
||||
) -> None:
|
||||
"""Test discovery of device_tracker demo platform."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
with patch("homeassistant.components.device_tracker.legacy.update_config"):
|
||||
await discovery.async_load_platform(
|
||||
hass, device_tracker.DOMAIN, "demo", {"test_key": "test_val"}, {"bla": {}}
|
||||
|
|
|
@ -75,6 +75,12 @@ VALID_CONFIG = {
|
|||
}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_healthybox():
|
||||
"""Mock fb.check_box_health."""
|
||||
|
|
|
@ -209,6 +209,7 @@ async def test_send_text_command_expired_token_refresh_failure(
|
|||
requires_reauth: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test failure refreshing token in send_text_command."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await setup_integration()
|
||||
|
||||
entries = hass.config_entries.async_entries(DOMAIN)
|
||||
|
|
|
@ -43,6 +43,12 @@ MOCK_START_STREAM_SESSION_UUID = UUID("3303d503-17cc-469a-b672-92436a71a2f6")
|
|||
PID_THAT_WILL_NEVER_BE_ALIVE = 2147483647
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
async def _async_start_streaming(hass, acc):
|
||||
"""Start streaming a camera."""
|
||||
acc.set_selected_stream_configuration(MOCK_START_STREAM_TLV)
|
||||
|
|
|
@ -16,6 +16,12 @@ from tests.common import assert_setup_component, async_capture_events
|
|||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_unused_port(event_loop, aiohttp_unused_port, socket_enabled):
|
||||
"""Return aiohttp_unused_port and allow opening sockets."""
|
||||
|
|
|
@ -21,6 +21,12 @@ from tests.test_util.aiohttp import AiohttpClientMocker
|
|||
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
async def test_get_image_http(
|
||||
hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator
|
||||
) -> None:
|
||||
|
|
|
@ -25,6 +25,7 @@ from tests.components.recorder.common import async_wait_recording_done
|
|||
async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant) -> None:
|
||||
"""Test media_player registered attributes to be excluded."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(
|
||||
hass, media_player.DOMAIN, {media_player.DOMAIN: {"platform": "demo"}}
|
||||
)
|
||||
|
|
|
@ -25,6 +25,12 @@ from tests.common import assert_setup_component, load_fixture
|
|||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
def create_group(hass, name):
|
||||
"""Create a new person group.
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@ CONFIG = {
|
|||
ENDPOINT_URL = f"https://westus.{mf.FACE_API_URL}"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store_mock():
|
||||
"""Mock update store."""
|
||||
|
|
|
@ -14,6 +14,12 @@ from tests.components.image_processing import common
|
|||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store_mock():
|
||||
"""Mock update store."""
|
||||
|
|
|
@ -14,6 +14,12 @@ from tests.components.image_processing import common
|
|||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def setup_openalpr_cloud(hass):
|
||||
"""Set up openalpr cloud."""
|
||||
|
|
|
@ -14,6 +14,7 @@ from homeassistant.components.rtsp_to_webrtc import CONF_STUN_SERVER, DOMAIN
|
|||
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .conftest import SERVER_URL, STREAM_SOURCE, ComponentSetup
|
||||
|
||||
|
@ -27,6 +28,12 @@ OFFER_SDP = "v=0\r\no=carol 28908764872 28908764872 IN IP4 100.3.6.6\r\n..."
|
|||
ANSWER_SDP = "v=0\r\no=bob 2890844730 2890844730 IN IP4 host.example.com\r\n..."
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
async def test_setup_success(
|
||||
hass: HomeAssistant, rtsp_to_webrtc_client: Any, setup_integration: ComponentSetup
|
||||
) -> None:
|
||||
|
|
|
@ -1373,6 +1373,7 @@ def test_compile_hourly_sum_statistics_negative_state(
|
|||
mocksensor._attr_should_poll = False
|
||||
platform.ENTITIES["custom_sensor"] = mocksensor
|
||||
|
||||
setup_component(hass, "homeassistant", {})
|
||||
setup_component(
|
||||
hass, "sensor", {"sensor": [{"platform": "demo"}, {"platform": "test"}]}
|
||||
)
|
||||
|
|
|
@ -46,6 +46,12 @@ MOCK_DETECTIONS = {
|
|||
MOCK_NOW = datetime.datetime(2020, 2, 20, 10, 5, 3)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_detections():
|
||||
"""Return a mock detection."""
|
||||
|
|
|
@ -72,6 +72,8 @@ async def test_setup_legacy_service(hass: HomeAssistant) -> None:
|
|||
},
|
||||
}
|
||||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
with assert_setup_component(1, tts.DOMAIN):
|
||||
assert await async_setup_component(hass, tts.DOMAIN, config)
|
||||
|
||||
|
|
|
@ -1105,6 +1105,7 @@ async def test_state_template(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_browse_media(hass: HomeAssistant) -> None:
|
||||
"""Test browse media."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(
|
||||
hass, "media_player", {"media_player": {"platform": "demo"}}
|
||||
)
|
||||
|
@ -1135,6 +1136,7 @@ async def test_browse_media(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_browse_media_override(hass: HomeAssistant) -> None:
|
||||
"""Test browse media override."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(
|
||||
hass, "media_player", {"media_player": {"platform": "demo"}}
|
||||
)
|
||||
|
|
|
@ -18,6 +18,7 @@ from tests.components.recorder.common import async_wait_recording_done
|
|||
async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant) -> None:
|
||||
"""Test weather attributes to be excluded."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {"platform": "demo"}})
|
||||
hass.config.units = METRIC_SYSTEM
|
||||
await hass.async_block_till_done()
|
||||
|
|
Loading…
Add table
Reference in a new issue