Generate json for history and logbook websocket responses in the executor (#71813)

This commit is contained in:
J. Nick Koston 2022-05-13 13:17:54 -04:00 committed by GitHub
parent 4885331509
commit 9bd508c0bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 138 additions and 46 deletions

View file

@ -1,12 +1,12 @@
"""Provide pre-made queries on top of the recorder component."""
from __future__ import annotations
from collections.abc import Iterable, MutableMapping
from collections.abc import Iterable
from datetime import datetime as dt, timedelta
from http import HTTPStatus
import logging
import time
from typing import Any, cast
from typing import Any, Literal, cast
from aiohttp import web
from sqlalchemy import not_, or_
@ -24,8 +24,10 @@ from homeassistant.components.recorder.statistics import (
statistics_during_period,
)
from homeassistant.components.recorder.util import session_scope
from homeassistant.components.websocket_api import messages
from homeassistant.components.websocket_api.const import JSON_DUMP
from homeassistant.const import CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE
from homeassistant.core import HomeAssistant, State
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.deprecation import deprecated_class, deprecated_function
from homeassistant.helpers.entityfilter import (
@ -104,6 +106,23 @@ class LazyState(history_models.LazyState):
"""A lazy version of core State."""
def _ws_get_statistics_during_period(
hass: HomeAssistant,
msg_id: int,
start_time: dt,
end_time: dt | None = None,
statistic_ids: list[str] | None = None,
period: Literal["5minute", "day", "hour", "month"] = "hour",
) -> str:
"""Fetch statistics and convert them to json in the executor."""
return JSON_DUMP(
messages.result_message(
msg_id,
statistics_during_period(hass, start_time, end_time, statistic_ids, period),
)
)
@websocket_api.websocket_command(
{
vol.Required("type"): "history/statistics_during_period",
@ -136,15 +155,28 @@ async def ws_get_statistics_during_period(
else:
end_time = None
statistics = await get_instance(hass).async_add_executor_job(
statistics_during_period,
hass,
start_time,
end_time,
msg.get("statistic_ids"),
msg.get("period"),
connection.send_message(
await get_instance(hass).async_add_executor_job(
_ws_get_statistics_during_period,
hass,
msg["id"],
start_time,
end_time,
msg.get("statistic_ids"),
msg.get("period"),
)
)
def _ws_get_list_statistic_ids(
hass: HomeAssistant,
msg_id: int,
statistic_type: Literal["mean"] | Literal["sum"] | None = None,
) -> str:
"""Fetch a list of available statistic_id and convert them to json in the executor."""
return JSON_DUMP(
messages.result_message(msg_id, list_statistic_ids(hass, None, statistic_type))
)
connection.send_result(msg["id"], statistics)
@websocket_api.websocket_command(
@ -158,13 +190,46 @@ async def ws_get_list_statistic_ids(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
) -> None:
"""Fetch a list of available statistic_id."""
statistic_ids = await get_instance(hass).async_add_executor_job(
list_statistic_ids,
hass,
None,
msg.get("statistic_type"),
connection.send_message(
await get_instance(hass).async_add_executor_job(
_ws_get_list_statistic_ids,
hass,
msg["id"],
msg.get("statistic_type"),
)
)
def _ws_get_significant_states(
hass: HomeAssistant,
msg_id: int,
start_time: dt,
end_time: dt | None = None,
entity_ids: list[str] | None = None,
filters: Any | None = None,
include_start_time_state: bool = True,
significant_changes_only: bool = True,
minimal_response: bool = False,
no_attributes: bool = False,
) -> str:
"""Fetch history significant_states and convert them to json in the executor."""
return JSON_DUMP(
messages.result_message(
msg_id,
history.get_significant_states(
hass,
start_time,
end_time,
entity_ids,
filters,
include_start_time_state,
significant_changes_only,
minimal_response,
no_attributes,
True,
),
)
)
connection.send_result(msg["id"], statistic_ids)
@websocket_api.websocket_command(
@ -220,24 +285,22 @@ async def ws_get_history_during_period(
significant_changes_only = msg["significant_changes_only"]
no_attributes = msg["no_attributes"]
minimal_response = msg["minimal_response"]
compressed_state_format = True
history_during_period: MutableMapping[
str, list[State | dict[str, Any]]
] = await get_instance(hass).async_add_executor_job(
history.get_significant_states,
hass,
start_time,
end_time,
entity_ids,
hass.data[HISTORY_FILTERS],
include_start_time_state,
significant_changes_only,
minimal_response,
no_attributes,
compressed_state_format,
connection.send_message(
await get_instance(hass).async_add_executor_job(
_ws_get_significant_states,
hass,
msg["id"],
start_time,
end_time,
entity_ids,
hass.data[HISTORY_FILTERS],
include_start_time_state,
significant_changes_only,
minimal_response,
no_attributes,
)
)
connection.send_result(msg["id"], history_during_period)
class HistoryPeriodView(HomeAssistantView):

View file

@ -30,6 +30,8 @@ from homeassistant.components.recorder.models import (
from homeassistant.components.recorder.util import session_scope
from homeassistant.components.script import EVENT_SCRIPT_STARTED
from homeassistant.components.sensor import ATTR_STATE_CLASS, DOMAIN as SENSOR_DOMAIN
from homeassistant.components.websocket_api import messages
from homeassistant.components.websocket_api.const import JSON_DUMP
from homeassistant.const import (
ATTR_DOMAIN,
ATTR_ENTITY_ID,
@ -210,6 +212,34 @@ async def _process_logbook_platform(
platform.async_describe_events(hass, _async_describe_event)
def _ws_formatted_get_events(
hass: HomeAssistant,
msg_id: int,
start_day: dt,
end_day: dt,
entity_ids: list[str] | None = None,
filters: Filters | None = None,
entities_filter: EntityFilter | Callable[[str], bool] | None = None,
context_id: str | None = None,
) -> str:
"""Fetch events and convert them to json in the executor."""
return JSON_DUMP(
messages.result_message(
msg_id,
_get_events(
hass,
start_day,
end_day,
entity_ids,
filters,
entities_filter,
context_id,
True,
),
)
)
@websocket_api.websocket_command(
{
vol.Required("type"): "logbook/get_events",
@ -249,20 +279,19 @@ async def ws_get_events(
entity_ids = msg.get("entity_ids")
context_id = msg.get("context_id")
logbook_events: list[dict[str, Any]] = await get_instance(
hass
).async_add_executor_job(
_get_events,
hass,
start_time,
end_time,
entity_ids,
hass.data[LOGBOOK_FILTERS],
hass.data[LOGBOOK_ENTITIES_FILTER],
context_id,
True,
connection.send_message(
await get_instance(hass).async_add_executor_job(
_ws_formatted_get_events,
hass,
msg["id"],
start_time,
end_time,
entity_ids,
hass.data[LOGBOOK_FILTERS],
hass.data[LOGBOOK_ENTITIES_FILTER],
context_id,
)
)
connection.send_result(msg["id"], logbook_events)
class LogbookView(HomeAssistantView):