273 lines
8.4 KiB
Python
273 lines
8.4 KiB
Python
|
"""Frigate HTTP views."""
|
||
|
from __future__ import annotations
|
||
|
|
||
|
import logging
|
||
|
|
||
|
import voluptuous as vol
|
||
|
|
||
|
from custom_components.frigate.api import FrigateApiClient, FrigateApiClientError
|
||
|
from custom_components.frigate.views import get_client_for_frigate_instance_id
|
||
|
from homeassistant.components import websocket_api
|
||
|
from homeassistant.core import HomeAssistant
|
||
|
|
||
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
def async_setup(hass: HomeAssistant) -> None:
|
||
|
"""Set up the recorder websocket API."""
|
||
|
websocket_api.async_register_command(hass, ws_retain_event)
|
||
|
websocket_api.async_register_command(hass, ws_get_recordings)
|
||
|
websocket_api.async_register_command(hass, ws_get_recordings_summary)
|
||
|
websocket_api.async_register_command(hass, ws_get_events)
|
||
|
websocket_api.async_register_command(hass, ws_get_events_summary)
|
||
|
websocket_api.async_register_command(hass, ws_get_ptz_info)
|
||
|
|
||
|
|
||
|
def _get_client_or_send_error(
|
||
|
hass: HomeAssistant,
|
||
|
instance_id: str,
|
||
|
msg_id: int,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
) -> FrigateApiClient | None:
|
||
|
"""Get the API client or send an error that it cannot be found."""
|
||
|
client = get_client_for_frigate_instance_id(hass, instance_id)
|
||
|
if client is None:
|
||
|
connection.send_error(
|
||
|
msg_id,
|
||
|
websocket_api.const.ERR_NOT_FOUND,
|
||
|
f"Unable to find Frigate instance with ID: {instance_id}",
|
||
|
)
|
||
|
return None
|
||
|
return client
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/event/retain",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Required("event_id"): str,
|
||
|
vol.Required("retain"): bool,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_retain_event(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Un/Retain an event."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_retain(
|
||
|
msg["event_id"], msg["retain"], decode_json=False
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst un/retaining event {msg['event_id']} "
|
||
|
f"for Frigate instance {msg['instance_id']}",
|
||
|
)
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/recordings/get",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Required("camera"): str,
|
||
|
vol.Optional("after"): int,
|
||
|
vol.Optional("before"): int,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_get_recordings(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Get recordings for a camera."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_get_recordings(
|
||
|
msg["camera"], msg.get("after"), msg.get("before"), decode_json=False
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst retrieving recordings for camera {msg['camera']} "
|
||
|
f"for Frigate instance {msg['instance_id']}",
|
||
|
)
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/recordings/summary",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Required("camera"): str,
|
||
|
vol.Optional("timezone"): str,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_get_recordings_summary(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Get recordings summary for a camera."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_get_recordings_summary(
|
||
|
msg["camera"], msg.get("timezone", "utc"), decode_json=False
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst retrieving recordings summary for camera "
|
||
|
f"{msg['camera']} for Frigate instance {msg['instance_id']}",
|
||
|
)
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/events/get",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Optional("cameras"): [str],
|
||
|
vol.Optional("labels"): [str],
|
||
|
vol.Optional("sub_labels"): [str],
|
||
|
vol.Optional("zones"): [str],
|
||
|
vol.Optional("after"): int,
|
||
|
vol.Optional("before"): int,
|
||
|
vol.Optional("limit"): int,
|
||
|
vol.Optional("has_clip"): bool,
|
||
|
vol.Optional("has_snapshot"): bool,
|
||
|
vol.Optional("has_snapshot"): bool,
|
||
|
vol.Optional("favorites"): bool,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_get_events(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Get events."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_get_events(
|
||
|
msg.get("cameras"),
|
||
|
msg.get("labels"),
|
||
|
msg.get("sub_labels"),
|
||
|
msg.get("zones"),
|
||
|
msg.get("after"),
|
||
|
msg.get("before"),
|
||
|
msg.get("limit"),
|
||
|
msg.get("has_clip"),
|
||
|
msg.get("has_snapshot"),
|
||
|
msg.get("favorites"),
|
||
|
decode_json=False,
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst retrieving events for cameras "
|
||
|
f"{msg['cameras']} for Frigate instance {msg['instance_id']}",
|
||
|
)
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/events/summary",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Optional("has_clip"): bool,
|
||
|
vol.Optional("has_snapshot"): bool,
|
||
|
vol.Optional("timezone"): str,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_get_events_summary(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Get events."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_get_event_summary(
|
||
|
msg.get("has_clip"),
|
||
|
msg.get("has_snapshot"),
|
||
|
msg.get("timezone", "utc"),
|
||
|
decode_json=False,
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst retrieving events summary for Frigate instance "
|
||
|
f"{msg['instance_id']}",
|
||
|
)
|
||
|
|
||
|
|
||
|
@websocket_api.websocket_command(
|
||
|
{
|
||
|
vol.Required("type"): "frigate/ptz/info",
|
||
|
vol.Required("instance_id"): str,
|
||
|
vol.Required("camera"): str,
|
||
|
}
|
||
|
) # type: ignore[misc]
|
||
|
@websocket_api.async_response # type: ignore[misc]
|
||
|
async def ws_get_ptz_info(
|
||
|
hass: HomeAssistant,
|
||
|
connection: websocket_api.ActiveConnection,
|
||
|
msg: dict,
|
||
|
) -> None:
|
||
|
"""Get PTZ info."""
|
||
|
client = _get_client_or_send_error(hass, msg["instance_id"], msg["id"], connection)
|
||
|
if not client:
|
||
|
return
|
||
|
|
||
|
try:
|
||
|
connection.send_result(
|
||
|
msg["id"],
|
||
|
await client.async_get_ptz_info(
|
||
|
msg["camera"],
|
||
|
decode_json=False,
|
||
|
),
|
||
|
)
|
||
|
except FrigateApiClientError:
|
||
|
connection.send_error(
|
||
|
msg["id"],
|
||
|
"frigate_error",
|
||
|
f"API error whilst retrieving PTZ info for camera "
|
||
|
f"{msg['camera']} for Frigate instance {msg['instance_id']}",
|
||
|
)
|