Amcrest: Add on/off support & attributes. Bump amcrest to 1.3.0 (#22418)

* Amcrest: Add on/off support & attributes to camera entity. Bump amcrest package to 1.3.0.

Add support for turn_on & turn_off services.

Add implementation of is_recording method, as well as brand, model, hardware_version, machine_name, serial_number, software_build and software_version attributes.

Bump amcrest package to 1.3.0 required for above changes and also handles errors in storage commands which resolves #19982.

* Update per review

Rebase to upstream/dev.

Remove video_enabled property and setter and replace with _enable_video_stream
method.

Remove static attributes from camera and sensors.
This commit is contained in:
Phil Bruckner 2019-04-01 17:36:29 -05:00 committed by Andrew Sayre
parent e78709c5f5
commit 82296aeb71
4 changed files with 85 additions and 19 deletions

View File

@ -12,7 +12,7 @@ from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['amcrest==1.2.7']
REQUIREMENTS = ['amcrest==1.3.0']
DEPENDENCIES = ['ffmpeg']
_LOGGER = logging.getLogger(__name__)

View File

@ -3,7 +3,7 @@ import asyncio
import logging
from homeassistant.components.camera import (
Camera, SUPPORT_STREAM)
Camera, SUPPORT_ON_OFF, SUPPORT_STREAM)
from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import (
@ -39,18 +39,23 @@ class AmcrestCam(Camera):
super(AmcrestCam, self).__init__()
self._name = amcrest.name
self._camera = amcrest.device
self._base_url = self._camera.get_base_url()
self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = amcrest.ffmpeg_arguments
self._stream_source = amcrest.stream_source
self._resolution = amcrest.resolution
self._token = self._auth = amcrest.authentication
self._is_recording = False
self._model = None
self._snapshot_lock = asyncio.Lock()
async def async_camera_image(self):
"""Return a still image response from the camera."""
from amcrest import AmcrestError
if not self.is_on:
_LOGGER.error(
'Attempt to take snaphot when %s camera is off', self.name)
return None
async with self._snapshot_lock:
try:
# Send the request to snap a picture and return raw jpg data
@ -59,7 +64,8 @@ class AmcrestCam(Camera):
return response.data
except AmcrestError as error:
_LOGGER.error(
'Could not get camera image due to error %s', error)
'Could not get image from %s camera due to error: %s',
self.name, error)
return None
async def handle_async_mjpeg_stream(self, request):
@ -94,6 +100,8 @@ class AmcrestCam(Camera):
finally:
await stream.close()
# Entity property overrides
@property
def name(self):
"""Return the name of this camera."""
@ -102,9 +110,80 @@ class AmcrestCam(Camera):
@property
def supported_features(self):
"""Return supported features."""
return SUPPORT_STREAM
return SUPPORT_ON_OFF | SUPPORT_STREAM
# Camera property overrides
@property
def is_recording(self):
"""Return true if the device is recording."""
return self._is_recording
@property
def brand(self):
"""Return the camera brand."""
return 'Amcrest'
@property
def model(self):
"""Return the camera model."""
return self._model
@property
def stream_source(self):
"""Return the source of the stream."""
return self._camera.rtsp_url(typeno=self._resolution)
@property
def is_on(self):
"""Return true if on."""
return self.is_streaming
# Other Entity method overrides
def update(self):
"""Update entity status."""
from amcrest import AmcrestError
_LOGGER.debug('Pulling data from %s camera', self.name)
if self._model is None:
try:
self._model = self._camera.device_type.split('=')[-1].strip()
except AmcrestError as error:
_LOGGER.error(
'Could not get %s camera model due to error: %s',
self.name, error)
self._model = ''
try:
self.is_streaming = self._camera.video_enabled
self._is_recording = self._camera.record_mode == 'Manual'
except AmcrestError as error:
_LOGGER.error(
'Could not get %s camera attributes due to error: %s',
self.name, error)
# Other Camera method overrides
def turn_off(self):
"""Turn off camera."""
self._enable_video_stream(False)
def turn_on(self):
"""Turn on camera."""
self._enable_video_stream(True)
# Utility methods
def _enable_video_stream(self, enable):
"""Enable or disable camera video stream."""
from amcrest import AmcrestError
try:
self._camera.video_enabled = enable
except AmcrestError as error:
_LOGGER.error(
'Could not %s %s camera video stream due to error: %s',
'enable' if enable else 'disable', self.name, error)
else:
self.is_streaming = enable
self.schedule_update_ha_state()

View File

@ -75,19 +75,6 @@ class AmcrestSensor(Entity):
"""Get the latest data and updates the state."""
_LOGGER.debug("Pulling data from %s sensor.", self._name)
try:
version, build_date = self._camera.software_information
self._attrs['Build Date'] = build_date.split('=')[-1]
self._attrs['Version'] = version.split('=')[-1]
except ValueError:
self._attrs['Build Date'] = 'Not Available'
self._attrs['Version'] = 'Not Available'
try:
self._attrs['Serial Number'] = self._camera.serial_number
except ValueError:
self._attrs['Serial Number'] = 'Not Available'
if self._sensor_type == 'motion_detector':
self._state = self._camera.is_motion_detected
self._attrs['Record Mode'] = self._camera.record_mode

View File

@ -155,7 +155,7 @@ alarmdecoder==1.13.2
alpha_vantage==2.1.0
# homeassistant.components.amcrest
amcrest==1.2.7
amcrest==1.3.0
# homeassistant.components.androidtv.media_player
androidtv==0.0.14