From c94968d8114c12f1c01e97a928ab5bb4b5defcf3 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 23 Feb 2021 16:36:53 +0100 Subject: [PATCH] Catch more zwave_js errors (#46957) --- homeassistant/components/zwave_js/__init__.py | 9 +++++++- homeassistant/components/zwave_js/climate.py | 10 +++++++-- tests/components/zwave_js/test_init.py | 21 +++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zwave_js/__init__.py b/homeassistant/components/zwave_js/__init__.py index 530a8022233..836bd771923 100644 --- a/homeassistant/components/zwave_js/__init__.py +++ b/homeassistant/components/zwave_js/__init__.py @@ -219,7 +219,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, handle_ha_shutdown) ) - await driver_ready.wait() + try: + await driver_ready.wait() + except asyncio.CancelledError: + LOGGER.debug("Cancelling start platforms") + return LOGGER.info("Connection to Zwave JS Server initialized") @@ -271,6 +275,9 @@ async def client_listen( should_reload = False except BaseZwaveJSServerError as err: LOGGER.error("Failed to listen: %s", err) + except Exception as err: # pylint: disable=broad-except + # We need to guard against unknown exceptions to not crash this task. + LOGGER.exception("Unexpected exception: %s", err) # The entry needs to be reloaded since a new driver state # will be acquired on reconnect. diff --git a/homeassistant/components/zwave_js/climate.py b/homeassistant/components/zwave_js/climate.py index f864efe91ff..54966538aae 100644 --- a/homeassistant/components/zwave_js/climate.py +++ b/homeassistant/components/zwave_js/climate.py @@ -261,7 +261,10 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity): if self._current_mode and self._current_mode.value is None: # guard missing value return None - temp = self._setpoint_value(self._current_mode_setpoint_enums[0]) + try: + temp = self._setpoint_value(self._current_mode_setpoint_enums[0]) + except ValueError: + return None return temp.value if temp else None @property @@ -270,7 +273,10 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity): if self._current_mode and self._current_mode.value is None: # guard missing value return None - temp = self._setpoint_value(self._current_mode_setpoint_enums[1]) + try: + temp = self._setpoint_value(self._current_mode_setpoint_enums[1]) + except ValueError: + return None return temp.value if temp else None @property diff --git a/tests/components/zwave_js/test_init.py b/tests/components/zwave_js/test_init.py index 1aad07400ad..6e41da42c8f 100644 --- a/tests/components/zwave_js/test_init.py +++ b/tests/components/zwave_js/test_init.py @@ -3,6 +3,7 @@ from copy import deepcopy from unittest.mock import patch import pytest +from zwave_js_server.exceptions import BaseZwaveJSServerError from zwave_js_server.model.node import Node from homeassistant.components.hassio.handler import HassioAPIError @@ -76,6 +77,26 @@ async def test_initialized_timeout(hass, client, connect_timeout): assert entry.state == ENTRY_STATE_SETUP_RETRY +@pytest.mark.parametrize("error", [BaseZwaveJSServerError("Boom"), Exception("Boom")]) +async def test_listen_failure(hass, client, error): + """Test we handle errors during client listen.""" + + async def listen(driver_ready): + """Mock the client listen method.""" + # Set the connect side effect to stop an endless loop on reload. + client.connect.side_effect = BaseZwaveJSServerError("Boom") + raise error + + client.listen.side_effect = listen + entry = MockConfigEntry(domain="zwave_js", data={"url": "ws://test.org"}) + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ENTRY_STATE_SETUP_RETRY + + async def test_on_node_added_ready( hass, multisensor_6_state, client, integration, device_registry ):