Finish migration of recorder to unit conversion (#78985)
This commit is contained in:
parent
3ad5d799c6
commit
c1bc26b413
1 changed files with 21 additions and 73 deletions
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable, Iterable, MutableMapping
|
||||
from collections.abc import Iterable, MutableMapping
|
||||
import datetime
|
||||
import itertools
|
||||
import logging
|
||||
|
@ -23,27 +23,7 @@ from homeassistant.components.recorder.models import (
|
|||
StatisticMetaData,
|
||||
StatisticResult,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
ENERGY_MEGA_WATT_HOUR,
|
||||
ENERGY_WATT_HOUR,
|
||||
POWER_KILO_WATT,
|
||||
POWER_WATT,
|
||||
PRESSURE_BAR,
|
||||
PRESSURE_HPA,
|
||||
PRESSURE_INHG,
|
||||
PRESSURE_KPA,
|
||||
PRESSURE_MBAR,
|
||||
PRESSURE_PA,
|
||||
PRESSURE_PSI,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
TEMP_KELVIN,
|
||||
VOLUME_CUBIC_FEET,
|
||||
VOLUME_CUBIC_METERS,
|
||||
)
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity import entity_sources
|
||||
|
@ -84,47 +64,6 @@ UNIT_CONVERTERS: dict[str, type[BaseUnitConverter]] = {
|
|||
SensorDeviceClass.GAS: VolumeConverter,
|
||||
}
|
||||
|
||||
UNIT_CONVERSIONS: dict[str, dict[str, Callable]] = {
|
||||
# Convert energy to kWh
|
||||
SensorDeviceClass.ENERGY: {
|
||||
ENERGY_KILO_WATT_HOUR: lambda x: x
|
||||
/ EnergyConverter.UNIT_CONVERSION[ENERGY_KILO_WATT_HOUR],
|
||||
ENERGY_MEGA_WATT_HOUR: lambda x: x
|
||||
/ EnergyConverter.UNIT_CONVERSION[ENERGY_MEGA_WATT_HOUR],
|
||||
ENERGY_WATT_HOUR: lambda x: x
|
||||
/ EnergyConverter.UNIT_CONVERSION[ENERGY_WATT_HOUR],
|
||||
},
|
||||
# Convert power to W
|
||||
SensorDeviceClass.POWER: {
|
||||
POWER_WATT: lambda x: x / PowerConverter.UNIT_CONVERSION[POWER_WATT],
|
||||
POWER_KILO_WATT: lambda x: x / PowerConverter.UNIT_CONVERSION[POWER_KILO_WATT],
|
||||
},
|
||||
# Convert pressure to Pa
|
||||
# Note: PressureConverter.convert is bypassed to avoid redundant error checking
|
||||
SensorDeviceClass.PRESSURE: {
|
||||
PRESSURE_BAR: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_BAR],
|
||||
PRESSURE_HPA: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_HPA],
|
||||
PRESSURE_INHG: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_INHG],
|
||||
PRESSURE_KPA: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_KPA],
|
||||
PRESSURE_MBAR: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_MBAR],
|
||||
PRESSURE_PA: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_PA],
|
||||
PRESSURE_PSI: lambda x: x / PressureConverter.UNIT_CONVERSION[PRESSURE_PSI],
|
||||
},
|
||||
# Convert temperature to °C
|
||||
# Note: TemperatureConverter.convert is bypassed to avoid redundant error checking
|
||||
SensorDeviceClass.TEMPERATURE: {
|
||||
TEMP_CELSIUS: lambda x: x,
|
||||
TEMP_FAHRENHEIT: TemperatureConverter.fahrenheit_to_celsius,
|
||||
TEMP_KELVIN: TemperatureConverter.kelvin_to_celsius,
|
||||
},
|
||||
# Convert volume to cubic meter
|
||||
SensorDeviceClass.GAS: {
|
||||
VOLUME_CUBIC_METERS: lambda x: x,
|
||||
VOLUME_CUBIC_FEET: lambda x: x
|
||||
/ VolumeConverter.UNIT_CONVERSION[VOLUME_CUBIC_FEET],
|
||||
},
|
||||
}
|
||||
|
||||
# Keep track of entities for which a warning about decreasing value has been logged
|
||||
SEEN_DIP = "sensor_seen_total_increasing_dip"
|
||||
WARN_DIP = "sensor_warn_total_increasing_dip"
|
||||
|
@ -212,9 +151,9 @@ def _normalize_states(
|
|||
entity_id: str,
|
||||
) -> tuple[str | None, str | None, list[tuple[float, State]]]:
|
||||
"""Normalize units."""
|
||||
state_unit = None
|
||||
state_unit: str | None = None
|
||||
|
||||
if device_class not in UNIT_CONVERSIONS:
|
||||
if device_class not in UNIT_CONVERTERS:
|
||||
# We're not normalizing this device class, return the state as they are
|
||||
fstates = []
|
||||
for state in entity_history:
|
||||
|
@ -250,6 +189,7 @@ def _normalize_states(
|
|||
state_unit = fstates[0][1].attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
return state_unit, state_unit, fstates
|
||||
|
||||
converter = UNIT_CONVERTERS[device_class]
|
||||
fstates = []
|
||||
|
||||
for state in entity_history:
|
||||
|
@ -259,7 +199,7 @@ def _normalize_states(
|
|||
continue
|
||||
state_unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
# Exclude unsupported units from statistics
|
||||
if state_unit not in UNIT_CONVERSIONS[device_class]:
|
||||
if state_unit not in converter.VALID_UNITS:
|
||||
if WARN_UNSUPPORTED_UNIT not in hass.data:
|
||||
hass.data[WARN_UNSUPPORTED_UNIT] = set()
|
||||
if entity_id not in hass.data[WARN_UNSUPPORTED_UNIT]:
|
||||
|
@ -272,7 +212,14 @@ def _normalize_states(
|
|||
)
|
||||
continue
|
||||
|
||||
fstates.append((UNIT_CONVERSIONS[device_class][state_unit](fstate), state))
|
||||
fstates.append(
|
||||
(
|
||||
converter.convert(
|
||||
fstate, from_unit=state_unit, to_unit=converter.NORMALIZED_UNIT
|
||||
),
|
||||
state,
|
||||
)
|
||||
)
|
||||
|
||||
return UNIT_CONVERTERS[device_class].NORMALIZED_UNIT, state_unit, fstates
|
||||
|
||||
|
@ -655,7 +602,7 @@ def list_statistic_ids(
|
|||
):
|
||||
continue
|
||||
|
||||
if device_class not in UNIT_CONVERSIONS:
|
||||
if device_class not in UNIT_CONVERTERS:
|
||||
result[state.entity_id] = {
|
||||
"has_mean": "mean" in provided_statistics,
|
||||
"has_sum": "sum" in provided_statistics,
|
||||
|
@ -667,10 +614,11 @@ def list_statistic_ids(
|
|||
}
|
||||
continue
|
||||
|
||||
if state_unit not in UNIT_CONVERSIONS[device_class]:
|
||||
converter = UNIT_CONVERTERS[device_class]
|
||||
if state_unit not in converter.VALID_UNITS:
|
||||
continue
|
||||
|
||||
statistics_unit = UNIT_CONVERTERS[device_class].NORMALIZED_UNIT
|
||||
statistics_unit = converter.NORMALIZED_UNIT
|
||||
result[state.entity_id] = {
|
||||
"has_mean": "mean" in provided_statistics,
|
||||
"has_sum": "sum" in provided_statistics,
|
||||
|
@ -721,7 +669,7 @@ def validate_statistics(
|
|||
)
|
||||
|
||||
metadata_unit = metadata[1]["unit_of_measurement"]
|
||||
if device_class not in UNIT_CONVERSIONS:
|
||||
if device_class not in UNIT_CONVERTERS:
|
||||
if state_unit != metadata_unit:
|
||||
# The unit has changed
|
||||
validation_result[entity_id].append(
|
||||
|
@ -761,8 +709,8 @@ def validate_statistics(
|
|||
|
||||
if (
|
||||
state_class in STATE_CLASSES
|
||||
and device_class in UNIT_CONVERSIONS
|
||||
and state_unit not in UNIT_CONVERSIONS[device_class]
|
||||
and device_class in UNIT_CONVERTERS
|
||||
and state_unit not in UNIT_CONVERTERS[device_class].VALID_UNITS
|
||||
):
|
||||
# The unit in the state is not supported for this device class
|
||||
validation_result[entity_id].append(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue