From 324aa09ebe7c34a600e920918af500a9df75fa83 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 13 Oct 2025 10:14:51 -1000 Subject: [PATCH] Update Improv BLE discovery notification when device name changes (#154352) Co-authored-by: Paulus Schoutsen --- .../components/improv_ble/config_flow.py | 6 ++ .../components/improv_ble/test_config_flow.py | 72 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/improv_ble/config_flow.py b/homeassistant/components/improv_ble/config_flow.py index bbe7153c7479..66e95f6d028b 100644 --- a/homeassistant/components/improv_ble/config_flow.py +++ b/homeassistant/components/improv_ble/config_flow.py @@ -170,6 +170,12 @@ class ImprovBLEConfigFlow(ConfigFlow, domain=DOMAIN): ) self._discovery_info = service_info + + # Update title placeholders if name changed + name = service_info.name or service_info.address + if self.context.get("title_placeholders", {}).get("name") != name: + self.async_update_title_placeholders({"name": name}) + try: self._abort_if_provisioned() except AbortFlow: diff --git a/tests/components/improv_ble/test_config_flow.py b/tests/components/improv_ble/test_config_flow.py index 028cb7fb4ad7..140b473cd7d4 100644 --- a/tests/components/improv_ble/test_config_flow.py +++ b/tests/components/improv_ble/test_config_flow.py @@ -8,7 +8,10 @@ from improv_ble_client import Error, State, errors as improv_ble_errors import pytest from homeassistant import config_entries -from homeassistant.components.bluetooth import BluetoothChange +from homeassistant.components.bluetooth import ( + BluetoothChange, + BluetoothServiceInfoBleak, +) from homeassistant.components.improv_ble.const import DOMAIN from homeassistant.config_entries import SOURCE_IGNORE from homeassistant.const import CONF_ADDRESS @@ -22,8 +25,12 @@ from . import ( PROVISIONED_IMPROV_BLE_DISCOVERY_INFO, ) -from tests.common import MockConfigEntry -from tests.components.bluetooth import inject_bluetooth_service_info_bleak +from tests.common import MockConfigEntry, async_capture_events +from tests.components.bluetooth import ( + generate_advertisement_data, + generate_ble_device, + inject_bluetooth_service_info_bleak, +) IMPROV_BLE = "homeassistant.components.improv_ble" @@ -803,3 +810,62 @@ async def test_provision_fails_invalid_data( "Received invalid improv via BLE data '000000000000' from device with bluetooth address 'AA:BB:CC:DD:EE:F0'" in caplog.text ) + + +async def test_bluetooth_name_update(hass: HomeAssistant) -> None: + """Test that discovery notification title updates when device name changes.""" + with patch( + f"{IMPROV_BLE}.config_flow.bluetooth.async_register_callback", + ) as mock_async_register_callback: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_BLUETOOTH}, + data=IMPROV_BLE_DISCOVERY_INFO, + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "bluetooth_confirm" + + # Get the flow to check initial title_placeholders + flow = hass.config_entries.flow.async_get(result["flow_id"]) + assert flow["context"]["title_placeholders"] == {"name": "00123456"} + + # Get the callback that was registered + callback = mock_async_register_callback.call_args.args[1] + + # Create updated discovery info with a new name + updated_discovery_info = BluetoothServiceInfoBleak( + name="improvtest", + address="AA:BB:CC:DD:EE:F0", + rssi=-60, + manufacturer_data={}, + service_uuids=[IMPROV_BLE_DISCOVERY_INFO.service_uuids[0]], + service_data=IMPROV_BLE_DISCOVERY_INFO.service_data, + source="local", + device=generate_ble_device(address="AA:BB:CC:DD:EE:F0", name="improvtest"), + advertisement=generate_advertisement_data( + service_uuids=IMPROV_BLE_DISCOVERY_INFO.service_uuids, + service_data=IMPROV_BLE_DISCOVERY_INFO.service_data, + ), + time=0, + connectable=True, + tx_power=-127, + ) + + # Capture events to verify frontend notification + events = async_capture_events(hass, "data_entry_flow_progressed") + + # Simulate receiving updated advertisement with new name + callback(updated_discovery_info, BluetoothChange.ADVERTISEMENT) + await hass.async_block_till_done() + + # Verify title_placeholders were updated + flow = hass.config_entries.flow.async_get(result["flow_id"]) + assert flow["context"]["title_placeholders"] == {"name": "improvtest"} + + # Verify frontend was notified + assert len(events) == 1 + assert events[0].data == { + "handler": DOMAIN, + "flow_id": result["flow_id"], + "refresh": True, + }