Add camera support to synology_dsm (#39838)

* Add camera support to synology_dsm

* Code improvements

* More code improvements
This commit is contained in:
Xiaonan Shen 2020-09-11 03:08:37 +08:00 committed by GitHub
parent 4d6e694d14
commit b66aaeea99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 1 deletions

View File

@ -829,6 +829,7 @@ omit =
homeassistant/components/synology/camera.py
homeassistant/components/synology_chat/notify.py
homeassistant/components/synology_dsm/__init__.py
homeassistant/components/synology_dsm/camera.py
homeassistant/components/synology_dsm/binary_sensor.py
homeassistant/components/synology_dsm/sensor.py
homeassistant/components/synology_srm/device_tracker.py

View File

@ -10,6 +10,7 @@ from synology_dsm.api.core.utilization import SynoCoreUtilization
from synology_dsm.api.dsm.information import SynoDSMInformation
from synology_dsm.api.dsm.network import SynoDSMNetwork
from synology_dsm.api.storage.storage import SynoStorage
from synology_dsm.api.surveillance_station import SynoSurveillanceStation
import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
@ -225,12 +226,14 @@ class SynoApi:
self.security: SynoCoreSecurity = None
self.storage: SynoStorage = None
self.utilisation: SynoCoreUtilization = None
self.surveillance_station: SynoSurveillanceStation = None
# Should we fetch them
self._fetching_entities = {}
self._with_security = True
self._with_storage = True
self._with_utilisation = True
self._with_surveillance_station = True
self._unsub_dispatcher = None
@ -250,6 +253,11 @@ class SynoApi:
device_token=self._entry.data.get("device_token"),
)
await self._hass.async_add_executor_job(self.dsm.discover_apis)
self._with_surveillance_station = bool(
self.dsm.apis.get(SynoSurveillanceStation.CAMERA_API_KEY)
)
self._async_setup_api_requests()
await self._hass.async_add_executor_job(self._fetch_device_configuration)
@ -294,6 +302,9 @@ class SynoApi:
self._with_utilisation = bool(
self._fetching_entities.get(SynoCoreUtilization.API_KEY)
)
self._with_surveillance_station = bool(
self._fetching_entities.get(SynoSurveillanceStation.CAMERA_API_KEY)
)
# Reset not used API
if not self._with_security:
@ -308,6 +319,10 @@ class SynoApi:
self.dsm.reset(self.utilisation)
self.utilisation = None
if not self._with_surveillance_station:
self.dsm.reset(self.surveillance_station)
self.surveillance_station = None
def _fetch_device_configuration(self):
"""Fetch initial device config."""
self.information = self.dsm.information
@ -324,6 +339,9 @@ class SynoApi:
if self._with_utilisation:
self.utilisation = self.dsm.utilisation
if self._with_surveillance_station:
self.surveillance_station = self.dsm.surveillance_station
async def async_unload(self):
"""Stop interacting with the NAS and prepare for removal from hass."""
self._unsub_dispatcher()
@ -345,6 +363,8 @@ class SynologyDSMEntity(Entity):
entity_info: Dict[str, str],
):
"""Initialize the Synology DSM entity."""
super().__init__()
self._api = api
self._api_key = entity_type.split(":")[0]
self.entity_type = entity_type.split(":")[-1]

View File

@ -0,0 +1,97 @@
"""Support for Synology DSM cameras."""
from typing import Dict
from synology_dsm.api.surveillance_station import SynoSurveillanceStation
from homeassistant.components.camera import SUPPORT_STREAM, Camera
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import SynologyDSMEntity
from .const import (
DOMAIN,
ENTITY_CLASS,
ENTITY_ENABLE,
ENTITY_ICON,
ENTITY_NAME,
ENTITY_UNIT,
SYNO_API,
)
async def async_setup_entry(
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the Synology NAS binary sensor."""
api = hass.data[DOMAIN][entry.unique_id][SYNO_API]
if SynoSurveillanceStation.CAMERA_API_KEY not in api.dsm.apis:
return True
surveillance_station = api.surveillance_station
await hass.async_add_executor_job(surveillance_station.update)
cameras = surveillance_station.get_all_cameras()
entities = [SynoDSMCamera(api, camera) for camera in cameras]
async_add_entities(entities)
class SynoDSMCamera(SynologyDSMEntity, Camera):
"""Representation a Synology camera."""
def __init__(self, api, camera):
"""Initialize a Synology camera."""
super().__init__(
api,
f"{SynoSurveillanceStation.CAMERA_API_KEY}:{camera.id}",
{
ENTITY_NAME: camera.name,
ENTITY_CLASS: None,
ENTITY_ICON: None,
ENTITY_ENABLE: True,
ENTITY_UNIT: None,
},
)
self._camera = camera
@property
def device_info(self) -> Dict[str, any]:
"""Return the device information."""
return {
"identifiers": {(DOMAIN, self._api.information.serial, self._camera.id)},
"name": self.name,
"model": self._camera.model,
"via_device": (DOMAIN, self._api.information.serial),
}
@property
def supported_features(self) -> int:
"""Return supported features of this camera."""
return SUPPORT_STREAM
@property
def is_recording(self):
"""Return true if the device is recording."""
return self._camera.is_recording
@property
def motion_detection_enabled(self):
"""Return the camera motion detection status."""
return self._camera.is_motion_detection_enabled
def camera_image(self) -> bytes:
"""Return bytes of camera image."""
return self._api.surveillance_station.get_camera_image(self._camera.id)
async def stream_source(self) -> str:
"""Return the source of the stream."""
return self._camera.live_view.rtsp
def enable_motion_detection(self):
"""Enable motion detection in the camera."""
self._api.surveillance_station.enable_motion_detection(self._camera.id)
def disable_motion_detection(self):
"""Disable motion detection in camera."""
self._api.surveillance_station.disable_motion_detection(self._camera.id)

View File

@ -13,7 +13,7 @@ from homeassistant.const import (
)
DOMAIN = "synology_dsm"
PLATFORMS = ["binary_sensor", "sensor"]
PLATFORMS = ["binary_sensor", "camera", "sensor"]
# Entry keys
SYNO_API = "syno_api"