Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92dda40e84 | ||
|
|
6c8fc0abce | ||
|
|
2d74b12d43 | ||
|
|
197695ee40 | ||
|
|
490c42550d | ||
|
|
7367eb6e87 | ||
|
|
414b647dc8 | ||
|
|
57882bb811 | ||
|
|
bb76f09f31 | ||
|
|
741cf489c8 | ||
|
|
7ce332b3ca | ||
|
|
8b7a491c89 | ||
|
|
604eebd1b7 | ||
|
|
c2f44b3dfd | ||
|
|
f4480da276 | ||
|
|
ccad3dcb0c | ||
|
|
7767d3af65 | ||
|
|
79e699ba78 | ||
|
|
b28d6f4eb4 | ||
|
|
d021f48c67 | ||
|
|
1e71af28dd | ||
|
|
cb5867d430 | ||
|
|
bb887936b6 | ||
|
|
afdd73118d | ||
|
|
0262f14a53 | ||
|
|
ff8f091a74 | ||
|
|
77e200f6a5 | ||
|
|
f3a8036649 | ||
|
|
853ccbce79 | ||
|
|
1a24e1896f | ||
|
|
ae946dbb53 | ||
|
|
80c6444c2e | ||
|
|
e872fc9ce5 | ||
|
|
4e6957a772 |
+33
-5
@@ -3,6 +3,34 @@ Changelog
|
||||
|
||||
A list of changes between each release
|
||||
|
||||
0.14.1 (2019-06-20)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Fix timeout problems blocking blinkpy startup
|
||||
- Updated login urls using ``rest-region`` subdomain
|
||||
- Removed deprecated thumbanil recovery from homescreen
|
||||
|
||||
0.14.0 (2019-05-23)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
**Breaking Changes:**
|
||||
|
||||
- ``BlinkCamera.battery`` no longer reports a percentage, instead it returns a string representing the state of the battery.
|
||||
- Previous logic for calculating percentage was incorrect
|
||||
- raw battery voltage can be accessed via ``BlinkCamera.battery_voltage``
|
||||
|
||||
**Bug Fixes:**
|
||||
|
||||
- Updated video endpoint (fixes broken motion detection)
|
||||
- Removed throttling from critical api methods which prevented proper operation of multi-sync unit setups
|
||||
- Slugify downloaded video names to allow for OS interoperability
|
||||
- Added one minute offset (``Blink.motion_interval``) when checking for recent motion to allow time for events to propagate to server prior to refresh call.
|
||||
|
||||
**Everything else:**
|
||||
|
||||
- Changed all urls to use ``rest-region`` rather than ``rest.region``. Ability to revert to old method is enabled by instantiating ``Blink()`` with the ``legacy_subdomain`` variable set to ``True``.
|
||||
- Added debug mode to ``blinkpy.download_videos`` routine to simply print the videos prepped for download, rather than actually saving them.
|
||||
- Use UTC for time conversions, rather than local timezone
|
||||
|
||||
|
||||
0.13.1 (2019-03-01)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Remove throttle decorator from network status request
|
||||
@@ -10,10 +38,10 @@ A list of changes between each release
|
||||
0.13.0 (2019-03-01)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
**Breaking change:**
|
||||
Wifi status reported in dBm again, instead of bars (which is great). Also, the old `get_camera_info` method has changed and requires a `camera_id` parameter.
|
||||
Wifi status reported in dBm again, instead of bars (which is great). Also, the old ``get_camera_info`` method has changed and requires a ``camera_id`` parameter.
|
||||
|
||||
- Adds throttle decorator
|
||||
- Decorate following functions with 4s throttle (call method with `force=True` to override):
|
||||
- Decorate following functions with 4s throttle (call method with ``force=True`` to override):
|
||||
- request_network_status
|
||||
- request_syncmodule
|
||||
- request_system_arm
|
||||
@@ -28,7 +56,7 @@ Wifi status reported in dBm again, instead of bars (which is great). Also, the
|
||||
- request_motion_detection_enable
|
||||
- request_motion_detection_disable
|
||||
- Use the updated homescreen api endpoint to retrieve camera information. The old method to retrieve all cameras at once seems to not exist, and this was the only solution I could figure out and confirm to work.
|
||||
- Adds throttle decorator to refresh function to prevent too many frequent calls with `force_cache` flag set to `True`. This additional throttle can be overridden with the `force=True` argument passed to the refresh function.
|
||||
- Adds throttle decorator to refresh function to prevent too many frequent calls with ``force_cache`` flag set to ``True``. This additional throttle can be overridden with the ``force=True`` argument passed to the refresh function.
|
||||
- Add ability to cycle through login api endpoints to anticipate future endpoint deprecation
|
||||
|
||||
|
||||
@@ -70,7 +98,7 @@ Wifi status reported in dBm again, instead of bars (which is great). Also, the
|
||||
0.10.2 (2018-10-30)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Set minimum required version of the requests library to 2.20.0 due to vulnerability in earlier releases.
|
||||
- When multiple networks detected, changed log level to 'warning' from 'error'
|
||||
- When multiple networks detected, changed log level to ``warning`` from ``error``
|
||||
|
||||
|
||||
0.10.1 (2018-10-18)
|
||||
@@ -98,7 +126,7 @@ Wifi status reported in dBm again, instead of bars (which is great). Also, the
|
||||
- Use session for http requests
|
||||
|
||||
**Breaking change:**
|
||||
- Cameras now accessed through sync module Blink.sync.cameras
|
||||
- Cameras now accessed through sync module ``Blink.sync.cameras``
|
||||
|
||||
|
||||
0.8.1 (2018-09-24)
|
||||
|
||||
+8
-8
@@ -78,7 +78,8 @@ class Blink():
|
||||
self.cameras = CaseInsensitiveDict({})
|
||||
self.video_list = CaseInsensitiveDict({})
|
||||
self._login_url = LOGIN_URL
|
||||
self.motion_interval = DEFAULT_MOTION_INTERVAL
|
||||
self.login_urls = []
|
||||
self.motion_interval = motion_interval
|
||||
self.version = __version__
|
||||
self.legacy = legacy_subdomain
|
||||
|
||||
@@ -131,9 +132,9 @@ class Blink():
|
||||
if not isinstance(self._password, str):
|
||||
raise BlinkAuthenticationException(ERROR.PASSWORD)
|
||||
|
||||
login_urls = [LOGIN_URL, OLD_LOGIN_URL, LOGIN_BACKUP_URL]
|
||||
self.login_urls = [LOGIN_URL, OLD_LOGIN_URL, LOGIN_BACKUP_URL]
|
||||
|
||||
response = self.login_request(login_urls, is_retry=is_retry)
|
||||
response = self.login_request(is_retry=is_retry)
|
||||
|
||||
if not response:
|
||||
return False
|
||||
@@ -148,10 +149,10 @@ class Blink():
|
||||
|
||||
return self._auth_header
|
||||
|
||||
def login_request(self, login_urls, is_retry=False):
|
||||
def login_request(self, is_retry=False):
|
||||
"""Make a login request."""
|
||||
try:
|
||||
login_url = login_urls.pop(0)
|
||||
login_url = self.login_urls.pop(0)
|
||||
except IndexError:
|
||||
_LOGGER.error("Could not login to blink servers.")
|
||||
return False
|
||||
@@ -165,14 +166,13 @@ class Blink():
|
||||
is_retry=is_retry)
|
||||
try:
|
||||
if response.status_code != 200:
|
||||
response = self.login_request(login_urls)
|
||||
response = self.login_request(is_retry=True)
|
||||
response = response.json()
|
||||
(self.region_id, self.region), = response['region'].items()
|
||||
|
||||
except AttributeError:
|
||||
_LOGGER.error("Login API endpoint failed with response %s",
|
||||
response,
|
||||
exc_info=True)
|
||||
response)
|
||||
return False
|
||||
|
||||
except KeyError:
|
||||
|
||||
+5
-18
@@ -117,13 +117,16 @@ class BlinkCamera():
|
||||
_LOGGER.warning("Could not retrieve calibrated temperature.")
|
||||
|
||||
# Check if thumbnail exists in config, if not try to
|
||||
# get it from the homescreen info in teh sync module
|
||||
# get it from the homescreen info in the sync module
|
||||
# otherwise set it to None and log an error
|
||||
new_thumbnail = None
|
||||
thumb_addr = None
|
||||
if config['thumbnail']:
|
||||
thumb_addr = config['thumbnail']
|
||||
else:
|
||||
thumb_addr = self.get_thumb_from_homescreen()
|
||||
_LOGGER.warning("Could not find thumbnail for camera %s",
|
||||
self.name,
|
||||
exc_info=True)
|
||||
|
||||
if thumb_addr is not None:
|
||||
new_thumbnail = "{}{}.jpg".format(self.sync.urls.base_url,
|
||||
@@ -192,19 +195,3 @@ class BlinkCamera():
|
||||
return
|
||||
with open(path, 'wb') as vidfile:
|
||||
copyfileobj(response.raw, vidfile)
|
||||
|
||||
def get_thumb_from_homescreen(self):
|
||||
"""Retrieve thumbnail from homescreen."""
|
||||
for device in self.sync.homescreen['devices']:
|
||||
try:
|
||||
device_type = device['device_type']
|
||||
device_name = device['name']
|
||||
device_thumb = device['thumbnail']
|
||||
if device_type == 'camera' and device_name == self.name:
|
||||
return device_thumb
|
||||
except KeyError:
|
||||
pass
|
||||
_LOGGER.error("Could not find thumbnail for camera %s",
|
||||
self.name,
|
||||
exc_info=True)
|
||||
return None
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 14
|
||||
PATCH_VERSION = '0.dev2'
|
||||
PATCH_VERSION = 1
|
||||
|
||||
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
|
||||
|
||||
@@ -33,6 +33,7 @@ PROJECT_CLASSIFIERS = [
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Home Automation'
|
||||
]
|
||||
|
||||
@@ -45,11 +46,11 @@ PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
|
||||
URLS
|
||||
'''
|
||||
BLINK_URL = 'immedia-semi.com'
|
||||
DEFAULT_URL = "{}.{}".format('prod', BLINK_URL)
|
||||
DEFAULT_URL = "{}.{}".format('rest-prod', BLINK_URL)
|
||||
BASE_URL = "https://{}".format(DEFAULT_URL)
|
||||
LOGIN_URL = "{}/api/v2/login".format(BASE_URL)
|
||||
OLD_LOGIN_URL = "{}/login".format(BASE_URL)
|
||||
LOGIN_BACKUP_URL = "https://{}.{}/login".format('rest.piri', BLINK_URL)
|
||||
LOGIN_BACKUP_URL = "https://{}.{}/login".format('rest-piri', BLINK_URL)
|
||||
|
||||
'''
|
||||
Dictionaries
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import logging
|
||||
import time
|
||||
from functools import wraps
|
||||
from functools import partial, wraps
|
||||
from requests import Request, Session, exceptions
|
||||
from blinkpy.helpers.constants import BLINK_URL, TIMESTAMP_FORMAT
|
||||
import blinkpy.helpers.errors as ERROR
|
||||
@@ -28,8 +28,14 @@ def merge_dicts(dict_a, dict_b):
|
||||
|
||||
|
||||
def create_session():
|
||||
"""Create a session for blink communication."""
|
||||
"""
|
||||
Create a session for blink communication.
|
||||
|
||||
From @ericfrederich via
|
||||
https://github.com/kennethreitz/requests/issues/2011
|
||||
"""
|
||||
sess = Session()
|
||||
sess.get = partial(sess.get, timeout=5)
|
||||
return sess
|
||||
|
||||
|
||||
@@ -65,7 +71,7 @@ def http_req(blink, url='http://example.com', data=None, headers=None,
|
||||
prepped = req.prepare()
|
||||
|
||||
try:
|
||||
response = blink.session.send(prepped, stream=stream, timeout=10)
|
||||
response = blink.session.send(prepped, stream=stream)
|
||||
if json_resp and 'code' in response.json():
|
||||
if is_retry:
|
||||
_LOGGER.error("Cannot obtain new token for server auth.")
|
||||
|
||||
@@ -69,7 +69,8 @@ class TestBlinkFunctions(unittest.TestCase):
|
||||
bad_req,
|
||||
new_req
|
||||
]
|
||||
self.blink.login_request(['test1', 'test2', 'test3'])
|
||||
self.blink.login_urls = ['test1', 'test2', 'test3']
|
||||
self.blink.login_request()
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(self.blink._login_url, 'test3')
|
||||
|
||||
@@ -78,7 +79,8 @@ class TestBlinkFunctions(unittest.TestCase):
|
||||
new_req,
|
||||
bad_req
|
||||
]
|
||||
self.blink.login_request(['test1', 'test2', 'test3'])
|
||||
self.blink.login_urls = ['test1', 'test2', 'test3']
|
||||
self.blink.login_request()
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(self.blink._login_url, 'test2')
|
||||
|
||||
|
||||
+1
-40
@@ -99,45 +99,6 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.assertEqual(self.camera.image_from_cache, 'test')
|
||||
self.assertEqual(self.camera.video_from_cache, 'foobar')
|
||||
|
||||
def test_thumbnail_not_in_info(self, mock_sess):
|
||||
"""Test that we grab thumbanil if not in camera_info."""
|
||||
mock_sess.side_effect = [
|
||||
mresp.MockResponse({'temp': 71}, 200),
|
||||
'foobar',
|
||||
'barfoo'
|
||||
]
|
||||
self.camera.last_record = ['1']
|
||||
self.camera.sync.last_record = {
|
||||
'new': {
|
||||
'clip': '/test.mp4',
|
||||
'time': '1970-01-01T00:00:00'
|
||||
}
|
||||
}
|
||||
config = {
|
||||
'name': 'new',
|
||||
'id': 1234,
|
||||
'network_id': 5678,
|
||||
'serial': '12345678',
|
||||
'enabled': False,
|
||||
'battery_voltage': 90,
|
||||
'battery_state': 'ok',
|
||||
'temperature': 68,
|
||||
'wifi_strength': 4,
|
||||
'thumbnail': '',
|
||||
}
|
||||
self.camera.sync.homescreen = {
|
||||
'devices': [
|
||||
{'foo': 'bar'},
|
||||
{'device_type': 'foobar'},
|
||||
{'device_type': 'camera',
|
||||
'name': 'new',
|
||||
'thumbnail': '/new/thumb'}
|
||||
]
|
||||
}
|
||||
self.camera.update(config)
|
||||
self.assertEqual(self.camera.thumbnail,
|
||||
'https://rest-test.immedia-semi.com/new/thumb.jpg')
|
||||
|
||||
def test_no_thumbnails(self, mock_sess):
|
||||
"""Tests that thumbnail is 'None' if none found."""
|
||||
mock_sess.return_value = 'foobar'
|
||||
@@ -167,7 +128,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
logrecord.output,
|
||||
[("WARNING:blinkpy.camera:Could not retrieve calibrated "
|
||||
"temperature."),
|
||||
("ERROR:blinkpy.camera:Could not find thumbnail for camera new"
|
||||
("WARNING:blinkpy.camera:Could not find thumbnail for camera new"
|
||||
"\nNoneType: None")]
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user