Skip to content

Commit 37350da

Browse files
authored
Merge pull request #402 from fronzbot/dev
0.16.4
2 parents 19b7eef + a2555a6 commit 37350da

14 files changed

+97
-59
lines changed

.github/workflows/coverage.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ jobs:
3333
run: |
3434
tox -r -e cov
3535
- name: Codecov
36-
uses: codecov/codecov-action@v1.0.6
36+
uses: codecov/codecov-action@v1
3737
with:
38+
token: ${{ secrets.CODECOV_TOKEN }}
3839
flags: unittests
3940
file: ./coverage.xml
4041
name: blinkpy

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ repos:
88
- --quiet
99
files: ^((blinkpy|tests)/.+)?[^/]+\.py$
1010
- repo: https://gitlab.com/pycqa/flake8
11-
rev: 3.8.2
11+
rev: 3.8.3
1212
hooks:
1313
- id: flake8
1414
additional_dependencies:
1515
- flake8-docstrings==1.5.0
16-
- pydocstyle==5.0.2
16+
- pydocstyle==5.1.1
1717
files: ^(blinkpy|tests)/.+\.py$
1818
- repo: https://github.com/Lucas-C/pre-commit-hooks-markup
1919
rev: v1.0.0

CHANGES.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@ Changelog
44

55
A list of changes between each release
66

7+
0.16.4 (2020-11-22)
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
10+
**Bugfixes:**
11+
12+
- Updated liveview endpoint (`#389 <https://github.com/fronzbot/blinkpy/pull/389>`__)
13+
- Fixed mini thumbnail not updating (`#388 <https://github.com/fronzbot/blinkpy/pull/388>`__)
14+
- Add exception catch to prevent NoneType error on refresh, added test to check behavior as well (`#401 <https://github.com/fronzbot/blinkpy/pull/401>`__)
15+
- Unrelated: had to add two force methods to refresh for testing purposes. Should not change normal usage.
16+
- Fix malformed stream url (`#395 <https://github.com/fronzbot/blinkpy/pull/395>`__)
17+
18+
**All:**
19+
20+
- Moved testtools to requirements_test.txt (`#387 <https://github.com/fronzbot/blinkpy/pull/387>`__)
21+
- Bumped pytest to 6.1.1
22+
- Bumped flake8 to 3.8.4
23+
- Fixed README spelling ((`#381 <https://github.com/fronzbot/blinkpy/pull/381>`__) via @rohitsud)
24+
- Bumped pygments to 2.7.1
25+
- Bumped coverage to 5.3
26+
- Bumped pydocstyle to 5.1.1
27+
- Bumped pre-commit to 2.7.1
28+
- Bumped pylint to 2.6.0
29+
- Bumped pytest-cov to 2.10.1
30+
31+
732
0.16.3 (2020-08-02)
833
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
934

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Similar methods exist for individual cameras:
174174
175175
Download videos
176176
----------------
177-
You can also use this library to download all videos from the server. In order to do this, you must specify a ``path``. You may also specifiy a how far back in time to go to retrieve videos via the ``since=`` variable (a simple string such as ``"2017/09/21"`` is sufficient), as well as how many pages to traverse via the ``page=`` variable. Note that by default, the library will search the first ten pages which is sufficient in most use cases. Additionally, you can specidy one or more cameras via the ``camera=`` property. This can be a single string indicating the name of the camera, or a list of camera names. By default, it is set to the string ``'all'`` to grab videos from all cameras.
177+
You can also use this library to download all videos from the server. In order to do this, you must specify a ``path``. You may also specifiy a how far back in time to go to retrieve videos via the ``since=`` variable (a simple string such as ``"2017/09/21"`` is sufficient), as well as how many pages to traverse via the ``stop=`` variable. Note that by default, the library will search the first ten pages which is sufficient in most use cases. Additionally, you can specify one or more cameras via the ``camera=`` property. This can be a single string indicating the name of the camera, or a list of camera names. By default, it is set to the string ``'all'`` to grab videos from all cameras.
178178

179179
Example usage, which downloads all videos recorded since July 4th, 2018 at 9:34am to the ``/home/blink`` directory:
180180

