Allow exposing entities not in the entity registry to assistants (#92363)
This commit is contained in:
parent
cc4e741cfa
commit
e3c16e634b
52 changed files with 563 additions and 224 deletions
|
@ -4,13 +4,13 @@ import pytest
|
|||
from homeassistant.components.homeassistant.exposed_entities import (
|
||||
DATA_EXPOSED_ENTITIES,
|
||||
ExposedEntities,
|
||||
ExposedEntity,
|
||||
async_get_assistant_settings,
|
||||
async_listen_entity_updates,
|
||||
async_should_expose,
|
||||
)
|
||||
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
@ -31,7 +31,7 @@ async def test_load_preferences(hass: HomeAssistant) -> None:
|
|||
assert list(exposed_entities._assistants) == ["test1", "test2"]
|
||||
|
||||
exposed_entities2 = ExposedEntities(hass)
|
||||
await flush_store(exposed_entities._store)
|
||||
await flush_store(exposed_entities.store)
|
||||
await exposed_entities2.async_load()
|
||||
|
||||
assert exposed_entities._assistants == exposed_entities2._assistants
|
||||
|
@ -50,6 +50,9 @@ async def test_expose_entity(
|
|||
entry1 = entity_registry.async_get_or_create("test", "test", "unique1")
|
||||
entry2 = entity_registry.async_get_or_create("test", "test", "unique2")
|
||||
|
||||
exposed_entities: ExposedEntities = hass.data[DATA_EXPOSED_ENTITIES]
|
||||
assert len(exposed_entities.data) == 0
|
||||
|
||||
# Set options
|
||||
await ws_client.send_json_auto_id(
|
||||
{
|
||||
|
@ -67,6 +70,7 @@ async def test_expose_entity(
|
|||
assert entry1.options == {"cloud.alexa": {"should_expose": True}}
|
||||
entry2 = entity_registry.async_get(entry2.entity_id)
|
||||
assert entry2.options == {}
|
||||
assert len(exposed_entities.data) == 0
|
||||
|
||||
# Update options
|
||||
await ws_client.send_json_auto_id(
|
||||
|
@ -91,6 +95,7 @@ async def test_expose_entity(
|
|||
"cloud.alexa": {"should_expose": False},
|
||||
"cloud.google_assistant": {"should_expose": False},
|
||||
}
|
||||
assert len(exposed_entities.data) == 0
|
||||
|
||||
|
||||
async def test_expose_entity_unknown(
|
||||
|
@ -103,6 +108,7 @@ async def test_expose_entity_unknown(
|
|||
await hass.async_block_till_done()
|
||||
|
||||
exposed_entities: ExposedEntities = hass.data[DATA_EXPOSED_ENTITIES]
|
||||
assert len(exposed_entities.data) == 0
|
||||
|
||||
# Set options
|
||||
await ws_client.send_json_auto_id(
|
||||
|
@ -115,14 +121,41 @@ async def test_expose_entity_unknown(
|
|||
)
|
||||
|
||||
response = await ws_client.receive_json()
|
||||
assert not response["success"]
|
||||
assert response["error"] == {
|
||||
"code": "not_found",
|
||||
"message": "can't expose 'test.test'",
|
||||
assert response["success"]
|
||||
|
||||
assert len(exposed_entities.data) == 1
|
||||
assert exposed_entities.data == {
|
||||
"test.test": ExposedEntity({"cloud.alexa": {"should_expose": True}})
|
||||
}
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
exposed_entities.async_expose_entity("cloud.alexa", "test.test", True)
|
||||
# Update options
|
||||
await ws_client.send_json_auto_id(
|
||||
{
|
||||
"type": "homeassistant/expose_entity",
|
||||
"assistants": ["cloud.alexa", "cloud.google_assistant"],
|
||||
"entity_ids": ["test.test", "test.test2"],
|
||||
"should_expose": False,
|
||||
}
|
||||
)
|
||||
|
||||
response = await ws_client.receive_json()
|
||||
assert response["success"]
|
||||
|
||||
assert len(exposed_entities.data) == 2
|
||||
assert exposed_entities.data == {
|
||||
"test.test": ExposedEntity(
|
||||
{
|
||||
"cloud.alexa": {"should_expose": False},
|
||||
"cloud.google_assistant": {"should_expose": False},
|
||||
}
|
||||
),
|
||||
"test.test2": ExposedEntity(
|
||||
{
|
||||
"cloud.alexa": {"should_expose": False},
|
||||
"cloud.google_assistant": {"should_expose": False},
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def test_expose_entity_blocked(
|
||||
|
@ -178,7 +211,7 @@ async def test_expose_new_entities(
|
|||
assert response["result"] == {"expose_new": False}
|
||||
|
||||
# Check if exposed - should be False
|
||||
assert async_should_expose(hass, "cloud.alexa", entry1.entity_id) is False
|
||||
assert await async_should_expose(hass, "cloud.alexa", entry1.entity_id) is False
|
||||
|
||||
# Expose new entities to Alexa
|
||||
await ws_client.send_json_auto_id(
|
||||
|
@ -201,10 +234,12 @@ async def test_expose_new_entities(
|
|||
assert response["result"] == {"expose_new": expose_new}
|
||||
|
||||
# Check again if exposed - should still be False
|
||||
assert async_should_expose(hass, "cloud.alexa", entry1.entity_id) is False
|
||||
assert await async_should_expose(hass, "cloud.alexa", entry1.entity_id) is False
|
||||
|
||||
# Check if exposed - should be True
|
||||
assert async_should_expose(hass, "cloud.alexa", entry2.entity_id) == expose_new
|
||||
assert (
|
||||
await async_should_expose(hass, "cloud.alexa", entry2.entity_id) == expose_new
|
||||
)
|
||||
|
||||
|
||||
async def test_listen_updates(
|
||||
|
@ -226,21 +261,21 @@ async def test_listen_updates(
|
|||
entry = entity_registry.async_get_or_create("climate", "test", "unique1")
|
||||
|
||||
# Call for another assistant - listener not called
|
||||
exposed_entities.async_expose_entity(
|
||||
await exposed_entities.async_expose_entity(
|
||||
"cloud.google_assistant", entry.entity_id, True
|
||||
)
|
||||
assert len(calls) == 0
|
||||
|
||||
# Call for our assistant - listener called
|
||||
exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
await exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
assert len(calls) == 1
|
||||
|
||||
# Settings not changed - listener not called
|
||||
exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
await exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
assert len(calls) == 1
|
||||
|
||||
# Settings changed - listener called
|
||||
exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, False)
|
||||
await exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, False)
|
||||
assert len(calls) == 2
|
||||
|
||||
|
||||
|
@ -258,7 +293,7 @@ async def test_get_assistant_settings(
|
|||
|
||||
assert async_get_assistant_settings(hass, "cloud.alexa") == {}
|
||||
|
||||
exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
await exposed_entities.async_expose_entity("cloud.alexa", entry.entity_id, True)
|
||||
assert async_get_assistant_settings(hass, "cloud.alexa") == {
|
||||
"climate.test_unique1": {"should_expose": True}
|
||||
}
|
||||
|
@ -287,40 +322,44 @@ async def test_should_expose(
|
|||
assert response["success"]
|
||||
|
||||
# Unknown entity is not exposed
|
||||
assert async_should_expose(hass, "test.test", "test.test") is False
|
||||
assert await async_should_expose(hass, "test.test", "test.test") is False
|
||||
|
||||
# Blocked entity is not exposed
|
||||
entry_blocked = entity_registry.async_get_or_create(
|
||||
"group", "test", "unique", suggested_object_id="all_locks"
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", entry_blocked.entity_id) is False
|
||||
assert (
|
||||
await async_should_expose(hass, "cloud.alexa", entry_blocked.entity_id) is False
|
||||
)
|
||||
|
||||
# Lock is exposed
|
||||
lock1 = entity_registry.async_get_or_create("lock", "test", "unique1")
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", lock1.entity_id) is True
|
||||
assert await async_should_expose(hass, "cloud.alexa", lock1.entity_id) is True
|
||||
|
||||
# Hidden entity is not exposed
|
||||
lock2 = entity_registry.async_get_or_create(
|
||||
"lock", "test", "unique2", hidden_by=er.RegistryEntryHider.USER
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", lock2.entity_id) is False
|
||||
assert await async_should_expose(hass, "cloud.alexa", lock2.entity_id) is False
|
||||
|
||||
# Entity with category is not exposed
|
||||
lock3 = entity_registry.async_get_or_create(
|
||||
"lock", "test", "unique3", entity_category=EntityCategory.CONFIG
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", lock3.entity_id) is False
|
||||
assert await async_should_expose(hass, "cloud.alexa", lock3.entity_id) is False
|
||||
|
||||
# Binary sensor without device class is not exposed
|
||||
binarysensor1 = entity_registry.async_get_or_create(
|
||||
"binary_sensor", "test", "unique1"
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", binarysensor1.entity_id) is False
|
||||
assert (
|
||||
await async_should_expose(hass, "cloud.alexa", binarysensor1.entity_id) is False
|
||||
)
|
||||
|
||||
# Binary sensor with certain device class is exposed
|
||||
binarysensor2 = entity_registry.async_get_or_create(
|
||||
|
@ -330,12 +369,14 @@ async def test_should_expose(
|
|||
original_device_class="door",
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", binarysensor2.entity_id) is True
|
||||
assert (
|
||||
await async_should_expose(hass, "cloud.alexa", binarysensor2.entity_id) is True
|
||||
)
|
||||
|
||||
# Sensor without device class is not exposed
|
||||
sensor1 = entity_registry.async_get_or_create("sensor", "test", "unique1")
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", sensor1.entity_id) is False
|
||||
assert await async_should_expose(hass, "cloud.alexa", sensor1.entity_id) is False
|
||||
|
||||
# Sensor with certain device class is exposed
|
||||
sensor2 = entity_registry.async_get_or_create(
|
||||
|
@ -345,4 +386,58 @@ async def test_should_expose(
|
|||
original_device_class="temperature",
|
||||
)
|
||||
assert entry_blocked.entity_id == CLOUD_NEVER_EXPOSED_ENTITIES[0]
|
||||
assert async_should_expose(hass, "cloud.alexa", sensor2.entity_id) is True
|
||||
assert await async_should_expose(hass, "cloud.alexa", sensor2.entity_id) is True
|
||||
|
||||
|
||||
async def test_list_exposed_entities(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
) -> None:
|
||||
"""Test list exposed entities."""
|
||||
ws_client = await hass_ws_client(hass)
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entry1 = entity_registry.async_get_or_create("test", "test", "unique1")
|
||||
entry2 = entity_registry.async_get_or_create("test", "test", "unique2")
|
||||
|
||||
# Set options for registered entities
|
||||
await ws_client.send_json_auto_id(
|
||||
{
|
||||
"type": "homeassistant/expose_entity",
|
||||
"assistants": ["cloud.alexa", "cloud.google_assistant"],
|
||||
"entity_ids": [entry1.entity_id, entry2.entity_id],
|
||||
"should_expose": True,
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert response["success"]
|
||||
|
||||
# Set options for entities not in the entity registry
|
||||
await ws_client.send_json_auto_id(
|
||||
{
|
||||
"type": "homeassistant/expose_entity",
|
||||
"assistants": ["cloud.alexa", "cloud.google_assistant"],
|
||||
"entity_ids": [
|
||||
"test.test",
|
||||
"test.test2",
|
||||
],
|
||||
"should_expose": False,
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert response["success"]
|
||||
|
||||
# List exposed entities
|
||||
await ws_client.send_json_auto_id({"type": "homeassistant/expose_entity/list"})
|
||||
response = await ws_client.receive_json()
|
||||
assert response["success"]
|
||||
assert response["result"] == {
|
||||
"exposed_entities": {
|
||||
"test.test": {"cloud.alexa": False, "cloud.google_assistant": False},
|
||||
"test.test2": {"cloud.alexa": False, "cloud.google_assistant": False},
|
||||
"test.test_unique1": {"cloud.alexa": True, "cloud.google_assistant": True},
|
||||
"test.test_unique2": {"cloud.alexa": True, "cloud.google_assistant": True},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue