Compare commits

...

7 Commits

23 changed files with 59 additions and 190 deletions
@@ -39,7 +39,6 @@ from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_SUPPORTED_FEATURES,
ATTR_UNIT_OF_MEASUREMENT,
CLOUD_NEVER_EXPOSED_ENTITIES,
CONF_DESCRIPTION,
CONF_NAME,
UnitOfTemperature,
@@ -373,9 +372,6 @@ def async_get_entities(
"""Return all entities that are supported by Alexa."""
entities: list[AlexaEntity] = []
for state in hass.states.async_all():
if state.entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
continue
if state.domain not in ENTITY_ADAPTERS:
continue
@@ -21,6 +21,6 @@
"bluetooth-auto-recovery==1.5.3",
"bluetooth-data-tools==1.29.11",
"dbus-fast==5.0.3",
"habluetooth==6.2.0"
"habluetooth==6.4.0"
]
}
@@ -32,7 +32,6 @@ from homeassistant.components.homeassistant.exposed_entities import (
async_should_expose,
)
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import Event, HomeAssistant, callback, split_entity_id
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er, start
@@ -275,9 +274,6 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
def _should_expose_legacy(self, entity_id: str) -> bool:
"""If an entity should be exposed."""
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
entity_configs = self._prefs.alexa_entity_configs
entity_config = entity_configs.get(entity_id, {})
entity_expose: bool | None = entity_config.get(PREF_SHOULD_EXPOSE)
@@ -308,8 +304,6 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
"""If an entity should be exposed."""
entity_filter: EntityFilter = self._config[CONF_FILTER]
if not entity_filter.empty_filter:
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
return entity_filter(entity_id)
return async_should_expose(self.hass, CLOUD_ALEXA, entity_id)
@@ -22,7 +22,6 @@ from homeassistant.components.homeassistant.exposed_entities import (
async_should_expose,
)
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import (
CoreState,
Event,
@@ -282,9 +281,6 @@ class CloudGoogleConfig(AbstractConfig):
def _should_expose_legacy(self, entity_id: str) -> bool:
"""If an entity ID should be exposed."""
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
entity_configs = self._prefs.google_entity_configs
entity_config = entity_configs.get(entity_id, {})
entity_expose: bool | None = entity_config.get(PREF_SHOULD_EXPOSE)
@@ -316,8 +312,6 @@ class CloudGoogleConfig(AbstractConfig):
"""If an entity should be exposed."""
entity_filter: EntityFilter = self._config[CONF_FILTER]
if not entity_filter.empty_filter:
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
return entity_filter(entity_id)
return async_should_expose(self.hass, CLOUD_GOOGLE, entity_id)
+2 -5
View File
@@ -29,7 +29,6 @@ from homeassistant.components.homeassistant import exposed_entities
from homeassistant.components.http import KEY_HASS, HomeAssistantView, require_admin
from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.components.system_health import get_info as get_system_health_info
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
@@ -973,7 +972,7 @@ async def google_assistant_get(
return
entity = google_helpers.GoogleEntity(hass, gconf, state)
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES or not entity.is_supported():
if not entity.is_supported():
connection.send_error(
msg["id"],
websocket_api.ERR_NOT_SUPPORTED,
@@ -1075,9 +1074,7 @@ async def alexa_get(
"""Get data for a single alexa entity."""
entity_id: str = msg["entity_id"]
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES or not entity_supported_by_alexa(
hass, entity_id
):
if not entity_supported_by_alexa(hass, entity_id):
connection.send_error(
msg["id"],
websocket_api.ERR_NOT_SUPPORTED,
@@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==45.0.4",
"aioesphomeapi==45.1.0",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.7.3"
],
@@ -18,7 +18,6 @@ from homeassistant.components import webhook
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_SUPPORTED_FEATURES,
CLOUD_NEVER_EXPOSED_ENTITIES,
CONF_NAME,
STATE_UNAVAILABLE,
)
@@ -803,8 +802,6 @@ def async_get_entities(
is_supported_cache = config.is_supported_cache
for state in hass.states.async_all():
entity_id = state.entity_id
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
continue
# Check check inlined for performance to avoid
# function calls for every entity since we enumerate
# the entire state machine here
@@ -12,7 +12,6 @@ import jwt
from homeassistant.components import webhook
from homeassistant.components.http import KEY_HASS, HomeAssistantView
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
@@ -167,9 +166,6 @@ class GoogleConfig(AbstractConfig):
# Ignore entities that are views
return False
if state.entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
entity_registry = er.async_get(self.hass)
registry_entry = entity_registry.async_get(state.entity_id)
if registry_entry:
+1 -1
View File
@@ -116,7 +116,7 @@ async def _validate_auth(
def _get_current_hosts(entry: HeosConfigEntry) -> set[str]:
"""Get a set of current hosts from the entry."""
hosts = set(entry.data[CONF_HOST])
hosts = {entry.data[CONF_HOST]}
if hasattr(entry, "runtime_data"):
hosts.update(
player.ip_address
@@ -473,6 +473,7 @@ class HeosMediaPlayer(CoordinatorEntity[HeosCoordinator], MediaPlayerEntity):
await self.coordinator.heos.set_group(new_members)
return
@catch_action_error("remove from queue")
async def async_remove_from_queue(self, queue_ids: list[int]) -> None:
"""Remove items from the queue."""
await self._player.remove_from_queue(queue_ids)
@@ -10,7 +10,6 @@ import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback, split_entity_id
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
@@ -246,9 +245,6 @@ class ExposedEntities:
"""Return True if an entity should be exposed to an assistant."""
should_expose: bool
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
entity_registry = er.async_get(self._hass)
if not (registry_entry := entity_registry.async_get(entity_id)):
return self._async_should_expose_legacy_entity(assistant, entity_id)
@@ -406,19 +402,6 @@ def ws_expose_entity(
"""Expose an entity to an assistant."""
entity_ids: list[str] = msg["entity_ids"]
if blocked := next(
(
entity_id
for entity_id in entity_ids
if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES
),
None,
):
connection.send_error(
msg["id"], websocket_api.ERR_NOT_ALLOWED, f"can't expose '{blocked}'"
)
return
for entity_id in entity_ids:
for assistant in msg["assistants"]:
async_expose_entity(hass, assistant, entity_id, msg["should_expose"])
@@ -73,6 +73,9 @@
}
},
"exceptions": {
"cannot_connect": {
"message": "Failed to connect to OpenRGB SDK server {server_address}: {error}"
},
"communication_error": {
"message": "Failed to communicate with OpenRGB SDK server {server_address}: {error}"
},
-4
View File
@@ -946,10 +946,6 @@ PRECISION_WHOLE: Final = 1
PRECISION_HALVES: Final = 0.5
PRECISION_TENTHS: Final = 0.1
# Static list of entities that will never be exposed to
# cloud, alexa, or google_home components
CLOUD_NEVER_EXPOSED_ENTITIES: Final[list[str]] = ["group.all_locks"]
class EntityCategory(StrEnum):
"""Category of an entity.
+1 -1
View File
@@ -35,7 +35,7 @@ file-read-backwards==2.0.0
fnv-hash-fast==2.0.2
go2rtc-client==0.4.0
ha-ffmpeg==3.2.2
habluetooth==6.2.0
habluetooth==6.4.0
hass-nabucasa==2.2.0
hassil==3.5.0
home-assistant-bluetooth==2.0.0
+2 -2
View File
@@ -254,7 +254,7 @@ aioelectricitymaps==1.1.1
aioemonitor==1.0.5
# homeassistant.components.esphome
aioesphomeapi==45.0.4
aioesphomeapi==45.1.0
# homeassistant.components.matrix
# homeassistant.components.slack
@@ -1210,7 +1210,7 @@ ha-xthings-cloud==1.0.5
habiticalib==0.4.7
# homeassistant.components.bluetooth
habluetooth==6.2.0
habluetooth==6.4.0
# homeassistant.components.hanna
hanna-cloud==0.0.7
-25
View File
@@ -3662,31 +3662,6 @@ async def test_include_filters(hass: HomeAssistant) -> None:
assert len(msg["payload"]["endpoints"]) == 3
async def test_never_exposed_entities(hass: HomeAssistant) -> None:
"""Test never exposed locks do not get discovered."""
request = get_new_request("Alexa.Discovery", "Discover")
# setup test devices
hass.states.async_set("group.all_locks", "on", {"friendly_name": "Blocked locks"})
hass.states.async_set("group.allow", "off", {"friendly_name": "Allowed group"})
alexa_config = MockConfig(hass)
alexa_config.should_expose = entityfilter.generate_filter(
include_domains=["group"],
include_entities=[],
exclude_domains=[],
exclude_entities=[],
)
msg = await smart_home.async_handle_message(hass, alexa_config, request)
await hass.async_block_till_done()
msg = msg["event"]
assert len(msg["payload"]["endpoints"]) == 1
async def test_api_entity_not_exists(hass: HomeAssistant) -> None:
"""Test api turn on process without entity."""
request = get_new_request("Alexa.PowerController", "TurnOn", "switch#test")
-1
View File
@@ -104,7 +104,6 @@ async def test_handler_google_actions(hass: HomeAssistant) -> None:
"""Test handler Google Actions."""
hass.states.async_set("switch.test", "on", {"friendly_name": "Test switch"})
hass.states.async_set("switch.test2", "on", {"friendly_name": "Test switch 2"})
hass.states.async_set("group.all_locks", "on", {"friendly_name": "Evil locks"})
await mock_cloud(
hass,
-34
View File
@@ -1418,23 +1418,6 @@ async def test_get_google_entity(
"message": "light.kitchen unknown",
}
# Test getting a blocked entity
entity_registry.async_get_or_create(
"group", "test", "unique", suggested_object_id="all_locks"
)
hass.states.async_set("group.all_locks", "bla")
await client.send_json_auto_id(
{"type": "cloud/google_assistant/entities/get", "entity_id": "group.all_locks"}
)
response = await client.receive_json()
assert not response["success"]
assert response["error"] == {
"code": "not_supported",
"message": "group.all_locks not supported by Google assistant",
}
entity_registry.async_get_or_create(
"light", "test", "unique", suggested_object_id="kitchen"
)
@@ -1617,23 +1600,6 @@ async def test_get_alexa_entity(
"message": "sensor.temperature not supported by Alexa",
}
# Test getting a blocked entity
entity_registry.async_get_or_create(
"group", "test", "unique", suggested_object_id="all_locks"
)
hass.states.async_set("group.all_locks", "bla")
await client.send_json_auto_id(
{"type": "cloud/alexa/entities/get", "entity_id": "group.all_locks"}
)
response = await client.receive_json()
assert not response["success"]
assert response["error"] == {
"code": "not_supported",
"message": "group.all_locks not supported by Alexa",
}
entity_registry.async_get_or_create(
"light", "test", "unique", suggested_object_id="kitchen"
)
@@ -626,15 +626,20 @@ async def test_migration_from_future_version(
assert config_entry.state is ConfigEntryState.MIGRATION_ERROR
async def test_migration_1_2(hass: HomeAssistant) -> None:
@pytest.mark.usefixtures("sensor_device")
async def test_migration_1_2(
hass: HomeAssistant,
sensor_entity_entry: er.RegistryEntry,
switch_entity_entry: er.RegistryEntry,
) -> None:
"""Test migration from 1.2 to 1.3 copies CONF_MIN_DUR to CONF_DUR_COOLDOWN."""
config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
"name": "My generic thermostat",
"heater": "switch.test",
"target_sensor": "sensor.test",
"heater": switch_entity_entry.entity_id,
"target_sensor": sensor_entity_entry.entity_id,
CONF_MIN_DUR: {"hours": 0, "minutes": 5, "seconds": 0},
"ac_mode": False,
"cold_tolerance": 0.3,
@@ -646,9 +651,10 @@ async def test_migration_1_2(hass: HomeAssistant) -> None:
)
config_entry.add_to_hass(hass)
# Run migration
result = await generic_thermostat.async_migrate_entry(hass, config_entry)
assert result is True
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
# After migration, cooldown should be set to min_cycle_duration
# and minor version bumped
@@ -657,4 +663,5 @@ async def test_migration_1_2(hass: HomeAssistant) -> None:
"minutes": 5,
"seconds": 0,
}
assert config_entry.version == 1
assert config_entry.minor_version == 3
@@ -15,7 +15,7 @@ from homeassistant.components import (
light,
media_player,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, EntityCategory, Platform
from homeassistant.const import EntityCategory, Platform
from homeassistant.helpers import entity_registry as er
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
@@ -146,9 +146,6 @@ async def test_sync_request(
dev["id"] for dev in DEMO_DEVICES
)
for dev in devices:
assert dev["id"] not in CLOUD_NEVER_EXPOSED_ENTITIES
for dev, demo in zip(
sorted(devices, key=lambda d: d["id"]),
sorted(DEMO_DEVICES, key=lambda d: d["id"]),
@@ -28,11 +28,7 @@ from homeassistant.components.google_assistant.http import (
_get_homegraph_token,
async_get_users,
)
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED,
)
from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STARTED
from homeassistant.core import CoreState, HomeAssistant, State
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
@@ -366,8 +362,6 @@ async def test_should_expose(hass: HomeAssistant) -> None:
# Wait for google_assistant.helpers.async_initialize.sync_google to be called
await hass.async_block_till_done()
assert config.should_expose(State(CLOUD_NEVER_EXPOSED_ENTITIES[0], "mock")) is False
async def test_missing_service_account(hass: HomeAssistant) -> None:
"""Test the google config _async_request_sync_devices."""
@@ -13,7 +13,7 @@ from homeassistant.components.homeassistant.exposed_entities import (
async_listen_entity_updates,
async_should_expose,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, EntityCategory
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
@@ -39,10 +39,10 @@ def entities_fixture(
def entities_unique_id(entity_registry: er.EntityRegistry) -> dict[str, str]:
"""Create some entities in the entity registry."""
entry_blocked = entity_registry.async_get_or_create(
entry_group = 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 entry_group.entity_id == "group.all_locks"
entry_lock = entity_registry.async_get_or_create("lock", "test", "unique1")
entry_binary_sensor = entity_registry.async_get_or_create(
"binary_sensor", "test", "unique1"
@@ -64,7 +64,7 @@ def entities_unique_id(entity_registry: er.EntityRegistry) -> dict[str, str]:
"media_player", "test", "unique4", original_device_class="media_player"
)
return {
"blocked": entry_blocked.entity_id,
"group": entry_group.entity_id,
"lock": entry_lock.entity_id,
"binary_sensor": entry_binary_sensor.entity_id,
"door_sensor": entry_binary_sensor_door.entity_id,
@@ -76,7 +76,7 @@ def entities_unique_id(entity_registry: er.EntityRegistry) -> dict[str, str]:
def entities_no_unique_id(hass: HomeAssistant) -> dict[str, str]:
"""Create some entities not in the entity registry."""
blocked = CLOUD_NEVER_EXPOSED_ENTITIES[0]
group = "group.all_locks"
lock = "lock.test"
binary_sensor = "binary_sensor.test"
door_sensor = "binary_sensor.door"
@@ -89,7 +89,7 @@ def entities_no_unique_id(hass: HomeAssistant) -> dict[str, str]:
hass.states.async_set(sensor_temperature, "on", {"device_class": "temperature"})
hass.states.async_set(media_player, "idle", {})
return {
"blocked": blocked,
"group": group,
"lock": lock,
"binary_sensor": binary_sensor,
"door_sensor": door_sensor,
@@ -248,33 +248,6 @@ async def test_expose_entity_unknown(
}
async def test_expose_entity_blocked(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test behavior when exposing a blocked entity."""
ws_client = await hass_ws_client(hass)
assert await async_setup_component(hass, "homeassistant", {})
await hass.async_block_till_done()
# Set options
await ws_client.send_json_auto_id(
{
"type": "homeassistant/expose_entity",
"assistants": ["cloud.alexa"],
"entity_ids": ["group.all_locks"],
"should_expose": True,
}
)
response = await ws_client.receive_json()
assert not response["success"]
assert response["error"] == {
"code": "not_allowed",
"message": "can't expose 'group.all_locks'",
}
@pytest.mark.parametrize("expose_new", [True, False])
async def test_expose_new_entities(
hass: HomeAssistant,
@@ -414,8 +387,8 @@ async def test_should_expose(
# Unknown entity is not exposed
assert async_should_expose(hass, "test.test", "test.test") is False
# Blocked entity is not exposed
assert async_should_expose(hass, "cloud.alexa", entities["blocked"]) is False
# Group entity is not exposed
assert async_should_expose(hass, "cloud.alexa", entities["group"]) is False
# Lock is not exposed
assert async_should_expose(hass, "cloud.alexa", entities["lock"]) is False
+24 -23
View File
@@ -8,9 +8,10 @@ import pytest
from homeassistant.components.labs import (
EVENT_LABS_UPDATED,
async_is_preview_feature_enabled,
async_setup,
)
from homeassistant.components.labs.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from . import assert_stored_labs_data
@@ -48,7 +49,7 @@ async def test_websocket_list_preview_features(
if load_integration:
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -68,7 +69,7 @@ async def test_websocket_update_preview_feature_enable(
"""Test enabling a preview feature via WebSocket."""
# Load kitchen_sink integration
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -132,7 +133,7 @@ async def test_websocket_update_preview_feature_disable(
}
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -164,7 +165,7 @@ async def test_websocket_update_nonexistent_feature(
hass_storage: dict[str, Any],
) -> None:
"""Test updating a preview feature that doesn't exist."""
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -193,7 +194,7 @@ async def test_websocket_update_unavailable_preview_feature(
) -> None:
"""Test updating a preview feature whose integration is not loaded still works."""
# Don't load kitchen_sink integration
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -235,7 +236,7 @@ async def test_websocket_requires_admin(
hass_admin_user.groups = []
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -264,7 +265,7 @@ async def test_websocket_update_validates_enabled_parameter(
) -> None:
"""Test that enabled parameter must be boolean."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -291,7 +292,7 @@ async def test_storage_persists_preview_feature_across_calls(
) -> None:
"""Test that storage persists preview feature state across multiple calls."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -350,7 +351,7 @@ async def test_preview_feature_urls_present(
) -> None:
"""Test that preview features include feedback and report URLs."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -401,7 +402,7 @@ async def test_websocket_update_preview_feature_backup_scenarios(
) -> None:
"""Test various backup scenarios when updating preview features."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -463,7 +464,7 @@ async def test_websocket_list_multiple_enabled_features(
}
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -484,7 +485,7 @@ async def test_websocket_update_rapid_toggle(
) -> None:
"""Test rapid toggling of a preview feature."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -534,7 +535,7 @@ async def test_websocket_update_same_state_idempotent(
) -> None:
"""Test that enabling an already-enabled feature is idempotent."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -572,7 +573,7 @@ async def test_websocket_list_filtered_by_loaded_components(
) -> None:
"""Test that list only shows features from loaded integrations."""
# Don't load kitchen_sink - its preview feature shouldn't appear
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -600,7 +601,7 @@ async def test_websocket_update_with_missing_required_field(
) -> None:
"""Test that missing required fields are rejected."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -625,7 +626,7 @@ async def test_websocket_event_data_structure(
) -> None:
"""Test that event data has correct structure."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -666,7 +667,7 @@ async def test_websocket_backup_timeout_handling(
) -> None:
"""Test handling of backup timeout/long-running backup."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -702,7 +703,7 @@ async def test_websocket_subscribe_feature(
) -> None:
"""Test subscribing to a specific preview feature."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -739,7 +740,7 @@ async def test_websocket_subscribe_feature_receives_updates(
) -> None:
"""Test that subscription receives updates when feature is toggled."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -793,7 +794,7 @@ async def test_websocket_subscribe_nonexistent_feature(
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test subscribing to a preview feature that doesn't exist."""
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -821,7 +822,7 @@ async def test_websocket_subscribe_does_not_require_admin(
hass_admin_user.groups = []
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)
@@ -847,7 +848,7 @@ async def test_websocket_subscribe_only_receives_subscribed_feature_updates(
) -> None:
"""Test that subscription only receives updates for the subscribed feature."""
hass.config.components.add("kitchen_sink")
assert await async_setup(hass, {})
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
client = await hass_ws_client(hass)