forked from home-assistant/core
Compare commits
2 Commits
bump-openc
...
sensor_num
Author | SHA1 | Date | |
---|---|---|---|
2f608d8650 | |||
65324431a4 |
@ -62,6 +62,7 @@ from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import ( # noqa: F401
|
||||
ATTR_LAST_RESET,
|
||||
ATTR_NUMERICAL_VALUE,
|
||||
ATTR_OPTIONS,
|
||||
ATTR_STATE_CLASS,
|
||||
CONF_STATE_CLASS,
|
||||
@ -167,6 +168,7 @@ class SensorEntity(Entity):
|
||||
_last_reset_reported = False
|
||||
_sensor_option_precision: int | None = None
|
||||
_sensor_option_unit_of_measurement: str | None | UndefinedType = UNDEFINED
|
||||
__numerical_value: int | float | None = None
|
||||
|
||||
@callback
|
||||
def add_to_platform_start(
|
||||
@ -312,6 +314,7 @@ class SensorEntity(Entity):
|
||||
@property
|
||||
def state_attributes(self) -> dict[str, Any] | None:
|
||||
"""Return state attributes."""
|
||||
attrs: dict[str, Any] = {}
|
||||
if last_reset := self.last_reset:
|
||||
if (
|
||||
self.state_class != SensorStateClass.TOTAL
|
||||
@ -334,9 +337,11 @@ class SensorEntity(Entity):
|
||||
)
|
||||
|
||||
if self.state_class == SensorStateClass.TOTAL:
|
||||
return {ATTR_LAST_RESET: last_reset.isoformat()}
|
||||
attrs[ATTR_LAST_RESET] = last_reset.isoformat()
|
||||
if (numerical_value := self.__numerical_value) is not None:
|
||||
attrs[ATTR_NUMERICAL_VALUE] = numerical_value
|
||||
|
||||
return None
|
||||
return attrs
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType | date | datetime | Decimal:
|
||||
@ -461,6 +466,7 @@ class SensorEntity(Entity):
|
||||
@property
|
||||
def state(self) -> Any: # noqa: C901
|
||||
"""Return the state of the sensor and perform unit conversions, if needed."""
|
||||
self.__numerical_value = None
|
||||
native_unit_of_measurement = self.native_unit_of_measurement
|
||||
unit_of_measurement = self.unit_of_measurement
|
||||
value = self.native_value
|
||||
@ -581,8 +587,8 @@ class SensorEntity(Entity):
|
||||
return value
|
||||
|
||||
# From here on a numerical value is expected
|
||||
numerical_value: int | float | Decimal
|
||||
if not isinstance(value, (int, float, Decimal)):
|
||||
numerical_value: int | float
|
||||
if not isinstance(value, (int, float)):
|
||||
try:
|
||||
if isinstance(value, str) and "." not in value:
|
||||
numerical_value = int(value)
|
||||
@ -645,12 +651,12 @@ class SensorEntity(Entity):
|
||||
)
|
||||
precision = precision + floor(ratio_log)
|
||||
|
||||
converted_numerical_value = converter.convert(
|
||||
numerical_value = converter.convert(
|
||||
float(numerical_value),
|
||||
native_unit_of_measurement,
|
||||
unit_of_measurement,
|
||||
)
|
||||
value = f"{converted_numerical_value:.{precision}f}"
|
||||
value = f"{numerical_value:.{precision}f}"
|
||||
# This can be replaced with adding the z option when we drop support for
|
||||
# Python 3.10
|
||||
value = NEGATIVE_ZERO_PATTERN.sub(r"\1", value)
|
||||
@ -660,6 +666,8 @@ class SensorEntity(Entity):
|
||||
# Python 3.10
|
||||
value = NEGATIVE_ZERO_PATTERN.sub(r"\1", value)
|
||||
|
||||
self.__numerical_value = numerical_value
|
||||
|
||||
# Validate unit of measurement used for sensors with a device class
|
||||
if (
|
||||
not self._invalid_unit_of_measurement_reported
|
||||
|
@ -55,6 +55,7 @@ DOMAIN: Final = "sensor"
|
||||
CONF_STATE_CLASS: Final = "state_class"
|
||||
|
||||
ATTR_LAST_RESET: Final = "last_reset"
|
||||
ATTR_NUMERICAL_VALUE: Final = "numerical_value"
|
||||
ATTR_STATE_CLASS: Final = "state_class"
|
||||
ATTR_OPTIONS: Final = "options"
|
||||
|
||||
|
@ -6,7 +6,6 @@ from collections.abc import Iterable, MutableMapping
|
||||
import datetime
|
||||
import itertools
|
||||
import logging
|
||||
import math
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm.session import Session
|
||||
@ -37,6 +36,7 @@ from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import (
|
||||
ATTR_LAST_RESET,
|
||||
ATTR_NUMERICAL_VALUE,
|
||||
ATTR_OPTIONS,
|
||||
ATTR_STATE_CLASS,
|
||||
DOMAIN,
|
||||
@ -142,14 +142,6 @@ def _equivalent_units(units: set[str | None]) -> bool:
|
||||
return len(units) == 1
|
||||
|
||||
|
||||
def _parse_float(state: str) -> float:
|
||||
"""Parse a float string, throw on inf or nan."""
|
||||
fstate = float(state)
|
||||
if math.isnan(fstate) or math.isinf(fstate):
|
||||
raise ValueError
|
||||
return fstate
|
||||
|
||||
|
||||
def _normalize_states(
|
||||
hass: HomeAssistant,
|
||||
session: Session,
|
||||
@ -163,9 +155,7 @@ def _normalize_states(
|
||||
|
||||
fstates: list[tuple[float, State]] = []
|
||||
for state in entity_history:
|
||||
try:
|
||||
fstate = _parse_float(state.state)
|
||||
except (ValueError, TypeError): # TypeError to guard for NULL state in DB
|
||||
if (fstate := state.attributes.get(ATTR_NUMERICAL_VALUE)) is None:
|
||||
continue
|
||||
fstates.append((fstate, state))
|
||||
|
||||
@ -298,7 +288,7 @@ def warn_dip(
|
||||
),
|
||||
entity_id,
|
||||
f"from integration {domain} " if domain else "",
|
||||
state.state,
|
||||
state.attributes[ATTR_NUMERICAL_VALUE],
|
||||
previous_fstate,
|
||||
state.last_updated.isoformat(),
|
||||
_suggest_report_issue(hass, entity_id),
|
||||
@ -319,7 +309,7 @@ def warn_negative(hass: HomeAssistant, entity_id: str, state: State) -> None:
|
||||
),
|
||||
entity_id,
|
||||
f"from integration {domain} " if domain else "",
|
||||
state.state,
|
||||
state.attributes[ATTR_NUMERICAL_VALUE],
|
||||
state.last_updated.isoformat(),
|
||||
_suggest_report_issue(hass, entity_id),
|
||||
)
|
||||
@ -424,6 +414,7 @@ def _compile_statistics( # noqa: C901
|
||||
start - datetime.timedelta.resolution,
|
||||
end,
|
||||
entity_ids=entities_significant_history,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
history_list = {**history_list, **_history_list}
|
||||
# If there are no recent state changes, the sensor's state may already be pruned
|
||||
|
@ -55,7 +55,9 @@ def test_compile_hourly_statistics(hass_recorder):
|
||||
instance = recorder.get_instance(hass)
|
||||
setup_component(hass, "sensor", {})
|
||||
zero, four, states = record_states(hass)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
# Should not fail if there is nothing there yet
|
||||
@ -316,7 +318,9 @@ def test_rename_entity(hass_recorder):
|
||||
hass.block_till_done()
|
||||
|
||||
zero, four, states = record_states(hass)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}):
|
||||
@ -382,7 +386,9 @@ def test_rename_entity_collision(hass_recorder, caplog):
|
||||
hass.block_till_done()
|
||||
|
||||
zero, four, states = record_states(hass)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}):
|
||||
@ -447,7 +453,9 @@ def test_statistics_duplicated(hass_recorder, caplog):
|
||||
hass = hass_recorder()
|
||||
setup_component(hass, "sensor", {})
|
||||
zero, four, states = record_states(hass)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
wait_recording_done(hass)
|
||||
@ -1709,6 +1717,14 @@ def record_states(hass):
|
||||
wait_recording_done(hass)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
def set_sensor_state(entity_id, numerical_value, attributes):
|
||||
"""Set the state."""
|
||||
hass.states.set(
|
||||
entity_id, "", attributes={**attributes, "numerical_value": numerical_value}
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
zero = dt_util.utcnow()
|
||||
one = zero + timedelta(seconds=1 * 5)
|
||||
two = one + timedelta(seconds=15 * 5)
|
||||
@ -1725,25 +1741,25 @@ def record_states(hass):
|
||||
states[mp].append(
|
||||
set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt2)})
|
||||
)
|
||||
states[sns1].append(set_state(sns1, "10", attributes=sns1_attr))
|
||||
states[sns2].append(set_state(sns2, "10", attributes=sns2_attr))
|
||||
states[sns3].append(set_state(sns3, "10", attributes=sns3_attr))
|
||||
states[sns4].append(set_state(sns4, "10", attributes=sns4_attr))
|
||||
states[sns1].append(set_sensor_state(sns1, 10, attributes=sns1_attr))
|
||||
states[sns2].append(set_sensor_state(sns2, 10, attributes=sns2_attr))
|
||||
states[sns3].append(set_sensor_state(sns3, 10, attributes=sns3_attr))
|
||||
states[sns4].append(set_sensor_state(sns4, 10, attributes=sns4_attr))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.core.dt_util.utcnow", return_value=two
|
||||
):
|
||||
states[sns1].append(set_state(sns1, "15", attributes=sns1_attr))
|
||||
states[sns2].append(set_state(sns2, "15", attributes=sns2_attr))
|
||||
states[sns3].append(set_state(sns3, "15", attributes=sns3_attr))
|
||||
states[sns4].append(set_state(sns4, "15", attributes=sns4_attr))
|
||||
states[sns1].append(set_sensor_state(sns1, 15, attributes=sns1_attr))
|
||||
states[sns2].append(set_sensor_state(sns2, 15, attributes=sns2_attr))
|
||||
states[sns3].append(set_sensor_state(sns3, 15, attributes=sns3_attr))
|
||||
states[sns4].append(set_sensor_state(sns4, 15, attributes=sns4_attr))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.core.dt_util.utcnow", return_value=three
|
||||
):
|
||||
states[sns1].append(set_state(sns1, "20", attributes=sns1_attr))
|
||||
states[sns2].append(set_state(sns2, "20", attributes=sns2_attr))
|
||||
states[sns3].append(set_state(sns3, "20", attributes=sns3_attr))
|
||||
states[sns4].append(set_state(sns4, "20", attributes=sns4_attr))
|
||||
states[sns1].append(set_sensor_state(sns1, 20, attributes=sns1_attr))
|
||||
states[sns2].append(set_sensor_state(sns2, 20, attributes=sns2_attr))
|
||||
states[sns3].append(set_sensor_state(sns3, 20, attributes=sns3_attr))
|
||||
states[sns4].append(set_sensor_state(sns4, 20, attributes=sns4_attr))
|
||||
|
||||
return zero, four, states
|
||||
|
@ -17,6 +17,7 @@ from homeassistant.components.recorder.statistics import (
|
||||
get_metadata,
|
||||
list_statistic_ids,
|
||||
)
|
||||
from homeassistant.components.sensor.const import ATTR_NUMERICAL_VALUE
|
||||
from homeassistant.helpers import recorder as recorder_helper
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -131,7 +132,11 @@ async def test_statistics_during_period(recorder_mock, hass, hass_ws_client):
|
||||
hass.config.units = US_CUSTOMARY_SYSTEM
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", 10, attributes=POWER_SENSOR_KW_ATTRIBUTES)
|
||||
hass.states.async_set(
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=POWER_SENSOR_KW_ATTRIBUTES | {ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
@ -892,7 +897,9 @@ async def test_statistics_during_period_unit_conversion(
|
||||
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", state, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
@ -983,8 +990,12 @@ async def test_sum_statistics_during_period_unit_conversion(
|
||||
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", 0, attributes=attributes)
|
||||
hass.states.async_set("sensor.test", state, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 0}
|
||||
)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
@ -1112,7 +1123,11 @@ async def test_statistics_during_period_in_the_past(
|
||||
past = now - timedelta(days=3)
|
||||
|
||||
with freeze_time(past):
|
||||
hass.states.async_set("sensor.test", 10, attributes=POWER_SENSOR_KW_ATTRIBUTES)
|
||||
hass.states.async_set(
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=POWER_SENSOR_KW_ATTRIBUTES | {ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
sensor_state = hass.states.get("sensor.test")
|
||||
@ -1340,7 +1355,9 @@ async def test_list_statistic_ids(
|
||||
assert response["success"]
|
||||
assert response["result"] == []
|
||||
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
await client.send_json({"id": 2, "type": "recorder/list_statistic_ids"})
|
||||
@ -1503,7 +1520,9 @@ async def test_list_statistic_ids_unit_change(
|
||||
assert response["success"]
|
||||
assert response["result"] == []
|
||||
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
@ -1526,7 +1545,9 @@ async def test_list_statistic_ids_unit_change(
|
||||
]
|
||||
|
||||
# Change the state unit
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes2)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes2 | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
|
||||
await client.send_json({"id": 3, "type": "recorder/list_statistic_ids"})
|
||||
response = await client.receive_json()
|
||||
@ -1579,9 +1600,15 @@ async def test_clear_statistics(recorder_mock, hass, hass_ws_client):
|
||||
hass.config.units = units
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test1", state, attributes=attributes)
|
||||
hass.states.async_set("sensor.test2", state * 2, attributes=attributes)
|
||||
hass.states.async_set("sensor.test3", state * 3, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test1", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
hass.states.async_set(
|
||||
"sensor.test2", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state * 2}
|
||||
)
|
||||
hass.states.async_set(
|
||||
"sensor.test3", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state * 3}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
@ -1704,7 +1731,9 @@ async def test_update_statistics_metadata(
|
||||
hass.config.units = units
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", state, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, period="hourly", start=now)
|
||||
@ -1795,7 +1824,9 @@ async def test_change_statistics_unit(recorder_mock, hass, hass_ws_client):
|
||||
hass.config.units = units
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", state, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, period="hourly", start=now)
|
||||
@ -1968,7 +1999,9 @@ async def test_change_statistics_unit_errors(
|
||||
hass.config.units = units
|
||||
await async_setup_component(hass, "sensor", {})
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set("sensor.test", state, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: state}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
do_adhoc_statistics(hass, period="hourly", start=now)
|
||||
@ -2311,10 +2344,14 @@ async def test_get_statistics_metadata(
|
||||
}
|
||||
]
|
||||
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
hass.states.async_set("sensor.test2", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test2", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
await client.send_json(
|
||||
|
@ -25,7 +25,11 @@ from homeassistant.components.recorder.statistics import (
|
||||
list_statistic_ids,
|
||||
)
|
||||
from homeassistant.components.recorder.util import get_instance, session_scope
|
||||
from homeassistant.components.sensor import ATTR_OPTIONS, DOMAIN
|
||||
from homeassistant.components.sensor.const import (
|
||||
ATTR_NUMERICAL_VALUE,
|
||||
ATTR_OPTIONS,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.setup import async_setup_component, setup_component
|
||||
@ -140,7 +144,9 @@ def test_compile_hourly_statistics(
|
||||
"unit_of_measurement": state_unit,
|
||||
}
|
||||
four, states = record_states(hass, zero, "sensor.test1", attributes)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -202,10 +208,12 @@ def test_compile_hourly_statistics_purged_state_changes(
|
||||
"unit_of_measurement": state_unit,
|
||||
}
|
||||
four, states = record_states(hass, zero, "sensor.test1", attributes)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
mean = min = max = float(hist["sensor.test1"][-1].state)
|
||||
mean = min = max = hist["sensor.test1"][-1].attributes[ATTR_NUMERICAL_VALUE]
|
||||
|
||||
# Purge all states from the database
|
||||
with patch(
|
||||
@ -214,7 +222,9 @@ def test_compile_hourly_statistics_purged_state_changes(
|
||||
hass.services.call("recorder", "purge", {"keep_days": 0})
|
||||
hass.block_till_done()
|
||||
wait_recording_done(hass)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert not hist
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -283,7 +293,9 @@ def test_compile_hourly_statistics_wrong_unit(hass_recorder, caplog, attributes)
|
||||
_, _states = record_states(hass, zero, "sensor.test7", attributes_tmp)
|
||||
states = {**states, **_states}
|
||||
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -474,7 +486,10 @@ async def test_compile_hourly_sum_statistics_amount(
|
||||
)
|
||||
await async_wait_recording_done(hass)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -857,6 +872,11 @@ def test_compile_hourly_sum_statistics_nan_inf_state(
|
||||
one + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
# Recorder will record state attributes with nan and inf replaced with null
|
||||
for state in states["sensor.test1"]:
|
||||
if not math.isfinite(state.attributes[ATTR_NUMERICAL_VALUE]):
|
||||
state.attributes = state.attributes | {ATTR_NUMERICAL_VALUE: None}
|
||||
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
)
|
||||
@ -1019,7 +1039,7 @@ def test_compile_hourly_sum_statistics_negative_state(
|
||||
},
|
||||
]
|
||||
assert "Error while processing event StatisticsTask" not in caplog.text
|
||||
state = states[entity_id][offending_state].state
|
||||
state = states[entity_id][offending_state].attributes[ATTR_NUMERICAL_VALUE]
|
||||
last_updated = states[entity_id][offending_state].last_updated.isoformat()
|
||||
assert (
|
||||
f"Entity {entity_id} {warning_1}has state class total_increasing, but its state "
|
||||
@ -1070,7 +1090,10 @@ def test_compile_hourly_sum_statistics_total_no_reset(
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -1172,7 +1195,10 @@ def test_compile_hourly_sum_statistics_total_increasing(
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -1272,7 +1298,10 @@ def test_compile_hourly_sum_statistics_total_increasing_small_dip(
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -1288,8 +1317,8 @@ def test_compile_hourly_sum_statistics_total_increasing_small_dip(
|
||||
) not in caplog.text
|
||||
do_adhoc_statistics(hass, start=period2)
|
||||
wait_recording_done(hass)
|
||||
state = states["sensor.test1"][6].state
|
||||
previous_state = float(states["sensor.test1"][5].state)
|
||||
state = states["sensor.test1"][6].attributes[ATTR_NUMERICAL_VALUE]
|
||||
previous_state = float(states["sensor.test1"][5].attributes[ATTR_NUMERICAL_VALUE])
|
||||
last_updated = states["sensor.test1"][6].last_updated.isoformat()
|
||||
assert (
|
||||
"Entity sensor.test1 has state class total_increasing, but its state is not "
|
||||
@ -1379,7 +1408,10 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog):
|
||||
wait_recording_done(hass)
|
||||
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -1471,7 +1503,10 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog):
|
||||
states = {**states, **_states}
|
||||
wait_recording_done(hass)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0 - timedelta.resolution, eight + timedelta.resolution
|
||||
hass,
|
||||
period0 - timedelta.resolution,
|
||||
eight + timedelta.resolution,
|
||||
significant_changes_only=False,
|
||||
)
|
||||
assert_multiple_states_equal_without_context_and_last_changed(
|
||||
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
|
||||
@ -1656,7 +1691,9 @@ def test_compile_hourly_statistics_unchanged(
|
||||
"unit_of_measurement": state_unit,
|
||||
}
|
||||
four, states = record_states(hass, zero, "sensor.test1", attributes)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=four)
|
||||
@ -1688,7 +1725,9 @@ def test_compile_hourly_statistics_partially_unavailable(hass_recorder, caplog):
|
||||
four, states = record_states_partially_unavailable(
|
||||
hass, zero, "sensor.test1", TEMPERATURE_SENSOR_ATTRIBUTES
|
||||
)
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -1757,7 +1796,9 @@ def test_compile_hourly_statistics_unavailable(
|
||||
)
|
||||
_, _states = record_states(hass, zero, "sensor.test2", attributes)
|
||||
states = {**states, **_states}
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=four)
|
||||
@ -1965,7 +2006,9 @@ def test_compile_hourly_statistics_changing_units_1(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -2075,7 +2118,9 @@ def test_compile_hourly_statistics_changing_units_2(
|
||||
hass, zero + timedelta(minutes=5), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5))
|
||||
@ -2143,7 +2188,9 @@ def test_compile_hourly_statistics_changing_units_3(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -2291,7 +2338,9 @@ def test_compile_hourly_statistics_convert_units_1(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
|
||||
wait_recording_done(hass)
|
||||
@ -2383,7 +2432,9 @@ def test_compile_hourly_statistics_equivalent_units_1(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero)
|
||||
@ -2497,7 +2548,9 @@ def test_compile_hourly_statistics_equivalent_units_2(
|
||||
hass, zero + timedelta(minutes=5), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5))
|
||||
@ -2612,7 +2665,9 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
# Run statistics again, additional statistics is generated
|
||||
@ -2667,7 +2722,9 @@ def test_compile_hourly_statistics_changing_device_class_1(
|
||||
hass, zero + timedelta(minutes=20), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
# Run statistics again, additional statistics is generated
|
||||
@ -2802,7 +2859,9 @@ def test_compile_hourly_statistics_changing_device_class_2(
|
||||
hass, zero + timedelta(minutes=10), "sensor.test1", attributes
|
||||
)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, zero, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, zero, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
# Run statistics again, additional statistics is generated
|
||||
@ -2918,7 +2977,9 @@ def test_compile_hourly_statistics_changing_state_class(
|
||||
# Add more states, with changed state class
|
||||
four, _states = record_states(hass, period1, "sensor.test1", attributes_2)
|
||||
states["sensor.test1"] += _states["sensor.test1"]
|
||||
hist = history.get_significant_states(hass, period0, four)
|
||||
hist = history.get_significant_states(
|
||||
hass, period0, four, significant_changes_only=False
|
||||
)
|
||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||
|
||||
do_adhoc_statistics(hass, start=period1)
|
||||
@ -3401,9 +3462,11 @@ def record_states(hass, zero, entity_id, attributes, seq=None):
|
||||
if seq is None:
|
||||
seq = [-10, 15, 30]
|
||||
|
||||
def set_state(entity_id, state, **kwargs):
|
||||
def set_state(entity_id, numerical_value, attributes):
|
||||
"""Set the state."""
|
||||
hass.states.set(entity_id, state, **kwargs)
|
||||
hass.states.set(
|
||||
entity_id, "", attributes={**attributes, "numerical_value": numerical_value}
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
@ -3416,23 +3479,17 @@ def record_states(hass, zero, entity_id, attributes, seq=None):
|
||||
with patch(
|
||||
"homeassistant.components.recorder.core.dt_util.utcnow", return_value=one
|
||||
):
|
||||
states[entity_id].append(
|
||||
set_state(entity_id, str(seq[0]), attributes=attributes)
|
||||
)
|
||||
states[entity_id].append(set_state(entity_id, seq[0], attributes=attributes))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.core.dt_util.utcnow", return_value=two
|
||||
):
|
||||
states[entity_id].append(
|
||||
set_state(entity_id, str(seq[1]), attributes=attributes)
|
||||
)
|
||||
states[entity_id].append(set_state(entity_id, seq[1], attributes=attributes))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.core.dt_util.utcnow", return_value=three
|
||||
):
|
||||
states[entity_id].append(
|
||||
set_state(entity_id, str(seq[2]), attributes=attributes)
|
||||
)
|
||||
states[entity_id].append(set_state(entity_id, seq[2], attributes=attributes))
|
||||
|
||||
return four, states
|
||||
|
||||
@ -3504,14 +3561,19 @@ async def test_validate_unit_change_convertible(
|
||||
|
||||
# No statistics, unit in state matching device class - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 10, attributes={**attributes, **{"unit_of_measurement": unit}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes | {"unit_of_measurement": unit, ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, unit in state not matching device class - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 11, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": "dogs", ATTR_NUMERICAL_VALUE: 11},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3520,7 +3582,10 @@ async def test_validate_unit_change_convertible(
|
||||
await async_recorder_block_till_done(hass)
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": "dogs", ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
expected = {
|
||||
@ -3540,7 +3605,9 @@ async def test_validate_unit_change_convertible(
|
||||
|
||||
# Valid state - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": unit}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes | {"unit_of_measurement": unit, ATTR_NUMERICAL_VALUE: 13},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3552,7 +3619,10 @@ async def test_validate_unit_change_convertible(
|
||||
|
||||
# Valid state in compatible unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 14},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3615,7 +3685,9 @@ async def test_validate_statistics_unit_ignore_device_class(
|
||||
|
||||
# No statistics, no device class - empty response
|
||||
initial_attributes = {"state_class": "measurement", "unit_of_measurement": "dogs"}
|
||||
hass.states.async_set("sensor.test", 10, attributes=initial_attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=initial_attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -3623,7 +3695,10 @@ async def test_validate_statistics_unit_ignore_device_class(
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
await async_recorder_block_till_done(hass)
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=initial_attributes
|
||||
| {"unit_of_measurement": "dogs", ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, {})
|
||||
@ -3703,14 +3778,19 @@ async def test_validate_statistics_unit_change_no_device_class(
|
||||
|
||||
# No statistics, sensor state set - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 10, attributes={**attributes, **{"unit_of_measurement": unit}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes | {"unit_of_measurement": unit, ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, sensor state set to an incompatible unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 11, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": "dogs", ATTR_NUMERICAL_VALUE: 11},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3719,7 +3799,10 @@ async def test_validate_statistics_unit_change_no_device_class(
|
||||
await async_recorder_block_till_done(hass)
|
||||
do_adhoc_statistics(hass, start=now)
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": "dogs"}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": "dogs", ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
expected = {
|
||||
@ -3739,7 +3822,9 @@ async def test_validate_statistics_unit_change_no_device_class(
|
||||
|
||||
# Valid state - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": unit}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes | {"unit_of_measurement": unit, ATTR_NUMERICAL_VALUE: 13},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3751,7 +3836,10 @@ async def test_validate_statistics_unit_change_no_device_class(
|
||||
|
||||
# Valid state in compatible unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 14},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
await assert_validation_result(client, {})
|
||||
@ -3810,7 +3898,9 @@ async def test_validate_statistics_unsupported_state_class(
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, valid state - empty response
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -3822,7 +3912,9 @@ async def test_validate_statistics_unsupported_state_class(
|
||||
# State update with invalid state class, expect error
|
||||
_attributes = dict(attributes)
|
||||
_attributes.pop("state_class")
|
||||
hass.states.async_set("sensor.test", 12, attributes=_attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=_attributes | {ATTR_NUMERICAL_VALUE: 12}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
expected = {
|
||||
"sensor.test": [
|
||||
@ -3874,7 +3966,9 @@ async def test_validate_statistics_sensor_no_longer_recorded(
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, valid state - empty response
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -3947,7 +4041,9 @@ async def test_validate_statistics_sensor_not_recorded(
|
||||
"homeassistant.components.sensor.recorder.is_entity_recorded",
|
||||
return_value=False,
|
||||
):
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, expected)
|
||||
|
||||
@ -3993,7 +4089,9 @@ async def test_validate_statistics_sensor_removed(
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, valid state - empty response
|
||||
hass.states.async_set("sensor.test", 10, attributes=attributes)
|
||||
hass.states.async_set(
|
||||
"sensor.test", "", attributes=attributes | {ATTR_NUMERICAL_VALUE: 10}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4063,13 +4161,19 @@ async def test_validate_statistics_unit_change_no_conversion(
|
||||
|
||||
# No statistics, original unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 10, attributes={**attributes, **{"unit_of_measurement": unit1}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit1, ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
# No statistics, changed unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 11, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 11},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4081,7 +4185,10 @@ async def test_validate_statistics_unit_change_no_conversion(
|
||||
|
||||
# No statistics, original unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": unit1}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit1, ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4096,7 +4203,10 @@ async def test_validate_statistics_unit_change_no_conversion(
|
||||
|
||||
# Change unit - expect error
|
||||
hass.states.async_set(
|
||||
"sensor.test", 13, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 13},
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
expected = {
|
||||
@ -4193,7 +4303,10 @@ async def test_validate_statistics_unit_change_equivalent_units(
|
||||
|
||||
# No statistics, original unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 10, attributes={**attributes, **{"unit_of_measurement": unit1}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit1, ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4207,7 +4320,10 @@ async def test_validate_statistics_unit_change_equivalent_units(
|
||||
|
||||
# Units changed to an equivalent unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4273,7 +4389,10 @@ async def test_validate_statistics_unit_change_equivalent_units_2(
|
||||
|
||||
# No statistics, original unit - empty response
|
||||
hass.states.async_set(
|
||||
"sensor.test", 10, attributes={**attributes, **{"unit_of_measurement": unit1}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit1, ATTR_NUMERICAL_VALUE: 10},
|
||||
)
|
||||
await assert_validation_result(client, {})
|
||||
|
||||
@ -4287,7 +4406,10 @@ async def test_validate_statistics_unit_change_equivalent_units_2(
|
||||
|
||||
# Units changed to an equivalent unit which is not known by the unit converters
|
||||
hass.states.async_set(
|
||||
"sensor.test", 12, attributes={**attributes, **{"unit_of_measurement": unit2}}
|
||||
"sensor.test",
|
||||
"",
|
||||
attributes=attributes
|
||||
| {"unit_of_measurement": unit2, ATTR_NUMERICAL_VALUE: 12},
|
||||
)
|
||||
expected = {
|
||||
"sensor.test": [
|
||||
@ -4366,9 +4488,11 @@ def record_meter_states(hass, zero, entity_id, _attributes, seq):
|
||||
We inject a bunch of state updates for meter sensors.
|
||||
"""
|
||||
|
||||
def set_state(entity_id, state, **kwargs):
|
||||
def set_state(entity_id, numerical_value, attributes):
|
||||
"""Set the state."""
|
||||
hass.states.set(entity_id, state, **kwargs)
|
||||
hass.states.set(
|
||||
entity_id, "", attributes={**attributes, "numerical_value": numerical_value}
|
||||
)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
one = zero + timedelta(seconds=15 * 5) # 00:01:15
|
||||
@ -4443,9 +4567,11 @@ def record_meter_state(hass, zero, entity_id, attributes, seq):
|
||||
We inject a state update for meter sensor.
|
||||
"""
|
||||
|
||||
def set_state(entity_id, state, **kwargs):
|
||||
def set_state(entity_id, numerical_value, attributes):
|
||||
"""Set the state."""
|
||||
hass.states.set(entity_id, state, **kwargs)
|
||||
hass.states.set(
|
||||
entity_id, "", attributes={**attributes, "numerical_value": numerical_value}
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
@ -4464,9 +4590,11 @@ def record_states_partially_unavailable(hass, zero, entity_id, attributes):
|
||||
We inject a bunch of state updates temperature sensors.
|
||||
"""
|
||||
|
||||
def set_state(entity_id, state, **kwargs):
|
||||
def set_state(entity_id, numerical_value, attributes):
|
||||
"""Set the state."""
|
||||
hass.states.set(entity_id, state, **kwargs)
|
||||
hass.states.set(
|
||||
entity_id, "", attributes={**attributes, "numerical_value": numerical_value}
|
||||
)
|
||||
wait_recording_done(hass)
|
||||
return hass.states.get(entity_id)
|
||||
|
||||
|
Reference in New Issue
Block a user