diff --git a/homeassistant/components/bluetooth/config_flow.py b/homeassistant/components/bluetooth/config_flow.py index 5bfe5e7089ccd3704a31072ca7a02b3b1c24ebe4..6425aabe12f8be7e038a03e73b5c59b05f9e3290 100644 --- a/homeassistant/components/bluetooth/config_flow.py +++ b/homeassistant/components/bluetooth/config_flow.py @@ -211,10 +211,16 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN): @callback def async_get_options_flow( config_entry: ConfigEntry, - ) -> SchemaOptionsFlowHandler | RemoteAdapterOptionsFlowHandler: + ) -> ( + SchemaOptionsFlowHandler + | RemoteAdapterOptionsFlowHandler + | LocalNoPassiveOptionsFlowHandler + ): """Get the options flow for this handler.""" if CONF_SOURCE in config_entry.data: return RemoteAdapterOptionsFlowHandler() + if not (manager := get_manager()) or not manager.supports_passive_scan: + return LocalNoPassiveOptionsFlowHandler() return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW) @classmethod @@ -232,3 +238,13 @@ class RemoteAdapterOptionsFlowHandler(OptionsFlow): ) -> ConfigFlowResult: """Handle options flow.""" return self.async_abort(reason="remote_adapters_not_supported") + + +class LocalNoPassiveOptionsFlowHandler(OptionsFlow): + """Handle a option flow for local adapters with no passive support.""" + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle options flow.""" + return self.async_abort(reason="local_adapters_no_passive_support") diff --git a/homeassistant/components/bluetooth/strings.json b/homeassistant/components/bluetooth/strings.json index 1b8231c66ca195f44013df57cc43756b10ac63c6..5f9a380d631396dd951f128a3270b3b75083e92b 100644 --- a/homeassistant/components/bluetooth/strings.json +++ b/homeassistant/components/bluetooth/strings.json @@ -35,7 +35,8 @@ } }, "abort": { - "remote_adapters_not_supported": "Bluetooth configuration for remote adapters is not supported." + "remote_adapters_not_supported": "Bluetooth configuration for remote adapters is not supported.", + "local_adapters_no_passive_support": "Local Bluetooth adapters that do not support passive scanning cannot be configured." } } } diff --git a/tests/components/bluetooth/test_config_flow.py b/tests/components/bluetooth/test_config_flow.py index abb3a5e23936866f0a36ccc11b14fbc782e46f97..0070bebe4b6ee9f8811542693e28591e283fc257 100644 --- a/tests/components/bluetooth/test_config_flow.py +++ b/tests/components/bluetooth/test_config_flow.py @@ -487,6 +487,33 @@ async def test_options_flow_remote_adapter(hass: HomeAssistant) -> None: assert result["reason"] == "remote_adapters_not_supported" +@pytest.mark.usefixtures( + "one_adapter", "mock_bleak_scanner_start", "mock_bluetooth_adapters" +) +async def test_options_flow_local_no_passive_support(hass: HomeAssistant) -> None: + """Test options are not available for local adapters without passive support.""" + source_entry = MockConfigEntry( + domain="test", + ) + source_entry.add_to_hass(hass) + entry = MockConfigEntry( + domain=DOMAIN, + data={}, + options={}, + unique_id="BB:BB:BB:BB:BB:BB", + ) + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + _get_manager()._adapters["hci0"]["passive_scan"] = False + + result = await hass.config_entries.options.async_init(entry.entry_id) + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "local_adapters_no_passive_support" + + @pytest.mark.usefixtures("one_adapter") async def test_async_step_user_linux_adapter_is_ignored(hass: HomeAssistant) -> None: """Test we give a hint that the adapter is ignored."""