Fix history stats query using incorrect microseconds (#91250)
parent
81f018b7e5
commit
da4c144a5e
|
@ -78,7 +78,7 @@ class HistoryStats:
|
|||
utc_now = dt_util.utcnow()
|
||||
now_timestamp = floored_timestamp(utc_now)
|
||||
|
||||
if current_period_start > utc_now:
|
||||
if current_period_start_timestamp > now_timestamp:
|
||||
# History cannot tell the future
|
||||
self._history_current_period = []
|
||||
self._previous_run_before_start = True
|
||||
|
@ -122,7 +122,9 @@ class HistoryStats:
|
|||
# Don't compute anything as the value cannot have changed
|
||||
return self._state
|
||||
else:
|
||||
await self._async_history_from_db(current_period_start, current_period_end)
|
||||
await self._async_history_from_db(
|
||||
current_period_start_timestamp, current_period_end_timestamp
|
||||
)
|
||||
self._previous_run_before_start = False
|
||||
|
||||
seconds_matched, match_count = self._async_compute_seconds_and_changes(
|
||||
|
@ -135,15 +137,15 @@ class HistoryStats:
|
|||
|
||||
async def _async_history_from_db(
|
||||
self,
|
||||
current_period_start: datetime.datetime,
|
||||
current_period_end: datetime.datetime,
|
||||
current_period_start_timestamp: float,
|
||||
current_period_end_timestamp: float,
|
||||
) -> None:
|
||||
"""Update history data for the current period from the database."""
|
||||
instance = get_instance(self.hass)
|
||||
states = await instance.async_add_executor_job(
|
||||
self._state_changes_during_period,
|
||||
current_period_start,
|
||||
current_period_end,
|
||||
current_period_start_timestamp,
|
||||
current_period_end_timestamp,
|
||||
)
|
||||
self._history_current_period = [
|
||||
HistoryState(state.state, state.last_changed.timestamp())
|
||||
|
@ -151,8 +153,11 @@ class HistoryStats:
|
|||
]
|
||||
|
||||
def _state_changes_during_period(
|
||||
self, start: datetime.datetime, end: datetime.datetime
|
||||
self, start_ts: float, end_ts: float
|
||||
) -> list[State]:
|
||||
"""Return state changes during a period."""
|
||||
start = dt_util.utc_from_timestamp(start_ts)
|
||||
end = dt_util.utc_from_timestamp(end_ts)
|
||||
return history.state_changes_during_period(
|
||||
self.hass,
|
||||
start,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""The test for the History Statistics sensor platform."""
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun import freeze_time
|
||||
|
@ -1534,3 +1534,58 @@ async def test_device_classes(recorder_mock: Recorder, hass: HomeAssistant) -> N
|
|||
assert hass.states.get("sensor.time").attributes[ATTR_DEVICE_CLASS] == "duration"
|
||||
assert ATTR_DEVICE_CLASS not in hass.states.get("sensor.ratio").attributes
|
||||
assert ATTR_DEVICE_CLASS not in hass.states.get("sensor.count").attributes
|
||||
|
||||
|
||||
async def test_history_stats_handles_floored_timestamps(
|
||||
recorder_mock: Recorder,
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test we account for microseconds when doing the data calculation."""
|
||||
hass.config.set_time_zone("UTC")
|
||||
utcnow = dt_util.utcnow()
|
||||
start_time = utcnow.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
last_times = None
|
||||
|
||||
def _fake_states(
|
||||
hass: HomeAssistant, start: datetime, end: datetime | None, *args, **kwargs
|
||||
) -> dict[str, list[ha.State]]:
|
||||
"""Fake state changes."""
|
||||
nonlocal last_times
|
||||
last_times = (start, end)
|
||||
return {
|
||||
"binary_sensor.state": [
|
||||
ha.State(
|
||||
"binary_sensor.state",
|
||||
"on",
|
||||
last_changed=start_time,
|
||||
last_updated=start_time,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.history.state_changes_during_period",
|
||||
_fake_states,
|
||||
), freeze_time(start_time):
|
||||
await async_setup_component(
|
||||
hass,
|
||||
"sensor",
|
||||
{
|
||||
"sensor": [
|
||||
{
|
||||
"platform": "history_stats",
|
||||
"entity_id": "binary_sensor.state",
|
||||
"name": "sensor1",
|
||||
"state": "on",
|
||||
"start": "{{ utcnow().replace(hour=0, minute=0, second=0, microsecond=100) }}",
|
||||
"duration": {"hours": 2},
|
||||
"type": "time",
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await async_update_entity(hass, "sensor.sensor1")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert last_times == (start_time, start_time + timedelta(hours=2))
|
||||
|
|
Loading…
Reference in New Issue