diff --git a/homeassistant/components/tessie/binary_sensor.py b/homeassistant/components/tessie/binary_sensor.py index 9030fee61b3..f425cd10134 100644 --- a/homeassistant/components/tessie/binary_sensor.py +++ b/homeassistant/components/tessie/binary_sensor.py @@ -20,6 +20,8 @@ from .const import TessieState from .entity import TessieEnergyEntity, TessieEntity from .models import TessieEnergyData, TessieVehicleData +PARALLEL_UPDATES = 0 + @dataclass(frozen=True, kw_only=True) class TessieBinarySensorEntityDescription(BinarySensorEntityDescription): diff --git a/homeassistant/components/tessie/button.py b/homeassistant/components/tessie/button.py index 8f80f27616b..bef9c2585f6 100644 --- a/homeassistant/components/tessie/button.py +++ b/homeassistant/components/tessie/button.py @@ -22,6 +22,8 @@ from . import TessieConfigEntry from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + @dataclass(frozen=True, kw_only=True) class TessieButtonEntityDescription(ButtonEntityDescription): diff --git a/homeassistant/components/tessie/climate.py b/homeassistant/components/tessie/climate.py index 7676d2f071b..e0649432e05 100644 --- a/homeassistant/components/tessie/climate.py +++ b/homeassistant/components/tessie/climate.py @@ -26,6 +26,8 @@ from .const import TessieClimateKeeper from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/config_flow.py b/homeassistant/components/tessie/config_flow.py index f3761d4c4ce..1cbc070e463 100644 --- a/homeassistant/components/tessie/config_flow.py +++ b/homeassistant/components/tessie/config_flow.py @@ -38,6 +38,7 @@ class TessieConfigFlow(ConfigFlow, domain=DOMAIN): """Get configuration from the user.""" errors: dict[str, str] = {} if user_input: + self._async_abort_entries_match(dict(user_input)) try: await get_state_of_all_vehicles( session=async_get_clientsession(self.hass), diff --git a/homeassistant/components/tessie/cover.py b/homeassistant/components/tessie/cover.py index 109bdbce2bf..93ce25993d9 100644 --- a/homeassistant/components/tessie/cover.py +++ b/homeassistant/components/tessie/cover.py @@ -29,6 +29,8 @@ from .const import TessieCoverStates from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/device_tracker.py b/homeassistant/components/tessie/device_tracker.py index 300aae7d858..d90222bf821 100644 --- a/homeassistant/components/tessie/device_tracker.py +++ b/homeassistant/components/tessie/device_tracker.py @@ -12,6 +12,8 @@ from . import TessieConfigEntry from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/lock.py b/homeassistant/components/tessie/lock.py index d73d83e399d..4f6ce3800e3 100644 --- a/homeassistant/components/tessie/lock.py +++ b/homeassistant/components/tessie/lock.py @@ -26,6 +26,8 @@ from .const import DOMAIN, TessieChargeCableLockStates from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/manifest.json b/homeassistant/components/tessie/manifest.json index c086c7b6876..e1908350e91 100644 --- a/homeassistant/components/tessie/manifest.json +++ b/homeassistant/components/tessie/manifest.json @@ -6,5 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/tessie", "iot_class": "cloud_polling", "loggers": ["tessie"], + "quality_scale": "platinum", "requirements": ["tessie-api==0.1.1", "tesla-fleet-api==0.7.2"] } diff --git a/homeassistant/components/tessie/media_player.py b/homeassistant/components/tessie/media_player.py index f3b5e266604..7dfe568926b 100644 --- a/homeassistant/components/tessie/media_player.py +++ b/homeassistant/components/tessie/media_player.py @@ -20,6 +20,8 @@ STATES = { "Stopped": MediaPlayerState.IDLE, } +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/number.py b/homeassistant/components/tessie/number.py index 4847ac55da5..74249d392a7 100644 --- a/homeassistant/components/tessie/number.py +++ b/homeassistant/components/tessie/number.py @@ -31,6 +31,8 @@ from .entity import TessieEnergyEntity, TessieEntity from .helpers import handle_command from .models import TessieEnergyData, TessieVehicleData +PARALLEL_UPDATES = 0 + @dataclass(frozen=True, kw_only=True) class TessieNumberEntityDescription(NumberEntityDescription): diff --git a/homeassistant/components/tessie/select.py b/homeassistant/components/tessie/select.py index 1d02d07a741..4dfe7088439 100644 --- a/homeassistant/components/tessie/select.py +++ b/homeassistant/components/tessie/select.py @@ -32,6 +32,8 @@ SEAT_COOLERS = { "climate_state_seat_fan_front_right": "front_right", } +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/sensor.py b/homeassistant/components/tessie/sensor.py index 586162fe779..7f09cef2acd 100644 --- a/homeassistant/components/tessie/sensor.py +++ b/homeassistant/components/tessie/sensor.py @@ -367,6 +367,8 @@ ENERGY_INFO_DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = ( ), ) +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/strings.json b/homeassistant/components/tessie/strings.json index dd8ac39f4e5..df488523900 100644 --- a/homeassistant/components/tessie/strings.json +++ b/homeassistant/components/tessie/strings.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" + }, "error": { "invalid_access_token": "[%key:common::config_flow::error::invalid_access_token%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", diff --git a/homeassistant/components/tessie/switch.py b/homeassistant/components/tessie/switch.py index ea1b804a86d..f0088a4444f 100644 --- a/homeassistant/components/tessie/switch.py +++ b/homeassistant/components/tessie/switch.py @@ -71,6 +71,8 @@ CHARGE_DESCRIPTION: TessieSwitchEntityDescription = TessieSwitchEntityDescriptio off_func=lambda: stop_charging, ) +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/homeassistant/components/tessie/update.py b/homeassistant/components/tessie/update.py index 73a01873e37..959a713047f 100644 --- a/homeassistant/components/tessie/update.py +++ b/homeassistant/components/tessie/update.py @@ -15,6 +15,8 @@ from .const import TessieUpdateStatus from .entity import TessieEntity from .models import TessieVehicleData +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, diff --git a/tests/components/tessie/test_config_flow.py b/tests/components/tessie/test_config_flow.py index f3dc98e6e18..043086971fa 100644 --- a/tests/components/tessie/test_config_flow.py +++ b/tests/components/tessie/test_config_flow.py @@ -67,6 +67,33 @@ async def test_form( assert result2["data"] == TEST_CONFIG +async def test_abort( + hass: HomeAssistant, + mock_config_flow_get_state_of_all_vehicles, + mock_async_setup_entry, +) -> None: + """Test a duplicate entry aborts.""" + + mock_entry = MockConfigEntry( + domain=DOMAIN, + data=TEST_CONFIG, + ) + mock_entry.add_to_hass(hass) + + result1 = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + result2 = await hass.config_entries.flow.async_configure( + result1["flow_id"], + TEST_CONFIG, + ) + await hass.async_block_till_done() + + assert result2["type"] is FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + @pytest.mark.parametrize( ("side_effect", "error"), [