Repository: plugwise/python-plugwise (language: python)

Issue:
[BUG]: Library didn't catch aiohttp.ClientConnectionError
### Describe the bug.

I just experienced a power grid outage @  my home, when it returned, I noticed that Plugwise didn't recover. The reason is that Home Assistant was faster in starting up than Plugwise and the connection failed.

```
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 335, in async_setup
    result = await component.async_setup_entry(hass, self)
  File "/usr/src/homeassistant/homeassistant/components/plugwise/__init__.py", line 13, in async_setup_entry
    return await async_setup_entry_gw(hass, entry)
  File "/usr/src/homeassistant/homeassistant/components/plugwise/gateway.py", line 43, in async_setup_entry_gw
    connected = await api.connect()
  File "/usr/local/lib/python3.9/site-packages/plugwise/smile.py", line 260, in connect
    result = await self._request(DOMAIN_OBJECTS)
  File "/usr/local/lib/python3.9/site-packages/plugwise/helper.py", line 259, in _request
    resp = await self._websession.get(url, headers=headers, auth=self._auth)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 542, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 907, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 1206, in _create_direct_connection
    raise last_exc
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 1175, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 992, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host 10.10.11.200:80 ssl:default [Connect call failed ('10.10.11.200', 80)]
```

Did a patch upstream: <https://github.com/home-assistant/core/pull/71642>
However, the library should handle connection issues (as its purpose is handling the connection).


### Expected behavior

...

### What version of Home Assistant Core has the issue?

2022.6.0dev0

### What type of installation are you running?

Home Assistant Core

### How and which version of the integration do you have installed?

Home Assistant Core

### What kind of Plugwise device is having issues?

Smile: Adam (including Lisa, Tom, Floor)

### What firmware version is your Plugwise product at?

3.6.7

### Home Assistant Logging (optional)

_No response_

### Diagnostics information

_No response_

### Additional information

_No response_
[BUG]: Library didn't catch aiohttp.ClientConnectionError
### Describe the bug.

I just experienced a power grid outage @  my home, when it returned, I noticed that Plugwise didn't recover. The reason is that Home Assistant was faster in starting up than Plugwise and the connection failed.

```
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 335, in async_setup
    result = await component.async_setup_entry(hass, self)
  File "/usr/src/homeassistant/homeassistant/components/plugwise/__init__.py", line 13, in async_setup_entry
    return await async_setup_entry_gw(hass, entry)
  File "/usr/src/homeassistant/homeassistant/components/plugwise/gateway.py", line 43, in async_setup_entry_gw
    connected = await api.connect()
  File "/usr/local/lib/python3.9/site-packages/plugwise/smile.py", line 260, in connect
    result = await self._request(DOMAIN_OBJECTS)
  File "/usr/local/lib/python3.9/site-packages/plugwise/helper.py", line 259, in _request
    resp = await self._websession.get(url, headers=headers, auth=self._auth)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 542, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 907, in _create_connection
    _, proto = await self._create_direct_connection(req, traces, timeout)
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 1206, in _create_direct_connection
    raise last_exc
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 1175, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
  File "/usr/local/lib/python3.9/site-packages/aiohttp/connector.py", line 992, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host 10.10.11.200:80 ssl:default [Connect call failed ('10.10.11.200', 80)]
```

Did a patch upstream: <https://github.com/home-assistant/core/pull/71642>
However, the library should handle connection issues (as its purpose is handling the connection).


### Expected behavior

...

### What version of Home Assistant Core has the issue?

2022.6.0dev0

### What type of installation are you running?

Home Assistant Core

### How and which version of the integration do you have installed?

Home Assistant Core

### What kind of Plugwise device is having issues?

Smile: Adam (including Lisa, Tom, Floor)

### What firmware version is your Plugwise product at?

3.6.7

### Home Assistant Logging (optional)

_No response_

### Diagnostics information

_No response_

### Additional information

_No response_


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e120c957b..b98b2cba6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
 # Changelog
 
+# v0.18.2: Smile: fix for https://github.com/plugwise/python-plugwise/issues/187
+
 # v0.18.1: Smile Adam: don't show vacation-preset, as not shown in the Plugwise App or on the local Adam-website
 
 # v0.18.0: Smile: add generation of cooling-schedules
diff --git a/plugwise/__init__.py b/plugwise/__init__.py
index ebea7b0df..a431d5154 100644
--- a/plugwise/__init__.py
+++ b/plugwise/__init__.py
@@ -1,6 +1,6 @@
 """Plugwise module."""
 
-__version__ = "0.18.1"
+__version__ = "0.18.2"
 
 from plugwise.smile import Smile
 from plugwise.stick import Stick
diff --git a/plugwise/helper.py b/plugwise/helper.py
index ce885bc2f..f25d1083d 100644
--- a/plugwise/helper.py
+++ b/plugwise/helper.py
@@ -7,13 +7,7 @@
 import datetime as dt
 
 # This way of importing aiohttp is because of patch/mocking in testing (aiohttp timeouts)
-from aiohttp import (
-    BasicAuth,
-    ClientResponse,
-    ClientSession,
-    ClientTimeout,
-    ServerTimeoutError,
-)
+from aiohttp import BasicAuth, ClientError, ClientResponse, ClientSession, ClientTimeout
 from dateutil.parser import parse
 from defusedxml import ElementTree as etree
 from munch import Munch
@@ -54,9 +48,9 @@
     ThermoLoc,
 )
 from .exceptions import (
-    DeviceTimeoutError,
     InvalidAuthentication,
     InvalidXMLError,
+    PlugwiseException,
     ResponseError,
 )
 from .util import (
@@ -266,12 +260,12 @@ async def _request(
                     data=data,
                     auth=self._auth,
                 )
-        except ServerTimeoutError:
+        except ClientError as err:  # ClientError is an ancestor class of ServerTimeoutError
             if retry < 1:
-                LOGGER.error("Timed out sending %s command to Plugwise", command)
-                raise DeviceTimeoutError(
-                    "Plugwise timeout error, check log for more info."
-                )
+                LOGGER.error("Failed sending %s %s to Plugwise Smile", method, command)
+                raise PlugwiseException(
+                    "Plugwise connection error, check log for more info."
+                ) from err
             return await self._request(command, retry - 1)
 
         return await self._request_validate(resp, method)


Test patch:
diff --git a/tests/test_smile.py b/tests/test_smile.py
index 255799999..75928607f 100644
--- a/tests/test_smile.py
+++ b/tests/test_smile.py
@@ -3853,7 +3853,7 @@ async def test_connect_timeout(self, timeout_test):
                 client,
             ) = await self.connect_wrapper()
             assert False  # pragma: no cover
-        except pw_exceptions.DeviceTimeoutError:
+        except pw_exceptions.PlugwiseException:
             assert True
 
     class PlugwiseTestError(Exception):