diff --git a/homeassistant/components/opentherm_gw/__init__.py b/homeassistant/components/opentherm_gw/__init__.py index 7c27eeceede..cdf360c8795 100644 --- a/homeassistant/components/opentherm_gw/__init__.py +++ b/homeassistant/components/opentherm_gw/__init__.py @@ -1,9 +1,11 @@ """Support for OpenTherm Gateway devices.""" +import asyncio from datetime import date, datetime import logging import pyotgw import pyotgw.vars as gw_vars +from serial import SerialException import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry @@ -23,6 +25,7 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv, device_registry as dr from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.typing import ConfigType @@ -37,6 +40,7 @@ from .const import ( CONF_PRECISION, CONF_READ_PRECISION, CONF_SET_PRECISION, + CONNECTION_TIMEOUT, DATA_GATEWAYS, DATA_OPENTHERM_GW, DOMAIN, @@ -107,8 +111,15 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b config_entry.add_update_listener(options_updated) - # Schedule directly on the loop to avoid blocking HA startup. - hass.loop.create_task(gateway.connect_and_subscribe()) + try: + await asyncio.wait_for( + gateway.connect_and_subscribe(), + timeout=CONNECTION_TIMEOUT, + ) + except (asyncio.TimeoutError, ConnectionError, SerialException) as ex: + raise ConfigEntryNotReady( + f"Could not connect to gateway at {gateway.device_path}: {ex}" + ) from ex await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) @@ -428,6 +439,9 @@ class OpenThermGatewayDevice: async def connect_and_subscribe(self): """Connect to serial device and subscribe report handler.""" self.status = await self.gateway.connect(self.device_path) + if not self.status: + await self.cleanup() + raise ConnectionError version_string = self.status[gw_vars.OTGW].get(gw_vars.OTGW_ABOUT) self.gw_version = version_string[18:] if version_string else None _LOGGER.debug( diff --git a/homeassistant/components/opentherm_gw/config_flow.py b/homeassistant/components/opentherm_gw/config_flow.py index 3f91496adab..c3a955b2387 100644 --- a/homeassistant/components/opentherm_gw/config_flow.py +++ b/homeassistant/components/opentherm_gw/config_flow.py @@ -26,6 +26,7 @@ from .const import ( CONF_READ_PRECISION, CONF_SET_PRECISION, CONF_TEMPORARY_OVRD_MODE, + CONNECTION_TIMEOUT, ) @@ -62,15 +63,21 @@ class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): otgw = pyotgw.OpenThermGateway() status = await otgw.connect(device) await otgw.disconnect() + if not status: + raise ConnectionError return status[gw_vars.OTGW].get(gw_vars.OTGW_ABOUT) try: - res = await asyncio.wait_for(test_connection(), timeout=10) - except (asyncio.TimeoutError, SerialException): + await asyncio.wait_for( + test_connection(), + timeout=CONNECTION_TIMEOUT, + ) + except asyncio.TimeoutError: + return self._show_form({"base": "timeout_connect"}) + except (ConnectionError, SerialException): return self._show_form({"base": "cannot_connect"}) - if res: - return self._create_entry(gw_id, name, device) + return self._create_entry(gw_id, name, device) return self._show_form() diff --git a/homeassistant/components/opentherm_gw/const.py b/homeassistant/components/opentherm_gw/const.py index a5042628529..d72469759f1 100644 --- a/homeassistant/components/opentherm_gw/const.py +++ b/homeassistant/components/opentherm_gw/const.py @@ -25,6 +25,8 @@ CONF_READ_PRECISION = "read_precision" CONF_SET_PRECISION = "set_precision" CONF_TEMPORARY_OVRD_MODE = "temporary_override_mode" +CONNECTION_TIMEOUT = 10 + DATA_GATEWAYS = "gateways" DATA_OPENTHERM_GW = "opentherm_gw" diff --git a/homeassistant/components/opentherm_gw/strings.json b/homeassistant/components/opentherm_gw/strings.json index f53ffeda6f6..a80a059481d 100644 --- a/homeassistant/components/opentherm_gw/strings.json +++ b/homeassistant/components/opentherm_gw/strings.json @@ -12,7 +12,8 @@ "error": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "id_exists": "Gateway id already exists", - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "timeout_connect": "[%key:common::config_flow::error::timeout_connect%]" } }, "options": { diff --git a/tests/components/opentherm_gw/test_config_flow.py b/tests/components/opentherm_gw/test_config_flow.py index 46d53bc54b5..080e9a96d58 100644 --- a/tests/components/opentherm_gw/test_config_flow.py +++ b/tests/components/opentherm_gw/test_config_flow.py @@ -164,7 +164,7 @@ async def test_form_connection_timeout(hass): ) assert result2["type"] == "form" - assert result2["errors"] == {"base": "cannot_connect"} + assert result2["errors"] == {"base": "timeout_connect"} assert len(mock_connect.mock_calls) == 1