diff --git a/homeassistant/components/bluetooth/const.py b/homeassistant/components/bluetooth/const.py index 3174603f08e..891e6d8be82 100644 --- a/homeassistant/components/bluetooth/const.py +++ b/homeassistant/components/bluetooth/const.py @@ -58,7 +58,7 @@ class AdapterDetails(TypedDict, total=False): address: str sw_version: str - hw_version: str + hw_version: str | None passive_scan: bool diff --git a/homeassistant/components/bluetooth/util.py b/homeassistant/components/bluetooth/util.py index d04685f34d9..860428a6106 100644 --- a/homeassistant/components/bluetooth/util.py +++ b/homeassistant/components/bluetooth/util.py @@ -79,7 +79,7 @@ async def async_get_bluetooth_adapters() -> dict[str, AdapterDetails]: adapters[adapter] = AdapterDetails( address=adapter1["Address"], sw_version=adapter1["Name"], # This is actually the BlueZ version - hw_version=adapter1["Modalias"], + hw_version=adapter1.get("Modalias"), passive_scan="org.bluez.AdvertisementMonitorManager1" in details, ) return adapters diff --git a/tests/components/bluetooth/conftest.py b/tests/components/bluetooth/conftest.py index 58b6e596629..857af1e7eaa 100644 --- a/tests/components/bluetooth/conftest.py +++ b/tests/components/bluetooth/conftest.py @@ -97,3 +97,27 @@ def two_adapters_fixture(bluez_dbus_mock): }, ): yield + + +@pytest.fixture(name="one_adapter_old_bluez") +def one_adapter_old_bluez(bluez_dbus_mock): + """Fixture that mocks two adapters on Linux.""" + with patch( + "homeassistant.components.bluetooth.platform.system", return_value="Linux" + ), patch( + "homeassistant.components.bluetooth.scanner.platform.system", + return_value="Linux", + ), patch( + "homeassistant.components.bluetooth.util.platform.system", return_value="Linux" + ), patch( + "bluetooth_adapters.get_bluetooth_adapter_details", + return_value={ + "hci0": { + "org.bluez.Adapter1": { + "Address": "00:00:00:00:00:01", + "Name": "BlueZ 4.43", + } + }, + }, + ): + yield diff --git a/tests/components/bluetooth/test_init.py b/tests/components/bluetooth/test_init.py index 32feb3d7b0f..a3045291286 100644 --- a/tests/components/bluetooth/test_init.py +++ b/tests/components/bluetooth/test_init.py @@ -116,6 +116,53 @@ async def test_setup_and_stop_passive(hass, mock_bleak_scanner_start, one_adapte } +async def test_setup_and_stop_old_bluez( + hass, mock_bleak_scanner_start, one_adapter_old_bluez +): + """Test we and setup and stop the scanner the passive scanner with older bluez.""" + entry = MockConfigEntry( + domain=bluetooth.DOMAIN, + data={}, + options={}, + unique_id="00:00:00:00:00:01", + ) + entry.add_to_hass(hass) + init_kwargs = None + + class MockBleakScanner: + def __init__(self, *args, **kwargs): + """Init the scanner.""" + nonlocal init_kwargs + init_kwargs = kwargs + + async def start(self, *args, **kwargs): + """Start the scanner.""" + + async def stop(self, *args, **kwargs): + """Stop the scanner.""" + + def register_detection_callback(self, *args, **kwargs): + """Register a callback.""" + + with patch( + "homeassistant.components.bluetooth.scanner.OriginalBleakScanner", + MockBleakScanner, + ): + assert await async_setup_component( + hass, bluetooth.DOMAIN, {bluetooth.DOMAIN: {}} + ) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() + + hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) + await hass.async_block_till_done() + + assert init_kwargs == { + "adapter": "hci0", + "scanning_mode": "active", + } + + async def test_setup_and_stop_no_bluetooth(hass, caplog, macos_adapter): """Test we fail gracefully when bluetooth is not available.""" mock_bt = [