Refresh camera stream source of Synology DSM connected cameras (#70938)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
pull/72088/head^2
Michael 2022-05-18 19:59:35 +02:00 committed by GitHub
parent 784fbf3291
commit e300908a8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 5 deletions

View File

@ -23,6 +23,7 @@ from homeassistant.const import CONF_MAC, CONF_SCAN_INTERVAL, CONF_VERIFY_SSL
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .common import SynoApi
@ -36,6 +37,7 @@ from .const import (
EXCEPTION_DETAILS,
EXCEPTION_UNKNOWN,
PLATFORMS,
SIGNAL_CAMERA_SOURCE_CHANGED,
SYNO_API,
SYSTEM_LOADED,
UNDO_UPDATE_LISTENER,
@ -123,6 +125,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return None
surveillance_station = api.surveillance_station
current_data: dict[str, SynoCamera] = {
camera.id: camera for camera in surveillance_station.get_all_cameras()
}
try:
async with async_timeout.timeout(30):
@ -130,12 +135,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except SynologyDSMAPIErrorException as err:
raise UpdateFailed(f"Error communicating with API: {err}") from err
return {
"cameras": {
camera.id: camera for camera in surveillance_station.get_all_cameras()
}
new_data: dict[str, SynoCamera] = {
camera.id: camera for camera in surveillance_station.get_all_cameras()
}
for cam_id, cam_data_new in new_data.items():
if (
(cam_data_current := current_data.get(cam_id)) is not None
and cam_data_current.live_view.rtsp != cam_data_new.live_view.rtsp
):
async_dispatcher_send(
hass,
f"{SIGNAL_CAMERA_SOURCE_CHANGED}_{entry.entry_id}_{cam_id}",
cam_data_new.live_view.rtsp,
)
return {"cameras": new_data}
async def async_coordinator_update_data_central() -> None:
"""Fetch all device and sensor data from api."""
try:

View File

@ -16,7 +16,8 @@ from homeassistant.components.camera import (
CameraEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@ -27,6 +28,7 @@ from .const import (
COORDINATOR_CAMERAS,
DEFAULT_SNAPSHOT_QUALITY,
DOMAIN,
SIGNAL_CAMERA_SOURCE_CHANGED,
SYNO_API,
)
from .entity import SynologyDSMBaseEntity, SynologyDSMEntityDescription
@ -130,6 +132,29 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"""Return the camera motion detection status."""
return self.camera_data.is_motion_detection_enabled # type: ignore[no-any-return]
def _listen_source_updates(self) -> None:
"""Listen for camera source changed events."""
@callback
def _handle_signal(url: str) -> None:
if self.stream:
_LOGGER.debug("Update stream URL for camera %s", self.camera_data.name)
self.stream.update_source(url)
assert self.platform
assert self.platform.config_entry
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{SIGNAL_CAMERA_SOURCE_CHANGED}_{self.platform.config_entry.entry_id}_{self.camera_data.id}",
_handle_signal,
)
)
async def async_added_to_hass(self) -> None:
"""Subscribe to signal."""
self._listen_source_updates()
def camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
@ -162,6 +187,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
)
if not self.available:
return None
return self.camera_data.live_view.rtsp # type: ignore[no-any-return]
def enable_motion_detection(self) -> None:

View File

@ -43,6 +43,9 @@ DEFAULT_SNAPSHOT_QUALITY = SNAPSHOT_PROFILE_BALANCED
ENTITY_UNIT_LOAD = "load"
# Signals
SIGNAL_CAMERA_SOURCE_CHANGED = "synology_dsm.camera_stream_source_changed"
# Services
SERVICE_REBOOT = "reboot"
SERVICE_SHUTDOWN = "shutdown"