mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Don't normalize units of long term statistics (#79320)
* Don't normalize units of long term statistics * Update statistics.py
This commit is contained in:
parent
e8650dd4b7
commit
a2e3978d53
@ -125,14 +125,14 @@ QUERY_STATISTIC_META = [
|
|||||||
|
|
||||||
|
|
||||||
STATISTIC_UNIT_TO_UNIT_CONVERTER: dict[str | None, type[BaseUnitConverter]] = {
|
STATISTIC_UNIT_TO_UNIT_CONVERTER: dict[str | None, type[BaseUnitConverter]] = {
|
||||||
DistanceConverter.NORMALIZED_UNIT: DistanceConverter,
|
**{unit: DistanceConverter for unit in DistanceConverter.VALID_UNITS},
|
||||||
EnergyConverter.NORMALIZED_UNIT: EnergyConverter,
|
**{unit: EnergyConverter for unit in EnergyConverter.VALID_UNITS},
|
||||||
MassConverter.NORMALIZED_UNIT: MassConverter,
|
**{unit: MassConverter for unit in MassConverter.VALID_UNITS},
|
||||||
PowerConverter.NORMALIZED_UNIT: PowerConverter,
|
**{unit: PowerConverter for unit in PowerConverter.VALID_UNITS},
|
||||||
PressureConverter.NORMALIZED_UNIT: PressureConverter,
|
**{unit: PressureConverter for unit in PressureConverter.VALID_UNITS},
|
||||||
SpeedConverter.NORMALIZED_UNIT: SpeedConverter,
|
**{unit: SpeedConverter for unit in SpeedConverter.VALID_UNITS},
|
||||||
TemperatureConverter.NORMALIZED_UNIT: TemperatureConverter,
|
**{unit: TemperatureConverter for unit in TemperatureConverter.VALID_UNITS},
|
||||||
VolumeConverter.NORMALIZED_UNIT: VolumeConverter,
|
**{unit: VolumeConverter for unit in VolumeConverter.VALID_UNITS},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _get_unit_class(unit: str | None) -> str | None:
|
def _get_unit_class(unit: str | None) -> str | None:
|
||||||
"""Get corresponding unit class from from the normalized statistics unit."""
|
"""Get corresponding unit class from from the statistics unit."""
|
||||||
if converter := STATISTIC_UNIT_TO_UNIT_CONVERTER.get(unit):
|
if converter := STATISTIC_UNIT_TO_UNIT_CONVERTER.get(unit):
|
||||||
return converter.UNIT_CLASS
|
return converter.UNIT_CLASS
|
||||||
return None
|
return None
|
||||||
@ -151,7 +151,7 @@ def _get_statistic_to_display_unit_converter(
|
|||||||
state_unit: str | None,
|
state_unit: str | None,
|
||||||
requested_units: dict[str, str] | None,
|
requested_units: dict[str, str] | None,
|
||||||
) -> Callable[[float | None], float | None]:
|
) -> Callable[[float | None], float | None]:
|
||||||
"""Prepare a converter from the normalized statistics unit to display unit."""
|
"""Prepare a converter from the statistics unit to display unit."""
|
||||||
|
|
||||||
def no_conversion(val: float | None) -> float | None:
|
def no_conversion(val: float | None) -> float | None:
|
||||||
"""Return val."""
|
"""Return val."""
|
||||||
@ -175,21 +175,26 @@ def _get_statistic_to_display_unit_converter(
|
|||||||
return no_conversion
|
return no_conversion
|
||||||
|
|
||||||
def from_normalized_unit(
|
def from_normalized_unit(
|
||||||
val: float | None, conv: type[BaseUnitConverter], to_unit: str
|
val: float | None, conv: type[BaseUnitConverter], from_unit: str, to_unit: str
|
||||||
) -> float | None:
|
) -> float | None:
|
||||||
"""Return val."""
|
"""Return val."""
|
||||||
if val is None:
|
if val is None:
|
||||||
return val
|
return val
|
||||||
return conv.convert(val, from_unit=conv.NORMALIZED_UNIT, to_unit=to_unit)
|
return conv.convert(val, from_unit=from_unit, to_unit=to_unit)
|
||||||
|
|
||||||
return partial(from_normalized_unit, conv=converter, to_unit=display_unit)
|
return partial(
|
||||||
|
from_normalized_unit,
|
||||||
|
conv=converter,
|
||||||
|
from_unit=statistic_unit,
|
||||||
|
to_unit=display_unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_display_to_statistic_unit_converter(
|
def _get_display_to_statistic_unit_converter(
|
||||||
display_unit: str | None,
|
display_unit: str | None,
|
||||||
statistic_unit: str | None,
|
statistic_unit: str | None,
|
||||||
) -> Callable[[float], float]:
|
) -> Callable[[float], float]:
|
||||||
"""Prepare a converter from the display unit to the normalized statistics unit."""
|
"""Prepare a converter from the display unit to the statistics unit."""
|
||||||
|
|
||||||
def no_conversion(val: float) -> float:
|
def no_conversion(val: float) -> float:
|
||||||
"""Return val."""
|
"""Return val."""
|
||||||
@ -201,9 +206,7 @@ def _get_display_to_statistic_unit_converter(
|
|||||||
if (converter := STATISTIC_UNIT_TO_UNIT_CONVERTER.get(statistic_unit)) is None:
|
if (converter := STATISTIC_UNIT_TO_UNIT_CONVERTER.get(statistic_unit)) is None:
|
||||||
return no_conversion
|
return no_conversion
|
||||||
|
|
||||||
return partial(
|
return partial(converter.convert, from_unit=display_unit, to_unit=statistic_unit)
|
||||||
converter.convert, from_unit=display_unit, to_unit=converter.NORMALIZED_UNIT
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_unit_converter(
|
def _get_unit_converter(
|
||||||
|
@ -164,10 +164,10 @@ def _normalize_states(
|
|||||||
if device_class not in UNIT_CONVERTERS or (
|
if device_class not in UNIT_CONVERTERS or (
|
||||||
old_metadata
|
old_metadata
|
||||||
and old_metadata["unit_of_measurement"]
|
and old_metadata["unit_of_measurement"]
|
||||||
!= UNIT_CONVERTERS[device_class].NORMALIZED_UNIT
|
not in UNIT_CONVERTERS[device_class].VALID_UNITS
|
||||||
):
|
):
|
||||||
# We're either not normalizing this device class or this entity is not stored
|
# We're either not normalizing this device class or this entity is not stored
|
||||||
# normalized, return the states as they are
|
# in a supported unit, return the states as they are
|
||||||
fstates = []
|
fstates = []
|
||||||
for state in entity_history:
|
for state in entity_history:
|
||||||
try:
|
try:
|
||||||
@ -205,6 +205,10 @@ def _normalize_states(
|
|||||||
converter = UNIT_CONVERTERS[device_class]
|
converter = UNIT_CONVERTERS[device_class]
|
||||||
fstates = []
|
fstates = []
|
||||||
|
|
||||||
|
statistics_unit: str | None = None
|
||||||
|
if old_metadata:
|
||||||
|
statistics_unit = old_metadata["unit_of_measurement"]
|
||||||
|
|
||||||
for state in entity_history:
|
for state in entity_history:
|
||||||
try:
|
try:
|
||||||
fstate = _parse_float(state.state)
|
fstate = _parse_float(state.state)
|
||||||
@ -224,17 +228,19 @@ def _normalize_states(
|
|||||||
device_class,
|
device_class,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
if statistics_unit is None:
|
||||||
|
statistics_unit = state_unit
|
||||||
|
|
||||||
fstates.append(
|
fstates.append(
|
||||||
(
|
(
|
||||||
converter.convert(
|
converter.convert(
|
||||||
fstate, from_unit=state_unit, to_unit=converter.NORMALIZED_UNIT
|
fstate, from_unit=state_unit, to_unit=statistics_unit
|
||||||
),
|
),
|
||||||
state,
|
state,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return UNIT_CONVERTERS[device_class].NORMALIZED_UNIT, state_unit, fstates
|
return statistics_unit, state_unit, fstates
|
||||||
|
|
||||||
|
|
||||||
def _suggest_report_issue(hass: HomeAssistant, entity_id: str) -> str:
|
def _suggest_report_issue(hass: HomeAssistant, entity_id: str) -> str:
|
||||||
@ -423,7 +429,7 @@ def _compile_statistics( # noqa: C901
|
|||||||
|
|
||||||
device_class = _state.attributes.get(ATTR_DEVICE_CLASS)
|
device_class = _state.attributes.get(ATTR_DEVICE_CLASS)
|
||||||
entity_history = history_list[entity_id]
|
entity_history = history_list[entity_id]
|
||||||
normalized_unit, state_unit, fstates = _normalize_states(
|
statistics_unit, state_unit, fstates = _normalize_states(
|
||||||
hass,
|
hass,
|
||||||
session,
|
session,
|
||||||
old_metadatas,
|
old_metadatas,
|
||||||
@ -438,7 +444,7 @@ def _compile_statistics( # noqa: C901
|
|||||||
state_class = _state.attributes[ATTR_STATE_CLASS]
|
state_class = _state.attributes[ATTR_STATE_CLASS]
|
||||||
|
|
||||||
to_process.append(
|
to_process.append(
|
||||||
(entity_id, normalized_unit, state_unit, state_class, fstates)
|
(entity_id, statistics_unit, state_unit, state_class, fstates)
|
||||||
)
|
)
|
||||||
if "sum" in wanted_statistics[entity_id]:
|
if "sum" in wanted_statistics[entity_id]:
|
||||||
to_query.append(entity_id)
|
to_query.append(entity_id)
|
||||||
@ -448,14 +454,14 @@ def _compile_statistics( # noqa: C901
|
|||||||
)
|
)
|
||||||
for ( # pylint: disable=too-many-nested-blocks
|
for ( # pylint: disable=too-many-nested-blocks
|
||||||
entity_id,
|
entity_id,
|
||||||
normalized_unit,
|
statistics_unit,
|
||||||
state_unit,
|
state_unit,
|
||||||
state_class,
|
state_class,
|
||||||
fstates,
|
fstates,
|
||||||
) in to_process:
|
) in to_process:
|
||||||
# Check metadata
|
# Check metadata
|
||||||
if old_metadata := old_metadatas.get(entity_id):
|
if old_metadata := old_metadatas.get(entity_id):
|
||||||
if old_metadata[1]["unit_of_measurement"] != normalized_unit:
|
if old_metadata[1]["unit_of_measurement"] != statistics_unit:
|
||||||
if WARN_UNSTABLE_UNIT not in hass.data:
|
if WARN_UNSTABLE_UNIT not in hass.data:
|
||||||
hass.data[WARN_UNSTABLE_UNIT] = set()
|
hass.data[WARN_UNSTABLE_UNIT] = set()
|
||||||
if entity_id not in hass.data[WARN_UNSTABLE_UNIT]:
|
if entity_id not in hass.data[WARN_UNSTABLE_UNIT]:
|
||||||
@ -467,7 +473,7 @@ def _compile_statistics( # noqa: C901
|
|||||||
"Go to %s to fix this",
|
"Go to %s to fix this",
|
||||||
"normalized " if device_class in UNIT_CONVERTERS else "",
|
"normalized " if device_class in UNIT_CONVERTERS else "",
|
||||||
entity_id,
|
entity_id,
|
||||||
normalized_unit,
|
statistics_unit,
|
||||||
old_metadata[1]["unit_of_measurement"],
|
old_metadata[1]["unit_of_measurement"],
|
||||||
old_metadata[1]["unit_of_measurement"],
|
old_metadata[1]["unit_of_measurement"],
|
||||||
LINK_DEV_STATISTICS,
|
LINK_DEV_STATISTICS,
|
||||||
@ -481,7 +487,7 @@ def _compile_statistics( # noqa: C901
|
|||||||
"name": None,
|
"name": None,
|
||||||
"source": RECORDER_DOMAIN,
|
"source": RECORDER_DOMAIN,
|
||||||
"statistic_id": entity_id,
|
"statistic_id": entity_id,
|
||||||
"unit_of_measurement": normalized_unit,
|
"unit_of_measurement": statistics_unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Make calculations
|
# Make calculations
|
||||||
@ -629,14 +635,13 @@ def list_statistic_ids(
|
|||||||
if state_unit not in converter.VALID_UNITS:
|
if state_unit not in converter.VALID_UNITS:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
statistics_unit = converter.NORMALIZED_UNIT
|
|
||||||
result[state.entity_id] = {
|
result[state.entity_id] = {
|
||||||
"has_mean": "mean" in provided_statistics,
|
"has_mean": "mean" in provided_statistics,
|
||||||
"has_sum": "sum" in provided_statistics,
|
"has_sum": "sum" in provided_statistics,
|
||||||
"name": None,
|
"name": None,
|
||||||
"source": RECORDER_DOMAIN,
|
"source": RECORDER_DOMAIN,
|
||||||
"statistic_id": state.entity_id,
|
"statistic_id": state.entity_id,
|
||||||
"unit_of_measurement": statistics_unit,
|
"unit_of_measurement": state_unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -680,13 +685,13 @@ def validate_statistics(
|
|||||||
|
|
||||||
metadata_unit = metadata[1]["unit_of_measurement"]
|
metadata_unit = metadata[1]["unit_of_measurement"]
|
||||||
if device_class not in UNIT_CONVERTERS:
|
if device_class not in UNIT_CONVERTERS:
|
||||||
issue_type = (
|
|
||||||
"units_changed_can_convert"
|
|
||||||
if statistics.can_convert_units(metadata_unit, state_unit)
|
|
||||||
else "units_changed"
|
|
||||||
)
|
|
||||||
if state_unit != metadata_unit:
|
if state_unit != metadata_unit:
|
||||||
# The unit has changed
|
# The unit has changed
|
||||||
|
issue_type = (
|
||||||
|
"units_changed_can_convert"
|
||||||
|
if statistics.can_convert_units(metadata_unit, state_unit)
|
||||||
|
else "units_changed"
|
||||||
|
)
|
||||||
validation_result[entity_id].append(
|
validation_result[entity_id].append(
|
||||||
statistics.ValidationIssue(
|
statistics.ValidationIssue(
|
||||||
issue_type,
|
issue_type,
|
||||||
@ -697,22 +702,19 @@ def validate_statistics(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif metadata_unit != UNIT_CONVERTERS[device_class].NORMALIZED_UNIT:
|
elif metadata_unit not in UNIT_CONVERTERS[device_class].VALID_UNITS:
|
||||||
# The unit in metadata is not supported for this device class
|
# The unit in metadata is not supported for this device class
|
||||||
statistics_unit = UNIT_CONVERTERS[device_class].NORMALIZED_UNIT
|
valid_units = ", ".join(
|
||||||
issue_type = (
|
sorted(UNIT_CONVERTERS[device_class].VALID_UNITS)
|
||||||
"unsupported_unit_metadata_can_convert"
|
|
||||||
if statistics.can_convert_units(metadata_unit, statistics_unit)
|
|
||||||
else "unsupported_unit_metadata"
|
|
||||||
)
|
)
|
||||||
validation_result[entity_id].append(
|
validation_result[entity_id].append(
|
||||||
statistics.ValidationIssue(
|
statistics.ValidationIssue(
|
||||||
issue_type,
|
"unsupported_unit_metadata",
|
||||||
{
|
{
|
||||||
"statistic_id": entity_id,
|
"statistic_id": entity_id,
|
||||||
"device_class": device_class,
|
"device_class": device_class,
|
||||||
"metadata_unit": metadata_unit,
|
"metadata_unit": metadata_unit,
|
||||||
"supported_unit": statistics_unit,
|
"supported_unit": valid_units,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -591,26 +591,26 @@ async def test_statistics_during_period_bad_end_time(
|
|||||||
[
|
[
|
||||||
(IMPERIAL_SYSTEM, DISTANCE_SENSOR_M_ATTRIBUTES, "m", "m", "distance"),
|
(IMPERIAL_SYSTEM, DISTANCE_SENSOR_M_ATTRIBUTES, "m", "m", "distance"),
|
||||||
(METRIC_SYSTEM, DISTANCE_SENSOR_M_ATTRIBUTES, "m", "m", "distance"),
|
(METRIC_SYSTEM, DISTANCE_SENSOR_M_ATTRIBUTES, "m", "m", "distance"),
|
||||||
(IMPERIAL_SYSTEM, DISTANCE_SENSOR_FT_ATTRIBUTES, "ft", "m", "distance"),
|
(IMPERIAL_SYSTEM, DISTANCE_SENSOR_FT_ATTRIBUTES, "ft", "ft", "distance"),
|
||||||
(METRIC_SYSTEM, DISTANCE_SENSOR_FT_ATTRIBUTES, "ft", "m", "distance"),
|
(METRIC_SYSTEM, DISTANCE_SENSOR_FT_ATTRIBUTES, "ft", "ft", "distance"),
|
||||||
(IMPERIAL_SYSTEM, ENERGY_SENSOR_WH_ATTRIBUTES, "Wh", "kWh", "energy"),
|
(IMPERIAL_SYSTEM, ENERGY_SENSOR_WH_ATTRIBUTES, "Wh", "Wh", "energy"),
|
||||||
(METRIC_SYSTEM, ENERGY_SENSOR_WH_ATTRIBUTES, "Wh", "kWh", "energy"),
|
(METRIC_SYSTEM, ENERGY_SENSOR_WH_ATTRIBUTES, "Wh", "Wh", "energy"),
|
||||||
(IMPERIAL_SYSTEM, GAS_SENSOR_FT3_ATTRIBUTES, "ft³", "m³", "volume"),
|
(IMPERIAL_SYSTEM, GAS_SENSOR_FT3_ATTRIBUTES, "ft³", "ft³", "volume"),
|
||||||
(METRIC_SYSTEM, GAS_SENSOR_FT3_ATTRIBUTES, "ft³", "m³", "volume"),
|
(METRIC_SYSTEM, GAS_SENSOR_FT3_ATTRIBUTES, "ft³", "ft³", "volume"),
|
||||||
(IMPERIAL_SYSTEM, POWER_SENSOR_KW_ATTRIBUTES, "kW", "W", "power"),
|
(IMPERIAL_SYSTEM, POWER_SENSOR_KW_ATTRIBUTES, "kW", "kW", "power"),
|
||||||
(METRIC_SYSTEM, POWER_SENSOR_KW_ATTRIBUTES, "kW", "W", "power"),
|
(METRIC_SYSTEM, POWER_SENSOR_KW_ATTRIBUTES, "kW", "kW", "power"),
|
||||||
(IMPERIAL_SYSTEM, PRESSURE_SENSOR_HPA_ATTRIBUTES, "hPa", "Pa", "pressure"),
|
(IMPERIAL_SYSTEM, PRESSURE_SENSOR_HPA_ATTRIBUTES, "hPa", "hPa", "pressure"),
|
||||||
(METRIC_SYSTEM, PRESSURE_SENSOR_HPA_ATTRIBUTES, "hPa", "Pa", "pressure"),
|
(METRIC_SYSTEM, PRESSURE_SENSOR_HPA_ATTRIBUTES, "hPa", "hPa", "pressure"),
|
||||||
(IMPERIAL_SYSTEM, SPEED_SENSOR_KPH_ATTRIBUTES, "km/h", "m/s", "speed"),
|
(IMPERIAL_SYSTEM, SPEED_SENSOR_KPH_ATTRIBUTES, "km/h", "km/h", "speed"),
|
||||||
(METRIC_SYSTEM, SPEED_SENSOR_KPH_ATTRIBUTES, "km/h", "m/s", "speed"),
|
(METRIC_SYSTEM, SPEED_SENSOR_KPH_ATTRIBUTES, "km/h", "km/h", "speed"),
|
||||||
(IMPERIAL_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "°C", "temperature"),
|
(IMPERIAL_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "°C", "temperature"),
|
||||||
(METRIC_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "°C", "temperature"),
|
(METRIC_SYSTEM, TEMPERATURE_SENSOR_C_ATTRIBUTES, "°C", "°C", "temperature"),
|
||||||
(IMPERIAL_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°C", "temperature"),
|
(IMPERIAL_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°F", "temperature"),
|
||||||
(METRIC_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°C", "temperature"),
|
(METRIC_SYSTEM, TEMPERATURE_SENSOR_F_ATTRIBUTES, "°F", "°F", "temperature"),
|
||||||
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "m³", "volume"),
|
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "ft³", "volume"),
|
||||||
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "m³", "volume"),
|
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES, "ft³", "ft³", "volume"),
|
||||||
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "m³", "volume"),
|
(IMPERIAL_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "ft³", "volume"),
|
||||||
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "m³", "volume"),
|
(METRIC_SYSTEM, VOLUME_SENSOR_FT3_ATTRIBUTES_TOTAL, "ft³", "ft³", "volume"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_list_statistic_ids(
|
async def test_list_statistic_ids(
|
||||||
@ -904,7 +904,7 @@ async def test_update_statistics_metadata(
|
|||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": "kW",
|
"statistics_unit_of_measurement": "kW",
|
||||||
"unit_class": None,
|
"unit_class": "power",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -994,7 +994,7 @@ async def test_change_statistics_unit(hass, hass_ws_client, recorder_mock):
|
|||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": "kW",
|
"statistics_unit_of_measurement": "kW",
|
||||||
"unit_class": None,
|
"unit_class": "power",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1101,7 +1101,7 @@ async def test_change_statistics_unit_errors(
|
|||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": "kW",
|
"statistics_unit_of_measurement": "kW",
|
||||||
"unit_class": None,
|
"unit_class": "power",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1504,7 +1504,7 @@ async def test_get_statistics_metadata(
|
|||||||
"has_sum": has_sum,
|
"has_sum": has_sum,
|
||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": unit,
|
"statistics_unit_of_measurement": attributes["unit_of_measurement"],
|
||||||
"unit_class": unit_class,
|
"unit_class": unit_class,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -1531,7 +1531,7 @@ async def test_get_statistics_metadata(
|
|||||||
"has_sum": has_sum,
|
"has_sum": has_sum,
|
||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": unit,
|
"statistics_unit_of_measurement": attributes["unit_of_measurement"],
|
||||||
"unit_class": unit_class,
|
"unit_class": unit_class,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -2160,9 +2160,9 @@ async def test_adjust_sum_statistics_gas(
|
|||||||
"state_unit, statistic_unit, unit_class, factor, valid_units, invalid_units",
|
"state_unit, statistic_unit, unit_class, factor, valid_units, invalid_units",
|
||||||
(
|
(
|
||||||
("kWh", "kWh", "energy", 1, ("Wh", "kWh", "MWh"), ("ft³", "m³", "cats", None)),
|
("kWh", "kWh", "energy", 1, ("Wh", "kWh", "MWh"), ("ft³", "m³", "cats", None)),
|
||||||
("MWh", "MWh", None, 1, ("MWh",), ("Wh", "kWh", "ft³", "m³", "cats", None)),
|
("MWh", "MWh", "energy", 1, ("Wh", "kWh", "MWh"), ("ft³", "m³", "cats", None)),
|
||||||
("m³", "m³", "volume", 1, ("ft³", "m³"), ("Wh", "kWh", "MWh", "cats", None)),
|
("m³", "m³", "volume", 1, ("ft³", "m³"), ("Wh", "kWh", "MWh", "cats", None)),
|
||||||
("ft³", "ft³", None, 1, ("ft³",), ("m³", "Wh", "kWh", "MWh", "cats", None)),
|
("ft³", "ft³", "volume", 1, ("ft³", "m³"), ("Wh", "kWh", "MWh", "cats", None)),
|
||||||
("dogs", "dogs", None, 1, ("dogs",), ("cats", None)),
|
("dogs", "dogs", None, 1, ("dogs",), ("cats", None)),
|
||||||
(None, None, None, 1, (None,), ("cats",)),
|
(None, None, None, 1, (None,), ("cats",)),
|
||||||
),
|
),
|
||||||
@ -2262,7 +2262,7 @@ async def test_adjust_sum_statistics_errors(
|
|||||||
"statistic_id": statistic_id,
|
"statistic_id": statistic_id,
|
||||||
"name": "Total imported energy",
|
"name": "Total imported energy",
|
||||||
"source": source,
|
"source": source,
|
||||||
"statistics_unit_of_measurement": statistic_unit,
|
"statistics_unit_of_measurement": state_unit,
|
||||||
"unit_class": unit_class,
|
"unit_class": unit_class,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -2276,7 +2276,7 @@ async def test_adjust_sum_statistics_errors(
|
|||||||
"name": "Total imported energy",
|
"name": "Total imported energy",
|
||||||
"source": source,
|
"source": source,
|
||||||
"statistic_id": statistic_id,
|
"statistic_id": statistic_id,
|
||||||
"unit_of_measurement": statistic_unit,
|
"unit_of_measurement": state_unit,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -86,22 +86,22 @@ def set_time_zone():
|
|||||||
("battery", "%", "%", "%", None, 13.050847, -10, 30),
|
("battery", "%", "%", "%", None, 13.050847, -10, 30),
|
||||||
("battery", None, None, None, None, 13.050847, -10, 30),
|
("battery", None, None, None, None, 13.050847, -10, 30),
|
||||||
("distance", "m", "m", "m", "distance", 13.050847, -10, 30),
|
("distance", "m", "m", "m", "distance", 13.050847, -10, 30),
|
||||||
("distance", "mi", "mi", "m", "distance", 13.050847, -10, 30),
|
("distance", "mi", "mi", "mi", "distance", 13.050847, -10, 30),
|
||||||
("humidity", "%", "%", "%", None, 13.050847, -10, 30),
|
("humidity", "%", "%", "%", None, 13.050847, -10, 30),
|
||||||
("humidity", None, None, None, None, 13.050847, -10, 30),
|
("humidity", None, None, None, None, 13.050847, -10, 30),
|
||||||
("pressure", "Pa", "Pa", "Pa", "pressure", 13.050847, -10, 30),
|
("pressure", "Pa", "Pa", "Pa", "pressure", 13.050847, -10, 30),
|
||||||
("pressure", "hPa", "hPa", "Pa", "pressure", 13.050847, -10, 30),
|
("pressure", "hPa", "hPa", "hPa", "pressure", 13.050847, -10, 30),
|
||||||
("pressure", "mbar", "mbar", "Pa", "pressure", 13.050847, -10, 30),
|
("pressure", "mbar", "mbar", "mbar", "pressure", 13.050847, -10, 30),
|
||||||
("pressure", "inHg", "inHg", "Pa", "pressure", 13.050847, -10, 30),
|
("pressure", "inHg", "inHg", "inHg", "pressure", 13.050847, -10, 30),
|
||||||
("pressure", "psi", "psi", "Pa", "pressure", 13.050847, -10, 30),
|
("pressure", "psi", "psi", "psi", "pressure", 13.050847, -10, 30),
|
||||||
("speed", "m/s", "m/s", "m/s", "speed", 13.050847, -10, 30),
|
("speed", "m/s", "m/s", "m/s", "speed", 13.050847, -10, 30),
|
||||||
("speed", "mph", "mph", "m/s", "speed", 13.050847, -10, 30),
|
("speed", "mph", "mph", "mph", "speed", 13.050847, -10, 30),
|
||||||
("temperature", "°C", "°C", "°C", "temperature", 13.050847, -10, 30),
|
("temperature", "°C", "°C", "°C", "temperature", 13.050847, -10, 30),
|
||||||
("temperature", "°F", "°F", "°C", "temperature", 13.050847, -10, 30),
|
("temperature", "°F", "°F", "°F", "temperature", 13.050847, -10, 30),
|
||||||
("volume", "m³", "m³", "m³", "volume", 13.050847, -10, 30),
|
("volume", "m³", "m³", "m³", "volume", 13.050847, -10, 30),
|
||||||
("volume", "ft³", "ft³", "m³", "volume", 13.050847, -10, 30),
|
("volume", "ft³", "ft³", "ft³", "volume", 13.050847, -10, 30),
|
||||||
("weight", "g", "g", "g", "mass", 13.050847, -10, 30),
|
("weight", "g", "g", "g", "mass", 13.050847, -10, 30),
|
||||||
("weight", "oz", "oz", "g", "mass", 13.050847, -10, 30),
|
("weight", "oz", "oz", "oz", "mass", 13.050847, -10, 30),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_statistics(
|
def test_compile_hourly_statistics(
|
||||||
@ -355,29 +355,29 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes
|
|||||||
"units, device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
"units, device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
||||||
[
|
[
|
||||||
(IMPERIAL_SYSTEM, "distance", "m", "m", "m", "distance", 1),
|
(IMPERIAL_SYSTEM, "distance", "m", "m", "m", "distance", 1),
|
||||||
(IMPERIAL_SYSTEM, "distance", "mi", "mi", "m", "distance", 1),
|
(IMPERIAL_SYSTEM, "distance", "mi", "mi", "mi", "distance", 1),
|
||||||
(IMPERIAL_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
|
(IMPERIAL_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
|
||||||
(IMPERIAL_SYSTEM, "energy", "Wh", "Wh", "kWh", "energy", 1),
|
(IMPERIAL_SYSTEM, "energy", "Wh", "Wh", "Wh", "energy", 1),
|
||||||
(IMPERIAL_SYSTEM, "gas", "m³", "m³", "m³", "volume", 1),
|
(IMPERIAL_SYSTEM, "gas", "m³", "m³", "m³", "volume", 1),
|
||||||
(IMPERIAL_SYSTEM, "gas", "ft³", "ft³", "m³", "volume", 1),
|
(IMPERIAL_SYSTEM, "gas", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
(IMPERIAL_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
|
(IMPERIAL_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
|
||||||
(IMPERIAL_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
|
(IMPERIAL_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
|
||||||
(IMPERIAL_SYSTEM, "volume", "m³", "m³", "m³", "volume", 1),
|
(IMPERIAL_SYSTEM, "volume", "m³", "m³", "m³", "volume", 1),
|
||||||
(IMPERIAL_SYSTEM, "volume", "ft³", "ft³", "m³", "volume", 1),
|
(IMPERIAL_SYSTEM, "volume", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
(IMPERIAL_SYSTEM, "weight", "g", "g", "g", "mass", 1),
|
(IMPERIAL_SYSTEM, "weight", "g", "g", "g", "mass", 1),
|
||||||
(IMPERIAL_SYSTEM, "weight", "oz", "oz", "g", "mass", 1),
|
(IMPERIAL_SYSTEM, "weight", "oz", "oz", "oz", "mass", 1),
|
||||||
(METRIC_SYSTEM, "distance", "m", "m", "m", "distance", 1),
|
(METRIC_SYSTEM, "distance", "m", "m", "m", "distance", 1),
|
||||||
(METRIC_SYSTEM, "distance", "mi", "mi", "m", "distance", 1),
|
(METRIC_SYSTEM, "distance", "mi", "mi", "mi", "distance", 1),
|
||||||
(METRIC_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
|
(METRIC_SYSTEM, "energy", "kWh", "kWh", "kWh", "energy", 1),
|
||||||
(METRIC_SYSTEM, "energy", "Wh", "Wh", "kWh", "energy", 1),
|
(METRIC_SYSTEM, "energy", "Wh", "Wh", "Wh", "energy", 1),
|
||||||
(METRIC_SYSTEM, "gas", "m³", "m³", "m³", "volume", 1),
|
(METRIC_SYSTEM, "gas", "m³", "m³", "m³", "volume", 1),
|
||||||
(METRIC_SYSTEM, "gas", "ft³", "ft³", "m³", "volume", 1),
|
(METRIC_SYSTEM, "gas", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
(METRIC_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
|
(METRIC_SYSTEM, "monetary", "EUR", "EUR", "EUR", None, 1),
|
||||||
(METRIC_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
|
(METRIC_SYSTEM, "monetary", "SEK", "SEK", "SEK", None, 1),
|
||||||
(METRIC_SYSTEM, "volume", "m³", "m³", "m³", "volume", 1),
|
(METRIC_SYSTEM, "volume", "m³", "m³", "m³", "volume", 1),
|
||||||
(METRIC_SYSTEM, "volume", "ft³", "ft³", "m³", "volume", 1),
|
(METRIC_SYSTEM, "volume", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
(METRIC_SYSTEM, "weight", "g", "g", "g", "mass", 1),
|
(METRIC_SYSTEM, "weight", "g", "g", "g", "mass", 1),
|
||||||
(METRIC_SYSTEM, "weight", "oz", "oz", "g", "mass", 1),
|
(METRIC_SYSTEM, "weight", "oz", "oz", "oz", "mass", 1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_compile_hourly_sum_statistics_amount(
|
async def test_compile_hourly_sum_statistics_amount(
|
||||||
@ -548,11 +548,11 @@ async def test_compile_hourly_sum_statistics_amount(
|
|||||||
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
||||||
[
|
[
|
||||||
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
||||||
("energy", "Wh", "Wh", "kWh", "energy", 1),
|
("energy", "Wh", "Wh", "Wh", "energy", 1),
|
||||||
("monetary", "EUR", "EUR", "EUR", None, 1),
|
("monetary", "EUR", "EUR", "EUR", None, 1),
|
||||||
("monetary", "SEK", "SEK", "SEK", None, 1),
|
("monetary", "SEK", "SEK", "SEK", None, 1),
|
||||||
("gas", "m³", "m³", "m³", "volume", 1),
|
("gas", "m³", "m³", "m³", "volume", 1),
|
||||||
("gas", "ft³", "ft³", "m³", "volume", 1),
|
("gas", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_sum_statistics_amount_reset_every_state_change(
|
def test_compile_hourly_sum_statistics_amount_reset_every_state_change(
|
||||||
@ -957,11 +957,11 @@ def test_compile_hourly_sum_statistics_negative_state(
|
|||||||
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
||||||
[
|
[
|
||||||
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
||||||
("energy", "Wh", "Wh", "kWh", "energy", 1),
|
("energy", "Wh", "Wh", "Wh", "energy", 1),
|
||||||
("monetary", "EUR", "EUR", "EUR", None, 1),
|
("monetary", "EUR", "EUR", "EUR", None, 1),
|
||||||
("monetary", "SEK", "SEK", "SEK", None, 1),
|
("monetary", "SEK", "SEK", "SEK", None, 1),
|
||||||
("gas", "m³", "m³", "m³", "volume", 1),
|
("gas", "m³", "m³", "m³", "volume", 1),
|
||||||
("gas", "ft³", "ft³", "m³", "volume", 1),
|
("gas", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_sum_statistics_total_no_reset(
|
def test_compile_hourly_sum_statistics_total_no_reset(
|
||||||
@ -1061,9 +1061,9 @@ def test_compile_hourly_sum_statistics_total_no_reset(
|
|||||||
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
"device_class, state_unit, display_unit, statistics_unit, unit_class, factor",
|
||||||
[
|
[
|
||||||
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
("energy", "kWh", "kWh", "kWh", "energy", 1),
|
||||||
("energy", "Wh", "Wh", "kWh", "energy", 1),
|
("energy", "Wh", "Wh", "Wh", "energy", 1),
|
||||||
("gas", "m³", "m³", "m³", "volume", 1),
|
("gas", "m³", "m³", "m³", "volume", 1),
|
||||||
("gas", "ft³", "ft³", "m³", "volume", 1),
|
("gas", "ft³", "ft³", "ft³", "volume", 1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_sum_statistics_total_increasing(
|
def test_compile_hourly_sum_statistics_total_increasing(
|
||||||
@ -1431,7 +1431,7 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog):
|
|||||||
"has_sum": True,
|
"has_sum": True,
|
||||||
"name": None,
|
"name": None,
|
||||||
"source": "recorder",
|
"source": "recorder",
|
||||||
"statistics_unit_of_measurement": "kWh",
|
"statistics_unit_of_measurement": "Wh",
|
||||||
"unit_class": "energy",
|
"unit_class": "energy",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -1728,40 +1728,40 @@ def test_compile_hourly_statistics_fails(hass_recorder, caplog):
|
|||||||
("measurement", "battery", "%", "%", "%", None, "mean"),
|
("measurement", "battery", "%", "%", "%", None, "mean"),
|
||||||
("measurement", "battery", None, None, None, None, "mean"),
|
("measurement", "battery", None, None, None, None, "mean"),
|
||||||
("measurement", "distance", "m", "m", "m", "distance", "mean"),
|
("measurement", "distance", "m", "m", "m", "distance", "mean"),
|
||||||
("measurement", "distance", "mi", "mi", "m", "distance", "mean"),
|
("measurement", "distance", "mi", "mi", "mi", "distance", "mean"),
|
||||||
("total", "distance", "m", "m", "m", "distance", "sum"),
|
("total", "distance", "m", "m", "m", "distance", "sum"),
|
||||||
("total", "distance", "mi", "mi", "m", "distance", "sum"),
|
("total", "distance", "mi", "mi", "mi", "distance", "sum"),
|
||||||
("total", "energy", "Wh", "Wh", "kWh", "energy", "sum"),
|
("total", "energy", "Wh", "Wh", "Wh", "energy", "sum"),
|
||||||
("total", "energy", "kWh", "kWh", "kWh", "energy", "sum"),
|
("total", "energy", "kWh", "kWh", "kWh", "energy", "sum"),
|
||||||
("measurement", "energy", "Wh", "Wh", "kWh", "energy", "mean"),
|
("measurement", "energy", "Wh", "Wh", "Wh", "energy", "mean"),
|
||||||
("measurement", "energy", "kWh", "kWh", "kWh", "energy", "mean"),
|
("measurement", "energy", "kWh", "kWh", "kWh", "energy", "mean"),
|
||||||
("measurement", "humidity", "%", "%", "%", None, "mean"),
|
("measurement", "humidity", "%", "%", "%", None, "mean"),
|
||||||
("measurement", "humidity", None, None, None, None, "mean"),
|
("measurement", "humidity", None, None, None, None, "mean"),
|
||||||
("total", "monetary", "USD", "USD", "USD", None, "sum"),
|
("total", "monetary", "USD", "USD", "USD", None, "sum"),
|
||||||
("total", "monetary", "None", "None", "None", None, "sum"),
|
("total", "monetary", "None", "None", "None", None, "sum"),
|
||||||
("total", "gas", "m³", "m³", "m³", "volume", "sum"),
|
("total", "gas", "m³", "m³", "m³", "volume", "sum"),
|
||||||
("total", "gas", "ft³", "ft³", "m³", "volume", "sum"),
|
("total", "gas", "ft³", "ft³", "ft³", "volume", "sum"),
|
||||||
("measurement", "monetary", "USD", "USD", "USD", None, "mean"),
|
("measurement", "monetary", "USD", "USD", "USD", None, "mean"),
|
||||||
("measurement", "monetary", "None", "None", "None", None, "mean"),
|
("measurement", "monetary", "None", "None", "None", None, "mean"),
|
||||||
("measurement", "gas", "m³", "m³", "m³", "volume", "mean"),
|
("measurement", "gas", "m³", "m³", "m³", "volume", "mean"),
|
||||||
("measurement", "gas", "ft³", "ft³", "m³", "volume", "mean"),
|
("measurement", "gas", "ft³", "ft³", "ft³", "volume", "mean"),
|
||||||
("measurement", "pressure", "Pa", "Pa", "Pa", "pressure", "mean"),
|
("measurement", "pressure", "Pa", "Pa", "Pa", "pressure", "mean"),
|
||||||
("measurement", "pressure", "hPa", "hPa", "Pa", "pressure", "mean"),
|
("measurement", "pressure", "hPa", "hPa", "hPa", "pressure", "mean"),
|
||||||
("measurement", "pressure", "mbar", "mbar", "Pa", "pressure", "mean"),
|
("measurement", "pressure", "mbar", "mbar", "mbar", "pressure", "mean"),
|
||||||
("measurement", "pressure", "inHg", "inHg", "Pa", "pressure", "mean"),
|
("measurement", "pressure", "inHg", "inHg", "inHg", "pressure", "mean"),
|
||||||
("measurement", "pressure", "psi", "psi", "Pa", "pressure", "mean"),
|
("measurement", "pressure", "psi", "psi", "psi", "pressure", "mean"),
|
||||||
("measurement", "speed", "m/s", "m/s", "m/s", "speed", "mean"),
|
("measurement", "speed", "m/s", "m/s", "m/s", "speed", "mean"),
|
||||||
("measurement", "speed", "mph", "mph", "m/s", "speed", "mean"),
|
("measurement", "speed", "mph", "mph", "mph", "speed", "mean"),
|
||||||
("measurement", "temperature", "°C", "°C", "°C", "temperature", "mean"),
|
("measurement", "temperature", "°C", "°C", "°C", "temperature", "mean"),
|
||||||
("measurement", "temperature", "°F", "°F", "°C", "temperature", "mean"),
|
("measurement", "temperature", "°F", "°F", "°F", "temperature", "mean"),
|
||||||
("measurement", "volume", "m³", "m³", "m³", "volume", "mean"),
|
("measurement", "volume", "m³", "m³", "m³", "volume", "mean"),
|
||||||
("measurement", "volume", "ft³", "ft³", "m³", "volume", "mean"),
|
("measurement", "volume", "ft³", "ft³", "ft³", "volume", "mean"),
|
||||||
("total", "volume", "m³", "m³", "m³", "volume", "sum"),
|
("total", "volume", "m³", "m³", "m³", "volume", "sum"),
|
||||||
("total", "volume", "ft³", "ft³", "m³", "volume", "sum"),
|
("total", "volume", "ft³", "ft³", "ft³", "volume", "sum"),
|
||||||
("measurement", "weight", "g", "g", "g", "mass", "mean"),
|
("measurement", "weight", "g", "g", "g", "mass", "mean"),
|
||||||
("measurement", "weight", "oz", "oz", "g", "mass", "mean"),
|
("measurement", "weight", "oz", "oz", "oz", "mass", "mean"),
|
||||||
("total", "weight", "g", "g", "g", "mass", "sum"),
|
("total", "weight", "g", "g", "g", "mass", "sum"),
|
||||||
("total", "weight", "oz", "oz", "g", "mass", "sum"),
|
("total", "weight", "oz", "oz", "oz", "mass", "sum"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_list_statistic_ids(
|
def test_list_statistic_ids(
|
||||||
@ -2134,7 +2134,7 @@ def test_compile_hourly_statistics_changing_units_3(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device_class, state_unit, statistic_unit, unit_class, mean1, mean2, min, max",
|
"device_class, state_unit, statistic_unit, unit_class, mean1, mean2, min, max",
|
||||||
[
|
[
|
||||||
("power", "kW", "W", None, 13.050847, 13.333333, -10, 30),
|
("power", "kW", "kW", "power", 13.050847, 13.333333, -10, 30),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_statistics_changing_device_class_1(
|
def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
@ -2207,7 +2207,7 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
|||||||
hist = history.get_significant_states(hass, zero, four)
|
hist = history.get_significant_states(hass, zero, four)
|
||||||
assert dict(states) == dict(hist)
|
assert dict(states) == dict(hist)
|
||||||
|
|
||||||
# Run statistics again, we get a warning, and no additional statistics is generated
|
# Run statistics again, additional statistics is generated
|
||||||
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
|
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
|
||||||
wait_recording_done(hass)
|
wait_recording_done(hass)
|
||||||
statistic_ids = list_statistic_ids(hass)
|
statistic_ids = list_statistic_ids(hass)
|
||||||
@ -2265,13 +2265,9 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
|||||||
hist = history.get_significant_states(hass, zero, four)
|
hist = history.get_significant_states(hass, zero, four)
|
||||||
assert dict(states) == dict(hist)
|
assert dict(states) == dict(hist)
|
||||||
|
|
||||||
# Run statistics again, we get a warning, and no additional statistics is generated
|
# Run statistics again, additional statistics is generated
|
||||||
do_adhoc_statistics(hass, start=zero + timedelta(minutes=20))
|
do_adhoc_statistics(hass, start=zero + timedelta(minutes=20))
|
||||||
wait_recording_done(hass)
|
wait_recording_done(hass)
|
||||||
assert (
|
|
||||||
f"The normalized unit of sensor.test1 ({statistic_unit}) does not match the "
|
|
||||||
f"unit of already compiled statistics ({state_unit})" in caplog.text
|
|
||||||
)
|
|
||||||
statistic_ids = list_statistic_ids(hass)
|
statistic_ids = list_statistic_ids(hass)
|
||||||
assert statistic_ids == [
|
assert statistic_ids == [
|
||||||
{
|
{
|
||||||
@ -2311,15 +2307,28 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
|||||||
"state": None,
|
"state": None,
|
||||||
"sum": None,
|
"sum": None,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"statistic_id": "sensor.test1",
|
||||||
|
"start": process_timestamp_to_utc_isoformat(
|
||||||
|
zero + timedelta(minutes=20)
|
||||||
|
),
|
||||||
|
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=25)),
|
||||||
|
"mean": approx(mean2),
|
||||||
|
"min": approx(min),
|
||||||
|
"max": approx(max),
|
||||||
|
"last_reset": None,
|
||||||
|
"state": None,
|
||||||
|
"sum": None,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
assert "Error while processing event StatisticsTask" not in caplog.text
|
assert "Error while processing event StatisticsTask" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device_class, state_unit, display_unit, statistic_unit, unit_class, mean, min, max",
|
"device_class, state_unit, display_unit, statistic_unit, unit_class, mean, mean2, min, max",
|
||||||
[
|
[
|
||||||
("power", "kW", "kW", "W", "power", 13.050847, -10, 30),
|
("power", "kW", "kW", "kW", "power", 13.050847, 13.333333, -10, 30),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_statistics_changing_device_class_2(
|
def test_compile_hourly_statistics_changing_device_class_2(
|
||||||
@ -2331,6 +2340,7 @@ def test_compile_hourly_statistics_changing_device_class_2(
|
|||||||
statistic_unit,
|
statistic_unit,
|
||||||
unit_class,
|
unit_class,
|
||||||
mean,
|
mean,
|
||||||
|
mean2,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
):
|
):
|
||||||
@ -2393,13 +2403,9 @@ def test_compile_hourly_statistics_changing_device_class_2(
|
|||||||
hist = history.get_significant_states(hass, zero, four)
|
hist = history.get_significant_states(hass, zero, four)
|
||||||
assert dict(states) == dict(hist)
|
assert dict(states) == dict(hist)
|
||||||
|
|
||||||
# Run statistics again, we get a warning, and no additional statistics is generated
|
# Run statistics again, additional statistics is generated
|
||||||
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
|
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
|
||||||
wait_recording_done(hass)
|
wait_recording_done(hass)
|
||||||
assert (
|
|
||||||
f"The unit of sensor.test1 ({state_unit}) does not match the "
|
|
||||||
f"unit of already compiled statistics ({statistic_unit})" in caplog.text
|
|
||||||
)
|
|
||||||
statistic_ids = list_statistic_ids(hass)
|
statistic_ids = list_statistic_ids(hass)
|
||||||
assert statistic_ids == [
|
assert statistic_ids == [
|
||||||
{
|
{
|
||||||
@ -2425,7 +2431,20 @@ def test_compile_hourly_statistics_changing_device_class_2(
|
|||||||
"last_reset": None,
|
"last_reset": None,
|
||||||
"state": None,
|
"state": None,
|
||||||
"sum": None,
|
"sum": None,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"statistic_id": "sensor.test1",
|
||||||
|
"start": process_timestamp_to_utc_isoformat(
|
||||||
|
zero + timedelta(minutes=10)
|
||||||
|
),
|
||||||
|
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=15)),
|
||||||
|
"mean": approx(mean2),
|
||||||
|
"min": approx(min),
|
||||||
|
"max": approx(max),
|
||||||
|
"last_reset": None,
|
||||||
|
"state": None,
|
||||||
|
"sum": None,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
assert "Error while processing event StatisticsTask" not in caplog.text
|
assert "Error while processing event StatisticsTask" not in caplog.text
|
||||||
@ -3120,13 +3139,13 @@ async def test_validate_statistics_supported_device_class(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"units, attributes, unit",
|
"units, attributes, valid_units",
|
||||||
[
|
[
|
||||||
(IMPERIAL_SYSTEM, POWER_SENSOR_ATTRIBUTES, "W"),
|
(IMPERIAL_SYSTEM, POWER_SENSOR_ATTRIBUTES, "W, kW"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_validate_statistics_supported_device_class_2(
|
async def test_validate_statistics_supported_device_class_2(
|
||||||
hass, hass_ws_client, recorder_mock, units, attributes, unit
|
hass, hass_ws_client, recorder_mock, units, attributes, valid_units
|
||||||
):
|
):
|
||||||
"""Test validate_statistics."""
|
"""Test validate_statistics."""
|
||||||
id = 1
|
id = 1
|
||||||
@ -3172,7 +3191,7 @@ async def test_validate_statistics_supported_device_class_2(
|
|||||||
"device_class": attributes["device_class"],
|
"device_class": attributes["device_class"],
|
||||||
"metadata_unit": None,
|
"metadata_unit": None,
|
||||||
"statistic_id": "sensor.test",
|
"statistic_id": "sensor.test",
|
||||||
"supported_unit": unit,
|
"supported_unit": valid_units,
|
||||||
},
|
},
|
||||||
"type": "unsupported_unit_metadata",
|
"type": "unsupported_unit_metadata",
|
||||||
}
|
}
|
||||||
@ -3192,7 +3211,7 @@ async def test_validate_statistics_supported_device_class_2(
|
|||||||
"device_class": attributes["device_class"],
|
"device_class": attributes["device_class"],
|
||||||
"metadata_unit": None,
|
"metadata_unit": None,
|
||||||
"statistic_id": "sensor.test",
|
"statistic_id": "sensor.test",
|
||||||
"supported_unit": unit,
|
"supported_unit": valid_units,
|
||||||
},
|
},
|
||||||
"type": "unsupported_unit_metadata",
|
"type": "unsupported_unit_metadata",
|
||||||
},
|
},
|
||||||
@ -3209,96 +3228,6 @@ async def test_validate_statistics_supported_device_class_2(
|
|||||||
await assert_validation_result(client, expected)
|
await assert_validation_result(client, expected)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"units, attributes, unit",
|
|
||||||
[
|
|
||||||
(IMPERIAL_SYSTEM, POWER_SENSOR_ATTRIBUTES, "W"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_validate_statistics_supported_device_class_3(
|
|
||||||
hass, hass_ws_client, recorder_mock, units, attributes, unit
|
|
||||||
):
|
|
||||||
"""Test validate_statistics."""
|
|
||||||
id = 1
|
|
||||||
|
|
||||||
def next_id():
|
|
||||||
nonlocal id
|
|
||||||
id += 1
|
|
||||||
return id
|
|
||||||
|
|
||||||
async def assert_validation_result(client, expected_result):
|
|
||||||
await client.send_json(
|
|
||||||
{"id": next_id(), "type": "recorder/validate_statistics"}
|
|
||||||
)
|
|
||||||
response = await client.receive_json()
|
|
||||||
assert response["success"]
|
|
||||||
assert response["result"] == expected_result
|
|
||||||
|
|
||||||
now = dt_util.utcnow()
|
|
||||||
|
|
||||||
hass.config.units = units
|
|
||||||
await async_setup_component(hass, "sensor", {})
|
|
||||||
await async_recorder_block_till_done(hass)
|
|
||||||
client = await hass_ws_client()
|
|
||||||
|
|
||||||
# No statistics, no state - empty response
|
|
||||||
await assert_validation_result(client, {})
|
|
||||||
|
|
||||||
# No statistics, valid state - empty response
|
|
||||||
initial_attributes = {"state_class": "measurement", "unit_of_measurement": "kW"}
|
|
||||||
hass.states.async_set("sensor.test", 10, attributes=initial_attributes)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
await assert_validation_result(client, {})
|
|
||||||
|
|
||||||
# Statistics has run, device class set - expect error
|
|
||||||
do_adhoc_statistics(hass, start=now)
|
|
||||||
await async_recorder_block_till_done(hass)
|
|
||||||
hass.states.async_set("sensor.test", 12, attributes=attributes)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
expected = {
|
|
||||||
"sensor.test": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"device_class": attributes["device_class"],
|
|
||||||
"metadata_unit": "kW",
|
|
||||||
"statistic_id": "sensor.test",
|
|
||||||
"supported_unit": unit,
|
|
||||||
},
|
|
||||||
"type": "unsupported_unit_metadata_can_convert",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
await assert_validation_result(client, expected)
|
|
||||||
|
|
||||||
# Invalid state too, expect double errors
|
|
||||||
hass.states.async_set(
|
|
||||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
|
||||||
)
|
|
||||||
await async_recorder_block_till_done(hass)
|
|
||||||
expected = {
|
|
||||||
"sensor.test": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"device_class": attributes["device_class"],
|
|
||||||
"metadata_unit": "kW",
|
|
||||||
"statistic_id": "sensor.test",
|
|
||||||
"supported_unit": unit,
|
|
||||||
},
|
|
||||||
"type": "unsupported_unit_metadata_can_convert",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"device_class": attributes["device_class"],
|
|
||||||
"state_unit": "dogs",
|
|
||||||
"statistic_id": "sensor.test",
|
|
||||||
},
|
|
||||||
"type": "unsupported_unit_state",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
await assert_validation_result(client, expected)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"units, attributes, unit",
|
"units, attributes, unit",
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user