2019-02-13 20:21:14 +00:00
|
|
|
"""Support for viewing the camera feed from a DoorBird video doorbell."""
|
2021-08-11 00:33:06 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2017-09-17 18:47:30 +00:00
|
|
|
import asyncio
|
|
|
|
import datetime
|
|
|
|
import logging
|
|
|
|
|
|
|
|
import aiohttp
|
|
|
|
import async_timeout
|
|
|
|
|
2019-12-05 05:22:51 +00:00
|
|
|
from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
2022-01-03 12:22:41 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
|
|
from homeassistant.core import HomeAssistant
|
2017-09-17 18:47:30 +00:00
|
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
2022-01-03 12:22:41 +00:00
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
2019-09-19 06:39:09 +00:00
|
|
|
import homeassistant.util.dt as dt_util
|
2017-09-17 18:47:30 +00:00
|
|
|
|
2020-06-25 20:17:05 +00:00
|
|
|
from .const import (
|
|
|
|
DOMAIN,
|
|
|
|
DOOR_STATION,
|
|
|
|
DOOR_STATION_EVENT_ENTITY_IDS,
|
|
|
|
DOOR_STATION_INFO,
|
|
|
|
)
|
2020-03-23 09:14:21 +00:00
|
|
|
from .entity import DoorBirdEntity
|
2019-03-21 05:56:46 +00:00
|
|
|
|
2020-03-23 09:14:21 +00:00
|
|
|
_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=2)
|
|
|
|
_LAST_MOTION_INTERVAL = datetime.timedelta(seconds=30)
|
|
|
|
_LIVE_INTERVAL = datetime.timedelta(seconds=45)
|
2017-09-17 18:47:30 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2020-03-23 09:14:21 +00:00
|
|
|
_TIMEOUT = 15 # seconds
|
2017-09-17 18:47:30 +00:00
|
|
|
|
|
|
|
|
2022-01-03 12:22:41 +00:00
|
|
|
async def async_setup_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: ConfigEntry,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
) -> None:
|
2017-09-17 18:47:30 +00:00
|
|
|
"""Set up the DoorBird camera platform."""
|
2020-03-23 09:14:21 +00:00
|
|
|
config_entry_id = config_entry.entry_id
|
2020-06-25 20:17:05 +00:00
|
|
|
config_data = hass.data[DOMAIN][config_entry_id]
|
|
|
|
doorstation = config_data[DOOR_STATION]
|
|
|
|
doorstation_info = config_data[DOOR_STATION_INFO]
|
2020-03-23 09:14:21 +00:00
|
|
|
device = doorstation.device
|
|
|
|
|
|
|
|
async_add_entities(
|
|
|
|
[
|
|
|
|
DoorBirdCamera(
|
|
|
|
doorstation,
|
|
|
|
doorstation_info,
|
|
|
|
device.live_image_url,
|
|
|
|
"live",
|
|
|
|
f"{doorstation.name} Live",
|
2020-06-25 20:17:05 +00:00
|
|
|
doorstation.doorstation_events,
|
2020-03-23 09:14:21 +00:00
|
|
|
_LIVE_INTERVAL,
|
|
|
|
device.rtsp_live_video_url,
|
|
|
|
),
|
|
|
|
DoorBirdCamera(
|
|
|
|
doorstation,
|
|
|
|
doorstation_info,
|
|
|
|
device.history_image_url(1, "doorbell"),
|
|
|
|
"last_ring",
|
|
|
|
f"{doorstation.name} Last Ring",
|
2020-06-25 20:17:05 +00:00
|
|
|
[],
|
2020-03-23 09:14:21 +00:00
|
|
|
_LAST_VISITOR_INTERVAL,
|
|
|
|
),
|
|
|
|
DoorBirdCamera(
|
|
|
|
doorstation,
|
|
|
|
doorstation_info,
|
|
|
|
device.history_image_url(1, "motionsensor"),
|
|
|
|
"last_motion",
|
|
|
|
f"{doorstation.name} Last Motion",
|
2020-06-25 20:17:05 +00:00
|
|
|
[],
|
2020-03-23 09:14:21 +00:00
|
|
|
_LAST_MOTION_INTERVAL,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class DoorBirdCamera(DoorBirdEntity, Camera):
|
2017-09-17 18:47:30 +00:00
|
|
|
"""The camera on a DoorBird device."""
|
|
|
|
|
2020-03-23 09:14:21 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
doorstation,
|
|
|
|
doorstation_info,
|
|
|
|
url,
|
|
|
|
camera_id,
|
|
|
|
name,
|
2020-06-25 20:17:05 +00:00
|
|
|
doorstation_events,
|
2020-03-23 09:14:21 +00:00
|
|
|
interval=None,
|
|
|
|
stream_url=None,
|
|
|
|
):
|
2017-09-17 18:47:30 +00:00
|
|
|
"""Initialize the camera on a DoorBird device."""
|
2020-03-23 09:14:21 +00:00
|
|
|
super().__init__(doorstation, doorstation_info)
|
2017-09-17 18:47:30 +00:00
|
|
|
self._url = url
|
2019-04-08 13:22:31 +00:00
|
|
|
self._stream_url = stream_url
|
2017-09-17 18:47:30 +00:00
|
|
|
self._name = name
|
|
|
|
self._last_image = None
|
2019-04-08 13:22:31 +00:00
|
|
|
self._supported_features = SUPPORT_STREAM if self._stream_url else 0
|
2017-09-17 18:47:30 +00:00
|
|
|
self._interval = interval or datetime.timedelta
|
|
|
|
self._last_update = datetime.datetime.min
|
2020-03-23 09:14:21 +00:00
|
|
|
self._unique_id = f"{self._mac_addr}_{camera_id}"
|
2020-06-25 20:17:05 +00:00
|
|
|
self._doorstation_events = doorstation_events
|
2017-09-17 18:47:30 +00:00
|
|
|
|
2019-05-23 16:45:30 +00:00
|
|
|
async def stream_source(self):
|
2019-04-08 13:22:31 +00:00
|
|
|
"""Return the stream source."""
|
|
|
|
return self._stream_url
|
|
|
|
|
2020-03-23 09:14:21 +00:00
|
|
|
@property
|
|
|
|
def unique_id(self):
|
|
|
|
"""Camera Unique id."""
|
|
|
|
return self._unique_id
|
|
|
|
|
2019-04-08 13:22:31 +00:00
|
|
|
@property
|
|
|
|
def supported_features(self):
|
|
|
|
"""Return supported features."""
|
|
|
|
return self._supported_features
|
|
|
|
|
2017-09-17 18:47:30 +00:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Get the name of the camera."""
|
|
|
|
return self._name
|
|
|
|
|
2021-08-11 00:33:06 +00:00
|
|
|
async def async_camera_image(
|
|
|
|
self, width: int | None = None, height: int | None = None
|
|
|
|
) -> bytes | None:
|
2017-09-17 18:47:30 +00:00
|
|
|
"""Pull a still image from the camera."""
|
2019-09-19 06:39:09 +00:00
|
|
|
now = dt_util.utcnow()
|
2017-09-17 18:47:30 +00:00
|
|
|
|
|
|
|
if self._last_image and now - self._last_update < self._interval:
|
|
|
|
return self._last_image
|
|
|
|
|
|
|
|
try:
|
|
|
|
websession = async_get_clientsession(self.hass)
|
2021-11-04 15:07:50 +00:00
|
|
|
async with async_timeout.timeout(_TIMEOUT):
|
2018-10-01 06:50:05 +00:00
|
|
|
response = await websession.get(self._url)
|
2017-09-17 18:47:30 +00:00
|
|
|
|
2018-10-01 06:50:05 +00:00
|
|
|
self._last_image = await response.read()
|
2017-09-17 18:47:30 +00:00
|
|
|
self._last_update = now
|
|
|
|
return self._last_image
|
|
|
|
except asyncio.TimeoutError:
|
2020-03-23 09:14:21 +00:00
|
|
|
_LOGGER.error("DoorBird %s: Camera image timed out", self._name)
|
2017-09-17 18:47:30 +00:00
|
|
|
return self._last_image
|
|
|
|
except aiohttp.ClientError as error:
|
2020-03-23 09:14:21 +00:00
|
|
|
_LOGGER.error(
|
|
|
|
"DoorBird %s: Error getting camera image: %s", self._name, error
|
|
|
|
)
|
2017-09-17 18:47:30 +00:00
|
|
|
return self._last_image
|
2020-06-25 20:17:05 +00:00
|
|
|
|
|
|
|
async def async_added_to_hass(self):
|
|
|
|
"""Add callback after being added to hass.
|
|
|
|
|
|
|
|
Registers entity_id map for the logbook
|
|
|
|
"""
|
|
|
|
event_to_entity_id = self.hass.data[DOMAIN].setdefault(
|
|
|
|
DOOR_STATION_EVENT_ENTITY_IDS, {}
|
|
|
|
)
|
|
|
|
for event in self._doorstation_events:
|
|
|
|
event_to_entity_id[event] = self.entity_id
|
|
|
|
|
|
|
|
async def will_remove_from_hass(self):
|
|
|
|
"""Unregister entity_id map for the logbook."""
|
|
|
|
event_to_entity_id = self.hass.data[DOMAIN][DOOR_STATION_EVENT_ENTITY_IDS]
|
|
|
|
for event in self._doorstation_events:
|
|
|
|
if event in event_to_entity_id:
|
|
|
|
del event_to_entity_id[event]
|