Update Bluetooth remote config entries if the MAC is corrected (#139457)
* fix ble mac * fixes * fixes * fixes * restore deleted testpull/125870/merge
parent
6ce48eab45
commit
5a6ffe1901
|
@ -311,11 +311,24 @@ async def async_update_device(
|
|||
update the device with the new location so they can
|
||||
figure out where the adapter is.
|
||||
"""
|
||||
address = details[ADAPTER_ADDRESS]
|
||||
connections = {(dr.CONNECTION_BLUETOOTH, address)}
|
||||
device_registry = dr.async_get(hass)
|
||||
# We only have one device for the config entry
|
||||
# so if the address has been corrected, make
|
||||
# sure the device entry reflects the correct
|
||||
# address
|
||||
for device in dr.async_entries_for_config_entry(device_registry, entry.entry_id):
|
||||
for conn_type, conn_value in device.connections:
|
||||
if conn_type == dr.CONNECTION_BLUETOOTH and conn_value != address:
|
||||
device_registry.async_update_device(
|
||||
device.id, new_connections=connections
|
||||
)
|
||||
break
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=entry.entry_id,
|
||||
name=adapter_human_name(adapter, details[ADAPTER_ADDRESS]),
|
||||
connections={(dr.CONNECTION_BLUETOOTH, details[ADAPTER_ADDRESS])},
|
||||
name=adapter_human_name(adapter, address),
|
||||
connections=connections,
|
||||
manufacturer=details[ADAPTER_MANUFACTURER],
|
||||
model=adapter_model(details),
|
||||
sw_version=details.get(ADAPTER_SW_VERSION),
|
||||
|
@ -342,9 +355,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
)
|
||||
)
|
||||
)
|
||||
return True
|
||||
address = entry.unique_id
|
||||
assert address is not None
|
||||
assert source_entry is not None
|
||||
source_domain = entry.data[CONF_SOURCE_DOMAIN]
|
||||
if mac_manufacturer := await get_manufacturer_from_mac(address):
|
||||
manufacturer = f"{mac_manufacturer} ({source_domain})"
|
||||
|
|
|
@ -186,16 +186,28 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
"""Handle a flow initialized by an external scanner."""
|
||||
source = user_input[CONF_SOURCE]
|
||||
await self.async_set_unique_id(source)
|
||||
source_config_entry_id = user_input[CONF_SOURCE_CONFIG_ENTRY_ID]
|
||||
data = {
|
||||
CONF_SOURCE: source,
|
||||
CONF_SOURCE_MODEL: user_input[CONF_SOURCE_MODEL],
|
||||
CONF_SOURCE_DOMAIN: user_input[CONF_SOURCE_DOMAIN],
|
||||
CONF_SOURCE_CONFIG_ENTRY_ID: user_input[CONF_SOURCE_CONFIG_ENTRY_ID],
|
||||
CONF_SOURCE_CONFIG_ENTRY_ID: source_config_entry_id,
|
||||
CONF_SOURCE_DEVICE_ID: user_input[CONF_SOURCE_DEVICE_ID],
|
||||
}
|
||||
self._abort_if_unique_id_configured(updates=data)
|
||||
manager = get_manager()
|
||||
scanner = manager.async_scanner_by_source(source)
|
||||
for entry in self._async_current_entries(include_ignore=False):
|
||||
# If the mac address needs to be corrected, migrate
|
||||
# the config entry to the new mac address
|
||||
if (
|
||||
entry.data.get(CONF_SOURCE_CONFIG_ENTRY_ID) == source_config_entry_id
|
||||
and entry.unique_id != source
|
||||
):
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry, unique_id=source, data={**entry.data, **data}
|
||||
)
|
||||
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
||||
return self.async_abort(reason="already_configured")
|
||||
scanner = get_manager().async_scanner_by_source(source)
|
||||
assert scanner is not None
|
||||
return self.async_create_entry(title=scanner.name, data=data)
|
||||
|
||||
|
|
|
@ -608,3 +608,40 @@ async def test_async_step_integration_discovery_remote_adapter(
|
|||
await hass.async_block_till_done()
|
||||
cancel_scanner()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_async_step_integration_discovery_remote_adapter_mac_fix(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
area_registry: ar.AreaRegistry,
|
||||
) -> None:
|
||||
"""Test remote adapter corrects mac address via integration discovery."""
|
||||
entry = MockConfigEntry(domain="test")
|
||||
entry.add_to_hass(hass)
|
||||
bluetooth_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_SOURCE: "AA:BB:CC:DD:EE:FF",
|
||||
CONF_SOURCE_DOMAIN: "test",
|
||||
CONF_SOURCE_MODEL: "test",
|
||||
CONF_SOURCE_CONFIG_ENTRY_ID: entry.entry_id,
|
||||
CONF_SOURCE_DEVICE_ID: None,
|
||||
},
|
||||
)
|
||||
bluetooth_entry.add_to_hass(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
|
||||
data={
|
||||
CONF_SOURCE: "AA:AA:AA:AA:AA:AA",
|
||||
CONF_SOURCE_DOMAIN: "test",
|
||||
CONF_SOURCE_MODEL: "test",
|
||||
CONF_SOURCE_CONFIG_ENTRY_ID: entry.entry_id,
|
||||
CONF_SOURCE_DEVICE_ID: None,
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert bluetooth_entry.unique_id == "AA:AA:AA:AA:AA:AA"
|
||||
assert bluetooth_entry.data[CONF_SOURCE] == "AA:AA:AA:AA:AA:AA"
|
||||
|
|
|
@ -3300,3 +3300,52 @@ async def test_cleanup_orphened_remote_scanner_config_entry(
|
|||
assert not hass.config_entries.async_entry_for_domain_unique_id(
|
||||
"bluetooth", scanner.source
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_fix_incorrect_mac_remote_scanner_config_entry(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test the remote scanner config entries can replace a incorrect mac."""
|
||||
source_entry = MockConfigEntry(domain="test")
|
||||
source_entry.add_to_hass(hass)
|
||||
connector = (
|
||||
HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False),
|
||||
)
|
||||
scanner = FakeRemoteScanner("AA:BB:CC:DD:EE:FF", "esp32", connector, True)
|
||||
assert scanner.source == "AA:BB:CC:DD:EE:FF"
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_SOURCE: scanner.source,
|
||||
CONF_SOURCE_DOMAIN: "test",
|
||||
CONF_SOURCE_MODEL: "test",
|
||||
CONF_SOURCE_CONFIG_ENTRY_ID: source_entry.entry_id,
|
||||
},
|
||||
unique_id=scanner.source,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.config_entries.async_entry_for_domain_unique_id(
|
||||
"bluetooth", scanner.source
|
||||
)
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
||||
new_scanner = FakeRemoteScanner("AA:BB:CC:DD:EE:AA", "esp32", connector, True)
|
||||
assert new_scanner.source == "AA:BB:CC:DD:EE:AA"
|
||||
hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
data={**entry.data, CONF_SOURCE: new_scanner.source},
|
||||
unique_id=new_scanner.source,
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.config_entries.async_entry_for_domain_unique_id(
|
||||
"bluetooth", new_scanner.source
|
||||
)
|
||||
# Incorrect connection should be removed
|
||||
assert not hass.config_entries.async_entry_for_domain_unique_id(
|
||||
"bluetooth", scanner.source
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue