Compare commits

..
19 changed files with 94 additions and 118 deletions
+2 -3
View File
@@ -1,5 +1,5 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
@@ -8,8 +8,7 @@ daysUntilClose: 7
exemptLabels:
- Priority
- bug
- help wanted
- feature request
- Help Wanted
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
+3 -2
View File
@@ -33,9 +33,10 @@ jobs:
run: |
tox -r -e cov
- name: Codecov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v1.0.6
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: unittests
file: ./coverage.xml
name: blinkpy
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.8'
python-version: '3.7'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
+2 -2
View File
@@ -10,11 +10,11 @@ jobs:
build:
runs-on: ${{ matrix.platform }}
strategy:
max-parallel: 4
max-parallel: 3
matrix:
platform:
- ubuntu-latest
python-version: [3.6, 3.7, 3.8, 3.9]
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
+25
View File
@@ -0,0 +1,25 @@
image: python
stages:
- test
before_script:
- curl -O https://bootstrap.pypa.io/get-pip.py
- python get-pip.py
- pip install tox
python35:
image: python:3.5
stage: test
script: tox -e py35
python36:
image: python:3.6
stage: test
script: tox -e py36
lint:
image: python:3.6
stage: test
script: tox -e lint
+2 -2
View File
@@ -8,12 +8,12 @@ repos:
- --quiet
files: ^((blinkpy|tests)/.+)?[^/]+\.py$
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
rev: 3.8.2
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.5.0
- pydocstyle==5.1.1
- pydocstyle==5.0.2
files: ^(blinkpy|tests)/.+\.py$
- repo: https://github.com/Lucas-C/pre-commit-hooks-markup
rev: v1.0.0
-25
View File
@@ -4,31 +4,6 @@ Changelog
A list of changes between each release
0.16.4 (2020-11-22)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Bugfixes:**
- Updated liveview endpoint (`#389 <https://github.com/fronzbot/blinkpy/pull/389>`__)
- Fixed mini thumbnail not updating (`#388 <https://github.com/fronzbot/blinkpy/pull/388>`__)
- Add exception catch to prevent NoneType error on refresh, added test to check behavior as well (`#401 <https://github.com/fronzbot/blinkpy/pull/401>`__)
- Unrelated: had to add two force methods to refresh for testing purposes. Should not change normal usage.
- Fix malformed stream url (`#395 <https://github.com/fronzbot/blinkpy/pull/395>`__)
**All:**
- Moved testtools to requirements_test.txt (`#387 <https://github.com/fronzbot/blinkpy/pull/387>`__)
- Bumped pytest to 6.1.1
- Bumped flake8 to 3.8.4
- Fixed README spelling ((`#381 <https://github.com/fronzbot/blinkpy/pull/381>`__) via @rohitsud)
- Bumped pygments to 2.7.1
- Bumped coverage to 5.3
- Bumped pydocstyle to 5.1.1
- Bumped pre-commit to 2.7.1
- Bumped pylint to 2.6.0
- Bumped pytest-cov to 2.10.1
0.16.3 (2020-08-02)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3 -1
View File
@@ -244,7 +244,9 @@ def request_camera_liveview(blink, network, camera_id):
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request liveview from.
"""
url = f"{blink.urls.base_url}/api/v5/accounts/{blink.account_id}/networks/{network}/cameras/{camera_id}/liveview"
url = (
f"{blink.urls.base_url}/api/v3/networks/{network}/cameras/{camera_id}/liveview"
)
return http_post(blink, url)
+1 -8
View File
@@ -58,11 +58,7 @@ class Auth:
"""Return authorization header."""
if self.token is None:
return None
return {
"TOKEN_AUTH": self.token,
"user-agent": DEFAULT_USER_AGENT,
"content-type": "application/json",
}
return {"TOKEN_AUTH": self.token, "user-agent": DEFAULT_USER_AGENT}
def create_session(self, opts=None):
"""Create a session for blink communication."""
@@ -231,9 +227,6 @@ class Auth:
try:
json_resp = response.json()
blink.available = json_resp["valid"]
if not json_resp["valid"]:
_LOGGER.error(f"{json_resp['message']}")
return False
except (KeyError, TypeError):
_LOGGER.error("Did not receive valid response from server.")
return False
+5 -7
View File
@@ -76,22 +76,20 @@ class Blink:
self.no_owls = no_owls
@util.Throttle(seconds=MIN_THROTTLE_TIME)
def refresh(self, force=False, force_cache=False):
def refresh(self, force=False):
"""
Perform a system refresh.
:param force: Used to override throttle, resets refresh
:param force_cache: Used to force update without overriding throttle
:param force: Force an update of the camera data
"""
if self.check_if_ok_to_update() or force or force_cache:
if self.check_if_ok_to_update() or force:
if not self.available:
self.setup_post_verify()
self.get_homescreen()
for sync_name, sync_module in self.sync.items():
_LOGGER.debug("Attempting refresh of sync %s", sync_name)
sync_module.refresh(force_cache=(force or force_cache))
if not force_cache:
sync_module.refresh(force_cache=force)
if not force:
# Prevents rapid clearing of motion detect property
self.last_refresh = int(time.time())
return True
+17 -15
View File
@@ -98,15 +98,6 @@ class BlinkCamera:
self.sync.blink, self.network_id, self.camera_id
)
def get_media(self, media_type="image"):
"""Download media (image or video)."""
url = self.thumbnail
if media_type.lower() == "video":
url = self.clip
return api.http_get(
self.sync.blink, url=url, stream=True, json=False, timeout=TIMEOUT_MEDIA,
)
def snap_picture(self):
"""Take a picture with camera to create a new thumbnail."""
return api.request_new_image(self.sync.blink, self.network_id, self.camera_id)
@@ -189,10 +180,21 @@ class BlinkCamera:
update_cached_video = True
if new_thumbnail is not None and (update_cached_image or force_cache):
self._cached_image = self.get_media()
self._cached_image = api.http_get(
self.sync.blink,
url=self.thumbnail,
stream=True,
json=False,
timeout=TIMEOUT_MEDIA,
)
if clip_addr is not None and (update_cached_video or force_cache):
self._cached_video = self.get_media(media_type="video")
self._cached_video = api.http_get(
self.sync.blink,
url=self.clip,
stream=True,
json=False,
timeout=TIMEOUT_MEDIA,
)
def get_liveview(self):
"""Get livewview rtsps link."""
@@ -208,7 +210,7 @@ class BlinkCamera:
:param path: Path to write file
"""
_LOGGER.debug("Writing image from %s to %s", self.name, path)
response = self.get_media()
response = self._cached_image
if response.status_code == 200:
with open(path, "wb") as imgfile:
copyfileobj(response.raw, imgfile)
@@ -224,7 +226,7 @@ class BlinkCamera:
:param path: Path to write file
"""
_LOGGER.debug("Writing video from %s to %s", self.name, path)
response = self.get_media(media_type="video")
response = self._cached_video
if response is None:
_LOGGER.error("No saved video exist for %s.", self.name)
return
@@ -266,6 +268,6 @@ class BlinkCameraMini(BlinkCamera):
response = api.http_post(self.sync.blink, url)
server = response["server"]
server_split = server.split(":")
server_split[0] = "rtsps:"
server_split[0] = "rtsps"
link = "".join(server_split)
return link
+2 -3
View File
@@ -3,8 +3,8 @@
import os
MAJOR_VERSION = 0
MINOR_VERSION = 16
PATCH_VERSION = "5.rc0"
MINOR_VERSION = 17
PATCH_VERSION = "0.dev0"
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
@@ -34,7 +34,6 @@ PROJECT_CLASSIFIERS = [
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Home Automation",
]
+2 -2
View File
@@ -145,7 +145,7 @@ class BlinkSyncModule:
for owl in self.blink.homescreen["owls"]:
if owl["name"] == name:
return owl
except (TypeError, KeyError):
except KeyError:
pass
return None
@@ -270,7 +270,7 @@ class BlinkOwl(BlinkSyncModule):
if owl["name"] == self.name:
self.status = owl["enabled"]
return owl
except (TypeError, KeyError):
except KeyError:
pass
return None
+1
View File
@@ -1,3 +1,4 @@
python-dateutil>=2.8.1
requests>=2.24.0
python-slugify>=4.0.1
testtools>=2.4.0
+9 -10
View File
@@ -1,14 +1,13 @@
black==19.10b0
coverage==5.4
flake8==3.8.4
coverage==5.3
flake8==3.8.3
flake8-docstrings==1.5.0
pre-commit==2.9.3
pylint==2.6.0
pydocstyle==5.1.1
pytest==6.2.2
pytest-cov==2.11.1
pre-commit==2.6.0
pylint==2.5.3
pydocstyle==5.0.2
pytest==6.1.1
pytest-cov==2.10.1
pytest-sugar==0.9.4
pytest-timeout==1.4.2
restructuredtext-lint==1.3.2
pygments==2.7.4
testtools>=2.4.0
restructuredtext-lint==1.3.1
pygments==2.6.1
+1 -5
View File
@@ -128,11 +128,7 @@ class TestAuth(unittest.TestCase):
def test_header(self):
"""Test header data."""
self.auth.token = "bar"
expected_header = {
"TOKEN_AUTH": "bar",
"user-agent": const.DEFAULT_USER_AGENT,
"content-type": "application/json",
}
expected_header = {"TOKEN_AUTH": "bar", "user-agent": const.DEFAULT_USER_AGENT}
self.assertDictEqual(self.auth.header, expected_header)
def test_header_no_token(self):
+16 -23
View File
@@ -5,23 +5,29 @@ import logging
from blinkpy import blinkpy
from blinkpy.sync_module import BlinkSyncModule
from blinkpy.camera import BlinkCamera
from blinkpy.helpers.util import get_time, BlinkURLHandler
class MockSyncModule(BlinkSyncModule):
"""Mock blink sync module object."""
"""Mock http requests from sync module."""
def get_network_info(self):
"""Mock network info method."""
return True
def __init__(self, blink, header):
"""Create mock sync module instance."""
super().__init__(blink, header, network_id=None, camera_list=None)
self.blink = blink
self.header = header
self.return_value = None
self.return_value2 = None
def http_get(self, url, stream=False, json=True):
"""Mock get request."""
if stream and self.return_value2 is not None:
return self.return_value2
return self.return_value
class MockCamera(BlinkCamera):
"""Mock blink camera object."""
def update(self, config, force_cache=False, **kwargs):
"""Mock camera update method."""
def http_post(self, url):
"""Mock post request."""
return self.return_value
class TestBlinkFunctions(unittest.TestCase):
@@ -115,16 +121,3 @@ class TestBlinkFunctions(unittest.TestCase):
with self.assertLogs() as dl_log:
blink.download_videos("/tmp", camera="bar", stop=2)
self.assertEqual(dl_log.output, expected_log)
@mock.patch("blinkpy.blinkpy.api.request_network_update")
@mock.patch("blinkpy.auth.Auth.query")
def test_refresh(self, mock_req, mock_update):
"""Test ability to refresh system."""
mock_update.return_value = {"network": {"sync_module_error": False}}
mock_req.return_value = None
self.blink.last_refresh = 0
self.blink.available = True
self.blink.sync["foo"] = MockSyncModule(self.blink, "foo", 1, [])
self.blink.cameras = {"bar": MockCamera(self.blink.sync)}
self.blink.sync["foo"].cameras = self.blink.cameras
self.assertTrue(self.blink.refresh())
+2 -2
View File
@@ -68,8 +68,8 @@ class TestBlinkSetup(unittest.TestCase):
self.assertEqual(self.blink.last_refresh, None)
with mock.patch(
"blinkpy.sync_module.BlinkSyncModule.refresh", return_value=True
), mock.patch("blinkpy.blinkpy.Blink.get_homescreen", return_value=True):
self.blink.refresh(force=True)
):
self.blink.refresh()
self.assertEqual(self.blink.last_refresh, now)
self.assertEqual(self.blink.check_if_ok_to_update(), False)
-7
View File
@@ -176,10 +176,3 @@ class TestBlinkCameraSetup(unittest.TestCase):
attr = camera.attributes
for key in attr:
self.assertEqual(attr[key], None)
def test_camera_stream(self, mock_resp):
"""Test that camera stream returns correct url."""
mock_resp.return_value = {"server": "rtsps://foo.bar"}
mini_camera = BlinkCameraMini(self.blink.sync["test"])
self.assertEqual(self.camera.get_liveview(), "rtsps://foo.bar")
self.assertEqual(mini_camera.get_liveview(), "rtsps://foo.bar")