From 2b51896d7a433427165ec2486470dfb145591805 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Tue, 14 Sep 2021 22:06:06 +0200 Subject: [PATCH] Use EntityDescription - vicare (#55932) * Use EntityDescription - vicare binary_sensor * Use EntityDescription - vicare sensor * Fix typing * Remove default values * Fix pylint --- homeassistant/components/vicare/__init__.py | 14 + .../components/vicare/binary_sensor.py | 108 ++-- homeassistant/components/vicare/sensor.py | 469 +++++++++--------- 3 files changed, 319 insertions(+), 272 deletions(-) diff --git a/homeassistant/components/vicare/__init__.py b/homeassistant/components/vicare/__init__.py index f3ffd7e1db6..b811b9bbfb5 100644 --- a/homeassistant/components/vicare/__init__.py +++ b/homeassistant/components/vicare/__init__.py @@ -1,6 +1,10 @@ """The ViCare integration.""" +from __future__ import annotations + +from dataclasses import dataclass import enum import logging +from typing import Callable, Generic, TypeVar from PyViCare.PyViCareDevice import Device from PyViCare.PyViCareFuelCell import FuelCell @@ -33,6 +37,16 @@ CONF_HEATING_TYPE = "heating_type" DEFAULT_HEATING_TYPE = "generic" +ApiT = TypeVar("ApiT", bound=Device) + + +@dataclass() +class ViCareRequiredKeysMixin(Generic[ApiT]): + """Mixin for required keys.""" + + value_getter: Callable[[ApiT], bool] + + class HeatingType(enum.Enum): """Possible options for heating type.""" diff --git a/homeassistant/components/vicare/binary_sensor.py b/homeassistant/components/vicare/binary_sensor.py index 0c98d22e9ae..9897b38ccf5 100644 --- a/homeassistant/components/vicare/binary_sensor.py +++ b/homeassistant/components/vicare/binary_sensor.py @@ -1,28 +1,35 @@ """Viessmann ViCare sensor device.""" +from __future__ import annotations + from contextlib import suppress +from dataclasses import dataclass import logging +from typing import Union from PyViCare.PyViCare import PyViCareNotSupportedFeatureError, PyViCareRateLimitError +from PyViCare.PyViCareDevice import Device +from PyViCare.PyViCareGazBoiler import GazBoiler +from PyViCare.PyViCareHeatPump import HeatPump import requests from homeassistant.components.binary_sensor import ( DEVICE_CLASS_POWER, BinarySensorEntity, + BinarySensorEntityDescription, ) -from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME from . import ( DOMAIN as VICARE_DOMAIN, VICARE_API, VICARE_HEATING_TYPE, VICARE_NAME, + ApiT, HeatingType, + ViCareRequiredKeysMixin, ) _LOGGER = logging.getLogger(__name__) -CONF_GETTER = "getter" - SENSOR_CIRCULATION_PUMP_ACTIVE = "circulationpump_active" # gas sensors @@ -31,33 +38,46 @@ SENSOR_BURNER_ACTIVE = "burner_active" # heatpump sensors SENSOR_COMPRESSOR_ACTIVE = "compressor_active" -SENSOR_TYPES = { - SENSOR_CIRCULATION_PUMP_ACTIVE: { - CONF_NAME: "Circulation pump active", - CONF_DEVICE_CLASS: DEVICE_CLASS_POWER, - CONF_GETTER: lambda api: api.getCirculationPumpActive(), - }, - # gas sensors - SENSOR_BURNER_ACTIVE: { - CONF_NAME: "Burner active", - CONF_DEVICE_CLASS: DEVICE_CLASS_POWER, - CONF_GETTER: lambda api: api.getBurnerActive(), - }, - # heatpump sensors - SENSOR_COMPRESSOR_ACTIVE: { - CONF_NAME: "Compressor active", - CONF_DEVICE_CLASS: DEVICE_CLASS_POWER, - CONF_GETTER: lambda api: api.getCompressorActive(), - }, -} + +@dataclass +class ViCareBinarySensorEntityDescription( + BinarySensorEntityDescription, ViCareRequiredKeysMixin[ApiT] +): + """Describes ViCare binary sensor entity.""" + + +SENSOR_TYPES_GENERIC: tuple[ViCareBinarySensorEntityDescription[Device]] = ( + ViCareBinarySensorEntityDescription[Device]( + key=SENSOR_CIRCULATION_PUMP_ACTIVE, + name="Circulation pump active", + device_class=DEVICE_CLASS_POWER, + value_getter=lambda api: api.getCirculationPumpActive(), + ), +) + +SENSOR_TYPES_GAS: tuple[ViCareBinarySensorEntityDescription[GazBoiler]] = ( + ViCareBinarySensorEntityDescription[GazBoiler]( + key=SENSOR_BURNER_ACTIVE, + name="Burner active", + device_class=DEVICE_CLASS_POWER, + value_getter=lambda api: api.getBurnerActive(), + ), +) + +SENSOR_TYPES_HEATPUMP: tuple[ViCareBinarySensorEntityDescription[HeatPump]] = ( + ViCareBinarySensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_ACTIVE, + name="Compressor active", + device_class=DEVICE_CLASS_POWER, + value_getter=lambda api: api.getCompressorActive(), + ), +) SENSORS_GENERIC = [SENSOR_CIRCULATION_PUMP_ACTIVE] SENSORS_BY_HEATINGTYPE = { HeatingType.gas: [SENSOR_BURNER_ACTIVE], - HeatingType.heatpump: [ - SENSOR_COMPRESSOR_ACTIVE, - ], + HeatingType.heatpump: [SENSOR_COMPRESSOR_ACTIVE], HeatingType.fuelcell: [SENSOR_BURNER_ACTIVE], } @@ -78,22 +98,34 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities( [ ViCareBinarySensor( - hass.data[VICARE_DOMAIN][VICARE_NAME], vicare_api, sensor + hass.data[VICARE_DOMAIN][VICARE_NAME], vicare_api, description ) - for sensor in sensors + for description in ( + *SENSOR_TYPES_GENERIC, + *SENSOR_TYPES_GAS, + *SENSOR_TYPES_HEATPUMP, + ) + if description.key in sensors ] ) +DescriptionT = Union[ + ViCareBinarySensorEntityDescription[Device], + ViCareBinarySensorEntityDescription[GazBoiler], + ViCareBinarySensorEntityDescription[HeatPump], +] + + class ViCareBinarySensor(BinarySensorEntity): """Representation of a ViCare sensor.""" - def __init__(self, name, api, sensor_type): + entity_description: DescriptionT + + def __init__(self, name, api, description: DescriptionT): """Initialize the sensor.""" - self._sensor = SENSOR_TYPES[sensor_type] - self._name = f"{name} {self._sensor[CONF_NAME]}" + self._attr_name = f"{name} {description.name}" self._api = api - self._sensor_type = sensor_type self._state = None @property @@ -104,28 +136,18 @@ class ViCareBinarySensor(BinarySensorEntity): @property def unique_id(self): """Return a unique ID.""" - return f"{self._api.service.id}-{self._sensor_type}" - - @property - def name(self): - """Return the name of the sensor.""" - return self._name + return f"{self._api.service.id}-{self.entity_description.key}" @property def is_on(self): """Return the state of the sensor.""" return self._state - @property - def device_class(self): - """Return the class of this device, from component DEVICE_CLASSES.""" - return self._sensor[CONF_DEVICE_CLASS] - def update(self): """Update state of sensor.""" try: with suppress(PyViCareNotSupportedFeatureError): - self._state = self._sensor[CONF_GETTER](self._api) + self._state = self.entity_description.value_getter(self._api) except requests.exceptions.ConnectionError: _LOGGER.error("Unable to retrieve data from ViCare server") except ValueError: diff --git a/homeassistant/components/vicare/sensor.py b/homeassistant/components/vicare/sensor.py index e96b3b8120a..c7e318a6c16 100644 --- a/homeassistant/components/vicare/sensor.py +++ b/homeassistant/components/vicare/sensor.py @@ -1,16 +1,20 @@ """Viessmann ViCare sensor device.""" +from __future__ import annotations + from contextlib import suppress +from dataclasses import dataclass import logging +from typing import Union from PyViCare.PyViCare import PyViCareNotSupportedFeatureError, PyViCareRateLimitError +from PyViCare.PyViCareDevice import Device +from PyViCare.PyViCareFuelCell import FuelCell +from PyViCare.PyViCareGazBoiler import GazBoiler +from PyViCare.PyViCareHeatPump import HeatPump import requests -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import SensorEntity, SensorEntityDescription from homeassistant.const import ( - CONF_DEVICE_CLASS, - CONF_ICON, - CONF_NAME, - CONF_UNIT_OF_MEASUREMENT, DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, DEVICE_CLASS_TEMPERATURE, @@ -26,13 +30,13 @@ from . import ( VICARE_API, VICARE_HEATING_TYPE, VICARE_NAME, + ApiT, HeatingType, + ViCareRequiredKeysMixin, ) _LOGGER = logging.getLogger(__name__) -CONF_GETTER = "getter" - SENSOR_TYPE_TEMPERATURE = "temperature" SENSOR_OUTSIDE_TEMPERATURE = "outside_temperature" @@ -70,200 +74,212 @@ SENSOR_POWER_PRODUCTION_THIS_WEEK = "power_production_this_week" SENSOR_POWER_PRODUCTION_THIS_MONTH = "power_production_this_month" SENSOR_POWER_PRODUCTION_THIS_YEAR = "power_production_this_year" -SENSOR_TYPES = { - SENSOR_OUTSIDE_TEMPERATURE: { - CONF_NAME: "Outside Temperature", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, - CONF_GETTER: lambda api: api.getOutsideTemperature(), - CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - }, - SENSOR_SUPPLY_TEMPERATURE: { - CONF_NAME: "Supply Temperature", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, - CONF_GETTER: lambda api: api.getSupplyTemperature(), - CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - }, - # gas sensors - SENSOR_BOILER_TEMPERATURE: { - CONF_NAME: "Boiler Temperature", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, - CONF_GETTER: lambda api: api.getBoilerTemperature(), - CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - }, - SENSOR_BURNER_MODULATION: { - CONF_NAME: "Burner modulation", - CONF_ICON: "mdi:percent", - CONF_UNIT_OF_MEASUREMENT: PERCENTAGE, - CONF_GETTER: lambda api: api.getBurnerModulation(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_DHW_GAS_CONSUMPTION_TODAY: { - CONF_NAME: "Hot water gas consumption today", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterToday(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_DHW_GAS_CONSUMPTION_THIS_WEEK: { - CONF_NAME: "Hot water gas consumption this week", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisWeek(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_DHW_GAS_CONSUMPTION_THIS_MONTH: { - CONF_NAME: "Hot water gas consumption this month", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisMonth(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_DHW_GAS_CONSUMPTION_THIS_YEAR: { - CONF_NAME: "Hot water gas consumption this year", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisYear(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_GAS_CONSUMPTION_TODAY: { - CONF_NAME: "Heating gas consumption today", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionHeatingToday(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_GAS_CONSUMPTION_THIS_WEEK: { - CONF_NAME: "Heating gas consumption this week", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisWeek(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_GAS_CONSUMPTION_THIS_MONTH: { - CONF_NAME: "Heating gas consumption this month", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisMonth(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_GAS_CONSUMPTION_THIS_YEAR: { - CONF_NAME: "Heating gas consumption this year", - CONF_ICON: "mdi:power", - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisYear(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_BURNER_STARTS: { - CONF_NAME: "Burner Starts", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: None, - CONF_GETTER: lambda api: api.getBurnerStarts(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_BURNER_HOURS: { - CONF_NAME: "Burner Hours", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getBurnerHours(), - CONF_DEVICE_CLASS: None, - }, - # heatpump sensors - SENSOR_COMPRESSOR_STARTS: { - CONF_NAME: "Compressor Starts", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: None, - CONF_GETTER: lambda api: api.getCompressorStarts(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS: { - CONF_NAME: "Compressor Hours", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHours(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS_LOADCLASS1: { - CONF_NAME: "Compressor Hours Load Class 1", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHoursLoadClass1(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS_LOADCLASS2: { - CONF_NAME: "Compressor Hours Load Class 2", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHoursLoadClass2(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS_LOADCLASS3: { - CONF_NAME: "Compressor Hours Load Class 3", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHoursLoadClass3(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS_LOADCLASS4: { - CONF_NAME: "Compressor Hours Load Class 4", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHoursLoadClass4(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_COMPRESSOR_HOURS_LOADCLASS5: { - CONF_NAME: "Compressor Hours Load Class 5", - CONF_ICON: "mdi:counter", - CONF_UNIT_OF_MEASUREMENT: TIME_HOURS, - CONF_GETTER: lambda api: api.getCompressorHoursLoadClass5(), - CONF_DEVICE_CLASS: None, - }, - SENSOR_RETURN_TEMPERATURE: { - CONF_NAME: "Return Temperature", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, - CONF_GETTER: lambda api: api.getReturnTemperature(), - CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - }, - # fuelcell sensors - SENSOR_POWER_PRODUCTION_CURRENT: { - CONF_NAME: "Power production current", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: POWER_WATT, - CONF_GETTER: lambda api: api.getPowerProductionCurrent(), - CONF_DEVICE_CLASS: DEVICE_CLASS_POWER, - }, - SENSOR_POWER_PRODUCTION_TODAY: { - CONF_NAME: "Power production today", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getPowerProductionToday(), - CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, - }, - SENSOR_POWER_PRODUCTION_THIS_WEEK: { - CONF_NAME: "Power production this week", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getPowerProductionThisWeek(), - CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, - }, - SENSOR_POWER_PRODUCTION_THIS_MONTH: { - CONF_NAME: "Power production this month", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getPowerProductionThisMonth(), - CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, - }, - SENSOR_POWER_PRODUCTION_THIS_YEAR: { - CONF_NAME: "Power production this year", - CONF_ICON: None, - CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, - CONF_GETTER: lambda api: api.getPowerProductionThisYear(), - CONF_DEVICE_CLASS: DEVICE_CLASS_ENERGY, - }, -} + +@dataclass +class ViCareSensorEntityDescription( + SensorEntityDescription, ViCareRequiredKeysMixin[ApiT] +): + """Describes ViCare sensor entity.""" + + +SENSOR_TYPES_GENERIC: tuple[ViCareSensorEntityDescription[Device], ...] = ( + ViCareSensorEntityDescription[Device]( + key=SENSOR_OUTSIDE_TEMPERATURE, + name="Outside Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + value_getter=lambda api: api.getOutsideTemperature(), + device_class=DEVICE_CLASS_TEMPERATURE, + ), + ViCareSensorEntityDescription[Device]( + key=SENSOR_SUPPLY_TEMPERATURE, + name="Supply Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + value_getter=lambda api: api.getSupplyTemperature(), + device_class=DEVICE_CLASS_TEMPERATURE, + ), +) + +SENSOR_TYPES_GAS: tuple[ViCareSensorEntityDescription[GazBoiler], ...] = ( + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_BOILER_TEMPERATURE, + name="Boiler Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + value_getter=lambda api: api.getBoilerTemperature(), + device_class=DEVICE_CLASS_TEMPERATURE, + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_BURNER_MODULATION, + name="Burner modulation", + icon="mdi:percent", + native_unit_of_measurement=PERCENTAGE, + value_getter=lambda api: api.getBurnerModulation(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_DHW_GAS_CONSUMPTION_TODAY, + name="Hot water gas consumption today", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionDomesticHotWaterToday(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_DHW_GAS_CONSUMPTION_THIS_WEEK, + name="Hot water gas consumption this week", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionDomesticHotWaterThisWeek(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_DHW_GAS_CONSUMPTION_THIS_MONTH, + name="Hot water gas consumption this month", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionDomesticHotWaterThisMonth(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_DHW_GAS_CONSUMPTION_THIS_YEAR, + name="Hot water gas consumption this year", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionDomesticHotWaterThisYear(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_GAS_CONSUMPTION_TODAY, + name="Heating gas consumption today", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionHeatingToday(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_GAS_CONSUMPTION_THIS_WEEK, + name="Heating gas consumption this week", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionHeatingThisWeek(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_GAS_CONSUMPTION_THIS_MONTH, + name="Heating gas consumption this month", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionHeatingThisMonth(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_GAS_CONSUMPTION_THIS_YEAR, + name="Heating gas consumption this year", + icon="mdi:power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getGasConsumptionHeatingThisYear(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_BURNER_STARTS, + name="Burner Starts", + icon="mdi:counter", + value_getter=lambda api: api.getBurnerStarts(), + ), + ViCareSensorEntityDescription[GazBoiler]( + key=SENSOR_BURNER_HOURS, + name="Burner Hours", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getBurnerHours(), + ), +) + +SENSOR_TYPES_HEATPUMP: tuple[ViCareSensorEntityDescription[HeatPump], ...] = ( + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_STARTS, + name="Compressor Starts", + icon="mdi:counter", + value_getter=lambda api: api.getCompressorStarts(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS, + name="Compressor Hours", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHours(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS_LOADCLASS1, + name="Compressor Hours Load Class 1", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHoursLoadClass1(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS_LOADCLASS2, + name="Compressor Hours Load Class 2", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHoursLoadClass2(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS_LOADCLASS3, + name="Compressor Hours Load Class 3", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHoursLoadClass3(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS_LOADCLASS4, + name="Compressor Hours Load Class 4", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHoursLoadClass4(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_COMPRESSOR_HOURS_LOADCLASS5, + name="Compressor Hours Load Class 5", + icon="mdi:counter", + native_unit_of_measurement=TIME_HOURS, + value_getter=lambda api: api.getCompressorHoursLoadClass5(), + ), + ViCareSensorEntityDescription[HeatPump]( + key=SENSOR_RETURN_TEMPERATURE, + name="Return Temperature", + native_unit_of_measurement=TEMP_CELSIUS, + value_getter=lambda api: api.getReturnTemperature(), + device_class=DEVICE_CLASS_TEMPERATURE, + ), +) + +SENSOR_TYPES_FUELCELL: tuple[ViCareSensorEntityDescription[FuelCell], ...] = ( + ViCareSensorEntityDescription[FuelCell]( + key=SENSOR_POWER_PRODUCTION_CURRENT, + name="Power production current", + native_unit_of_measurement=POWER_WATT, + value_getter=lambda api: api.getPowerProductionCurrent(), + device_class=DEVICE_CLASS_POWER, + ), + ViCareSensorEntityDescription[FuelCell]( + key=SENSOR_POWER_PRODUCTION_TODAY, + name="Power production today", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getPowerProductionToday(), + device_class=DEVICE_CLASS_ENERGY, + ), + ViCareSensorEntityDescription[FuelCell]( + key=SENSOR_POWER_PRODUCTION_THIS_WEEK, + name="Power production this week", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getPowerProductionThisWeek(), + device_class=DEVICE_CLASS_ENERGY, + ), + ViCareSensorEntityDescription[FuelCell]( + key=SENSOR_POWER_PRODUCTION_THIS_MONTH, + name="Power production this month", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getPowerProductionThisMonth(), + device_class=DEVICE_CLASS_ENERGY, + ), + ViCareSensorEntityDescription[FuelCell]( + key=SENSOR_POWER_PRODUCTION_THIS_YEAR, + name="Power production this year", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + value_getter=lambda api: api.getPowerProductionThisYear(), + device_class=DEVICE_CLASS_ENERGY, + ), +) SENSORS_GENERIC = [SENSOR_OUTSIDE_TEMPERATURE, SENSOR_SUPPLY_TEMPERATURE] @@ -331,21 +347,36 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities( [ - ViCareSensor(hass.data[VICARE_DOMAIN][VICARE_NAME], vicare_api, sensor) - for sensor in sensors + ViCareSensor(hass.data[VICARE_DOMAIN][VICARE_NAME], vicare_api, description) + for description in ( + *SENSOR_TYPES_GENERIC, + *SENSOR_TYPES_GAS, + *SENSOR_TYPES_HEATPUMP, + *SENSOR_TYPES_FUELCELL, + ) + if description.key in sensors ] ) +DescriptionT = Union[ + ViCareSensorEntityDescription[Device], + ViCareSensorEntityDescription[GazBoiler], + ViCareSensorEntityDescription[HeatPump], + ViCareSensorEntityDescription[FuelCell], +] + + class ViCareSensor(SensorEntity): """Representation of a ViCare sensor.""" - def __init__(self, name, api, sensor_type): + entity_description: DescriptionT + + def __init__(self, name, api, description: DescriptionT): """Initialize the sensor.""" - self._sensor = SENSOR_TYPES[sensor_type] - self._name = f"{name} {self._sensor[CONF_NAME]}" + self.entity_description = description + self._attr_name = f"{name} {description.name}" self._api = api - self._sensor_type = sensor_type self._state = None @property @@ -356,38 +387,18 @@ class ViCareSensor(SensorEntity): @property def unique_id(self): """Return a unique ID.""" - return f"{self._api.service.id}-{self._sensor_type}" - - @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def icon(self): - """Icon to use in the frontend, if any.""" - return self._sensor[CONF_ICON] + return f"{self._api.service.id}-{self.entity_description.key}" @property def native_value(self): """Return the state of the sensor.""" return self._state - @property - def native_unit_of_measurement(self): - """Return the unit of measurement.""" - return self._sensor[CONF_UNIT_OF_MEASUREMENT] - - @property - def device_class(self): - """Return the class of this device, from component DEVICE_CLASSES.""" - return self._sensor[CONF_DEVICE_CLASS] - def update(self): """Update state of sensor.""" try: with suppress(PyViCareNotSupportedFeatureError): - self._state = self._sensor[CONF_GETTER](self._api) + self._state = self.entity_description.value_getter(self._api) except requests.exceptions.ConnectionError: _LOGGER.error("Unable to retrieve data from ViCare server") except ValueError: