Handle failed connection attempts in opentherm_gw (#75961)

This commit is contained in:
mvn23 2022-07-31 12:21:25 +02:00 committed by GitHub
parent 377f56ff5f
commit abb7495ced
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 8 deletions

View File

@ -1,9 +1,11 @@
"""Support for OpenTherm Gateway devices.""" """Support for OpenTherm Gateway devices."""
import asyncio
from datetime import date, datetime from datetime import date, datetime
import logging import logging
import pyotgw import pyotgw
import pyotgw.vars as gw_vars import pyotgw.vars as gw_vars
from serial import SerialException
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
@ -23,6 +25,7 @@ from homeassistant.const import (
Platform, Platform,
) )
from homeassistant.core import HomeAssistant, ServiceCall 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 import config_validation as cv, device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
@ -37,6 +40,7 @@ from .const import (
CONF_PRECISION, CONF_PRECISION,
CONF_READ_PRECISION, CONF_READ_PRECISION,
CONF_SET_PRECISION, CONF_SET_PRECISION,
CONNECTION_TIMEOUT,
DATA_GATEWAYS, DATA_GATEWAYS,
DATA_OPENTHERM_GW, DATA_OPENTHERM_GW,
DOMAIN, DOMAIN,
@ -107,8 +111,15 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
config_entry.add_update_listener(options_updated) config_entry.add_update_listener(options_updated)
# Schedule directly on the loop to avoid blocking HA startup. try:
hass.loop.create_task(gateway.connect_and_subscribe()) 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) await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
@ -428,6 +439,9 @@ class OpenThermGatewayDevice:
async def connect_and_subscribe(self): async def connect_and_subscribe(self):
"""Connect to serial device and subscribe report handler.""" """Connect to serial device and subscribe report handler."""
self.status = await self.gateway.connect(self.device_path) 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) version_string = self.status[gw_vars.OTGW].get(gw_vars.OTGW_ABOUT)
self.gw_version = version_string[18:] if version_string else None self.gw_version = version_string[18:] if version_string else None
_LOGGER.debug( _LOGGER.debug(

View File

@ -26,6 +26,7 @@ from .const import (
CONF_READ_PRECISION, CONF_READ_PRECISION,
CONF_SET_PRECISION, CONF_SET_PRECISION,
CONF_TEMPORARY_OVRD_MODE, CONF_TEMPORARY_OVRD_MODE,
CONNECTION_TIMEOUT,
) )
@ -62,15 +63,21 @@ class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
otgw = pyotgw.OpenThermGateway() otgw = pyotgw.OpenThermGateway()
status = await otgw.connect(device) status = await otgw.connect(device)
await otgw.disconnect() await otgw.disconnect()
if not status:
raise ConnectionError
return status[gw_vars.OTGW].get(gw_vars.OTGW_ABOUT) return status[gw_vars.OTGW].get(gw_vars.OTGW_ABOUT)
try: try:
res = await asyncio.wait_for(test_connection(), timeout=10) await asyncio.wait_for(
except (asyncio.TimeoutError, SerialException): 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"}) 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() return self._show_form()

View File

@ -25,6 +25,8 @@ CONF_READ_PRECISION = "read_precision"
CONF_SET_PRECISION = "set_precision" CONF_SET_PRECISION = "set_precision"
CONF_TEMPORARY_OVRD_MODE = "temporary_override_mode" CONF_TEMPORARY_OVRD_MODE = "temporary_override_mode"
CONNECTION_TIMEOUT = 10
DATA_GATEWAYS = "gateways" DATA_GATEWAYS = "gateways"
DATA_OPENTHERM_GW = "opentherm_gw" DATA_OPENTHERM_GW = "opentherm_gw"

View File

@ -12,7 +12,8 @@
"error": { "error": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"id_exists": "Gateway id already exists", "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": { "options": {

View File

@ -164,7 +164,7 @@ async def test_form_connection_timeout(hass):
) )
assert result2["type"] == "form" assert result2["type"] == "form"
assert result2["errors"] == {"base": "cannot_connect"} assert result2["errors"] == {"base": "timeout_connect"}
assert len(mock_connect.mock_calls) == 1 assert len(mock_connect.mock_calls) == 1