Keep storing statistics for sensors which change device class (#79155)
This commit is contained in:
parent
a561b608bf
commit
9084beda32
2 changed files with 90 additions and 11 deletions
|
@ -156,10 +156,16 @@ def _normalize_states(
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
) -> tuple[str | None, str | None, list[tuple[float, State]]]:
|
) -> tuple[str | None, str | None, list[tuple[float, State]]]:
|
||||||
"""Normalize units."""
|
"""Normalize units."""
|
||||||
|
old_metadata = old_metadatas[entity_id][1] if entity_id in old_metadatas else None
|
||||||
state_unit: str | None = None
|
state_unit: str | None = None
|
||||||
|
|
||||||
if device_class not in UNIT_CONVERTERS:
|
if device_class not in UNIT_CONVERTERS or (
|
||||||
# We're not normalizing this device class, return the state as they are
|
old_metadata
|
||||||
|
and old_metadata["unit_of_measurement"]
|
||||||
|
!= UNIT_CONVERTERS[device_class].NORMALIZED_UNIT
|
||||||
|
):
|
||||||
|
# We're either not normalizing this device class or this entity is not stored
|
||||||
|
# normalized, return the states as they are
|
||||||
fstates = []
|
fstates = []
|
||||||
for state in entity_history:
|
for state in entity_history:
|
||||||
try:
|
try:
|
||||||
|
@ -176,10 +182,10 @@ def _normalize_states(
|
||||||
if entity_id not in hass.data[WARN_UNSTABLE_UNIT]:
|
if entity_id not in hass.data[WARN_UNSTABLE_UNIT]:
|
||||||
hass.data[WARN_UNSTABLE_UNIT].add(entity_id)
|
hass.data[WARN_UNSTABLE_UNIT].add(entity_id)
|
||||||
extra = ""
|
extra = ""
|
||||||
if old_metadata := old_metadatas.get(entity_id):
|
if old_metadata:
|
||||||
extra = (
|
extra = (
|
||||||
" and matches the unit of already compiled statistics "
|
" and matches the unit of already compiled statistics "
|
||||||
f"({old_metadata[1]['unit_of_measurement']})"
|
f"({old_metadata['unit_of_measurement']})"
|
||||||
)
|
)
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"The unit of %s is changing, got multiple %s, generation of long term "
|
"The unit of %s is changing, got multiple %s, generation of long term "
|
||||||
|
|
|
@ -2142,9 +2142,9 @@ def test_compile_hourly_statistics_changing_units_3(
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device_class, state_unit, statistic_unit, unit_class, mean, min, max",
|
"device_class, state_unit, statistic_unit, unit_class, mean1, mean2, min, max",
|
||||||
[
|
[
|
||||||
("power", "kW", "W", None, 13.050847, -10, 30),
|
("power", "kW", "W", None, 13.050847, 13.333333, -10, 30),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_compile_hourly_statistics_changing_device_class_1(
|
def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
|
@ -2154,7 +2154,8 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
state_unit,
|
state_unit,
|
||||||
statistic_unit,
|
statistic_unit,
|
||||||
unit_class,
|
unit_class,
|
||||||
mean,
|
mean1,
|
||||||
|
mean2,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
):
|
):
|
||||||
|
@ -2194,7 +2195,7 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
"statistic_id": "sensor.test1",
|
"statistic_id": "sensor.test1",
|
||||||
"start": process_timestamp_to_utc_isoformat(zero),
|
"start": process_timestamp_to_utc_isoformat(zero),
|
||||||
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=5)),
|
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=5)),
|
||||||
"mean": approx(mean),
|
"mean": approx(mean1),
|
||||||
"min": approx(min),
|
"min": approx(min),
|
||||||
"max": approx(max),
|
"max": approx(max),
|
||||||
"last_reset": None,
|
"last_reset": None,
|
||||||
|
@ -2204,7 +2205,7 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update device class and record additional states
|
# Update device class and record additional states in the original UoM
|
||||||
attributes["device_class"] = device_class
|
attributes["device_class"] = device_class
|
||||||
four, _states = record_states(
|
four, _states = record_states(
|
||||||
hass, zero + timedelta(minutes=5), "sensor.test1", attributes
|
hass, zero + timedelta(minutes=5), "sensor.test1", attributes
|
||||||
|
@ -2220,6 +2221,65 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
# Run statistics again, we get a warning, and no additional statistics is generated
|
# Run statistics again, we get a warning, and no 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)
|
||||||
|
assert statistic_ids == [
|
||||||
|
{
|
||||||
|
"statistic_id": "sensor.test1",
|
||||||
|
"display_unit_of_measurement": state_unit,
|
||||||
|
"has_mean": True,
|
||||||
|
"has_sum": False,
|
||||||
|
"name": None,
|
||||||
|
"source": "recorder",
|
||||||
|
"statistics_unit_of_measurement": state_unit,
|
||||||
|
"unit_class": unit_class,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
stats = statistics_during_period(hass, zero, period="5minute")
|
||||||
|
assert stats == {
|
||||||
|
"sensor.test1": [
|
||||||
|
{
|
||||||
|
"statistic_id": "sensor.test1",
|
||||||
|
"start": process_timestamp_to_utc_isoformat(zero),
|
||||||
|
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=5)),
|
||||||
|
"mean": approx(mean1),
|
||||||
|
"min": approx(min),
|
||||||
|
"max": approx(max),
|
||||||
|
"last_reset": None,
|
||||||
|
"state": 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,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update device class and record additional states in a different UoM
|
||||||
|
attributes["unit_of_measurement"] = statistic_unit
|
||||||
|
four, _states = record_states(
|
||||||
|
hass, zero + timedelta(minutes=15), "sensor.test1", attributes
|
||||||
|
)
|
||||||
|
states["sensor.test1"] += _states["sensor.test1"]
|
||||||
|
four, _states = record_states(
|
||||||
|
hass, zero + timedelta(minutes=20), "sensor.test1", attributes
|
||||||
|
)
|
||||||
|
states["sensor.test1"] += _states["sensor.test1"]
|
||||||
|
hist = history.get_significant_states(hass, zero, four)
|
||||||
|
assert dict(states) == dict(hist)
|
||||||
|
|
||||||
|
# Run statistics again, we get a warning, and no additional statistics is generated
|
||||||
|
do_adhoc_statistics(hass, start=zero + timedelta(minutes=20))
|
||||||
|
wait_recording_done(hass)
|
||||||
assert (
|
assert (
|
||||||
f"The normalized unit of sensor.test1 ({statistic_unit}) does not match the "
|
f"The normalized unit of sensor.test1 ({statistic_unit}) does not match the "
|
||||||
f"unit of already compiled statistics ({state_unit})" in caplog.text
|
f"unit of already compiled statistics ({state_unit})" in caplog.text
|
||||||
|
@ -2244,13 +2304,26 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||||
"statistic_id": "sensor.test1",
|
"statistic_id": "sensor.test1",
|
||||||
"start": process_timestamp_to_utc_isoformat(zero),
|
"start": process_timestamp_to_utc_isoformat(zero),
|
||||||
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=5)),
|
"end": process_timestamp_to_utc_isoformat(zero + timedelta(minutes=5)),
|
||||||
"mean": approx(mean),
|
"mean": approx(mean1),
|
||||||
"min": approx(min),
|
"min": approx(min),
|
||||||
"max": approx(max),
|
"max": approx(max),
|
||||||
"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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue