Add bluetooth adapter model and manufacturer to config flow (#115780)

* Show bluetooth adapter model and manufacturer in config flow

If there are multiple adapters, it could be a bit difficult
to figure out which one is which

* Show bluetooth adapter model and manufacturer in config flow

If there are multiple adapters, it could be a bit difficult
to figure out which one is which

* reorder

* reorder

* names

* remove

* fix incomplete mocking

* more missing mocks
This commit is contained in:
J. Nick Koston 2024-04-18 09:39:32 -05:00 committed by GitHub
parent fbdef7f5cd
commit 53c48537d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 102 additions and 46 deletions

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -11,7 +11,7 @@
"description": "[%key:component::bluetooth::config::step::bluetooth_confirm::description%]" "description": "[%key:component::bluetooth::config::step::bluetooth_confirm::description%]"
} }
}, },
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"error": { "error": {
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"
}, },

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -6,8 +6,10 @@ from typing import Any, cast
from bluetooth_adapters import ( from bluetooth_adapters import (
ADAPTER_ADDRESS, ADAPTER_ADDRESS,
ADAPTER_MANUFACTURER,
AdapterDetails, AdapterDetails,
adapter_human_name, adapter_human_name,
adapter_model,
adapter_unique_name, adapter_unique_name,
get_adapters, get_adapters,
) )
@ -35,6 +37,22 @@ OPTIONS_FLOW = {
} }
def adapter_display_info(adapter: str, details: AdapterDetails) -> str:
"""Return the adapter display info."""
name = adapter_human_name(adapter, details[ADAPTER_ADDRESS])
model = adapter_model(details)
manufacturer = details[ADAPTER_MANUFACTURER] or "Unknown"
return f"{name} {manufacturer} {model}"
def adapter_title(adapter: str, details: AdapterDetails) -> str:
"""Return the adapter title."""
unique_name = adapter_unique_name(adapter, details[ADAPTER_ADDRESS])
model = adapter_model(details)
manufacturer = details[ADAPTER_MANUFACTURER] or "Unknown"
return f"{manufacturer} {model} ({unique_name})"
class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN): class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
"""Config flow for Bluetooth.""" """Config flow for Bluetooth."""
@ -45,6 +63,7 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
self._adapter: str | None = None self._adapter: str | None = None
self._details: AdapterDetails | None = None self._details: AdapterDetails | None = None
self._adapters: dict[str, AdapterDetails] = {} self._adapters: dict[str, AdapterDetails] = {}
self._placeholders: dict[str, str] = {}
async def async_step_integration_discovery( async def async_step_integration_discovery(
self, discovery_info: DiscoveryInfoType self, discovery_info: DiscoveryInfoType
@ -54,11 +73,23 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
self._details = cast(AdapterDetails, discovery_info[CONF_DETAILS]) self._details = cast(AdapterDetails, discovery_info[CONF_DETAILS])
await self.async_set_unique_id(self._details[ADAPTER_ADDRESS]) await self.async_set_unique_id(self._details[ADAPTER_ADDRESS])
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
self.context["title_placeholders"] = { details = self._details
"name": adapter_human_name(self._adapter, self._details[ADAPTER_ADDRESS]) self._async_set_adapter_info(self._adapter, details)
}
return await self.async_step_single_adapter() return await self.async_step_single_adapter()
@callback
def _async_set_adapter_info(self, adapter: str, details: AdapterDetails) -> None:
"""Set the adapter info."""
name = adapter_human_name(adapter, details[ADAPTER_ADDRESS])
model = adapter_model(details)
manufacturer = details[ADAPTER_MANUFACTURER]
self._placeholders = {
"name": name,
"model": model,
"manufacturer": manufacturer or "Unknown",
}
self.context["title_placeholders"] = self._placeholders
async def async_step_single_adapter( async def async_step_single_adapter(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
@ -67,6 +98,7 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
details = self._details details = self._details
assert adapter is not None assert adapter is not None
assert details is not None assert details is not None
assert self._placeholders is not None
address = details[ADAPTER_ADDRESS] address = details[ADAPTER_ADDRESS]
@ -74,12 +106,12 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(address, raise_on_progress=False) await self.async_set_unique_id(address, raise_on_progress=False)
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
return self.async_create_entry( return self.async_create_entry(
title=adapter_unique_name(adapter, address), data={} title=adapter_title(adapter, details), data={}
) )
return self.async_show_form( return self.async_show_form(
step_id="single_adapter", step_id="single_adapter",
description_placeholders={"name": adapter_human_name(adapter, address)}, description_placeholders=self._placeholders,
) )
async def async_step_multiple_adapters( async def async_step_multiple_adapters(
@ -89,11 +121,12 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None: if user_input is not None:
assert self._adapters is not None assert self._adapters is not None
adapter = user_input[CONF_ADAPTER] adapter = user_input[CONF_ADAPTER]
address = self._adapters[adapter][ADAPTER_ADDRESS] details = self._adapters[adapter]
address = details[ADAPTER_ADDRESS]
await self.async_set_unique_id(address, raise_on_progress=False) await self.async_set_unique_id(address, raise_on_progress=False)
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
return self.async_create_entry( return self.async_create_entry(
title=adapter_unique_name(adapter, address), data={} title=adapter_title(adapter, details), data={}
) )
configured_addresses = self._async_current_ids() configured_addresses = self._async_current_ids()
@ -116,6 +149,7 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
if len(unconfigured_adapters) == 1: if len(unconfigured_adapters) == 1:
self._adapter = list(self._adapters)[0] self._adapter = list(self._adapters)[0]
self._details = self._adapters[self._adapter] self._details = self._adapters[self._adapter]
self._async_set_adapter_info(self._adapter, self._details)
return await self.async_step_single_adapter() return await self.async_step_single_adapter()
return self.async_show_form( return self.async_show_form(
@ -124,8 +158,8 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
{ {
vol.Required(CONF_ADAPTER): vol.In( vol.Required(CONF_ADAPTER): vol.In(
{ {
adapter: adapter_human_name( adapter: adapter_display_info(
adapter, self._adapters[adapter][ADAPTER_ADDRESS] adapter, self._adapters[adapter]
) )
for adapter in sorted(unconfigured_adapters) for adapter in sorted(unconfigured_adapters)
} }

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "{name}", "flow_title": "{name} {manufacturer} {model}",
"step": { "step": {
"user": { "user": {
"description": "Choose a device to set up", "description": "Choose a device to set up",
@ -18,7 +18,7 @@
} }
}, },
"single_adapter": { "single_adapter": {
"description": "Do you want to set up the Bluetooth adapter {name}?" "description": "Do you want to set up the Bluetooth adapter {name} {manufacturer} {model}?"
} }
}, },
"abort": { "abort": {

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "What is the IRK (Identity Resolving Key) of the BLE device you want to track?", "description": "What is the IRK (Identity Resolving Key) of the BLE device you want to track?",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -1,6 +1,6 @@
{ {
"config": { "config": {
"flow_title": "[%key:component::bluetooth::config::flow_title%]", "flow_title": "{name}",
"step": { "step": {
"user": { "user": {
"description": "[%key:component::bluetooth::config::step::user::description%]", "description": "[%key:component::bluetooth::config::step::user::description%]",

View File

@ -65,7 +65,7 @@ async def test_async_step_user_macos(hass: HomeAssistant, macos_adapter: None) -
result["flow_id"], user_input={} result["flow_id"], user_input={}
) )
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "Core Bluetooth" assert result2["title"] == "Apple Unknown MacOS Model (Core Bluetooth)"
assert result2["data"] == {} assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -81,6 +81,11 @@ async def test_async_step_user_linux_one_adapter(
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "single_adapter" assert result["step_id"] == "single_adapter"
assert result["description_placeholders"] == {
"name": "hci0 (00:00:00:00:00:01)",
"model": "Bluetooth Adapter 5.0 (cc01:aa01)",
"manufacturer": "ACME",
}
with ( with (
patch("homeassistant.components.bluetooth.async_setup", return_value=True), patch("homeassistant.components.bluetooth.async_setup", return_value=True),
patch( patch(
@ -91,7 +96,9 @@ async def test_async_step_user_linux_one_adapter(
result["flow_id"], user_input={} result["flow_id"], user_input={}
) )
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "00:00:00:00:00:01" assert (
result2["title"] == "ACME Bluetooth Adapter 5.0 (cc01:aa01) (00:00:00:00:00:01)"
)
assert result2["data"] == {} assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -107,6 +114,10 @@ async def test_async_step_user_linux_two_adapters(
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "multiple_adapters" assert result["step_id"] == "multiple_adapters"
assert result["data_schema"].schema["adapter"].container == {
"hci0": "hci0 (00:00:00:00:00:01) ACME Bluetooth Adapter 5.0 (cc01:aa01)",
"hci1": "hci1 (00:00:00:00:00:02) ACME Bluetooth Adapter 5.0 (cc01:aa01)",
}
with ( with (
patch("homeassistant.components.bluetooth.async_setup", return_value=True), patch("homeassistant.components.bluetooth.async_setup", return_value=True),
patch( patch(
@ -117,7 +128,9 @@ async def test_async_step_user_linux_two_adapters(
result["flow_id"], user_input={CONF_ADAPTER: "hci1"} result["flow_id"], user_input={CONF_ADAPTER: "hci1"}
) )
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "00:00:00:00:00:02" assert (
result2["title"] == "ACME Bluetooth Adapter 5.0 (cc01:aa01) (00:00:00:00:00:02)"
)
assert result2["data"] == {} assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -153,6 +166,11 @@ async def test_async_step_integration_discovery(hass: HomeAssistant) -> None:
data={CONF_ADAPTER: "hci0", CONF_DETAILS: details}, data={CONF_ADAPTER: "hci0", CONF_DETAILS: details},
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["description_placeholders"] == {
"name": "hci0 (00:00:00:00:00:01)",
"model": "Unknown",
"manufacturer": "ACME",
}
assert result["step_id"] == "single_adapter" assert result["step_id"] == "single_adapter"
with ( with (
patch("homeassistant.components.bluetooth.async_setup", return_value=True), patch("homeassistant.components.bluetooth.async_setup", return_value=True),
@ -164,7 +182,7 @@ async def test_async_step_integration_discovery(hass: HomeAssistant) -> None:
result["flow_id"], user_input={} result["flow_id"], user_input={}
) )
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "00:00:00:00:00:01" assert result2["title"] == "ACME Unknown (00:00:00:00:00:01)"
assert result2["data"] == {} assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -196,7 +214,7 @@ async def test_async_step_integration_discovery_during_onboarding_one_adapter(
data={CONF_ADAPTER: "hci0", CONF_DETAILS: details}, data={CONF_ADAPTER: "hci0", CONF_DETAILS: details},
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "00:00:00:00:00:01" assert result["title"] == "ACME Unknown (00:00:00:00:00:01)"
assert result["data"] == {} assert result["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_onboarding.mock_calls) == 1 assert len(mock_onboarding.mock_calls) == 1
@ -240,11 +258,11 @@ async def test_async_step_integration_discovery_during_onboarding_two_adapters(
data={CONF_ADAPTER: "hci1", CONF_DETAILS: details2}, data={CONF_ADAPTER: "hci1", CONF_DETAILS: details2},
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "00:00:00:00:00:01" assert result["title"] == "ACME Unknown (00:00:00:00:00:01)"
assert result["data"] == {} assert result["data"] == {}
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "00:00:00:00:00:02" assert result2["title"] == "ACME Unknown (00:00:00:00:00:02)"
assert result2["data"] == {} assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 2 assert len(mock_setup_entry.mock_calls) == 2
@ -278,7 +296,7 @@ async def test_async_step_integration_discovery_during_onboarding(
data={CONF_ADAPTER: "Core Bluetooth", CONF_DETAILS: details}, data={CONF_ADAPTER: "Core Bluetooth", CONF_DETAILS: details},
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "Core Bluetooth" assert result["title"] == "ACME Unknown (Core Bluetooth)"
assert result["data"] == {} assert result["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_onboarding.mock_calls) == 1 assert len(mock_onboarding.mock_calls) == 1

View File

@ -3015,12 +3015,14 @@ async def test_discover_new_usb_adapters(
"hw_version": "usb:v1D6Bp0246d053F", "hw_version": "usb:v1D6Bp0246d053F",
"passive_scan": False, "passive_scan": False,
"sw_version": "homeassistant", "sw_version": "homeassistant",
"manufacturer": "ACME",
}, },
"hci1": { "hci1": {
"address": "00:00:00:00:00:02", "address": "00:00:00:00:00:02",
"hw_version": "usb:v1D6Bp0246d053F", "hw_version": "usb:v1D6Bp0246d053F",
"passive_scan": False, "passive_scan": False,
"sw_version": "homeassistant", "sw_version": "homeassistant",
"manufacturer": "ACME",
}, },
}, },
), ),
@ -3088,12 +3090,14 @@ async def test_discover_new_usb_adapters_with_firmware_fallback_delay(
"hw_version": "usb:v1D6Bp0246d053F", "hw_version": "usb:v1D6Bp0246d053F",
"passive_scan": False, "passive_scan": False,
"sw_version": "homeassistant", "sw_version": "homeassistant",
"manufacturer": "ACME",
}, },
"hci1": { "hci1": {
"address": "00:00:00:00:00:02", "address": "00:00:00:00:00:02",
"hw_version": "usb:v1D6Bp0246d053F", "hw_version": "usb:v1D6Bp0246d053F",
"passive_scan": False, "passive_scan": False,
"sw_version": "homeassistant", "sw_version": "homeassistant",
"manufacturer": "ACME",
}, },
}, },
), ),