Add live streaming logbook websocket endpoint (#72258)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
3390d62b3d
commit
9c3f949165
17 changed files with 2592 additions and 733 deletions
120
homeassistant/components/logbook/rest_api.py
Normal file
120
homeassistant/components/logbook/rest_api.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
"""Event parser and human readable log generator."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from http import HTTPStatus
|
||||
from typing import Any, cast
|
||||
|
||||
from aiohttp import web
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.components.recorder import get_instance
|
||||
from homeassistant.components.recorder.filters import Filters
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import InvalidEntityFormatError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import EntityFilter
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .helpers import async_determine_event_types
|
||||
from .processor import EventProcessor
|
||||
|
||||
|
||||
@callback
|
||||
def async_setup(
|
||||
hass: HomeAssistant,
|
||||
conf: ConfigType,
|
||||
filters: Filters | None,
|
||||
entities_filter: EntityFilter | None,
|
||||
) -> None:
|
||||
"""Set up the logbook rest API."""
|
||||
hass.http.register_view(LogbookView(conf, filters, entities_filter))
|
||||
|
||||
|
||||
class LogbookView(HomeAssistantView):
|
||||
"""Handle logbook view requests."""
|
||||
|
||||
url = "/api/logbook"
|
||||
name = "api:logbook"
|
||||
extra_urls = ["/api/logbook/{datetime}"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: dict[str, Any],
|
||||
filters: Filters | None,
|
||||
entities_filter: EntityFilter | None,
|
||||
) -> None:
|
||||
"""Initialize the logbook view."""
|
||||
self.config = config
|
||||
self.filters = filters
|
||||
self.entities_filter = entities_filter
|
||||
|
||||
async def get(
|
||||
self, request: web.Request, datetime: str | None = None
|
||||
) -> web.Response:
|
||||
"""Retrieve logbook entries."""
|
||||
if datetime:
|
||||
if (datetime_dt := dt_util.parse_datetime(datetime)) is None:
|
||||
return self.json_message("Invalid datetime", HTTPStatus.BAD_REQUEST)
|
||||
else:
|
||||
datetime_dt = dt_util.start_of_local_day()
|
||||
|
||||
if (period_str := request.query.get("period")) is None:
|
||||
period: int = 1
|
||||
else:
|
||||
period = int(period_str)
|
||||
|
||||
if entity_ids_str := request.query.get("entity"):
|
||||
try:
|
||||
entity_ids = cv.entity_ids(entity_ids_str)
|
||||
except vol.Invalid:
|
||||
raise InvalidEntityFormatError(
|
||||
f"Invalid entity id(s) encountered: {entity_ids_str}. "
|
||||
"Format should be <domain>.<object_id>"
|
||||
) from vol.Invalid
|
||||
else:
|
||||
entity_ids = None
|
||||
|
||||
if (end_time_str := request.query.get("end_time")) is None:
|
||||
start_day = dt_util.as_utc(datetime_dt) - timedelta(days=period - 1)
|
||||
end_day = start_day + timedelta(days=period)
|
||||
else:
|
||||
start_day = datetime_dt
|
||||
if (end_day_dt := dt_util.parse_datetime(end_time_str)) is None:
|
||||
return self.json_message("Invalid end_time", HTTPStatus.BAD_REQUEST)
|
||||
end_day = end_day_dt
|
||||
|
||||
hass = request.app["hass"]
|
||||
|
||||
context_id = request.query.get("context_id")
|
||||
|
||||
if entity_ids and context_id:
|
||||
return self.json_message(
|
||||
"Can't combine entity with context_id", HTTPStatus.BAD_REQUEST
|
||||
)
|
||||
|
||||
event_types = async_determine_event_types(hass, entity_ids, None)
|
||||
event_processor = EventProcessor(
|
||||
hass,
|
||||
event_types,
|
||||
entity_ids,
|
||||
None,
|
||||
context_id,
|
||||
timestamp=False,
|
||||
include_entity_name=True,
|
||||
)
|
||||
|
||||
def json_events() -> web.Response:
|
||||
"""Fetch events and generate JSON."""
|
||||
return self.json(
|
||||
event_processor.get_events(
|
||||
start_day,
|
||||
end_day,
|
||||
)
|
||||
)
|
||||
|
||||
return cast(
|
||||
web.Response, await get_instance(hass).async_add_executor_job(json_events)
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue