Centralize ViCare error handling in base entity class (#162619)

This commit is contained in:
Christian Lackas
2026-02-24 16:43:16 +01:00
committed by GitHub
parent 6f1a021197
commit 9259db0b85
8 changed files with 62 additions and 172 deletions
@@ -12,14 +12,7 @@ from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceComponent,
)
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
import requests
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
@@ -233,18 +226,5 @@ class ViCareBinarySensor(ViCareEntity, BinarySensorEntity):
def update(self) -> None:
"""Update state of sensor."""
try:
with suppress(PyViCareNotSupportedFeatureError):
self._attr_is_on = self.entity_description.value_getter(self._api)
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
with self.vicare_api_handler(), suppress(PyViCareNotSupportedFeatureError):
self._attr_is_on = self.entity_description.value_getter(self._api)
+3 -23
View File
@@ -8,14 +8,7 @@ import logging
from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
import requests
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.const import EntityCategory
@@ -104,18 +97,5 @@ class ViCareButton(ViCareEntity, ButtonEntity):
def press(self) -> None:
"""Handle the button press."""
try:
with suppress(PyViCareNotSupportedFeatureError):
self.entity_description.value_setter(self._api)
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
with self.vicare_api_handler(), suppress(PyViCareNotSupportedFeatureError):
self.entity_description.value_setter(self._api)
+1 -19
View File
@@ -11,13 +11,8 @@ from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import HeatingCircuit as PyViCareHeatingCircuit
from PyViCare.PyViCareUtils import (
PyViCareCommandError,
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
import requests
import voluptuous as vol
from homeassistant.components.climate import (
@@ -160,7 +155,7 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
def update(self) -> None:
"""Let HA know there has been an update from the ViCare API."""
try:
with self.vicare_api_handler():
_room_temperature = None
with suppress(PyViCareNotSupportedFeatureError):
self._attributes["room_temperature"] = _room_temperature = (
@@ -216,19 +211,6 @@ class ViCareClimate(ViCareEntity, ClimateEntity):
self._current_action or compressor.getActive()
)
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
@property
def hvac_mode(self) -> HVACMode | None:
"""Return current hvac mode."""
+31
View File
@@ -1,22 +1,53 @@
"""Entities for the ViCare integration."""
from collections.abc import Generator
from contextlib import contextmanager
import logging
from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceComponent,
)
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareRateLimitError,
)
from requests.exceptions import ConnectionError as RequestConnectionError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import Entity
from .const import DOMAIN, VIESSMANN_DEVELOPER_PORTAL
_LOGGER = logging.getLogger(__name__)
class ViCareEntity(Entity):
"""Base class for ViCare entities."""
_attr_has_entity_name = True
@contextmanager
def vicare_api_handler(self) -> Generator[None]:
"""Handle common ViCare API errors."""
try:
yield
except RequestConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as err:
_LOGGER.error("ViCare API rate limit exceeded: %s", err)
except PyViCareInvalidDataError as err:
_LOGGER.error("Invalid data from ViCare server: %s", err)
except PyViCareDeviceCommunicationError as err:
_LOGGER.warning("Device communication error: %s", err)
except PyViCareInternalServerError as err:
_LOGGER.warning("ViCare server error: %s", err)
def __init__(
self,
unique_id_suffix: str,
+2 -21
View File
@@ -9,14 +9,7 @@ from typing import Any
from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
from requests.exceptions import ConnectionError as RequestConnectionError
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.core import HomeAssistant
@@ -173,7 +166,7 @@ class ViCareFan(ViCareEntity, FanEntity):
def update(self) -> None:
"""Update state of fan."""
level: str | None = None
try:
with self.vicare_api_handler():
with suppress(PyViCareNotSupportedFeatureError):
self._attr_preset_mode = VentilationMode.from_vicare_mode(
self._api.getActiveVentilationMode()
@@ -187,18 +180,6 @@ class ViCareFan(ViCareEntity, FanEntity):
)
else:
self._attr_percentage = 0
except RequestConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
@property
def is_on(self) -> bool | None:
+15 -37
View File
@@ -13,14 +13,7 @@ from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceComponent,
)
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
from requests.exceptions import ConnectionError as RequestConnectionError
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.number import (
NumberDeviceClass,
@@ -437,38 +430,23 @@ class ViCareNumber(ViCareEntity, NumberEntity):
def update(self) -> None:
"""Update state of number."""
try:
with suppress(PyViCareNotSupportedFeatureError):
self._attr_native_value = self.entity_description.value_getter(
self._api
)
with self.vicare_api_handler(), suppress(PyViCareNotSupportedFeatureError):
self._attr_native_value = self.entity_description.value_getter(self._api)
if min_value := _get_value(
self.entity_description.min_value_getter, self._api
):
self._attr_native_min_value = min_value
if min_value := _get_value(
self.entity_description.min_value_getter, self._api
):
self._attr_native_min_value = min_value
if max_value := _get_value(
self.entity_description.max_value_getter, self._api
):
self._attr_native_max_value = max_value
if max_value := _get_value(
self.entity_description.max_value_getter, self._api
):
self._attr_native_max_value = max_value
if stepping_value := _get_value(
self.entity_description.stepping_getter, self._api
):
self._attr_native_step = stepping_value
except RequestConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
if stepping_value := _get_value(
self.entity_description.stepping_getter, self._api
):
self._attr_native_step = stepping_value
def _get_value(
+5 -27
View File
@@ -12,14 +12,7 @@ from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceComponent,
)
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
import requests
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.sensor import (
SensorDeviceClass,
@@ -1556,26 +1549,11 @@ class ViCareSensor(ViCareEntity, SensorEntity):
def update(self) -> None:
"""Update state of sensor."""
vicare_unit = None
try:
with suppress(PyViCareNotSupportedFeatureError):
self._attr_native_value = self.entity_description.value_getter(
self._api
)
with self.vicare_api_handler(), suppress(PyViCareNotSupportedFeatureError):
self._attr_native_value = self.entity_description.value_getter(self._api)
if self.entity_description.unit_getter:
vicare_unit = self.entity_description.unit_getter(self._api)
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
if self.entity_description.unit_getter:
vicare_unit = self.entity_description.unit_getter(self._api)
if vicare_unit is not None:
if (
@@ -9,14 +9,7 @@ from typing import Any
from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import HeatingCircuit as PyViCareHeatingCircuit
from PyViCare.PyViCareUtils import (
PyViCareDeviceCommunicationError,
PyViCareInternalServerError,
PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError,
PyViCareRateLimitError,
)
import requests
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError
from homeassistant.components.water_heater import (
WaterHeaterEntity,
@@ -120,7 +113,7 @@ class ViCareWater(ViCareEntity, WaterHeaterEntity):
def update(self) -> None:
"""Let HA know there has been an update from the ViCare API."""
try:
with self.vicare_api_handler():
with suppress(PyViCareNotSupportedFeatureError):
self._attr_current_temperature = (
self._api.getDomesticHotWaterStorageTemperature()
@@ -137,19 +130,6 @@ class ViCareWater(ViCareEntity, WaterHeaterEntity):
with suppress(PyViCareNotSupportedFeatureError):
self._dhw_active = self._api.getDomesticHotWaterActive()
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except PyViCareRateLimitError as limit_exception:
_LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
except ValueError:
_LOGGER.error("Unable to decode data from ViCare server")
except PyViCareInvalidDataError as invalid_data_exception:
_LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
except PyViCareDeviceCommunicationError as comm_exception:
_LOGGER.warning("Device communication error: %s", comm_exception)
except PyViCareInternalServerError as server_exception:
_LOGGER.warning("Vicare server error: %s", server_exception)
def set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperatures."""
if (temp := kwargs.get(ATTR_TEMPERATURE)) is not None: