diff --git a/homeassistant/components/bluetooth/base_scanner.py b/homeassistant/components/bluetooth/base_scanner.py index f1ffd6ecf582947c6db308043da56340e6a9a72d..97b2aebba7a5522be469a86aa8f3cee698478a90 100644 --- a/homeassistant/components/bluetooth/base_scanner.py +++ b/homeassistant/components/bluetooth/base_scanner.py @@ -345,12 +345,27 @@ class BaseHaRemoteScanner(BaseHaScanner): tx_power=NO_RSSI_VALUE if tx_power is None else tx_power, platform_data=(), ) - device = BLEDevice( - address=address, - name=local_name, - details=self._details | details, - rssi=rssi, # deprecated, will be removed in newer bleak - ) + if prev_discovery: + # + # Bleak updates the BLEDevice via create_or_update_device. + # We need to do the same to ensure integrations that already + # have the BLEDevice object get the updated details when they + # change. + # + # https://github.com/hbldh/bleak/blob/222618b7747f0467dbb32bd3679f8cfaa19b1668/bleak/backends/scanner.py#L203 + # + device = prev_device + device.name = local_name + device.details = self._details | details + # pylint: disable-next=protected-access + device._rssi = rssi # deprecated, will be removed in newer bleak + else: + device = BLEDevice( + address=address, + name=local_name, + details=self._details | details, + rssi=rssi, # deprecated, will be removed in newer bleak + ) self._discovered_device_advertisement_datas[address] = ( device, advertisement_data, diff --git a/tests/components/bluetooth/test_base_scanner.py b/tests/components/bluetooth/test_base_scanner.py index 79a36630df22d1903d10c6d35973c917aedf0f3e..8817acad4684973a838e06fb61391b853594f8dc 100644 --- a/tests/components/bluetooth/test_base_scanner.py +++ b/tests/components/bluetooth/test_base_scanner.py @@ -481,7 +481,18 @@ async def test_device_with_ten_minute_advertising_interval( connectable=False, ) - for _ in range(0, 20): + with patch( + "homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME", + return_value=new_time, + ): + scanner.inject_advertisement(bparasite_device, bparasite_device_adv) + + original_device = scanner.discovered_devices_and_advertisement_data[ + bparasite_device.address + ][0] + assert original_device is not bparasite_device + + for _ in range(1, 20): new_time += advertising_interval with patch( "homeassistant.components.bluetooth.base_scanner.MONOTONIC_TIME", @@ -489,6 +500,13 @@ async def test_device_with_ten_minute_advertising_interval( ): scanner.inject_advertisement(bparasite_device, bparasite_device_adv) + # Make sure the BLEDevice object gets updated + # and not replaced + assert ( + scanner.discovered_devices_and_advertisement_data[bparasite_device.address][0] + is original_device + ) + future_time = new_time assert ( bluetooth.async_address_present(hass, bparasite_device.address, False) is True