mirror of
https://github.com/home-assistant/core.git
synced 2026-09-17 22:19:00 +01:00
Abort Teslemetry Bluetooth vehicle setup when no Bluetooth is available (#182068)
This commit is contained in:
@@ -36,6 +36,7 @@ from homeassistant.components.application_credentials import (
|
||||
from homeassistant.components.bluetooth import (
|
||||
async_discovered_service_info,
|
||||
async_request_active_scan,
|
||||
async_scanner_count,
|
||||
)
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_REAUTH,
|
||||
@@ -227,6 +228,8 @@ class VehicleSubentryFlowHandler(ConfigSubentryFlow):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> SubentryFlowResult:
|
||||
"""Select an account vehicle to add over Bluetooth, then pair it."""
|
||||
if not async_scanner_count(self.hass, connectable=True):
|
||||
return self.async_abort(reason="bluetooth_not_available")
|
||||
entry = self._get_entry()
|
||||
if entry.state is not ConfigEntryState.LOADED:
|
||||
return self.async_abort(reason="entry_not_loaded")
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"vehicle": {
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"bluetooth_not_available": "At least one Bluetooth adapter or remote Bluetooth proxy must be configured to add a vehicle over Bluetooth.",
|
||||
"entry_not_loaded": "The Teslemetry configuration entry is not loaded. Please ensure it is set up correctly before adding a vehicle.",
|
||||
"no_vehicles": "Every eligible vehicle in your Teslemetry account has already been added over Bluetooth."
|
||||
},
|
||||
|
||||
@@ -796,6 +796,7 @@ async def _start_pairing_at_scan(
|
||||
return result
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_pairing_already_whitelisted(hass: HomeAssistant) -> None:
|
||||
"""The add flow creates the subentry when the key is already whitelisted."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -828,6 +829,7 @@ async def test_subentry_pairing_already_whitelisted(hass: HomeAssistant) -> None
|
||||
vehicle.disconnect.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_pairing_duplicate_vin_aborts(hass: HomeAssistant) -> None:
|
||||
"""A second flow racing on the same VIN aborts with already_configured."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -866,6 +868,7 @@ async def test_subentry_pairing_duplicate_vin_aborts(hass: HomeAssistant) -> Non
|
||||
assert len(entry.get_subentries_of_type(SUBENTRY_TYPE_VEHICLE)) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_pairing_requires_key_approval(hass: HomeAssistant) -> None:
|
||||
"""Pairing walks through instructions and key install when not whitelisted."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -913,6 +916,7 @@ async def test_subentry_pairing_requires_key_approval(hass: HomeAssistant) -> No
|
||||
vehicle.pair.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_scan_connect_fails(hass: HomeAssistant) -> None:
|
||||
"""The scan step re-shows the form with an error when BLE connect fails."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -951,6 +955,7 @@ async def test_subentry_scan_connect_fails(hass: HomeAssistant) -> None:
|
||||
],
|
||||
ids=["timeout", "transport", "rejected"],
|
||||
)
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_authorize_failure(
|
||||
hass: HomeAssistant, error: type[TeslaFleetError], expected: str
|
||||
) -> None:
|
||||
@@ -998,6 +1003,7 @@ async def test_subentry_authorize_failure(
|
||||
vehicle.pair.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_authorize_unexpected_error_disconnects(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
@@ -1029,6 +1035,7 @@ async def test_subentry_authorize_unexpected_error_disconnects(
|
||||
assert not entry.get_subentries_of_type(SUBENTRY_TYPE_VEHICLE)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_authorize_existing_key_finishes(hass: HomeAssistant) -> None:
|
||||
"""Approving the key after a timeout, then retrying, completes the pairing."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -1103,6 +1110,7 @@ async def test_subentry_authorize_existing_key_finishes(hass: HomeAssistant) ->
|
||||
pytest.param(TimeoutError(), id="timeout_error"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_handshake_error_recovers(
|
||||
hass: HomeAssistant, handshake_error: Exception
|
||||
) -> None:
|
||||
@@ -1145,6 +1153,7 @@ async def test_subentry_handshake_error_recovers(
|
||||
assert vehicle.disconnect.await_count == 2
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_pairing_abandoned(hass: HomeAssistant) -> None:
|
||||
"""Abandoning the flow mid-pairing cancels the pair task and disconnects."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -1188,6 +1197,7 @@ async def test_subentry_pairing_abandoned(hass: HomeAssistant) -> None:
|
||||
assert not entry.get_subentries_of_type(SUBENTRY_TYPE_VEHICLE)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_scan_device_not_found(hass: HomeAssistant) -> None:
|
||||
"""The scan step re-shows the form with an error when no device is found."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
@@ -1225,6 +1235,7 @@ async def test_subentry_scan_device_not_found(hass: HomeAssistant) -> None:
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_scan_key_load_recovers(
|
||||
hass: HomeAssistant, key_error: Exception
|
||||
) -> None:
|
||||
@@ -1266,6 +1277,7 @@ async def test_subentry_scan_key_load_recovers(
|
||||
vehicle.connect.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_scan_finds_device_after_active_scan(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
@@ -1306,6 +1318,7 @@ async def test_subentry_scan_finds_device_after_active_scan(
|
||||
vehicle.connect.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_add_flow_keeps_device_on_parent(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
@@ -1408,6 +1421,7 @@ async def test_subentry_add_flow_keeps_device_on_parent(
|
||||
assert all(entity.config_subentry_id is None for entity in bound_entities)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_add_flow_no_available_vehicles(hass: HomeAssistant) -> None:
|
||||
"""The add flow aborts when every account vehicle is already added."""
|
||||
entry = await _setup_paired_entry(hass)
|
||||
@@ -1421,6 +1435,20 @@ async def test_subentry_add_flow_no_available_vehicles(hass: HomeAssistant) -> N
|
||||
assert result["reason"] == "no_vehicles"
|
||||
|
||||
|
||||
async def test_subentry_add_flow_no_bluetooth(hass: HomeAssistant) -> None:
|
||||
"""The add flow aborts immediately when no Bluetooth integration is set up."""
|
||||
entry = await _setup_account_entry(hass)
|
||||
|
||||
result = await hass.config_entries.subentries.async_init(
|
||||
(entry.entry_id, SUBENTRY_TYPE_VEHICLE),
|
||||
context={"source": "user"},
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "bluetooth_not_available"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_subentry_add_flow_entry_not_loaded(hass: HomeAssistant) -> None:
|
||||
"""The add flow aborts when the parent entry is not loaded."""
|
||||
entry = mock_config_entry()
|
||||
|
||||
Reference in New Issue
Block a user