forked from home-assistant/core
Warn if a sensor with state_class_total has a decreasing value (#55197)
This commit is contained in:
@ -298,7 +298,12 @@ class EnergyCostSensor(SensorEntity):
|
||||
)
|
||||
return
|
||||
|
||||
if reset_detected(energy, float(self._last_energy_sensor_state)):
|
||||
if reset_detected(
|
||||
self.hass,
|
||||
cast(str, self._config[self._adapter.entity_energy_key]),
|
||||
energy,
|
||||
float(self._last_energy_sensor_state),
|
||||
):
|
||||
# Energy meter was reset, reset cost sensor too
|
||||
self._reset(0)
|
||||
# Update with newly incurred cost
|
||||
|
@ -39,6 +39,7 @@ from homeassistant.const import (
|
||||
VOLUME_CUBIC_METERS,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.helpers.entity import entity_sources
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.util.pressure as pressure_util
|
||||
import homeassistant.util.temperature as temperature_util
|
||||
@ -106,6 +107,8 @@ UNIT_CONVERSIONS: dict[str, dict[str, Callable]] = {
|
||||
},
|
||||
}
|
||||
|
||||
# Keep track of entities for which a warning about decreasing value has been logged
|
||||
WARN_DIP = "sensor_warn_total_increasing_dip"
|
||||
# Keep track of entities for which a warning about unsupported unit has been logged
|
||||
WARN_UNSUPPORTED_UNIT = "sensor_warn_unsupported_unit"
|
||||
WARN_UNSTABLE_UNIT = "sensor_warn_unstable_unit"
|
||||
@ -229,9 +232,36 @@ def _normalize_states(
|
||||
return DEVICE_CLASS_UNITS[device_class], fstates
|
||||
|
||||
|
||||
def reset_detected(state: float, previous_state: float | None) -> bool:
|
||||
def warn_dip(hass: HomeAssistant, entity_id: str) -> None:
|
||||
"""Log a warning once if a sensor with state_class_total has a decreasing value."""
|
||||
if WARN_DIP not in hass.data:
|
||||
hass.data[WARN_DIP] = set()
|
||||
if entity_id not in hass.data[WARN_DIP]:
|
||||
hass.data[WARN_DIP].add(entity_id)
|
||||
domain = entity_sources(hass).get(entity_id, {}).get("domain")
|
||||
if domain in ["energy", "growatt_server", "solaredge"]:
|
||||
return
|
||||
_LOGGER.warning(
|
||||
"Entity %s %shas state class total_increasing, but its state is "
|
||||
"not strictly increasing. Please create a bug report at %s",
|
||||
entity_id,
|
||||
f"from integration {domain} " if domain else "",
|
||||
"https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue"
|
||||
"+label%3A%22integration%3A+recorder%22",
|
||||
)
|
||||
|
||||
|
||||
def reset_detected(
|
||||
hass: HomeAssistant, entity_id: str, state: float, previous_state: float | None
|
||||
) -> bool:
|
||||
"""Test if a total_increasing sensor has been reset."""
|
||||
return previous_state is not None and state < 0.9 * previous_state
|
||||
if previous_state is None:
|
||||
return False
|
||||
|
||||
if 0.9 * previous_state <= state < previous_state:
|
||||
warn_dip(hass, entity_id)
|
||||
|
||||
return state < 0.9 * previous_state
|
||||
|
||||
|
||||
def compile_statistics(
|
||||
@ -337,7 +367,8 @@ def compile_statistics(
|
||||
fstate,
|
||||
)
|
||||
elif state_class == STATE_CLASS_TOTAL_INCREASING and (
|
||||
old_state is None or reset_detected(fstate, new_state)
|
||||
old_state is None
|
||||
or reset_detected(hass, entity_id, fstate, new_state)
|
||||
):
|
||||
reset = True
|
||||
_LOGGER.info(
|
||||
|
@ -427,6 +427,12 @@ def test_compile_hourly_sum_statistics_total_increasing_small_dip(
|
||||
]
|
||||
}
|
||||
assert "Error while processing event StatisticsTask" not in caplog.text
|
||||
assert (
|
||||
"Entity sensor.test1 has state class total_increasing, but its state is not "
|
||||
"strictly increasing. Please create a bug report at https://github.com/"
|
||||
"home-assistant/core/issues?q=is%3Aopen+is%3Aissue+label%3A%22integration%3A"
|
||||
"+recorder%22"
|
||||
) in caplog.text
|
||||
|
||||
|
||||
def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog):
|
||||
|
Reference in New Issue
Block a user