From 82296aeb7127fa3532098ea7b53e2f33b54e7c42 Mon Sep 17 00:00:00 2001 From: Phil Bruckner Date: Mon, 1 Apr 2019 17:36:29 -0500 Subject: [PATCH] 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. --- homeassistant/components/amcrest/__init__.py | 2 +- homeassistant/components/amcrest/camera.py | 87 +++++++++++++++++++- homeassistant/components/amcrest/sensor.py | 13 --- requirements_all.txt | 2 +- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/amcrest/__init__.py b/homeassistant/components/amcrest/__init__.py index 84dc0b5bb01..295b798c3b1 100644 --- a/homeassistant/components/amcrest/__init__.py +++ b/homeassistant/components/amcrest/__init__.py @@ -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__) diff --git a/homeassistant/components/amcrest/camera.py b/homeassistant/components/amcrest/camera.py index 63c2c720781..853d5404dab 100644 --- a/homeassistant/components/amcrest/camera.py +++ b/homeassistant/components/amcrest/camera.py @@ -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() diff --git a/homeassistant/components/amcrest/sensor.py b/homeassistant/components/amcrest/sensor.py index c721914c73c..68bc86da94c 100644 --- a/homeassistant/components/amcrest/sensor.py +++ b/homeassistant/components/amcrest/sensor.py @@ -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 diff --git a/requirements_all.txt b/requirements_all.txt index ea76277be4d..4a67141d743 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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