mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Update Bluetooth remote config entries if the MAC is corrected (#139457)
* fix ble mac * fixes * fixes * fixes * restore deleted test
This commit is contained in:
parent
6ce48eab45
commit
5a6ffe1901
@ -311,11 +311,24 @@ async def async_update_device(
|
|||||||
update the device with the new location so they can
|
update the device with the new location so they can
|
||||||
figure out where the adapter is.
|
figure out where the adapter is.
|
||||||
"""
|
"""
|
||||||
|
address = details[ADAPTER_ADDRESS]
|
||||||
|
connections = {(dr.CONNECTION_BLUETOOTH, address)}
|
||||||
device_registry = dr.async_get(hass)
|
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(
|
device_entry = device_registry.async_get_or_create(
|
||||||
config_entry_id=entry.entry_id,
|
config_entry_id=entry.entry_id,
|
||||||
name=adapter_human_name(adapter, details[ADAPTER_ADDRESS]),
|
name=adapter_human_name(adapter, address),
|
||||||
connections={(dr.CONNECTION_BLUETOOTH, details[ADAPTER_ADDRESS])},
|
connections=connections,
|
||||||
manufacturer=details[ADAPTER_MANUFACTURER],
|
manufacturer=details[ADAPTER_MANUFACTURER],
|
||||||
model=adapter_model(details),
|
model=adapter_model(details),
|
||||||
sw_version=details.get(ADAPTER_SW_VERSION),
|
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
|
address = entry.unique_id
|
||||||
assert address is not None
|
assert address is not None
|
||||||
assert source_entry is not None
|
|
||||||
source_domain = entry.data[CONF_SOURCE_DOMAIN]
|
source_domain = entry.data[CONF_SOURCE_DOMAIN]
|
||||||
if mac_manufacturer := await get_manufacturer_from_mac(address):
|
if mac_manufacturer := await get_manufacturer_from_mac(address):
|
||||||
manufacturer = f"{mac_manufacturer} ({source_domain})"
|
manufacturer = f"{mac_manufacturer} ({source_domain})"
|
||||||
|
@ -186,16 +186,28 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
"""Handle a flow initialized by an external scanner."""
|
"""Handle a flow initialized by an external scanner."""
|
||||||
source = user_input[CONF_SOURCE]
|
source = user_input[CONF_SOURCE]
|
||||||
await self.async_set_unique_id(source)
|
await self.async_set_unique_id(source)
|
||||||
|
source_config_entry_id = user_input[CONF_SOURCE_CONFIG_ENTRY_ID]
|
||||||
data = {
|
data = {
|
||||||
CONF_SOURCE: source,
|
CONF_SOURCE: source,
|
||||||
CONF_SOURCE_MODEL: user_input[CONF_SOURCE_MODEL],
|
CONF_SOURCE_MODEL: user_input[CONF_SOURCE_MODEL],
|
||||||
CONF_SOURCE_DOMAIN: user_input[CONF_SOURCE_DOMAIN],
|
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],
|
CONF_SOURCE_DEVICE_ID: user_input[CONF_SOURCE_DEVICE_ID],
|
||||||
}
|
}
|
||||||
self._abort_if_unique_id_configured(updates=data)
|
self._abort_if_unique_id_configured(updates=data)
|
||||||
manager = get_manager()
|
for entry in self._async_current_entries(include_ignore=False):
|
||||||
scanner = manager.async_scanner_by_source(source)
|
# 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
|
assert scanner is not None
|
||||||
return self.async_create_entry(title=scanner.name, data=data)
|
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()
|
await hass.async_block_till_done()
|
||||||
cancel_scanner()
|
cancel_scanner()
|
||||||
await hass.async_block_till_done()
|
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(
|
assert not hass.config_entries.async_entry_for_domain_unique_id(
|
||||||
"bluetooth", scanner.source
|
"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…
x
Reference in New Issue
Block a user