Integrations v2.1: Differentiating hubs, devices and services (#80524)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
0c8884fd51
commit
c4bbc439a5
11 changed files with 1376 additions and 105 deletions
|
@ -6,5 +6,6 @@
|
|||
"requirements": ["adguardhome==0.5.1"],
|
||||
"codeowners": ["@frenck"],
|
||||
"iot_class": "local_polling",
|
||||
"integration_type": "service",
|
||||
"loggers": ["adguardhome"]
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ from homeassistant.components import websocket_api
|
|||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import DependencyError, Unauthorized
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.data_entry_flow import (
|
||||
FlowManagerIndexView,
|
||||
FlowManagerResourceView,
|
||||
|
@ -64,7 +65,7 @@ class ConfigManagerEntryIndexView(HomeAssistantView):
|
|||
domain = request.query["domain"]
|
||||
type_filter = None
|
||||
if "type" in request.query:
|
||||
type_filter = request.query["type"]
|
||||
type_filter = [request.query["type"]]
|
||||
return self.json(await async_matching_config_entries(hass, type_filter, domain))
|
||||
|
||||
|
||||
|
@ -405,7 +406,7 @@ async def ignore_config_flow(
|
|||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config_entries/get",
|
||||
vol.Optional("type_filter"): str,
|
||||
vol.Optional("type_filter"): vol.All(cv.ensure_list, [str]),
|
||||
vol.Optional("domain"): str,
|
||||
}
|
||||
)
|
||||
|
@ -427,7 +428,7 @@ async def config_entries_get(
|
|||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "config_entries/subscribe",
|
||||
vol.Optional("type_filter"): str,
|
||||
vol.Optional("type_filter"): vol.All(cv.ensure_list, [str]),
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
|
@ -445,7 +446,7 @@ async def config_entries_subscribe(
|
|||
"""Forward config entry state events to websocket."""
|
||||
if type_filter:
|
||||
integration = await async_get_integration(hass, entry.domain)
|
||||
if integration.integration_type != type_filter:
|
||||
if integration.integration_type not in type_filter:
|
||||
return
|
||||
|
||||
connection.send_message(
|
||||
|
@ -475,7 +476,7 @@ async def config_entries_subscribe(
|
|||
|
||||
|
||||
async def async_matching_config_entries(
|
||||
hass: HomeAssistant, type_filter: str | None, domain: str | None
|
||||
hass: HomeAssistant, type_filter: list[str] | None, domain: str | None
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Return matching config entries by type and/or domain."""
|
||||
kwargs = {}
|
||||
|
@ -483,7 +484,7 @@ async def async_matching_config_entries(
|
|||
kwargs["domain"] = domain
|
||||
entries = hass.config_entries.async_entries(**kwargs)
|
||||
|
||||
if type_filter is None:
|
||||
if not type_filter:
|
||||
return [entry_json(entry) for entry in entries]
|
||||
|
||||
integrations = {}
|
||||
|
@ -499,13 +500,17 @@ async def async_matching_config_entries(
|
|||
elif not isinstance(integration_or_exc, IntegrationNotFound):
|
||||
raise integration_or_exc
|
||||
|
||||
# Filter out entries that don't match the type filter
|
||||
# when only helpers are requested, also filter out entries
|
||||
# from unknown integrations. This prevent them from showing
|
||||
# up in the helpers UI.
|
||||
entries = [
|
||||
entry
|
||||
for entry in entries
|
||||
if (type_filter != "helper" and entry.domain not in integrations)
|
||||
if (type_filter != ["helper"] and entry.domain not in integrations)
|
||||
or (
|
||||
entry.domain in integrations
|
||||
and integrations[entry.domain].integration_type == type_filter
|
||||
and integrations[entry.domain].integration_type in type_filter
|
||||
)
|
||||
]
|
||||
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
"codeowners": ["@OttoWinter", "@jesserockz"],
|
||||
"after_dependencies": ["bluetooth", "zeroconf", "tag"],
|
||||
"iot_class": "local_push",
|
||||
"integration_type": "device",
|
||||
"loggers": ["aioesphomeapi", "noiseprotocol"]
|
||||
}
|
||||
|
|
|
@ -25,5 +25,6 @@
|
|||
"codeowners": ["@balloob", "@marcelveldt"],
|
||||
"quality_scale": "platinum",
|
||||
"iot_class": "local_push",
|
||||
"integration_type": "hub",
|
||||
"loggers": ["aiohue"]
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -130,7 +130,9 @@ class Manifest(TypedDict, total=False):
|
|||
name: str
|
||||
disabled: str
|
||||
domain: str
|
||||
integration_type: Literal["entity", "integration", "hardware", "helper", "system"]
|
||||
integration_type: Literal[
|
||||
"entity", "device", "hardware", "helper", "hub", "service", "system"
|
||||
]
|
||||
dependencies: list[str]
|
||||
after_dependencies: list[str]
|
||||
requirements: list[str]
|
||||
|
@ -224,7 +226,7 @@ async def async_get_custom_components(
|
|||
|
||||
async def async_get_config_flows(
|
||||
hass: HomeAssistant,
|
||||
type_filter: Literal["helper", "integration"] | None = None,
|
||||
type_filter: Literal["device", "helper", "hub", "service"] | None = None,
|
||||
) -> set[str]:
|
||||
"""Return cached list of config flows."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
|
@ -262,9 +264,11 @@ async def async_get_integration_descriptions(
|
|||
core_flows: dict[str, Any] = json_loads(flow)
|
||||
custom_integrations = await async_get_custom_components(hass)
|
||||
custom_flows: dict[str, Any] = {
|
||||
"integration": {},
|
||||
"device": {},
|
||||
"hardware": {},
|
||||
"helper": {},
|
||||
"hub": {},
|
||||
"service": {},
|
||||
}
|
||||
|
||||
for integration in custom_integrations.values():
|
||||
|
@ -272,7 +276,7 @@ async def async_get_integration_descriptions(
|
|||
if integration.integration_type in ("entity", "system"):
|
||||
continue
|
||||
|
||||
for integration_type in ("integration", "hardware", "helper"):
|
||||
for integration_type in ("device", "hardware", "helper", "hub", "service"):
|
||||
if integration.domain not in core_flows[integration_type]:
|
||||
continue
|
||||
del core_flows[integration_type][integration.domain]
|
||||
|
@ -281,6 +285,7 @@ async def async_get_integration_descriptions(
|
|||
|
||||
metadata = {
|
||||
"config_flow": integration.config_flow,
|
||||
"integration_type": integration.integration_type,
|
||||
"iot_class": integration.iot_class,
|
||||
"name": integration.name,
|
||||
}
|
||||
|
@ -599,9 +604,9 @@ class Integration:
|
|||
@property
|
||||
def integration_type(
|
||||
self,
|
||||
) -> Literal["entity", "integration", "hardware", "helper", "system"]:
|
||||
) -> Literal["entity", "device", "hardware", "helper", "hub", "service", "system"]:
|
||||
"""Return the integration type."""
|
||||
return self.manifest.get("integration_type", "integration")
|
||||
return self.manifest.get("integration_type", "hub")
|
||||
|
||||
@property
|
||||
def mqtt(self) -> list[str] | None:
|
||||
|
|
|
@ -86,7 +86,10 @@ def _generate_and_validate(integrations: dict[str, Integration], config: Config)
|
|||
|
||||
_validate_integration(config, integration)
|
||||
|
||||
domains[integration.integration_type].append(domain)
|
||||
if integration.integration_type == "helper":
|
||||
domains["helper"].append(domain)
|
||||
else:
|
||||
domains["integration"].append(domain)
|
||||
|
||||
return black.format_str(BASE.format(to_string(domains)), mode=black.Mode())
|
||||
|
||||
|
@ -106,6 +109,7 @@ def _populate_brand_integrations(
|
|||
metadata = {}
|
||||
metadata["config_flow"] = integration.config_flow
|
||||
metadata["iot_class"] = integration.iot_class
|
||||
metadata["integration_type"] = integration.integration_type
|
||||
if integration.translated_name:
|
||||
integration_data["translated_name"].add(domain)
|
||||
else:
|
||||
|
@ -169,11 +173,16 @@ def _generate_integrations(
|
|||
continue
|
||||
metadata["config_flow"] = integration.config_flow
|
||||
metadata["iot_class"] = integration.iot_class
|
||||
metadata["integration_type"] = integration.integration_type
|
||||
if integration.translated_name:
|
||||
result["translated_name"].add(domain)
|
||||
else:
|
||||
metadata["name"] = integration.name
|
||||
result[integration.integration_type][domain] = metadata
|
||||
|
||||
if integration.integration_type == "helper":
|
||||
result["helper"][domain] = metadata
|
||||
else:
|
||||
result["integration"][domain] = metadata
|
||||
|
||||
return json.dumps(
|
||||
result | {"translated_name": sorted(result["translated_name"])}, indent=2
|
||||
|
|
|
@ -162,8 +162,16 @@ MANIFEST_SCHEMA = vol.Schema(
|
|||
{
|
||||
vol.Required("domain"): str,
|
||||
vol.Required("name"): str,
|
||||
vol.Optional("integration_type"): vol.In(
|
||||
["entity", "hardware", "helper", "system"]
|
||||
vol.Optional("integration_type", default="hub"): vol.In(
|
||||
[
|
||||
"device",
|
||||
"entity",
|
||||
"hardware",
|
||||
"helper",
|
||||
"hub",
|
||||
"service",
|
||||
"system",
|
||||
]
|
||||
),
|
||||
vol.Optional("config_flow"): bool,
|
||||
vol.Optional("mqtt"): [str],
|
||||
|
|
|
@ -177,7 +177,7 @@ class Integration:
|
|||
@property
|
||||
def integration_type(self) -> str:
|
||||
"""Get integration_type."""
|
||||
return self.manifest.get("integration_type", "integration")
|
||||
return self.manifest.get("integration_type", "hub")
|
||||
|
||||
@property
|
||||
def iot_class(self) -> str | None:
|
||||
|
|
|
@ -37,7 +37,6 @@ async def test_options_flow_disabled_not_setup(
|
|||
"id": 5,
|
||||
"type": "config_entries/get",
|
||||
"domain": "bluetooth",
|
||||
"type_filter": "integration",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
@ -341,7 +340,6 @@ async def test_options_flow_disabled_macos(
|
|||
"id": 5,
|
||||
"type": "config_entries/get",
|
||||
"domain": "bluetooth",
|
||||
"type_filter": "integration",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
@ -371,7 +369,6 @@ async def test_options_flow_enabled_linux(
|
|||
"id": 5,
|
||||
"type": "config_entries/get",
|
||||
"domain": "bluetooth",
|
||||
"type_filter": "integration",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
|
|
@ -51,7 +51,15 @@ async def test_get_entries(hass, client, clear_handlers):
|
|||
mock_integration(
|
||||
hass, MockModule("comp2", partial_manifest={"integration_type": "helper"})
|
||||
)
|
||||
mock_integration(hass, MockModule("comp3"))
|
||||
mock_integration(
|
||||
hass, MockModule("comp3", partial_manifest={"integration_type": "hub"})
|
||||
)
|
||||
mock_integration(
|
||||
hass, MockModule("comp4", partial_manifest={"integration_type": "device"})
|
||||
)
|
||||
mock_integration(
|
||||
hass, MockModule("comp5", partial_manifest={"integration_type": "service"})
|
||||
)
|
||||
|
||||
@HANDLERS.register("comp1")
|
||||
class Comp1ConfigFlow:
|
||||
|
@ -91,6 +99,16 @@ async def test_get_entries(hass, client, clear_handlers):
|
|||
source="bla3",
|
||||
disabled_by=core_ce.ConfigEntryDisabler.USER,
|
||||
).add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="comp4",
|
||||
title="Test 4",
|
||||
source="bla4",
|
||||
).add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="comp5",
|
||||
title="Test 5",
|
||||
source="bla5",
|
||||
).add_to_hass(hass)
|
||||
|
||||
resp = await client.get("/api/config/config_entries/entry")
|
||||
assert resp.status == HTTPStatus.OK
|
||||
|
@ -137,6 +155,32 @@ async def test_get_entries(hass, client, clear_handlers):
|
|||
"disabled_by": core_ce.ConfigEntryDisabler.USER,
|
||||
"reason": None,
|
||||
},
|
||||
{
|
||||
"domain": "comp4",
|
||||
"title": "Test 4",
|
||||
"source": "bla4",
|
||||
"state": core_ce.ConfigEntryState.NOT_LOADED.value,
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"disabled_by": None,
|
||||
"reason": None,
|
||||
},
|
||||
{
|
||||
"domain": "comp5",
|
||||
"title": "Test 5",
|
||||
"source": "bla5",
|
||||
"state": core_ce.ConfigEntryState.NOT_LOADED.value,
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"disabled_by": None,
|
||||
"reason": None,
|
||||
},
|
||||
]
|
||||
|
||||
resp = await client.get("/api/config/config_entries/entry?domain=comp3")
|
||||
|
@ -150,20 +194,25 @@ async def test_get_entries(hass, client, clear_handlers):
|
|||
data = await resp.json()
|
||||
assert len(data) == 0
|
||||
|
||||
resp = await client.get(
|
||||
"/api/config/config_entries/entry?domain=comp3&type=integration"
|
||||
)
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
assert len(data) == 1
|
||||
|
||||
resp = await client.get("/api/config/config_entries/entry?type=integration")
|
||||
resp = await client.get("/api/config/config_entries/entry?type=hub")
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
assert len(data) == 2
|
||||
assert data[0]["domain"] == "comp1"
|
||||
assert data[1]["domain"] == "comp3"
|
||||
|
||||
resp = await client.get("/api/config/config_entries/entry?type=device")
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
assert len(data) == 1
|
||||
assert data[0]["domain"] == "comp4"
|
||||
|
||||
resp = await client.get("/api/config/config_entries/entry?type=service")
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
assert len(data) == 1
|
||||
assert data[0]["domain"] == "comp5"
|
||||
|
||||
|
||||
async def test_remove_entry(hass, client):
|
||||
"""Test removing an entry via the API."""
|
||||
|
@ -1123,7 +1172,16 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
mock_integration(
|
||||
hass, MockModule("comp2", partial_manifest={"integration_type": "helper"})
|
||||
)
|
||||
mock_integration(hass, MockModule("comp3"))
|
||||
mock_integration(
|
||||
hass, MockModule("comp3", partial_manifest={"integration_type": "hub"})
|
||||
)
|
||||
mock_integration(
|
||||
hass, MockModule("comp4", partial_manifest={"integration_type": "device"})
|
||||
)
|
||||
mock_integration(
|
||||
hass, MockModule("comp5", partial_manifest={"integration_type": "service"})
|
||||
)
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain="comp1",
|
||||
title="Test 1",
|
||||
|
@ -1143,6 +1201,16 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
source="bla3",
|
||||
disabled_by=core_ce.ConfigEntryDisabler.USER,
|
||||
).add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="comp4",
|
||||
title="Test 4",
|
||||
source="bla4",
|
||||
).add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="comp5",
|
||||
title="Test 5",
|
||||
source="bla5",
|
||||
).add_to_hass(hass)
|
||||
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
|
@ -1197,6 +1265,34 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
"supports_unload": False,
|
||||
"title": "Test 3",
|
||||
},
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp4",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla4",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 4",
|
||||
},
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp5",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla5",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 5",
|
||||
},
|
||||
]
|
||||
|
||||
await ws_client.send_json(
|
||||
|
@ -1204,7 +1300,7 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
"id": 6,
|
||||
"type": "config_entries/get",
|
||||
"domain": "comp1",
|
||||
"type_filter": "integration",
|
||||
"type_filter": "hub",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
@ -1225,22 +1321,102 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
"title": "Test 1",
|
||||
}
|
||||
]
|
||||
# Verify we skip broken integrations
|
||||
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 7,
|
||||
"type": "config_entries/get",
|
||||
"type_filter": ["service", "device"],
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert response["id"] == 7
|
||||
assert response["result"] == [
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp4",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla4",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 4",
|
||||
},
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp5",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla5",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 5",
|
||||
},
|
||||
]
|
||||
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 8,
|
||||
"type": "config_entries/get",
|
||||
"type_filter": "hub",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
assert response["id"] == 8
|
||||
assert response["result"] == [
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp1",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 1",
|
||||
},
|
||||
{
|
||||
"disabled_by": "user",
|
||||
"domain": "comp3",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla3",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 3",
|
||||
},
|
||||
]
|
||||
|
||||
# Verify we skip broken integrations
|
||||
with patch(
|
||||
"homeassistant.components.config.config_entries.async_get_integration",
|
||||
side_effect=IntegrationNotFound("any"),
|
||||
):
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 7,
|
||||
"id": 9,
|
||||
"type": "config_entries/get",
|
||||
"type_filter": "integration",
|
||||
"type_filter": "hub",
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
||||
assert response["id"] == 7
|
||||
assert response["id"] == 9
|
||||
assert response["result"] == [
|
||||
{
|
||||
"disabled_by": None,
|
||||
|
@ -1284,8 +1460,53 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
"supports_unload": False,
|
||||
"title": "Test 3",
|
||||
},
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp4",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla4",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 4",
|
||||
},
|
||||
{
|
||||
"disabled_by": None,
|
||||
"domain": "comp5",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla5",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "Test 5",
|
||||
},
|
||||
]
|
||||
|
||||
# Verify we don't send config entries when only helpers are requested
|
||||
with patch(
|
||||
"homeassistant.components.config.config_entries.async_get_integration",
|
||||
side_effect=IntegrationNotFound("any"),
|
||||
):
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 10,
|
||||
"type": "config_entries/get",
|
||||
"type_filter": ["helper"],
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
||||
assert response["id"] == 10
|
||||
assert response["result"] == []
|
||||
|
||||
# Verify we raise if something really goes wrong
|
||||
|
||||
with patch(
|
||||
|
@ -1294,14 +1515,14 @@ async def test_get_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
):
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 8,
|
||||
"id": 11,
|
||||
"type": "config_entries/get",
|
||||
"type_filter": "integration",
|
||||
"type_filter": ["device", "hub", "service"],
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
||||
assert response["id"] == 8
|
||||
assert response["id"] == 11
|
||||
assert response["success"] is False
|
||||
|
||||
|
||||
|
@ -1312,7 +1533,9 @@ async def test_subscribe_entries_ws(hass, hass_ws_client, clear_handlers):
|
|||
mock_integration(
|
||||
hass, MockModule("comp2", partial_manifest={"integration_type": "helper"})
|
||||
)
|
||||
mock_integration(hass, MockModule("comp3"))
|
||||
mock_integration(
|
||||
hass, MockModule("comp3", partial_manifest={"integration_type": "device"})
|
||||
)
|
||||
entry = MockConfigEntry(
|
||||
domain="comp1",
|
||||
title="Test 1",
|
||||
|
@ -1476,7 +1699,12 @@ async def test_subscribe_entries_ws_filtered(hass, hass_ws_client, clear_handler
|
|||
mock_integration(
|
||||
hass, MockModule("comp2", partial_manifest={"integration_type": "helper"})
|
||||
)
|
||||
mock_integration(hass, MockModule("comp3"))
|
||||
mock_integration(
|
||||
hass, MockModule("comp3", partial_manifest={"integration_type": "device"})
|
||||
)
|
||||
mock_integration(
|
||||
hass, MockModule("comp4", partial_manifest={"integration_type": "service"})
|
||||
)
|
||||
entry = MockConfigEntry(
|
||||
domain="comp1",
|
||||
title="Test 1",
|
||||
|
@ -1491,12 +1719,19 @@ async def test_subscribe_entries_ws_filtered(hass, hass_ws_client, clear_handler
|
|||
reason="Unsupported API",
|
||||
)
|
||||
entry2.add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
entry3 = MockConfigEntry(
|
||||
domain="comp3",
|
||||
title="Test 3",
|
||||
source="bla3",
|
||||
disabled_by=core_ce.ConfigEntryDisabler.USER,
|
||||
).add_to_hass(hass)
|
||||
)
|
||||
entry3.add_to_hass(hass)
|
||||
entry4 = MockConfigEntry(
|
||||
domain="comp4",
|
||||
title="Test 4",
|
||||
source="bla4",
|
||||
)
|
||||
entry4.add_to_hass(hass)
|
||||
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
|
@ -1504,7 +1739,7 @@ async def test_subscribe_entries_ws_filtered(hass, hass_ws_client, clear_handler
|
|||
{
|
||||
"id": 5,
|
||||
"type": "config_entries/subscribe",
|
||||
"type_filter": "integration",
|
||||
"type_filter": ["hub", "device"],
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
@ -1551,6 +1786,8 @@ async def test_subscribe_entries_ws_filtered(hass, hass_ws_client, clear_handler
|
|||
},
|
||||
]
|
||||
assert hass.config_entries.async_update_entry(entry, title="changed")
|
||||
assert hass.config_entries.async_update_entry(entry3, title="changed too")
|
||||
assert hass.config_entries.async_update_entry(entry4, title="changed but ignored")
|
||||
response = await ws_client.receive_json()
|
||||
assert response["id"] == 5
|
||||
assert response["event"] == [
|
||||
|
@ -1572,6 +1809,27 @@ async def test_subscribe_entries_ws_filtered(hass, hass_ws_client, clear_handler
|
|||
"type": "updated",
|
||||
}
|
||||
]
|
||||
response = await ws_client.receive_json()
|
||||
assert response["id"] == 5
|
||||
assert response["event"] == [
|
||||
{
|
||||
"entry": {
|
||||
"disabled_by": "user",
|
||||
"domain": "comp3",
|
||||
"entry_id": ANY,
|
||||
"pref_disable_new_entities": False,
|
||||
"pref_disable_polling": False,
|
||||
"reason": None,
|
||||
"source": "bla3",
|
||||
"state": "not_loaded",
|
||||
"supports_options": False,
|
||||
"supports_remove_device": False,
|
||||
"supports_unload": False,
|
||||
"title": "changed too",
|
||||
},
|
||||
"type": "updated",
|
||||
}
|
||||
]
|
||||
await hass.config_entries.async_remove(entry.entry_id)
|
||||
await hass.config_entries.async_remove(entry2.entry_id)
|
||||
response = await ws_client.receive_json()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue