mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 09:47:52 +00:00
Switch underlying history stats calculation to use seconds (#77857)
* Switch history stats to report in seconds Because hours were previously used, the data would always be off because of the loss of resolution when the time being tracked was in a window of more than 12s * Apply suggestions from code review * Update homeassistant/components/history_stats/sensor.py * tweak
This commit is contained in:
parent
4dcf7c6267
commit
e34853a82a
@ -18,7 +18,7 @@ MIN_TIME_UTC = datetime.datetime.min.replace(tzinfo=dt_util.UTC)
|
||||
class HistoryStatsState:
|
||||
"""The current stats of the history stats."""
|
||||
|
||||
hours_matched: float | None
|
||||
seconds_matched: float | None
|
||||
match_count: int | None
|
||||
period: tuple[datetime.datetime, datetime.datetime]
|
||||
|
||||
@ -125,12 +125,12 @@ class HistoryStats:
|
||||
await self._async_history_from_db(current_period_start, current_period_end)
|
||||
self._previous_run_before_start = False
|
||||
|
||||
hours_matched, match_count = self._async_compute_hours_and_changes(
|
||||
seconds_matched, match_count = self._async_compute_seconds_and_changes(
|
||||
now_timestamp,
|
||||
current_period_start_timestamp,
|
||||
current_period_end_timestamp,
|
||||
)
|
||||
self._state = HistoryStatsState(hours_matched, match_count, self._period)
|
||||
self._state = HistoryStatsState(seconds_matched, match_count, self._period)
|
||||
return self._state
|
||||
|
||||
async def _async_history_from_db(
|
||||
@ -162,10 +162,10 @@ class HistoryStats:
|
||||
no_attributes=True,
|
||||
).get(self.entity_id, [])
|
||||
|
||||
def _async_compute_hours_and_changes(
|
||||
def _async_compute_seconds_and_changes(
|
||||
self, now_timestamp: float, start_timestamp: float, end_timestamp: float
|
||||
) -> tuple[float, int]:
|
||||
"""Compute the hours matched and changes from the history list and first state."""
|
||||
"""Compute the seconds matched and changes from the history list and first state."""
|
||||
# state_changes_during_period is called with include_start_time_state=True
|
||||
# which is the default and always provides the state at the start
|
||||
# of the period
|
||||
@ -195,6 +195,6 @@ class HistoryStats:
|
||||
measure_end = min(end_timestamp, now_timestamp)
|
||||
elapsed += measure_end - last_state_change_timestamp
|
||||
|
||||
# Save value in hours
|
||||
hours_matched = elapsed / 3600
|
||||
return hours_matched, match_count
|
||||
# Save value in seconds
|
||||
seconds_matched = elapsed
|
||||
return seconds_matched, match_count
|
||||
|
@ -79,7 +79,7 @@ def pretty_ratio(
|
||||
if len(period) != 2 or period[0] == period[1]:
|
||||
return 0.0
|
||||
|
||||
ratio = 100 * 3600 * value / (period[1] - period[0]).total_seconds()
|
||||
ratio = 100 * value / (period[1] - period[0]).total_seconds()
|
||||
return round(ratio, 1)
|
||||
|
||||
|
||||
|
@ -163,13 +163,13 @@ class HistoryStatsSensor(HistoryStatsSensorBase):
|
||||
def _process_update(self) -> None:
|
||||
"""Process an update from the coordinator."""
|
||||
state = self.coordinator.data
|
||||
if state is None or state.hours_matched is None:
|
||||
if state is None or state.seconds_matched is None:
|
||||
self._attr_native_value = None
|
||||
return
|
||||
|
||||
if self._type == CONF_TYPE_TIME:
|
||||
self._attr_native_value = round(state.hours_matched, 2)
|
||||
self._attr_native_value = round(state.seconds_matched / 3600, 2)
|
||||
elif self._type == CONF_TYPE_RATIO:
|
||||
self._attr_native_value = pretty_ratio(state.hours_matched, state.period)
|
||||
self._attr_native_value = pretty_ratio(state.seconds_matched, state.period)
|
||||
elif self._type == CONF_TYPE_COUNT:
|
||||
self._attr_native_value = state.match_count
|
||||
|
Loading…
x
Reference in New Issue
Block a user