blinkpy/api.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,7 @@ def request_camera_liveview(blink, network, camera_id):
244244
:param network: Sync module network id.
245245
:param camera_id: Camera ID of camera to request liveview from.
246246
"""
247-
url = (
248-
f"{blink.urls.base_url}/api/v3/networks/{network}/cameras/{camera_id}/liveview"
249-
)
247+
url = f"{blink.urls.base_url}/api/v5/accounts/{blink.account_id}/networks/{network}/cameras/{camera_id}/liveview"
250248
return http_post(blink, url)
251249

252250

blinkpy/blinkpy.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,22 @@ def __init__(
7676
self.no_owls = no_owls
7777

7878
@util.Throttle(seconds=MIN_THROTTLE_TIME)
79-
def refresh(self, force=False):
79+
def refresh(self, force=False, force_cache=False):
8080
"""
8181
Perform a system refresh.
8282
83-
:param force: Force an update of the camera data
83+
:param force: Used to override throttle, resets refresh
84+
:param force_cache: Used to force update without overriding throttle
8485
"""
85-
if self.check_if_ok_to_update() or force:
86+
if self.check_if_ok_to_update() or force or force_cache:
8687
if not self.available:
8788
self.setup_post_verify()
8889

90+
self.get_homescreen()
8991
for sync_name, sync_module in self.sync.items():
9092
_LOGGER.debug("Attempting refresh of sync %s", sync_name)
91-
sync_module.refresh(force_cache=force)
92-
if not force:
93+
sync_module.refresh(force_cache=(force or force_cache))
94+
if not force_cache:
9395
# Prevents rapid clearing of motion detect property
9496
self.last_refresh = int(time.time())
9597
return True

blinkpy/camera.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ def arm(self, value):
9898
self.sync.blink, self.network_id, self.camera_id
9999
)
100100

101+
def get_media(self, media_type="image"):
102+
"""Download media (image or video)."""
103+
url = self.thumbnail
104+
if media_type.lower() == "video":
105+
url = self.clip
106+
return api.http_get(
107+
self.sync.blink, url=url, stream=True, json=False, timeout=TIMEOUT_MEDIA,
108+
)
109+
101110
def snap_picture(self):
102111
"""Take a picture with camera to create a new thumbnail."""
103112
return api.request_new_image(self.sync.blink, self.network_id, self.camera_id)
@@ -180,21 +189,10 @@ def update_images(self, config, force_cache=False):
180189
update_cached_video = True
181190

182191
if new_thumbnail is not None and (update_cached_image or force_cache):
183-
self._cached_image = api.http_get(
184-
self.sync.blink,
185-
url=self.thumbnail,
186-
stream=True,
187-
json=False,
188-
timeout=TIMEOUT_MEDIA,
189-
)
192+
self._cached_image = self.get_media()
193+
190194
if clip_addr is not None and (update_cached_video or force_cache):
191-
self._cached_video = api.http_get(
192-
self.sync.blink,
193-
url=self.clip,
194-
stream=True,
195-
json=False,
196-
timeout=TIMEOUT_MEDIA,
197-
)
195+
self._cached_video = self.get_media(media_type="video")
198196

199197
def get_liveview(self):
200198
"""Get livewview rtsps link."""
@@ -210,7 +208,7 @@ def image_to_file(self, path):
210208
:param path: Path to write file
211209
"""
212210
_LOGGER.debug("Writing image from %s to %s", self.name, path)
213-
response = self._cached_image
211+
response = self.get_media()
214212
if response.status_code == 200:
215213
with open(path, "wb") as imgfile:
216214
copyfileobj(response.raw, imgfile)
@@ -226,7 +224,7 @@ def video_to_file(self, path):
226224
:param path: Path to write file
227225
"""
228226
_LOGGER.debug("Writing video from %s to %s", self.name, path)
229-
response = self._cached_video
227+
response = self.get_media(media_type="video")
230228
if response is None:
231229
_LOGGER.error("No saved video exist for %s.", self.name)
232230
return
@@ -268,6 +266,6 @@ def get_liveview(self):
268266
response = api.http_post(self.sync.blink, url)
269267
server = response["server"]
270268
server_split = server.split(":")
271-
server_split[0] = "rtsps"
269+
server_split[0] = "rtsps:"
272270
link = "".join(server_split)
273271
return link

blinkpy/helpers/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
MAJOR_VERSION = 0
66
MINOR_VERSION = 16
7-
PATCH_VERSION = 3
7+
PATCH_VERSION = 4
88

99
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
1010

blinkpy/sync_module.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def get_owl_info(self, name):
145145
for owl in self.blink.homescreen["owls"]:
146146
if owl["name"] == name:
147147
return owl
148-
except KeyError:
148+
except (TypeError, KeyError):
149149
pass
150150
return None
151151

@@ -270,7 +270,7 @@ def get_camera_info(self, camera_id, **kwargs):
270270
if owl["name"] == self.name:
271271
self.status = owl["enabled"]
272272
return owl
273-
except KeyError:
273+
except (TypeError, KeyError):
274274
pass
275275
return None
276276

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
python-dateutil>=2.8.1
22
requests>=2.24.0
33
python-slugify>=4.0.1
4-
testtools>=2.4.0

requirements_test.txt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
black==19.10b0
2-
coverage==5.2.1
3-
flake8==3.8.3
2+
coverage==5.3
3+
flake8==3.8.4
44
flake8-docstrings==1.5.0
5-
pre-commit==2.6.0
6-
pylint==2.5.3
7-
pydocstyle==5.0.2
8-
pytest==6.0.1
9-
pytest-cov==2.10.0
5+
pre-commit==2.7.1
6+
pylint==2.6.0
7+
pydocstyle==5.1.1
8+
pytest==6.1.1
9+
pytest-cov==2.10.1
1010
pytest-sugar==0.9.4
1111
pytest-timeout==1.4.2
1212
restructuredtext-lint==1.3.1
13-
pygments==2.6.1
13+
pygments==2.7.1
14+
testtools>=2.4.0

tests/test_blink_functions.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,23 @@
55

66
from blinkpy import blinkpy
77
from blinkpy.sync_module import BlinkSyncModule
8+
from blinkpy.camera import BlinkCamera
89
from blinkpy.helpers.util import get_time, BlinkURLHandler
910

1011

1112
class MockSyncModule(BlinkSyncModule):
12-
"""Mock http requests from sync module."""
13+
"""Mock blink sync module object."""
1314

14-
def __init__(self, blink, header):
15-
"""Create mock sync module instance."""
16-
super().__init__(blink, header, network_id=None, camera_list=None)
17-
self.blink = blink
18-
self.header = header
19-
self.return_value = None
20-
self.return_value2 = None
15+
def get_network_info(self):
16+
"""Mock network info method."""
17+
return True
2118

22-
def http_get(self, url, stream=False, json=True):
23-
"""Mock get request."""
24-
if stream and self.return_value2 is not None:
25-
return self.return_value2
26-
return self.return_value
2719

28-
def http_post(self, url):
29-
"""Mock post request."""
30-
return self.return_value
20+
class MockCamera(BlinkCamera):
21+
"""Mock blink camera object."""
22+
23+
def update(self, config, force_cache=False, **kwargs):
24+
"""Mock camera update method."""
3125

3226

3327
class TestBlinkFunctions(unittest.TestCase):
@@ -121,3 +115,16 @@ def test_parse_camera_not_in_list(self, mock_req):
121115
with self.assertLogs() as dl_log:
122116
blink.download_videos("/tmp", camera="bar", stop=2)
123117
self.assertEqual(dl_log.output, expected_log)
118+
119+
@mock.patch("blinkpy.blinkpy.api.request_network_update")
120+
@mock.patch("blinkpy.auth.Auth.query")
121+
def test_refresh(self, mock_req, mock_update):
122+
"""Test ability to refresh system."""
123+
mock_update.return_value = {"network": {"sync_module_error": False}}
124+
mock_req.return_value = None
125+
self.blink.last_refresh = 0
126+
self.blink.available = True
127+
self.blink.sync["foo"] = MockSyncModule(self.blink, "foo", 1, [])
128+
self.blink.cameras = {"bar": MockCamera(self.blink.sync)}
129+
self.blink.sync["foo"].cameras = self.blink.cameras
130+
self.assertTrue(self.blink.refresh())

tests/test_blinkpy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ def test_throttle(self, mock_time):
6868
self.assertEqual(self.blink.last_refresh, None)
6969
with mock.patch(
7070
"blinkpy.sync_module.BlinkSyncModule.refresh", return_value=True
71-
):
72-
self.blink.refresh()
71+
), mock.patch("blinkpy.blinkpy.Blink.get_homescreen", return_value=True):
72+
self.blink.refresh(force=True)
7373

7474
self.assertEqual(self.blink.last_refresh, now)
7575
self.assertEqual(self.blink.check_if_ok_to_update(), False)

tests/test_cameras.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,10 @@ def test_mini_missing_attributes(self, mock_resp):
176176
attr = camera.attributes
177177
for key in attr:
178178
self.assertEqual(attr[key], None)
179+
180+
def test_camera_stream(self, mock_resp):
181+
"""Test that camera stream returns correct url."""
182+
mock_resp.return_value = {"server": "rtsps://foo.bar"}
183+
mini_camera = BlinkCameraMini(self.blink.sync["test"])
184+
self.assertEqual(self.camera.get_liveview(), "rtsps://foo.bar")
185+
self.assertEqual(mini_camera.get_liveview(), "rtsps://foo.bar")

0 commit comments

Comments
 (0)