diff --git a/.gitignore b/.gitignore index 166cd502..4f5a0bf8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.pytest_cache/* .cache/* .tox/* __pycache__/* diff --git a/CHANGES.rst b/CHANGES.rst index cf975d90..7dde1643 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,9 @@ Changelog A list of changes between each release +0.9.0.dev (Development Version) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 0.8.0 (2018-05-21) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added support for battery voltage level (fixes `#64 `_) diff --git a/blinkpy/blinkpy.py b/blinkpy/blinkpy.py index a5388402..492271c9 100644 --- a/blinkpy/blinkpy.py +++ b/blinkpy/blinkpy.py @@ -26,6 +26,8 @@ _LOGGER = logging.getLogger('blinkpy') +MAX_CLIPS = 5 + def _attempt_reauthorization(blink): """Attempt to refresh auth token and links.""" @@ -79,7 +81,7 @@ class BlinkAuthenticationException(BlinkException): pass -class BlinkURLHandler(object): +class BlinkURLHandler(): """Class that handles Blink URLS.""" def __init__(self, region_id): @@ -93,7 +95,7 @@ def __init__(self, region_id): _LOGGER.debug("Setting base url to %s.", self.base_url) -class BlinkCamera(object): +class BlinkCamera(): """Class to initialize individual camera.""" def __init__(self, config, blink): @@ -118,6 +120,8 @@ def __init__(self, config, blink): self.motion_detected = None self.wifi_strength = None self.camera_config = dict() + self.motion_enabled = None + self.last_record = list() @property def attributes(self): @@ -132,10 +136,12 @@ def attributes(self): 'battery': self.battery, 'thumbnail': self.thumbnail, 'video': self.clip, + 'motion_enabled': self.motion_enabled, 'notifications': self.notifications, 'motion_detected': self.motion_detected, 'wifi_strength': self.wifi_strength, - 'network_id': self.blink.network_id + 'network_id': self.blink.network_id, + 'last_record': self.last_record } return attributes @@ -205,13 +211,31 @@ def update(self, values): try: self.battery_voltage = cfg['camera'][0]['battery_voltage'] - self.motion_detected = cfg['camera'][0]['motion_alert'] + self.motion_enabled = cfg['camera'][0]['motion_alert'] self.wifi_strength = cfg['camera'][0]['wifi_strength'] self.temperature = cfg['camera'][0]['temperature'] except KeyError: _LOGGER.warning("Problem extracting config for camera %s", self.name) + # Check if the most recent clip is included in the last_record list + # and that the last_record list is populated + try: + new_clip = self.blink.videos[self.name][0]['clip'] + if new_clip not in self.last_record and self.last_record: + self.motion_detected = True + self.last_record.insert(0, new_clip) + if len(self.last_record) > MAX_CLIPS: + self.last_record.pop() + elif not self.last_record: + self.last_record.insert(0, new_clip) + self.motion_detected = False + else: + self.motion_detected = False + except KeyError: + _LOGGER.warning("Could not extract clip info from camera %s", + self.name) + def image_refresh(self): """Refresh current thumbnail.""" url = self.urls.home_url @@ -248,7 +272,7 @@ def video_to_file(self, path): copyfileobj(response.raw, vidfile) -class Blink(object): +class Blink(): """Class to initialize communication and sync module.""" def __init__(self, username=None, password=None): @@ -348,7 +372,6 @@ def refresh(self): camera.update(element) except KeyError: pass - return None def get_videos(self, start_page=0, end_page=1): """Retrieve last recorded videos per camera.""" diff --git a/blinkpy/helpers/constants.py b/blinkpy/helpers/constants.py index 65603d24..ee441021 100644 --- a/blinkpy/helpers/constants.py +++ b/blinkpy/helpers/constants.py @@ -4,7 +4,7 @@ MAJOR_VERSION = 0 MINOR_VERSION = 8 -PATCH_VERSION = 0 +PATCH_VERSION = 1 __version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION) diff --git a/pylintrc b/pylintrc index 4c1c3618..95ef2707 100644 --- a/pylintrc +++ b/pylintrc @@ -7,6 +7,7 @@ reports=no # unused-argument - generic callbacks and setup methods create a lot of warnings # too-many-* - are not enforced for the sake of readability # too-few-* - same as too-many-* +# no-else-return - I don't see any reason to enforce this. both forms are readable disable= locally-disabled, @@ -20,4 +21,5 @@ disable= too-many-return-statements, too-many-statements, too-many-lines, - too-few-public-methods, \ No newline at end of file + too-few-public-methods, + no-else-return, diff --git a/requirements_test.txt b/requirements_test.txt index d2b61970..2f3eaa1e 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,10 +1,10 @@ -flake8==3.3 -flake8-docstrings==1.1.0 -pylint==1.8.1 -pydocstyle==2.0.0 -pytest==3.3.1 +flake8==3.5.0 +flake8-docstrings==1.3.0 +pylint==2.1.1 +pydocstyle==2.1.1 +pytest==3.7.1 pytest-cov>=2.3.1 pytest-sugar>=0.9.0 pytest-timeout>=1.0.0 restructuredtext-lint>=1.0.1 -pygments>=2.2.0 +pygments>=2.2.0 \ No newline at end of file diff --git a/tests/mock_responses.py b/tests/mock_responses.py index a20cf4ac..d626a787 100644 --- a/tests/mock_responses.py +++ b/tests/mock_responses.py @@ -39,7 +39,7 @@ def json(self): response_to_return = {'message': 'Error', 'code': 404} code_to_return = 404 - if url_arg == const.LOGIN_URL or url_arg == const.LOGIN_BACKUP_URL: + if url_arg in (const.LOGIN_URL, const.LOGIN_BACKUP_URL): response_to_return = LOGIN_RESPONSE code_to_return = 200 elif url_arg is not None: @@ -77,6 +77,7 @@ def raw(self): url_arg = args[0] + # pylint: disable=R1711 if url_arg == 'use_bad_response': return MockGetResponse({'foo': 'bar'}, 200) elif url_arg == 'reauth': diff --git a/tests/test_blink_cameras.py b/tests/test_blink_cameras.py index 0d65349b..e902fead 100644 --- a/tests/test_blink_cameras.py +++ b/tests/test_blink_cameras.py @@ -88,7 +88,7 @@ def test_camera_properties(self, mock_get, mock_post, mock_cfg): self.assertEqual(camera.battery_string, "OK") self.assertEqual(camera.notifications, 2) self.assertEqual(camera.region_id, 'test') - self.assertEqual(camera.motion_detected, True) + self.assertEqual(camera.motion_enabled, True) self.assertEqual(camera.wifi_strength, -30) camera_config = self.camera_config @@ -154,5 +154,5 @@ def test_camera_attributes(self, mock_cfg): self.assertEqual(camera_attr['battery'], 50) self.assertEqual(camera_attr['notifications'], 2) self.assertEqual(camera_attr['network_id'], '0000') - self.assertEqual(camera_attr['motion_detected'], True) + self.assertEqual(camera_attr['motion_enabled'], True) self.assertEqual(camera_attr['wifi_strength'], -30) diff --git a/tests/test_blink_setup.py b/tests/test_blink_setup.py index 67eb4994..86fa7979 100644 --- a/tests/test_blink_setup.py +++ b/tests/test_blink_setup.py @@ -8,7 +8,7 @@ import unittest from unittest import mock -from blinkpy import blinkpy as blinkpy +from blinkpy import blinkpy import tests.mock_responses as mresp USERNAME = 'foobar'