From 0c66346fb089acee3cd6bb3fed761679fc371e9d Mon Sep 17 00:00:00 2001 From: Thibaut Date: Wed, 1 Mar 2023 13:46:26 +0100 Subject: [PATCH] Add dynamic unit of measurement support for Overkiz sensor (#80490) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add dynamic unit support * Import all units * Fix typing * Add fallback to CORE_ELECTRIC_POWER_CONSUMPTION_STATE_MEASURED_VALUE_TYPE * Fix rebase * Give priority to the more accurate attribute * Don’t use hardcoded seconds unit * Don’t change SensorDescription * Rework comment --- homeassistant/components/overkiz/const.py | 62 +++++++++++++++++++++- homeassistant/components/overkiz/sensor.py | 30 ++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/overkiz/const.py b/homeassistant/components/overkiz/const.py index 806ba435c20..0db01a2d84c 100644 --- a/homeassistant/components/overkiz/const.py +++ b/homeassistant/components/overkiz/const.py @@ -5,9 +5,28 @@ from datetime import timedelta import logging from typing import Final -from pyoverkiz.enums import OverkizCommandParam, UIClass, UIWidget +from pyoverkiz.enums import MeasuredValueType, OverkizCommandParam, UIClass, UIWidget -from homeassistant.const import Platform +from homeassistant.const import ( + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_PARTS_PER_MILLION, + DEGREE, + LIGHT_LUX, + PERCENTAGE, + Platform, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfIrradiance, + UnitOfLength, + UnitOfPower, + UnitOfPressure, + UnitOfSpeed, + UnitOfTemperature, + UnitOfTime, + UnitOfVolume, + UnitOfVolumeFlowRate, +) DOMAIN: Final = "overkiz" LOGGER: logging.Logger = logging.getLogger(__package__) @@ -98,3 +117,42 @@ OVERKIZ_STATE_TO_TRANSLATION: dict[str, str] = { OverkizCommandParam.SFC: "sfc", OverkizCommandParam.UPS: "ups", } + +OVERKIZ_UNIT_TO_HA: dict[str, str] = { + MeasuredValueType.ABSOLUTE_VALUE: "", + MeasuredValueType.ANGLE_IN_DEGREES: DEGREE, + MeasuredValueType.ANGULAR_SPEED_IN_DEGREES_PER_SECOND: f"{DEGREE}/{UnitOfTime.SECONDS}", + MeasuredValueType.ELECTRICAL_ENERGY_IN_KWH: UnitOfEnergy.KILO_WATT_HOUR, + MeasuredValueType.ELECTRICAL_ENERGY_IN_WH: UnitOfEnergy.WATT_HOUR, + MeasuredValueType.ELECTRICAL_POWER_IN_KW: UnitOfPower.KILO_WATT, + MeasuredValueType.ELECTRICAL_POWER_IN_W: UnitOfPower.WATT, + MeasuredValueType.ELECTRIC_CURRENT_IN_AMPERE: UnitOfElectricCurrent.AMPERE, + MeasuredValueType.ELECTRIC_CURRENT_IN_MILLI_AMPERE: UnitOfElectricCurrent.MILLIAMPERE, + MeasuredValueType.ENERGY_IN_CAL: "cal", + MeasuredValueType.ENERGY_IN_KCAL: "kcal", + MeasuredValueType.FLOW_IN_LITRE_PER_SECOND: f"{UnitOfVolume.LITERS}/{UnitOfTime.SECONDS}", + MeasuredValueType.FLOW_IN_METER_CUBE_PER_HOUR: UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR, + MeasuredValueType.FLOW_IN_METER_CUBE_PER_SECOND: f"{UnitOfVolume.CUBIC_METERS}/{UnitOfTime.SECONDS}", + MeasuredValueType.FOSSIL_ENERGY_IN_WH: UnitOfEnergy.WATT_HOUR, + MeasuredValueType.GRADIENT_IN_PERCENTAGE_PER_SECOND: f"{PERCENTAGE}/{UnitOfTime.SECONDS}", + MeasuredValueType.LENGTH_IN_METER: UnitOfLength.METERS, + MeasuredValueType.LINEAR_SPEED_IN_METER_PER_SECOND: UnitOfSpeed.METERS_PER_SECOND, + MeasuredValueType.LUMINANCE_IN_LUX: LIGHT_LUX, + MeasuredValueType.PARTS_PER_BILLION: CONCENTRATION_PARTS_PER_BILLION, + MeasuredValueType.PARTS_PER_MILLION: CONCENTRATION_PARTS_PER_MILLION, + MeasuredValueType.PARTS_PER_QUADRILLION: "ppq", + MeasuredValueType.PARTS_PER_TRILLION: "ppt", + MeasuredValueType.POWER_PER_SQUARE_METER: UnitOfIrradiance.WATTS_PER_SQUARE_METER, + MeasuredValueType.PRESSURE_IN_HPA: UnitOfPressure.HPA, + MeasuredValueType.PRESSURE_IN_MILLI_BAR: UnitOfPressure.MBAR, + MeasuredValueType.RELATIVE_VALUE_IN_PERCENTAGE: PERCENTAGE, + MeasuredValueType.TEMPERATURE_IN_CELCIUS: UnitOfTemperature.CELSIUS, + MeasuredValueType.TEMPERATURE_IN_KELVIN: UnitOfTemperature.KELVIN, + MeasuredValueType.TIME_IN_SECOND: UnitOfTime.SECONDS, + # MeasuredValueType.VECTOR_COORDINATE: "", + MeasuredValueType.VOLTAGE_IN_MILLI_VOLT: UnitOfElectricPotential.MILLIVOLT, + MeasuredValueType.VOLTAGE_IN_VOLT: UnitOfElectricPotential.VOLT, + MeasuredValueType.VOLUME_IN_CUBIC_METER: UnitOfVolume.CUBIC_METERS, + MeasuredValueType.VOLUME_IN_GALLON: UnitOfVolume.GALLONS, + MeasuredValueType.VOLUME_IN_LITER: UnitOfVolume.LITERS, +} diff --git a/homeassistant/components/overkiz/sensor.py b/homeassistant/components/overkiz/sensor.py index 1e37d938cc6..4c70bab70f5 100644 --- a/homeassistant/components/overkiz/sensor.py +++ b/homeassistant/components/overkiz/sensor.py @@ -34,7 +34,12 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType from . import HomeAssistantOverkizData -from .const import DOMAIN, IGNORED_OVERKIZ_DEVICES, OVERKIZ_STATE_TO_TRANSLATION +from .const import ( + DOMAIN, + IGNORED_OVERKIZ_DEVICES, + OVERKIZ_STATE_TO_TRANSLATION, + OVERKIZ_UNIT_TO_HA, +) from .coordinator import OverkizDataUpdateCoordinator from .entity import OverkizDescriptiveEntity, OverkizEntity @@ -473,6 +478,29 @@ class OverkizStateSensor(OverkizDescriptiveEntity, SensorEntity): return state.value + @property + def native_unit_of_measurement(self) -> str | None: + """Return the unit of measurement.""" + if ( + not (default_unit := self.entity_description.native_unit_of_measurement) + or not (state := self.device.states.get(self.entity_description.key)) + or not state.value + ): + return default_unit + + attrs = self.device.attributes + if (unit := attrs[f"{state.name}MeasuredValueType"]) and ( + unit_value := unit.value_as_str + ): + return OVERKIZ_UNIT_TO_HA.get(unit_value, default_unit) + + if (unit := attrs[OverkizAttribute.CORE_MEASURED_VALUE_TYPE]) and ( + unit_value := unit.value_as_str + ): + return OVERKIZ_UNIT_TO_HA.get(unit_value, default_unit) + + return default_unit + class OverkizHomeKitSetupCodeSensor(OverkizEntity, SensorEntity): """Representation of an Overkiz HomeKit Setup Code."""