1
0
mirror of https://github.com/home-assistant/core.git synced 2026-06-06 23:46:56 +01:00

Add derivative tests exhibiting unit issues (#153051)

This commit is contained in:
karwosts
2025-10-14 06:58:14 -07:00
committed by GitHub
parent 7a3630e647
commit a3dec46d59
2 changed files with 149 additions and 0 deletions
@@ -1,14 +1,18 @@
"""Test the Derivative config flow."""
from datetime import timedelta
from unittest.mock import patch
from freezegun import freeze_time
import pytest
from homeassistant import config_entries
from homeassistant.components.derivative.const import DOMAIN
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import selector
from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry, get_schema_suggested_value
@@ -154,3 +158,86 @@ async def test_options(
await hass.async_block_till_done()
state = hass.states.get(f"{platform}.my_derivative")
assert state.attributes["unit_of_measurement"] == "cat/h"
async def test_update_unit(hass: HomeAssistant) -> None:
"""Test behavior of changing the unit_time option."""
# Setup the config entry
source_id = "sensor.source"
config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
"name": "My derivative",
"round": 1.0,
"source": source_id,
"unit_time": "min",
"time_window": {"seconds": 0.0},
},
title="My derivative",
)
derivative_id = "sensor.my_derivative"
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get(derivative_id)
assert state.state == STATE_UNAVAILABLE
assert state.attributes.get("unit_of_measurement") is None
time = dt_util.utcnow()
with freeze_time(time) as freezer:
# First state update of the source.
# Derivative does not learn the unit yet.
hass.states.async_set(source_id, 5, {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(derivative_id)
assert state.state == "0.0"
assert state.attributes.get("unit_of_measurement") is None
# Second state update of the source.
time += timedelta(minutes=1)
freezer.move_to(time)
hass.states.async_set(source_id, "7", {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(derivative_id)
assert state.state == "2.0"
assert state.attributes.get("unit_of_measurement") == "dogs/min"
# Update the unit_time from minutes to seconds.
result = await hass.config_entries.options.async_init(config_entry.entry_id)
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
"source": source_id,
"round": 1.0,
"unit_time": "s",
"time_window": {"seconds": 0.0},
},
)
await hass.async_block_till_done()
# Check the state after reconfigure. Neither unit or state has changed.
state = hass.states.get(derivative_id)
assert state.state == "2.0"
assert state.attributes.get("unit_of_measurement") == "dogs/min"
# Third state update of the source.
time += timedelta(seconds=1)
freezer.move_to(time)
hass.states.async_set(source_id, "10", {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(derivative_id)
assert state.state == "3.0"
# While the state is correctly reporting a state of 3 dogs per second, it incorrectly keeps
# the unit as dogs/min
assert state.attributes.get("unit_of_measurement") == "dogs/min"
# Fourth state update of the source.
time += timedelta(seconds=1)
freezer.move_to(time)
hass.states.async_set(source_id, "20", {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(derivative_id)
assert state.state == "10.0"
assert state.attributes.get("unit_of_measurement") == "dogs/min"
@@ -934,3 +934,65 @@ async def test_unavailable_boot(
assert state is not None
# Now that the source sensor has two valid datapoints, we can calculate derivative
assert state.state == "5.00"
async def test_source_unit_change(
hass: HomeAssistant,
) -> None:
"""Test how derivative responds when the source sensor changes unit."""
source_id = "sensor.source"
config = {
"sensor": {
"platform": "derivative",
"name": "derivative",
"source": source_id,
"unit_time": "s",
}
}
assert await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
entity_id = "sensor.derivative"
state = hass.states.get(entity_id)
assert state.state == STATE_UNAVAILABLE
assert state.attributes.get("unit_of_measurement") is None
time = dt_util.utcnow()
with freeze_time(time) as freezer:
# First state update of the source.
# Derivative does not learn the UoM yet.
hass.states.async_set(source_id, "5", {"unit_of_measurement": "cats"})
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "0.000"
assert state.attributes.get("unit_of_measurement") is None
# Second state update of the source.
time += timedelta(seconds=1)
freezer.move_to(time)
hass.states.async_set(source_id, "7", {"unit_of_measurement": "cats"})
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "2.000"
assert state.attributes.get("unit_of_measurement") == "cats/s"
# Third state update of the source, source unit changes to dogs.
# Ignored by derivative which continues reporting cats.
time += timedelta(seconds=1)
freezer.move_to(time)
hass.states.async_set(source_id, "12", {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "5.000"
assert state.attributes.get("unit_of_measurement") == "cats/s"
# Fourth state update of the source, still dogs.
# Ignored by derivative which continues reporting cats.
time += timedelta(seconds=1)
freezer.move_to(time)
hass.states.async_set(source_id, "20", {"unit_of_measurement": "dogs"})
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == "8.000"
assert state.attributes.get("unit_of_measurement") == "cats/s"