From d1b2f697138efa78b2d50173fd2f0887b4a9c865 Mon Sep 17 00:00:00 2001 From: HoffmanEl <140370244+HoffmanEl@users.noreply.github.com> Date: Mon, 4 May 2026 14:32:00 +0100 Subject: [PATCH] Add reconfiguration flow to actron_air integration (#169712) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../components/actron_air/config_flow.py | 29 ++++++++- .../components/actron_air/quality_scale.yaml | 2 +- .../components/actron_air/strings.json | 7 ++- .../components/actron_air/test_config_flow.py | 61 +++++++++++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/actron_air/config_flow.py b/homeassistant/components/actron_air/config_flow.py index e03b6bbdebd..8b5a6f4bc5a 100644 --- a/homeassistant/components/actron_air/config_flow.py +++ b/homeassistant/components/actron_air/config_flow.py @@ -6,7 +6,12 @@ from typing import Any from actron_neo_api import ActronAirAPI, ActronAirAuthError -from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ( + SOURCE_REAUTH, + SOURCE_RECONFIGURE, + ConfigFlow, + ConfigFlowResult, +) from homeassistant.const import CONF_API_TOKEN from homeassistant.exceptions import HomeAssistantError @@ -105,6 +110,14 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN): data_updates={CONF_API_TOKEN: self._api.refresh_token_value}, ) + # Check if this is a reconfigure flow + if self.source == SOURCE_RECONFIGURE: + self._abort_if_unique_id_mismatch(reason="wrong_account") + return self.async_update_reload_and_abort( + self._get_reconfigure_entry(), + data_updates={CONF_API_TOKEN: self._api.refresh_token_value}, + ) + self._abort_if_unique_id_configured() return self.async_create_entry( title=user_data.email, @@ -138,6 +151,20 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN): return self.async_show_form(step_id="reauth_confirm") + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfiguration request.""" + return await self.async_step_reconfigure_confirm() + + async def async_step_reconfigure_confirm( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Confirm reconfiguration dialog.""" + if user_input is not None: + return await self.async_step_user() + return self.async_show_form(step_id="reconfigure_confirm") + async def async_step_connection_error( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: diff --git a/homeassistant/components/actron_air/quality_scale.yaml b/homeassistant/components/actron_air/quality_scale.yaml index c74421b177e..4d8dd96fa86 100644 --- a/homeassistant/components/actron_air/quality_scale.yaml +++ b/homeassistant/components/actron_air/quality_scale.yaml @@ -60,7 +60,7 @@ rules: entity-translations: done exception-translations: done icon-translations: done - reconfiguration-flow: todo + reconfiguration-flow: done repair-issues: status: exempt comment: This integration does not have any known issues that require repair. diff --git a/homeassistant/components/actron_air/strings.json b/homeassistant/components/actron_air/strings.json index fc17e510e99..cf7c2fc677b 100644 --- a/homeassistant/components/actron_air/strings.json +++ b/homeassistant/components/actron_air/strings.json @@ -4,7 +4,8 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_account%]", "oauth2_error": "Failed to start authentication flow", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", - "wrong_account": "You must reauthenticate with the same Actron Air account that was originally configured." + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]", + "wrong_account": "You must authenticate with the same Actron Air account that was originally configured." }, "error": { "oauth2_error": "Failed to start authentication flow. Please try again later." @@ -22,6 +23,10 @@ "description": "Your Actron Air authentication has expired. Select continue to reauthenticate with your Actron Air account. You will be prompted to log in again to restore the connection.", "title": "Authentication expired" }, + "reconfigure_confirm": { + "description": "Reconfigure your Actron Air account. You will be prompted to log in again. Note: you must use the same account that was originally configured.", + "title": "Reconfigure Actron Air" + }, "timeout": { "data": {}, "description": "The authentication process timed out. Please try again.", diff --git a/tests/components/actron_air/test_config_flow.py b/tests/components/actron_air/test_config_flow.py index 272e4627a3b..075a756fede 100644 --- a/tests/components/actron_air/test_config_flow.py +++ b/tests/components/actron_air/test_config_flow.py @@ -336,3 +336,64 @@ async def test_finish_login_auth_error( # Should abort with oauth2_error assert result["type"] is FlowResultType.ABORT assert result["reason"] == "oauth2_error" + + +async def test_reconfigure_flow_success( + hass: HomeAssistant, + mock_actron_api: AsyncMock, + mock_config_entry: MockConfigEntry, + mock_setup_entry: AsyncMock, +) -> None: + """Test successful reconfiguration flow.""" + mock_config_entry.add_to_hass(hass) + + result = await mock_config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure_confirm" + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result["type"] is FlowResultType.SHOW_PROGRESS + assert result["step_id"] == "user" + assert result["progress_action"] == "wait_for_authorization" + + await hass.async_block_till_done() + + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert mock_config_entry.data[CONF_API_TOKEN] == "test_refresh_token" + + +async def test_reconfigure_flow_wrong_account( + hass: HomeAssistant, + mock_actron_api: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test reconfiguration flow aborts when wrong account is used.""" + mock_config_entry.add_to_hass(hass) + + mock_actron_api.get_user_info = AsyncMock( + return_value=ActronAirUserInfo( + id="different_user_id", email="different@example.com" + ) + ) + + result = await mock_config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure_confirm" + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result["type"] is FlowResultType.SHOW_PROGRESS + assert result["step_id"] == "user" + + await hass.async_block_till_done() + + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "wrong_account"