Add sensors for energy storage system to ViCare integration (#106600)

* add sensors for vitocharge

* add further sensors

* add unig getters

* remove icons

* Update strings.json

* handle percent uom

* handle unknown uom device class mapping

* add device class to sensor

* add sensor options

* Apply suggestions from code review

* fix

* align sensor naming

* add feed-in and consumption sensors for pcc

* Update strings.json

* battery symbol

* fix format

* remove obsolete device classes

* add icons

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* refactor

* modify lambda

* use helper

* Apply suggestions from code review

* Apply suggestions from code review

* Update strings.json

* Update sensor.py

* Apply suggestions from code review

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
pull/110498/head^2
Christopher Fenner 2024-02-26 09:59:58 +01:00 committed by GitHub
parent 4a128f1225
commit 1e564f777e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 144 additions and 16 deletions

View File

@ -1,7 +1,7 @@
"""Constants for the ViCare integration."""
import enum
from homeassistant.const import Platform, UnitOfEnergy, UnitOfVolume
from homeassistant.const import Platform
DOMAIN = "vicare"
@ -22,14 +22,12 @@ CONF_HEATING_TYPE = "heating_type"
DEFAULT_CACHE_DURATION = 60
VICARE_CUBIC_METER = "cubicMeter"
VICARE_PERCENT = "percent"
VICARE_W = "watt"
VICARE_KW = "kilowatt"
VICARE_WH = "wattHour"
VICARE_KWH = "kilowattHour"
VICARE_UNIT_TO_UNIT_OF_MEASUREMENT = {
VICARE_KWH: UnitOfEnergy.KILO_WATT_HOUR,
VICARE_CUBIC_METER: UnitOfVolume.CUBIC_METERS,
}
VICARE_CUBIC_METER = "cubicMeter"
class HeatingType(enum.Enum):

View File

@ -42,8 +42,11 @@ from .const import (
DEVICE_LIST,
DOMAIN,
VICARE_CUBIC_METER,
VICARE_KW,
VICARE_KWH,
VICARE_UNIT_TO_UNIT_OF_MEASUREMENT,
VICARE_PERCENT,
VICARE_W,
VICARE_WH,
)
from .entity import ViCareEntity
from .types import ViCareDevice, ViCareRequiredKeysMixin
@ -52,10 +55,22 @@ from .utils import get_burners, get_circuits, get_compressors, is_supported
_LOGGER = logging.getLogger(__name__)
VICARE_UNIT_TO_DEVICE_CLASS = {
VICARE_WH: SensorDeviceClass.ENERGY,
VICARE_KWH: SensorDeviceClass.ENERGY,
VICARE_W: SensorDeviceClass.POWER,
VICARE_KW: SensorDeviceClass.POWER,
VICARE_CUBIC_METER: SensorDeviceClass.GAS,
}
VICARE_UNIT_TO_HA_UNIT = {
VICARE_PERCENT: PERCENTAGE,
VICARE_W: UnitOfPower.WATT,
VICARE_KW: UnitOfPower.KILO_WATT,
VICARE_WH: UnitOfEnergy.WATT_HOUR,
VICARE_KWH: UnitOfEnergy.KILO_WATT_HOUR,
VICARE_CUBIC_METER: UnitOfVolume.CUBIC_METERS,
}
@dataclass(frozen=True)
class ViCareSensorEntityDescription(SensorEntityDescription, ViCareRequiredKeysMixin):
@ -581,8 +596,83 @@ GLOBAL_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
),
ViCareSensorEntityDescription(
key="ess_state_of_charge",
icon="mdi:home-battery",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
value_getter=lambda api: api.getElectricalEnergySystemSOC(),
unit_getter=lambda api: api.getElectricalEnergySystemSOCUnit(),
),
ViCareSensorEntityDescription(
key="ess_power_current",
translation_key="ess_power_current",
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
value_getter=lambda api: api.getElectricalEnergySystemPower(),
unit_getter=lambda api: api.getElectricalEnergySystemPowerUnit(),
),
ViCareSensorEntityDescription(
key="ess_state",
translation_key="ess_state",
device_class=SensorDeviceClass.ENUM,
options=["charge", "discharge", "standby"],
value_getter=lambda api: api.getElectricalEnergySystemOperationState(),
),
ViCareSensorEntityDescription(
key="pcc_transfer_power_exchange",
translation_key="pcc_transfer_power_exchange",
icon="mdi:transmission-tower",
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
value_getter=lambda api: api.getPointOfCommonCouplingTransferPowerExchange(),
),
ViCareSensorEntityDescription(
key="pcc_energy_consumption",
translation_key="pcc_energy_consumption",
icon="mdi:transmission-tower-export",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
value_getter=lambda api: api.getPointOfCommonCouplingTransferConsumptionTotal(),
unit_getter=lambda api: api.getPointOfCommonCouplingTransferConsumptionTotalUnit(),
),
ViCareSensorEntityDescription(
key="pcc_energy_feed_in",
translation_key="pcc_energy_feed_in",
icon="mdi:transmission-tower-import",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
value_getter=lambda api: api.getPointOfCommonCouplingTransferFeedInTotal(),
unit_getter=lambda api: api.getPointOfCommonCouplingTransferFeedInTotalUnit(),
),
ViCareSensorEntityDescription(
key="photovoltaic_power_production_current",
translation_key="photovoltaic_power_production_current",
native_unit_of_measurement=UnitOfPower.KILO_WATT,
state_class=SensorStateClass.MEASUREMENT,
value_getter=lambda api: api.getPhotovoltaicProductionCurrent(),
unit_getter=lambda api: api.getPhotovoltaicProductionCurrentUnit(),
),
ViCareSensorEntityDescription(
key="photovoltaic_energy_production_today",
translation_key="photovoltaic_energy_production_today",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
value_getter=lambda api: api.getPhotovoltaicProductionCumulatedCurrentDay(),
unit_getter=lambda api: api.getPhotovoltaicProductionCumulatedUnit(),
),
ViCareSensorEntityDescription(
key="photovoltaic_status",
translation_key="photovoltaic_status",
device_class=SensorDeviceClass.ENUM,
options=["ready", "production"],
value_getter=lambda api: _filter_pv_states(api.getPhotovoltaicStatus()),
),
)
CIRCUIT_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
ViCareSensorEntityDescription(
key="supply_temperature",
@ -700,6 +790,10 @@ COMPRESSOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
)
def _filter_pv_states(state: str) -> str | None:
return None if state in ("nothing", "unknown") else state
def _build_entities(
device_list: list[ViCareDevice],
) -> list[ViCareSensor]:
@ -800,6 +894,7 @@ 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(
@ -808,13 +903,6 @@ class ViCareSensor(ViCareEntity, SensorEntity):
if self.entity_description.unit_getter:
vicare_unit = self.entity_description.unit_getter(self._api)
if vicare_unit is not None:
self._attr_device_class = VICARE_UNIT_TO_DEVICE_CLASS.get(
vicare_unit
)
self._attr_native_unit_of_measurement = (
VICARE_UNIT_TO_UNIT_OF_MEASUREMENT.get(vicare_unit)
)
except requests.exceptions.ConnectionError:
_LOGGER.error("Unable to retrieve data from ViCare server")
except ValueError:
@ -823,3 +911,12 @@ class ViCareSensor(ViCareEntity, SensorEntity):
_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)
if vicare_unit is not None:
if (
device_class := VICARE_UNIT_TO_DEVICE_CLASS.get(vicare_unit)
) is not None:
self._attr_device_class = device_class
self._attr_native_unit_of_measurement = VICARE_UNIT_TO_HA_UNIT.get(
vicare_unit
)

View File

@ -275,6 +275,39 @@
"volumetric_flow": {
"name": "Volumetric flow"
},
"ess_power_current": {
"name": "Battery power"
},
"ess_state": {
"name": "Battery state",
"state": {
"charge": "Charging",
"discharge": "Discharging",
"standby": "Standby"
}
},
"pcc_current_power_exchange": {
"name": "Grid power exchange"
},
"pcc_energy_consumption": {
"name": "Energy import from grid"
},
"pcc_energy_feed_in": {
"name": "Energy export to grid"
},
"photovoltaic_power_production_current": {
"name": "Solar power"
},
"photovoltaic_energy_production_today": {
"name": "Solar energy production today"
},
"photovoltaic_status": {
"name": "Solar state",
"state": {
"ready": "Standby",
"production": "Producing"
}
},
"supply_temperature": {
"name": "Supply temperature"
},