Skip to content

Commit 5284d5b

Browse files
committed
Handle PACKAGE_NOT_PAID_FOR API error gracefully
Viessmann API returns errorType PACKAGE_NOT_PAID_FOR for users without a paid feature package. Previously this caused PyViCareInvalidDataError and crashed the integration setup. Now raises PyViCareNotPaidForError at the API layer, which is caught in the cached service and re-raised as PyViCareNotSupportedFeatureError. This allows downstream code (e.g. Home Assistant) to skip the feature gracefully instead of crashing during platform setup.
1 parent 147a1f2 commit 5284d5b

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

PyViCare/PyViCareAbstractOAuthManager.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from PyViCare.PyViCareUtils import (PyViCareCommandError,
1010
PyViCareDeviceCommunicationError,
1111
PyViCareInternalServerError,
12+
PyViCareNotPaidForError,
1213
PyViCareRateLimitError)
1314

1415
logger = logging.getLogger('ViCare')
@@ -48,6 +49,7 @@ def get(self, url: str) -> Any:
4849
self.__handle_expired_token(response)
4950
self.__handle_rate_limit(response)
5051
self.__handle_device_communication_error(response)
52+
self.__handle_not_paid_for(response)
5153
self.__handle_server_error(response)
5254
return response
5355
except TokenExpiredError:
@@ -72,6 +74,10 @@ def __handle_device_communication_error(self, response):
7274
if ("errorType" in response and response["errorType"] == "DEVICE_COMMUNICATION_ERROR"):
7375
raise PyViCareDeviceCommunicationError(response)
7476

77+
def __handle_not_paid_for(self, response):
78+
if ("errorType" in response and response["errorType"] == "PACKAGE_NOT_PAID_FOR"):
79+
raise PyViCareNotPaidForError(response)
80+
7581
def __handle_server_error(self, response):
7682
if ("statusCode" in response and response["statusCode"] >= 500):
7783
raise PyViCareInternalServerError(response)

PyViCare/PyViCareCachedService.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from PyViCare.PyViCareUtils import (PyViCareDeviceCommunicationError,
99
PyViCareInvalidDataError,
1010
PyViCareInternalServerError,
11+
PyViCareNotPaidForError,
12+
PyViCareNotSupportedFeatureError,
1113
ViCareTimer)
1214

1315
logger = logging.getLogger('ViCare')
@@ -44,6 +46,11 @@ def __get_or_update_cache(self):
4446

4547
try:
4648
data = self.fetch_all_features()
49+
except PyViCareNotPaidForError as e:
50+
logger.error("Viessmann API denied access (PACKAGE_NOT_PAID_FOR). Features unavailable: %s", e)
51+
if self.__cache is not None:
52+
return self.__cache
53+
raise PyViCareNotSupportedFeatureError("PACKAGE_NOT_PAID_FOR")
4754
except (PyViCareDeviceCommunicationError, PyViCareInternalServerError) as e:
4855
if self.__cache is not None:
4956
logger.warning("API error, returning stale cache: %s", e)

PyViCare/PyViCareUtils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ class PyViCareInvalidDataError(Exception):
105105
pass
106106

107107

108+
class PyViCareNotPaidForError(Exception):
109+
def __init__(self, response):
110+
extended_payload = response.get("extendedPayload", {})
111+
monetization = extended_payload.get("monetization", "Unknown")
112+
113+
msg = f"Feature not available: {monetization}"
114+
115+
super().__init__(self, msg)
116+
self.message = msg
117+
118+
108119
class PyViCareDeviceCommunicationError(Exception):
109120
def __init__(self, response):
110121
extended_payload = response.get("extendedPayload", {})

0 commit comments

Comments
 (0)