From 7cf19260814fa20a913a09e7cdcd558e9aa9df02 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 5 Apr 2023 00:19:37 -1000 Subject: [PATCH] Fix BLEDevice not getting updated when details change for remote scanners (#90815) --- .../components/bluetooth/base_scanner.py | 27 ++++++++++++++----- .../components/bluetooth/test_base_scanner.py | 20 +++++++++++++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/bluetooth/base_scanner.py b/homeassistant/components/bluetooth/base_scanner.py index f1ffd6ecf58..97b2aebba7a 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 79a36630df2..8817acad468 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