mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Ignore negative derivative when the input is total_increasing (#119141)
* if the derivative is negative, ignore it * add option to ignore the negatives or not * add tests for a new ignore negative derivative * add missing description when editing * rename to ignore_negative_derivative to increase clarity of which negative I mean in case in the future we want a ignore_negative_value... * use state_class=total_increasing to ignore the negative derivative * remove ignore negative from the config * add test for total_increasing_reset case * add comments * update test_total_increasing_reset with history tests Also remove the last comment because the test is already clear My existing comment there isn't unique to this unit test but applies to the entire component. The existing web documentation pointing to Wikipedia should suffice. --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
c77a3674b0
commit
156a88a3a3
@ -10,9 +10,11 @@ from typing import TYPE_CHECKING
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
|
ATTR_STATE_CLASS,
|
||||||
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
||||||
RestoreSensor,
|
RestoreSensor,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -238,6 +240,16 @@ class DerivativeSensor(RestoreSensor, SensorEntity):
|
|||||||
except AssertionError as err:
|
except AssertionError as err:
|
||||||
_LOGGER.error("Could not calculate derivative: %s", err)
|
_LOGGER.error("Could not calculate derivative: %s", err)
|
||||||
|
|
||||||
|
# For total inreasing sensors, the value is expected to continuously increase.
|
||||||
|
# A negative derivative for a total increasing sensor likely indicates the
|
||||||
|
# sensor has been reset. To prevent inaccurate data, discard this sample.
|
||||||
|
if (
|
||||||
|
new_state.attributes.get(ATTR_STATE_CLASS)
|
||||||
|
== SensorStateClass.TOTAL_INCREASING
|
||||||
|
and new_derivative < 0
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
# add latest derivative to the window list
|
# add latest derivative to the window list
|
||||||
self._state_list.append(
|
self._state_list.append(
|
||||||
(old_state.last_updated, new_state.last_updated, new_derivative)
|
(old_state.last_updated, new_state.last_updated, new_derivative)
|
||||||
|
@ -8,6 +8,7 @@ from typing import Any
|
|||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from homeassistant.components.derivative.const import DOMAIN
|
from homeassistant.components.derivative.const import DOMAIN
|
||||||
|
from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorStateClass
|
||||||
from homeassistant.const import UnitOfPower, UnitOfTime
|
from homeassistant.const import UnitOfPower, UnitOfTime
|
||||||
from homeassistant.core import HomeAssistant, State
|
from homeassistant.core import HomeAssistant, State
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
@ -354,6 +355,41 @@ async def test_suffix(hass: HomeAssistant) -> None:
|
|||||||
assert round(float(state.state), config["sensor"]["round"]) == 0.0
|
assert round(float(state.state), config["sensor"]["round"]) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_total_increasing_reset(hass: HomeAssistant) -> None:
|
||||||
|
"""Test derivative sensor state with total_increasing sensor input where it should ignore the reset value."""
|
||||||
|
times = [0, 20, 30, 35, 40, 50, 60]
|
||||||
|
values = [0, 10, 30, 40, 0, 10, 40]
|
||||||
|
expected_times = [0, 20, 30, 35, 50, 60]
|
||||||
|
expected_values = ["0.00", "0.50", "2.00", "2.00", "1.00", "3.00"]
|
||||||
|
|
||||||
|
config, entity_id = await _setup_sensor(hass, {"unit_time": UnitOfTime.SECONDS})
|
||||||
|
|
||||||
|
base_time = dt_util.utcnow()
|
||||||
|
actual_times = []
|
||||||
|
actual_values = []
|
||||||
|
with freeze_time(base_time) as freezer:
|
||||||
|
for time, value in zip(times, values, strict=False):
|
||||||
|
current_time = base_time + timedelta(seconds=time)
|
||||||
|
freezer.move_to(current_time)
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
value,
|
||||||
|
{ATTR_STATE_CLASS: SensorStateClass.TOTAL_INCREASING},
|
||||||
|
force_update=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.power")
|
||||||
|
assert state is not None
|
||||||
|
|
||||||
|
if state.last_reported == current_time:
|
||||||
|
actual_times.append(time)
|
||||||
|
actual_values.append(state.state)
|
||||||
|
|
||||||
|
assert actual_times == expected_times
|
||||||
|
assert actual_values == expected_values
|
||||||
|
|
||||||
|
|
||||||
async def test_device_id(
|
async def test_device_id(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_registry: er.EntityRegistry,
|
entity_registry: er.EntityRegistry,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user