mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Cache Canary camera image (#73923)
* Cache camera image Cache camera image so a new image isn't generated each call. Adds debug logging * Apply suggestions from code review code compression with walrus operator Co-authored-by: Erik Montnemery <erik@montnemery.com> * fix after walrus operator suggested tweak fully use the live_stream_session variable in async_camera_image * Invalidate cached image after 15 minutes requested code change; invalidate cached image * Removed unnecessary if statement based on code review * Image capture flow updates now sets the image expiration upon getting an updated image updates the cache image only when a new image is captured Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
5774f2e7b9
commit
2d2fd3e48f
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from aiohttp.web import Request, StreamResponse
|
from aiohttp.web import Request, StreamResponse
|
||||||
@ -23,7 +24,7 @@ from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
|
|||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_FFMPEG_ARGUMENTS,
|
CONF_FFMPEG_ARGUMENTS,
|
||||||
@ -34,7 +35,7 @@ from .const import (
|
|||||||
)
|
)
|
||||||
from .coordinator import CanaryDataUpdateCoordinator
|
from .coordinator import CanaryDataUpdateCoordinator
|
||||||
|
|
||||||
MIN_TIME_BETWEEN_SESSION_RENEW: Final = timedelta(seconds=90)
|
FORCE_CAMERA_REFRESH_INTERVAL: Final = timedelta(minutes=15)
|
||||||
|
|
||||||
PLATFORM_SCHEMA: Final = vol.All(
|
PLATFORM_SCHEMA: Final = vol.All(
|
||||||
cv.deprecated(CONF_FFMPEG_ARGUMENTS),
|
cv.deprecated(CONF_FFMPEG_ARGUMENTS),
|
||||||
@ -47,6 +48,8 @@ PLATFORM_SCHEMA: Final = vol.All(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -105,6 +108,11 @@ class CanaryCamera(CoordinatorEntity[CanaryDataUpdateCoordinator], Camera):
|
|||||||
model=device.device_type["name"],
|
model=device.device_type["name"],
|
||||||
name=device.name,
|
name=device.name,
|
||||||
)
|
)
|
||||||
|
self._image: bytes | None = None
|
||||||
|
self._expires_at = dt_util.utcnow()
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s %s has been initialized", self.name, device.device_type["name"]
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location(self) -> Location:
|
def location(self) -> Location:
|
||||||
@ -125,17 +133,33 @@ class CanaryCamera(CoordinatorEntity[CanaryDataUpdateCoordinator], Camera):
|
|||||||
self, width: int | None = None, height: int | None = None
|
self, width: int | None = None, height: int | None = None
|
||||||
) -> bytes | None:
|
) -> bytes | None:
|
||||||
"""Return a still image response from the camera."""
|
"""Return a still image response from the camera."""
|
||||||
await self.hass.async_add_executor_job(self.renew_live_stream_session)
|
utcnow = dt_util.utcnow()
|
||||||
live_stream_url = await self.hass.async_add_executor_job(
|
if self._expires_at <= utcnow:
|
||||||
getattr, self._live_stream_session, "live_stream_url"
|
_LOGGER.debug("Grabbing a live view image from %s", self.name)
|
||||||
)
|
await self.hass.async_add_executor_job(self.renew_live_stream_session)
|
||||||
return await ffmpeg.async_get_image(
|
|
||||||
self.hass,
|
if (live_stream_session := self._live_stream_session) is None:
|
||||||
live_stream_url,
|
return None
|
||||||
extra_cmd=self._ffmpeg_arguments,
|
|
||||||
width=width,
|
if not (live_stream_url := live_stream_session.live_stream_url):
|
||||||
height=height,
|
return None
|
||||||
)
|
|
||||||
|
image = await ffmpeg.async_get_image(
|
||||||
|
self.hass,
|
||||||
|
live_stream_url,
|
||||||
|
extra_cmd=self._ffmpeg_arguments,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
)
|
||||||
|
|
||||||
|
if image:
|
||||||
|
self._image = image
|
||||||
|
self._expires_at = FORCE_CAMERA_REFRESH_INTERVAL + utcnow
|
||||||
|
_LOGGER.debug("Grabbed a live view image from %s", self.name)
|
||||||
|
await self.hass.async_add_executor_job(live_stream_session.stop_session)
|
||||||
|
_LOGGER.debug("Stopped live session from %s", self.name)
|
||||||
|
|
||||||
|
return self._image
|
||||||
|
|
||||||
async def handle_async_mjpeg_stream(
|
async def handle_async_mjpeg_stream(
|
||||||
self, request: Request
|
self, request: Request
|
||||||
@ -161,9 +185,14 @@ class CanaryCamera(CoordinatorEntity[CanaryDataUpdateCoordinator], Camera):
|
|||||||
finally:
|
finally:
|
||||||
await stream.close()
|
await stream.close()
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_SESSION_RENEW)
|
|
||||||
def renew_live_stream_session(self) -> None:
|
def renew_live_stream_session(self) -> None:
|
||||||
"""Renew live stream session."""
|
"""Renew live stream session."""
|
||||||
self._live_stream_session = self.coordinator.canary.get_live_stream_session(
|
self._live_stream_session = self.coordinator.canary.get_live_stream_session(
|
||||||
self._device
|
self._device
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Live Stream URL for %s is %s",
|
||||||
|
self.name,
|
||||||
|
self._live_stream_session.live_stream_url,
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user