From 16d79b52c35a20f2dc97a387ab6282b5dcaf7d5a Mon Sep 17 00:00:00 2001 From: Phil Bruckner Date: Tue, 5 Mar 2019 10:03:19 -0600 Subject: [PATCH] Serialize amcrest snapshot commands and bump PyPI package to 1.2.4 (#21664) * Serialize snapshot commands and bump amcrest package to 1.2.4 Attempting to send a snapshot command when a previous one hasn't finished will result in warnings and/or errors. This can happen when the camera picture is clicked on in the frontend, resulting in the thread that updates the thumbnail in the background every 10 seconds to sometimes collide with the thread that updates the large picture in the foreground quickly. An automation that calls the camera.snapshot service in yet another thread can make the situation worse. Fix by adding a thread lock to serialize snapshot commands. Also bump the amcrest package to 1.2.4 which fixes error handling in the command method and improves performance by reusing requests sessions. * Update amcrest package to 1.2.4 --- homeassistant/components/amcrest/__init__.py | 2 +- homeassistant/components/amcrest/camera.py | 16 +++++++++++++--- requirements_all.txt | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/amcrest/__init__.py b/homeassistant/components/amcrest/__init__.py index 49f11570b21..bcb18402900 100644 --- a/homeassistant/components/amcrest/__init__.py +++ b/homeassistant/components/amcrest/__init__.py @@ -13,7 +13,7 @@ from homeassistant.const import ( from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['amcrest==1.2.3'] +REQUIREMENTS = ['amcrest==1.2.4'] DEPENDENCIES = ['ffmpeg'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/amcrest/camera.py b/homeassistant/components/amcrest/camera.py index 7c943b89734..6acaa5fc86e 100644 --- a/homeassistant/components/amcrest/camera.py +++ b/homeassistant/components/amcrest/camera.py @@ -1,5 +1,9 @@ """Support for Amcrest IP cameras.""" import logging +import threading + +from requests import RequestException +from urllib3.exceptions import ReadTimeoutError from homeassistant.components.amcrest import ( DATA_AMCREST, STREAM_SOURCE_LIST, TIMEOUT) @@ -43,12 +47,18 @@ class AmcrestCam(Camera): self._stream_source = amcrest.stream_source self._resolution = amcrest.resolution self._token = self._auth = amcrest.authentication + self._snapshot_lock = threading.Lock() def camera_image(self): """Return a still image response from the camera.""" - # Send the request to snap a picture and return raw jpg data - response = self._camera.snapshot(channel=self._resolution) - return response.data + with self._snapshot_lock: + try: + # Send the request to snap a picture and return raw jpg data + return self._camera.snapshot(channel=self._resolution).data + except (RequestException, ReadTimeoutError, ValueError) as error: + _LOGGER.error( + 'Could not get camera image due to error %s', error) + return None async def handle_async_mjpeg_stream(self, request): """Return an MJPEG stream.""" diff --git a/requirements_all.txt b/requirements_all.txt index bf6834c18f4..dd476bc1fed 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -152,7 +152,7 @@ alarmdecoder==1.13.2 alpha_vantage==2.1.0 # homeassistant.components.amcrest -amcrest==1.2.3 +amcrest==1.2.4 # homeassistant.components.switch.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2