diff --git a/homeassistant/components/intellifire/__init__.py b/homeassistant/components/intellifire/__init__.py index 3f2f693b198cc7..a2e3fe6b425731 100644 --- a/homeassistant/components/intellifire/__init__.py +++ b/homeassistant/components/intellifire/__init__.py @@ -2,6 +2,7 @@ import asyncio +import aiohttp from intellifire4py import UnifiedFireplace from intellifire4py.cloud_interface import IntelliFireCloudInterface from intellifire4py.const import IntelliFireApiMode @@ -153,6 +154,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: IntellifireConfigEntry) raise ConfigEntryNotReady( "Initialization of fireplace timed out after 10 minutes" ) from err + except (aiohttp.ClientConnectionError, ConnectionError) as err: + raise ConfigEntryNotReady( + "Error communicating with fireplace during initialization" + ) from err # Construct coordinator data_update_coordinator = IntellifireDataUpdateCoordinator(hass, entry, fireplace) diff --git a/homeassistant/components/intellifire/config_flow.py b/homeassistant/components/intellifire/config_flow.py index 95b1ee0c1d8eea..403daf4ab5194a 100644 --- a/homeassistant/components/intellifire/config_flow.py +++ b/homeassistant/components/intellifire/config_flow.py @@ -13,6 +13,7 @@ from homeassistant.config_entries import ( SOURCE_REAUTH, + ConfigEntryState, ConfigFlow, ConfigFlowResult, OptionsFlow, @@ -287,10 +288,8 @@ async def async_step_init( errors: dict[str, str] = {} if user_input is not None: - # Validate connectivity for requested modes if runtime data is available - coordinator = self.config_entry.runtime_data - if coordinator is not None: - fireplace = coordinator.fireplace + if self.config_entry.state is ConfigEntryState.LOADED: + fireplace = self.config_entry.runtime_data.fireplace # Refresh connectivity status before validating await fireplace.async_validate_connectivity() diff --git a/tests/components/intellifire/test_config_flow.py b/tests/components/intellifire/test_config_flow.py index 20223d255e67da..2d10873748a218 100644 --- a/tests/components/intellifire/test_config_flow.py +++ b/tests/components/intellifire/test_config_flow.py @@ -272,6 +272,38 @@ async def test_options_flow( } +async def test_options_flow_allows_submit_when_not_loaded( + hass: HomeAssistant, + mock_config_entry_current: MockConfigEntry, +) -> None: + """Test options flow allows submit when runtime data is missing.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + version=mock_config_entry_current.version, + minor_version=mock_config_entry_current.minor_version, + data=dict(mock_config_entry_current.data), + options=dict(mock_config_entry_current.options), + unique_id=mock_config_entry_current.unique_id, + state=config_entries.ConfigEntryState.SETUP_ERROR, + ) + config_entry.add_to_hass(hass) + + result = await hass.config_entries.options.async_init(config_entry.entry_id) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + {CONF_READ_MODE: API_MODE_CLOUD, CONF_CONTROL_MODE: API_MODE_LOCAL}, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == { + CONF_READ_MODE: API_MODE_CLOUD, + CONF_CONTROL_MODE: API_MODE_LOCAL, + } + + async def test_options_flow_local_read_unavailable( hass: HomeAssistant, mock_config_entry_current: MockConfigEntry, diff --git a/tests/components/intellifire/test_init.py b/tests/components/intellifire/test_init.py index ac689a164b5bab..f71681c81e6fef 100644 --- a/tests/components/intellifire/test_init.py +++ b/tests/components/intellifire/test_init.py @@ -1,8 +1,10 @@ """Test the IntelliFire config flow.""" -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch +import aiohttp from intellifire4py.const import IntelliFireApiMode +import pytest from homeassistant.components.intellifire import CONF_USER_ID from homeassistant.components.intellifire.const import ( @@ -159,22 +161,28 @@ async def test_init_with_no_username(hass: HomeAssistant, mock_apis_single_fp) - assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR -async def test_connectivity_bad( +@pytest.mark.parametrize( + "setup_error", + [aiohttp.ClientConnectionError, ConnectionError, TimeoutError], +) +async def test_connectivity_error_during_setup_retries( hass: HomeAssistant, - mock_config_entry_current, - mock_apis_single_fp, + mock_config_entry_current: MockConfigEntry, + mock_apis_single_fp: tuple[AsyncMock, AsyncMock, MagicMock], + setup_error: type[Exception], ) -> None: - """Test a timeout error on the setup flow.""" + """Test a connection error during setup retries the config entry.""" with patch( "homeassistant.components.intellifire.UnifiedFireplace.build_fireplace_from_common", new_callable=AsyncMock, - side_effect=TimeoutError, + side_effect=setup_error, ): mock_config_entry_current.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry_current.entry_id) await hass.async_block_till_done() + assert mock_config_entry_current.state is ConfigEntryState.SETUP_RETRY assert len(hass.states.async_all()) == 0