* Change datetime.now() to dt_util.now() in cases where the functionality should stay the same These changes should not affect the functionality, rather cleanup our codebase. In general we would like integrations to not to use datetime.now() unless there's a very good reason for it, rather use our own dt_util.now() which makes the code aware of our current time zone. * Use datetime.utcnow() for season sensor to get offset-naive utc time * Revert "Use datetime.utcnow() for season sensor to get offset-naive utc time" This reverts commit 5f36463d9c7d52f8e11ffcec7e57dfbc7b21bdd1. * BOM sensor last_updated should be UTC as well * Run black * Remove unused last_partition_update variable
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
"""Support for viewing the camera feed from a DoorBird video doorbell."""
|
|
import asyncio
|
|
import datetime
|
|
import logging
|
|
|
|
import aiohttp
|
|
import async_timeout
|
|
|
|
from homeassistant.components.camera import Camera, SUPPORT_STREAM
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
import homeassistant.util.dt as dt_util
|
|
|
|
from . import DOMAIN as DOORBIRD_DOMAIN
|
|
|
|
_CAMERA_LAST_VISITOR = "{} Last Ring"
|
|
_CAMERA_LAST_MOTION = "{} Last Motion"
|
|
_CAMERA_LIVE = "{} Live"
|
|
_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=1)
|
|
_LAST_MOTION_INTERVAL = datetime.timedelta(minutes=1)
|
|
_LIVE_INTERVAL = datetime.timedelta(seconds=1)
|
|
_LOGGER = logging.getLogger(__name__)
|
|
_TIMEOUT = 10 # seconds
|
|
|
|
|
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
|
"""Set up the DoorBird camera platform."""
|
|
for doorstation in hass.data[DOORBIRD_DOMAIN]:
|
|
device = doorstation.device
|
|
async_add_entities(
|
|
[
|
|
DoorBirdCamera(
|
|
device.live_image_url,
|
|
_CAMERA_LIVE.format(doorstation.name),
|
|
_LIVE_INTERVAL,
|
|
device.rtsp_live_video_url,
|
|
),
|
|
DoorBirdCamera(
|
|
device.history_image_url(1, "doorbell"),
|
|
_CAMERA_LAST_VISITOR.format(doorstation.name),
|
|
_LAST_VISITOR_INTERVAL,
|
|
),
|
|
DoorBirdCamera(
|
|
device.history_image_url(1, "motionsensor"),
|
|
_CAMERA_LAST_MOTION.format(doorstation.name),
|
|
_LAST_MOTION_INTERVAL,
|
|
),
|
|
]
|
|
)
|
|
|
|
|
|
class DoorBirdCamera(Camera):
|
|
"""The camera on a DoorBird device."""
|
|
|
|
def __init__(self, url, name, interval=None, stream_url=None):
|
|
"""Initialize the camera on a DoorBird device."""
|
|
self._url = url
|
|
self._stream_url = stream_url
|
|
self._name = name
|
|
self._last_image = None
|
|
self._supported_features = SUPPORT_STREAM if self._stream_url else 0
|
|
self._interval = interval or datetime.timedelta
|
|
self._last_update = datetime.datetime.min
|
|
super().__init__()
|
|
|
|
async def stream_source(self):
|
|
"""Return the stream source."""
|
|
return self._stream_url
|
|
|
|
@property
|
|
def supported_features(self):
|
|
"""Return supported features."""
|
|
return self._supported_features
|
|
|
|
@property
|
|
def name(self):
|
|
"""Get the name of the camera."""
|
|
return self._name
|
|
|
|
async def async_camera_image(self):
|
|
"""Pull a still image from the camera."""
|
|
now = dt_util.utcnow()
|
|
|
|
if self._last_image and now - self._last_update < self._interval:
|
|
return self._last_image
|
|
|
|
try:
|
|
websession = async_get_clientsession(self.hass)
|
|
with async_timeout.timeout(_TIMEOUT):
|
|
response = await websession.get(self._url)
|
|
|
|
self._last_image = await response.read()
|
|
self._last_update = now
|
|
return self._last_image
|
|
except asyncio.TimeoutError:
|
|
_LOGGER.error("Camera image timed out")
|
|
return self._last_image
|
|
except aiohttp.ClientError as error:
|
|
_LOGGER.error("Error getting camera image: %s", error)
|
|
return self._last_image
|