Merge pull request #21 from fronzbot/cleanup
Cleanup and Coverage Increase
This commit is contained in:
@@ -10,7 +10,7 @@ The Client API is a straightforward REST API using JSON and HTTPS.
|
|||||||
## This Document
|
## This Document
|
||||||
The purpose here is to describe what is going on behind the scenes, and what commands we know are available to communicate with Blink servers. This is NOT a description of the blinkpy module, but a description of the commands blinkpy relies on to effectively communicate.
|
The purpose here is to describe what is going on behind the scenes, and what commands we know are available to communicate with Blink servers. This is NOT a description of the blinkpy module, but a description of the commands blinkpy relies on to effectively communicate.
|
||||||
|
|
||||||
##Login
|
## Login
|
||||||
|
|
||||||
Client login to the Blink Servers.
|
Client login to the Blink Servers.
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ JSON response containing information including Network ID and Account ID.
|
|||||||
Network ID is needed to issue arm/disarm calls
|
Network ID is needed to issue arm/disarm calls
|
||||||
|
|
||||||
|
|
||||||
##Sync Modules
|
## Sync Modules
|
||||||
|
|
||||||
Obtain information about the Blink Sync Modules on the given network.
|
Obtain information about the Blink Sync Modules on the given network.
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ JSON response containing information about the known state of the Sync module, m
|
|||||||
Probably not strictly needed but checking result can verify that the sync module is online and will respond to requests to arm/disarm, etc.
|
Probably not strictly needed but checking result can verify that the sync module is online and will respond to requests to arm/disarm, etc.
|
||||||
|
|
||||||
|
|
||||||
##Arm
|
## Arm
|
||||||
|
|
||||||
Arm the given network (start recording/reporting motion events)
|
Arm the given network (start recording/reporting motion events)
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ JSON response containing information about the arm command request, including th
|
|||||||
**Notes:**
|
**Notes:**
|
||||||
When this call returns, it does not mean the arm request is complete, the client must gather the request ID from the response and poll for the status of the command.
|
When this call returns, it does not mean the arm request is complete, the client must gather the request ID from the response and poll for the status of the command.
|
||||||
|
|
||||||
##Disarm
|
## Disarm
|
||||||
|
|
||||||
Disarm the given network (stop recording/reporting motion events)
|
Disarm the given network (stop recording/reporting motion events)
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ JSON response containing information about the disarm command request, including
|
|||||||
When this call returns, it does not mean the disarm request is complete, the client must gather the request ID from the response and poll for the status of the command.
|
When this call returns, it does not mean the disarm request is complete, the client must gather the request ID from the response and poll for the status of the command.
|
||||||
|
|
||||||
|
|
||||||
##Command Status
|
## Command Status
|
||||||
|
|
||||||
Get status info on the given command
|
Get status info on the given command
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ After an arm/disarm command, the client appears to poll this URL every second or
|
|||||||
**Known Commands:**
|
**Known Commands:**
|
||||||
lv_relay, arm, disarm, thumbnail, clip
|
lv_relay, arm, disarm, thumbnail, clip
|
||||||
|
|
||||||
##Home Screen
|
## Home Screen
|
||||||
|
|
||||||
Return information displayed on the home screen of the mobile client
|
Return information displayed on the home screen of the mobile client
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ Deletes all videos
|
|||||||
**Response**
|
**Response**
|
||||||
Unknown - not tested
|
Unknown - not tested
|
||||||
|
|
||||||
##Cameras
|
## Cameras
|
||||||
|
|
||||||
**Request**
|
**Request**
|
||||||
Gets a list of cameras
|
Gets a list of cameras
|
||||||
@@ -252,7 +252,7 @@ JSON response containing camera information
|
|||||||
*Note*: enabling or disabling motion detection is independent of arming or disarming the system. No motion detection or video recording will take place unless the system is armed.
|
*Note*: enabling or disabling motion detection is independent of arming or disarming the system. No motion detection or video recording will take place unless the system is armed.
|
||||||
|
|
||||||
|
|
||||||
##Miscellaneous
|
## Miscellaneous
|
||||||
|
|
||||||
**Request**
|
**Request**
|
||||||
Gets information about devices that have connected to the blink service
|
Gets information about devices that have connected to the blink service
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
# Changelog
|
||||||
|
-----------
|
||||||
|
|
||||||
|
A list of changes between each release
|
||||||
|
|
||||||
|
0.6.0.dev0 (unreleased)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Removed redundent properties that only called hidden variables
|
||||||
|
- Revised request wrapper function to be more intelligent
|
||||||
|
- Added tests to ensure exceptions are caught and handled (100% coverage!)
|
||||||
|
|
||||||
|
0.5.2 (2017-03-12)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed packaging mishap, same as 0.5.0 otherwise
|
||||||
|
|
||||||
|
0.5.0 (2017-03-12)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed region handling problem
|
||||||
|
- Added rest.piri subdomain as a backup if region can't be found
|
||||||
|
- Improved the file writing function
|
||||||
|
- Large test coverage increase
|
||||||
|
|
||||||
|
0.4.4 (2017-03-06)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed bug where region id was not being set in the header
|
||||||
|
|
||||||
|
0.4.3 (2017-03-05)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Changed to bdist_wheel release
|
||||||
|
|
||||||
|
0.4.2 (2017-01-28)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed inability to retrieve motion data due to Key Error
|
||||||
|
|
||||||
|
0.4.1 (2017-01-27)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed refresh bug (0.3.1 did not actually fix the problem)
|
||||||
|
- Image refresh routine added (per camera)
|
||||||
|
- Dictionary of thumbnails per camera added
|
||||||
|
- Improved test coverage
|
||||||
|
|
||||||
|
0.3.1 (2017-01-25)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Fixed refresh bug (Key Error)
|
||||||
|
|
||||||
|
0.3.0 (2017-01-25)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Added device id to camera lookup table
|
||||||
|
- Added image to file method
|
||||||
|
|
||||||
|
0.2.0 (2017-01-21)
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
- Initial release of blinkpy
|
||||||
+62
-200
@@ -25,26 +25,23 @@ from helpers.constants import (BLINK_URL, LOGIN_URL,
|
|||||||
def _request(url, data=None, headers=None, reqtype='get',
|
def _request(url, data=None, headers=None, reqtype='get',
|
||||||
stream=False, json_resp=True):
|
stream=False, json_resp=True):
|
||||||
"""Wrapper function for request."""
|
"""Wrapper function for request."""
|
||||||
if reqtype is 'post' and json_resp:
|
if reqtype == 'post':
|
||||||
response = requests.post(url, headers=headers,
|
|
||||||
data=data).json()
|
|
||||||
elif reqtype is 'post' and not json_resp:
|
|
||||||
response = requests.post(url, headers=headers,
|
response = requests.post(url, headers=headers,
|
||||||
data=data)
|
data=data)
|
||||||
elif reqtype is 'get' and json_resp:
|
elif reqtype == 'get':
|
||||||
response = requests.get(url, headers=headers,
|
|
||||||
stream=stream).json()
|
|
||||||
elif reqtype is 'get' and not json_resp:
|
|
||||||
response = requests.get(url, headers=headers,
|
response = requests.get(url, headers=headers,
|
||||||
stream=stream)
|
stream=stream)
|
||||||
else:
|
else:
|
||||||
raise BlinkException(ERROR.REQUEST)
|
raise BlinkException(ERROR.REQUEST)
|
||||||
|
|
||||||
if json_resp and 'code' in response:
|
if json_resp and 'code' in response.json():
|
||||||
raise BlinkAuthenticationException(
|
raise BlinkAuthenticationException(
|
||||||
(response['code'], response['message']))
|
(response.json()['code'], response.json()['message']))
|
||||||
|
|
||||||
return response
|
if json_resp:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=super-init-not-called
|
# pylint: disable=super-init-not-called
|
||||||
@@ -81,169 +78,58 @@ class BlinkCamera(object):
|
|||||||
def __init__(self, config, urls):
|
def __init__(self, config, urls):
|
||||||
"""Initiailize BlinkCamera."""
|
"""Initiailize BlinkCamera."""
|
||||||
self.urls = urls
|
self.urls = urls
|
||||||
self._id = str(config['device_id'])
|
self.id = str(config['device_id']) # pylint: disable=invalid-name
|
||||||
self._name = config['name']
|
self.name = config['name']
|
||||||
self._status = config['armed']
|
self._status = config['armed']
|
||||||
self._thumb = self.urls.base_url + config['thumbnail'] + '.jpg'
|
self.thumbnail = self.urls.base_url + config['thumbnail'] + '.jpg'
|
||||||
self._clip = self.urls.base_url + config['thumbnail'] + '.mp4'
|
self.clip = self.urls.base_url + config['thumbnail'] + '.mp4'
|
||||||
self._temperature = config['temp']
|
self.temperature = config['temp']
|
||||||
self._battery = config['battery']
|
self.battery = config['battery']
|
||||||
self._notifications = config['notifications']
|
self.notifications = config['notifications']
|
||||||
self._motion = {}
|
self.motion = {}
|
||||||
self._header = None
|
self.header = None
|
||||||
self._image_link = None
|
self.image_link = None
|
||||||
self._arm_link = None
|
self.arm_link = None
|
||||||
self._region_id = config['region_id']
|
self.region_id = config['region_id']
|
||||||
|
|
||||||
@property
|
|
||||||
# pylint: disable=invalid-name
|
|
||||||
def id(self):
|
|
||||||
"""Return camera id."""
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return camera name."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""Set camera name."""
|
|
||||||
self._name = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def region_id(self):
|
|
||||||
"""Return region id."""
|
|
||||||
return self._region_id
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def armed(self):
|
def armed(self):
|
||||||
"""Return camera arm status."""
|
"""Return camera arm status."""
|
||||||
return self._status
|
return self._status
|
||||||
|
|
||||||
@property
|
|
||||||
def clip(self):
|
|
||||||
"""Return current clip."""
|
|
||||||
return self._clip
|
|
||||||
|
|
||||||
@clip.setter
|
|
||||||
def clip(self, value):
|
|
||||||
"""Set current clip."""
|
|
||||||
self._clip = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def thumbnail(self):
|
|
||||||
"""Return current thumbnail."""
|
|
||||||
return self._thumb
|
|
||||||
|
|
||||||
@thumbnail.setter
|
|
||||||
def thumbnail(self, value):
|
|
||||||
"""Set current thumbnail."""
|
|
||||||
self._thumb = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def temperature(self):
|
|
||||||
"""Return camera temperature."""
|
|
||||||
return self._temperature
|
|
||||||
|
|
||||||
@temperature.setter
|
|
||||||
def temperature(self, value):
|
|
||||||
"""Set camera temperature."""
|
|
||||||
self._temperature = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def battery(self):
|
|
||||||
"""Return battery level."""
|
|
||||||
return self._battery
|
|
||||||
|
|
||||||
@battery.setter
|
|
||||||
def battery(self, value):
|
|
||||||
"""Set battery level."""
|
|
||||||
self._battery = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notifications(self):
|
|
||||||
"""Return number of notifications."""
|
|
||||||
return self._notifications
|
|
||||||
|
|
||||||
@notifications.setter
|
|
||||||
def notifications(self, value):
|
|
||||||
"""Set number of notifications."""
|
|
||||||
self._notifications = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def image_link(self):
|
|
||||||
"""Return image link."""
|
|
||||||
return self._image_link
|
|
||||||
|
|
||||||
@image_link.setter
|
|
||||||
def image_link(self, value):
|
|
||||||
"""Set image link."""
|
|
||||||
self._image_link = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def arm_link(self):
|
|
||||||
"""Return link to arm camera."""
|
|
||||||
return self._arm_link
|
|
||||||
|
|
||||||
@arm_link.setter
|
|
||||||
def arm_link(self, value):
|
|
||||||
"""Set link to arm camera."""
|
|
||||||
self._arm_link = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def header(self):
|
|
||||||
"""Return request header."""
|
|
||||||
return self._header
|
|
||||||
|
|
||||||
@header.setter
|
|
||||||
def header(self, value):
|
|
||||||
"""Set request header."""
|
|
||||||
self._header = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def motion(self):
|
|
||||||
"""Return last motion event detail."""
|
|
||||||
return self._motion
|
|
||||||
|
|
||||||
@motion.setter
|
|
||||||
def motion(self, value):
|
|
||||||
"""Set link to last motion and timestamp."""
|
|
||||||
self._motion = value
|
|
||||||
|
|
||||||
def snap_picture(self):
|
def snap_picture(self):
|
||||||
"""Take a picture with camera to create a new thumbnail."""
|
"""Take a picture with camera to create a new thumbnail."""
|
||||||
_request(self._image_link, headers=self._header, reqtype='post')
|
_request(self.image_link, headers=self.header, reqtype='post')
|
||||||
|
|
||||||
def set_motion_detect(self, enable):
|
def set_motion_detect(self, enable):
|
||||||
"""Set motion detection."""
|
"""Set motion detection."""
|
||||||
url = self._arm_link
|
url = self.arm_link
|
||||||
if enable:
|
if enable:
|
||||||
_request(url + 'enable', headers=self._header, reqtype='post')
|
_request(url + 'enable', headers=self.header, reqtype='post')
|
||||||
else:
|
else:
|
||||||
_request(url + 'disable', headers=self._header, reqtype='post')
|
_request(url + 'disable', headers=self.header, reqtype='post')
|
||||||
|
|
||||||
def update(self, values):
|
def update(self, values):
|
||||||
"""Update camera information."""
|
"""Update camera information."""
|
||||||
self._name = values['name']
|
self.name = values['name']
|
||||||
self._status = values['armed']
|
self._status = values['armed']
|
||||||
self._thumb = self.urls.base_url + values['thumbnail'] + '.jpg'
|
self.thumbnail = self.urls.base_url + values['thumbnail'] + '.jpg'
|
||||||
self._clip = self.urls.base_url + values['thumbnail'] + '.mp4'
|
self.clip = self.urls.base_url + values['thumbnail'] + '.mp4'
|
||||||
self._temperature = values['temp']
|
self.temperature = values['temp']
|
||||||
self._battery = values['battery']
|
self.battery = values['battery']
|
||||||
self._notifications = values['notifications']
|
self.notifications = values['notifications']
|
||||||
|
|
||||||
def image_refresh(self):
|
def image_refresh(self):
|
||||||
"""Refresh current thumbnail."""
|
"""Refresh current thumbnail."""
|
||||||
url = self.urls.home_url
|
url = self.urls.home_url
|
||||||
response = _request(url, headers=self._header,
|
response = _request(url, headers=self.header,
|
||||||
reqtype='get')['devices']
|
reqtype='get')['devices']
|
||||||
for element in response:
|
for element in response:
|
||||||
try:
|
try:
|
||||||
if str(element['device_id']) == self._id:
|
if str(element['device_id']) == self.id:
|
||||||
self._thumb = (self.urls.base_url +
|
self.thumbnail = (self.urls.base_url +
|
||||||
element['thumbnail'] + '.jpg')
|
element['thumbnail'] + '.jpg')
|
||||||
return self._thumb
|
return self.thumbnail
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
@@ -251,7 +137,7 @@ class BlinkCamera(object):
|
|||||||
def image_to_file(self, path):
|
def image_to_file(self, path):
|
||||||
"""Write image to file."""
|
"""Write image to file."""
|
||||||
thumb = self.image_refresh()
|
thumb = self.image_refresh()
|
||||||
response = _request(thumb, headers=self._header,
|
response = _request(thumb, headers=self.header,
|
||||||
reqtype='get', stream=True, json_resp=False)
|
reqtype='get', stream=True, json_resp=False)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
with open(path, 'wb') as imgfile:
|
with open(path, 'wb') as imgfile:
|
||||||
@@ -267,27 +153,22 @@ class Blink(object):
|
|||||||
self._password = password
|
self._password = password
|
||||||
self._token = None
|
self._token = None
|
||||||
self._auth_header = None
|
self._auth_header = None
|
||||||
self._network_id = None
|
self.network_id = None
|
||||||
self._account_id = None
|
self.account_id = None
|
||||||
self._region = None
|
self.region = None
|
||||||
self._region_id = None
|
self.region_id = None
|
||||||
self._host = None
|
self._host = None
|
||||||
self._events = []
|
self._events = []
|
||||||
self._cameras = {}
|
self.cameras = {}
|
||||||
self._idlookup = {}
|
self._idlookup = {}
|
||||||
self.urls = None
|
self.urls = None
|
||||||
|
|
||||||
@property
|
|
||||||
def cameras(self):
|
|
||||||
"""Return camera/id pairs."""
|
|
||||||
return self._cameras
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def camera_thumbs(self):
|
def camera_thumbs(self):
|
||||||
"""Return camera thumbnails."""
|
"""Return camera thumbnails."""
|
||||||
self.refresh()
|
self.refresh()
|
||||||
data = {}
|
data = {}
|
||||||
for name, camera in self._cameras.items():
|
for name, camera in self.cameras.items():
|
||||||
data[name] = camera.thumbnail
|
data[name] = camera.thumbnail
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@@ -297,30 +178,10 @@ class Blink(object):
|
|||||||
"""Return id/camera pairs."""
|
"""Return id/camera pairs."""
|
||||||
return self._idlookup
|
return self._idlookup
|
||||||
|
|
||||||
@property
|
|
||||||
def network_id(self):
|
|
||||||
"""Return network id."""
|
|
||||||
return self._network_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def account_id(self):
|
|
||||||
"""Return account id."""
|
|
||||||
return self._account_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def region(self):
|
|
||||||
"""Return current region."""
|
|
||||||
return self._region
|
|
||||||
|
|
||||||
@property
|
|
||||||
def region_id(self):
|
|
||||||
"""Return region id."""
|
|
||||||
return self._region_id
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def events(self):
|
def events(self):
|
||||||
"""Get all events on server."""
|
"""Get all events on server."""
|
||||||
url = self.urls.event_url + self._network_id
|
url = self.urls.event_url + self.network_id
|
||||||
headers = self._auth_header
|
headers = self._auth_header
|
||||||
self._events = _request(url, headers=headers,
|
self._events = _request(url, headers=headers,
|
||||||
reqtype='get')['event']
|
reqtype='get')['event']
|
||||||
@@ -329,7 +190,7 @@ class Blink(object):
|
|||||||
@property
|
@property
|
||||||
def online(self):
|
def online(self):
|
||||||
"""Return boolean system online status."""
|
"""Return boolean system online status."""
|
||||||
url = self.urls.network_url + self._network_id + '/syncmodules'
|
url = self.urls.network_url + self.network_id + '/syncmodules'
|
||||||
headers = self._auth_header
|
headers = self._auth_header
|
||||||
return ONLINE[_request(url, headers=headers,
|
return ONLINE[_request(url, headers=headers,
|
||||||
reqtype='get')['syncmodule']['status']]
|
reqtype='get')['syncmodule']['status']]
|
||||||
@@ -340,8 +201,8 @@ class Blink(object):
|
|||||||
for element in recent:
|
for element in recent:
|
||||||
try:
|
try:
|
||||||
camera_id = str(element['camera_id'])
|
camera_id = str(element['camera_id'])
|
||||||
camera_name = self._idlookup[camera_id]
|
camera_name = self.id_table[camera_id]
|
||||||
camera = self._cameras[camera_name]
|
camera = self.cameras[camera_name]
|
||||||
if element['type'] == 'motion':
|
if element['type'] == 'motion':
|
||||||
url = self.urls.base_url + element['video_url']
|
url = self.urls.base_url + element['video_url']
|
||||||
camera.motion = {'video': url,
|
camera.motion = {'video': url,
|
||||||
@@ -362,21 +223,22 @@ class Blink(object):
|
|||||||
value_to_append = 'arm'
|
value_to_append = 'arm'
|
||||||
else:
|
else:
|
||||||
value_to_append = 'disarm'
|
value_to_append = 'disarm'
|
||||||
url = self.urls.network_url + self._network_id + '/' + value_to_append
|
url = self.urls.network_url + self.network_id + '/' + value_to_append
|
||||||
_request(url, headers=self._auth_header, reqtype='post')
|
_request(url, headers=self._auth_header, reqtype='post')
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""Get all blink cameras and pulls their most recent status."""
|
"""Get all blink cameras and pulls their most recent status."""
|
||||||
response = self.get_summary()['devices']
|
response = self.get_summary()['devices']
|
||||||
|
|
||||||
for name in self._cameras:
|
for name in self.cameras:
|
||||||
camera = self._cameras[name]
|
camera = self.cameras[name]
|
||||||
for element in response:
|
for element in response:
|
||||||
try:
|
try:
|
||||||
if str(element['device_id']) == camera.id:
|
if str(element['device_id']) == camera.id:
|
||||||
camera.update(element)
|
camera.update(element)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
def get_summary(self):
|
def get_summary(self):
|
||||||
"""Get a full summary of device information."""
|
"""Get a full summary of device information."""
|
||||||
@@ -395,16 +257,16 @@ class Blink(object):
|
|||||||
if ('device_type' in element and
|
if ('device_type' in element and
|
||||||
element['device_type'] == 'camera'):
|
element['device_type'] == 'camera'):
|
||||||
# Add region to config
|
# Add region to config
|
||||||
element['region_id'] = self._region_id
|
element['region_id'] = self.region_id
|
||||||
device = BlinkCamera(element, self.urls)
|
device = BlinkCamera(element, self.urls)
|
||||||
self._cameras[device.name] = device
|
self.cameras[device.name] = device
|
||||||
self._idlookup[device.id] = device.name
|
self._idlookup[device.id] = device.name
|
||||||
|
|
||||||
def set_links(self):
|
def set_links(self):
|
||||||
"""Set access links and required headers for each camera in system."""
|
"""Set access links and required headers for each camera in system."""
|
||||||
for name in self._cameras:
|
for name in self.cameras:
|
||||||
camera = self._cameras[name]
|
camera = self.cameras[name]
|
||||||
network_id_url = self.urls.network_url + self._network_id
|
network_id_url = self.urls.network_url + self.network_id
|
||||||
image_url = network_id_url + '/camera/' + camera.id + '/thumbnail'
|
image_url = network_id_url + '/camera/' + camera.id + '/thumbnail'
|
||||||
arm_url = network_id_url + '/camera/' + camera.id + '/'
|
arm_url = network_id_url + '/camera/' + camera.id + '/'
|
||||||
camera.image_link = image_url
|
camera.image_link = image_url
|
||||||
@@ -448,20 +310,20 @@ class Blink(object):
|
|||||||
data=data, json_resp=False, reqtype='post')
|
data=data, json_resp=False, reqtype='post')
|
||||||
if response.status_code is 200:
|
if response.status_code is 200:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
(self._region_id, self._region), = response['region'].items()
|
(self.region_id, self.region), = response['region'].items()
|
||||||
else:
|
else:
|
||||||
response = _request(LOGIN_BACKUP_URL, headers=headers,
|
response = _request(LOGIN_BACKUP_URL, headers=headers,
|
||||||
data=data, reqtype='post')
|
data=data, reqtype='post')
|
||||||
self._region_id = 'rest.piri'
|
self.region_id = 'rest.piri'
|
||||||
self._region = "UNKNOWN"
|
self.region = "UNKNOWN"
|
||||||
|
|
||||||
self._host = self._region_id + '.' + BLINK_URL
|
self._host = self.region_id + '.' + BLINK_URL
|
||||||
self._token = response['authtoken']['authtoken']
|
self._token = response['authtoken']['authtoken']
|
||||||
|
|
||||||
self._auth_header = {'Host': self._host,
|
self._auth_header = {'Host': self._host,
|
||||||
'TOKEN_AUTH': self._token}
|
'TOKEN_AUTH': self._token}
|
||||||
|
|
||||||
self.urls = BlinkURLHandler(self._region_id)
|
self.urls = BlinkURLHandler(self.region_id)
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
"""Set the network ID and Account ID."""
|
"""Set the network ID and Account ID."""
|
||||||
@@ -472,5 +334,5 @@ class Blink(object):
|
|||||||
raise BlinkException(ERROR.AUTH_TOKEN)
|
raise BlinkException(ERROR.AUTH_TOKEN)
|
||||||
|
|
||||||
response = _request(url, headers=headers, reqtype='get')
|
response = _request(url, headers=headers, reqtype='get')
|
||||||
self._network_id = str(response['networks'][0]['id'])
|
self.network_id = str(response['networks'][0]['id'])
|
||||||
self._account_id = str(response['networks'][0]['account_id'])
|
self.account_id = str(response['networks'][0]['account_id'])
|
||||||
|
|||||||
+56
-55
@@ -1,55 +1,56 @@
|
|||||||
'''
|
'''
|
||||||
constants.py
|
constants.py
|
||||||
Generates constants for use in blinkpy
|
Generates constants for use in blinkpy
|
||||||
'''
|
'''
|
||||||
import os
|
import os
|
||||||
|
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 5
|
MINOR_VERSION = 6
|
||||||
PATCH_VERSION = '3.dev0'
|
PATCH_VERSION = '0.dev0'
|
||||||
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
|
|
||||||
|
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
|
||||||
REQUIRED_PYTHON_VER = (3, 4, 2)
|
|
||||||
|
REQUIRED_PYTHON_VER = (3, 4, 2)
|
||||||
PROJECT_NAME = 'blinkpy'
|
|
||||||
PROJECT_PACKAGE_NAME = 'blinkpy'
|
PROJECT_NAME = 'blinkpy'
|
||||||
PROJECT_LICENSE = 'MIT'
|
PROJECT_PACKAGE_NAME = 'blinkpy'
|
||||||
PROJECT_AUTHOR = 'Kevin Fronczak'
|
PROJECT_LICENSE = 'MIT'
|
||||||
PROJECT_COPYRIGHT = ' 2017, {}'.format(PROJECT_AUTHOR)
|
PROJECT_AUTHOR = 'Kevin Fronczak'
|
||||||
PROJECT_URL = 'https://github.com/fronzbot/blinkpy'
|
PROJECT_COPYRIGHT = ' 2017, {}'.format(PROJECT_AUTHOR)
|
||||||
PROJECT_EMAIL = 'kfronczak@gmail.com'
|
PROJECT_URL = 'https://github.com/fronzbot/blinkpy'
|
||||||
PROJECT_DESCRIPTION = ('A Blink camera Python library '
|
PROJECT_EMAIL = 'kfronczak@gmail.com'
|
||||||
'running on Python 3.')
|
PROJECT_DESCRIPTION = ('A Blink camera Python library '
|
||||||
PROJECT_LONG_DESCRIPTION = ('blinkpy is an open-source '
|
'running on Python 3.')
|
||||||
'unofficial API for the Blink Camera '
|
PROJECT_LONG_DESCRIPTION = ('blinkpy is an open-source '
|
||||||
'system with the intention for easy '
|
'unofficial API for the Blink Camera '
|
||||||
'integration into various home '
|
'system with the intention for easy '
|
||||||
'automation platforms.')
|
'integration into various home '
|
||||||
if os.path.exists('README.rst'):
|
'automation platforms.')
|
||||||
PROJECT_LONG_DESCRIPTION = open('README.rst').read()
|
if os.path.exists('README.rst'):
|
||||||
PROJECT_CLASSIFIERS = [
|
PROJECT_LONG_DESCRIPTION = open('README.rst').read()
|
||||||
'Intended Audience :: Developers',
|
PROJECT_CLASSIFIERS = [
|
||||||
'License :: OSI Approved :: MIT License',
|
'Intended Audience :: Developers',
|
||||||
'Operating System :: OS Independent',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Operating System :: OS Independent',
|
||||||
'Topic :: Home Automation'
|
'Programming Language :: Python :: 3.4',
|
||||||
]
|
'Topic :: Home Automation'
|
||||||
|
]
|
||||||
PROJECT_GITHUB_USERNAME = 'fronzbot'
|
|
||||||
PROJECT_GITHUB_REPOSITORY = 'blinkpy'
|
PROJECT_GITHUB_USERNAME = 'fronzbot'
|
||||||
|
PROJECT_GITHUB_REPOSITORY = 'blinkpy'
|
||||||
PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
|
|
||||||
|
PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
|
||||||
'''
|
|
||||||
URLS
|
'''
|
||||||
'''
|
URLS
|
||||||
BLINK_URL = 'immedia-semi.com'
|
'''
|
||||||
LOGIN_URL = 'https://prod.' + BLINK_URL + '/login'
|
BLINK_URL = 'immedia-semi.com'
|
||||||
LOGIN_BACKUP_URL = 'https://rest.piri/' + BLINK_URL + '/login'
|
LOGIN_URL = 'https://prod.' + BLINK_URL + '/login'
|
||||||
BASE_URL = 'https://prod.' + BLINK_URL
|
LOGIN_BACKUP_URL = 'https://rest.piri/' + BLINK_URL + '/login'
|
||||||
DEFAULT_URL = 'prod.' + BLINK_URL
|
BASE_URL = 'https://prod.' + BLINK_URL
|
||||||
|
DEFAULT_URL = 'prod.' + BLINK_URL
|
||||||
'''
|
|
||||||
Dictionaries
|
'''
|
||||||
'''
|
Dictionaries
|
||||||
ONLINE = {'online': True, 'offline': False}
|
'''
|
||||||
|
ONLINE = {'online': True, 'offline': False}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
flake8==3.3
|
flake8==3.3
|
||||||
pylint==1.6.5
|
pylint==1.6.5
|
||||||
pydocstyle==1.1.1
|
pydocstyle==1.1.1
|
||||||
|
pytest>=2.9.2
|
||||||
|
pytest-sugar>=0.8.0
|
||||||
+286
-274
@@ -1,274 +1,286 @@
|
|||||||
"""
|
"""
|
||||||
Mock responses that mimic actual responses from Blink servers.
|
Mock responses that mimic actual responses from Blink servers.
|
||||||
|
|
||||||
This file should be updated any time the Blink server responses
|
This file should be updated any time the Blink server responses
|
||||||
change so we can make sure blinkpy can still communicate.
|
change so we can make sure blinkpy can still communicate.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import helpers.constants as const
|
import helpers.constants as const
|
||||||
|
|
||||||
NETWORKS_RESPONSE = {}
|
NETWORKS_RESPONSE = {}
|
||||||
NETWORKS_RESPONSE['summary'] = {'onboarded': True, 'name': 'Nilfgaard'}
|
NETWORKS_RESPONSE['summary'] = {'onboarded': True, 'name': 'Nilfgaard'}
|
||||||
NETWORKS_RESPONSE['networks'] = [{
|
NETWORKS_RESPONSE['networks'] = [{
|
||||||
'network_key': None,
|
'network_key': None,
|
||||||
'name': NETWORKS_RESPONSE['summary']['name'],
|
'name': NETWORKS_RESPONSE['summary']['name'],
|
||||||
'account_id': 1989,
|
'account_id': 1989,
|
||||||
'id': 9898,
|
'id': 9898,
|
||||||
'encryption_key': None,
|
'encryption_key': None,
|
||||||
'armed': True,
|
'armed': True,
|
||||||
'ping_interval': 60,
|
'ping_interval': 60,
|
||||||
'video_destination': 'server',
|
'video_destination': 'server',
|
||||||
'arm_string': 'Armed',
|
'arm_string': 'Armed',
|
||||||
'feature_plan_id': None
|
'feature_plan_id': None
|
||||||
}]
|
}]
|
||||||
|
|
||||||
NEW_THUMBNAIL = '/NEW/THUMBNAIL/YAY'
|
NEW_THUMBNAIL = '/NEW/THUMBNAIL/YAY'
|
||||||
|
|
||||||
FIRST_CAMERA = {'device_type': 'camera',
|
FIRST_CAMERA = {'device_type': 'camera',
|
||||||
'notifications': 1,
|
'notifications': 1,
|
||||||
'battery': 2,
|
'battery': 2,
|
||||||
'active': 'enabled',
|
'active': 'enabled',
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'temp': 70,
|
'temp': 70,
|
||||||
'updated_at': '2017-01-01T01:23:45+00:00',
|
'updated_at': '2017-01-01T01:23:45+00:00',
|
||||||
'lfr_strength': 3,
|
'lfr_strength': 3,
|
||||||
'armed': True,
|
'armed': True,
|
||||||
'device_id': 2112,
|
'device_id': 2112,
|
||||||
'wifi_strength': 5,
|
'wifi_strength': 5,
|
||||||
'thumbnail': '/this/is/url1/thumb',
|
'thumbnail': '/this/is/url1/thumb',
|
||||||
'name': 'First Camera',
|
'name': 'First Camera',
|
||||||
'status': 'done'}
|
'status': 'done'}
|
||||||
|
|
||||||
SECOND_CAMERA = {'device_type': 'camera',
|
SECOND_CAMERA = {'device_type': 'camera',
|
||||||
'notifications': 0,
|
'notifications': 0,
|
||||||
'battery': 3,
|
'battery': 3,
|
||||||
'active': 'disabled',
|
'active': 'disabled',
|
||||||
'enabled': False,
|
'enabled': False,
|
||||||
'temp': 82,
|
'temp': 82,
|
||||||
'updated_at': '2017-12-21T01:21:12+00:00',
|
'updated_at': '2017-12-21T01:21:12+00:00',
|
||||||
'lfr_strength': 1,
|
'lfr_strength': 1,
|
||||||
'armed': False,
|
'armed': False,
|
||||||
'device_id': 1221,
|
'device_id': 1221,
|
||||||
'wifi_strength': 1,
|
'wifi_strength': 1,
|
||||||
'thumbnail': '/this/is/url2/thumb',
|
'thumbnail': '/this/is/url2/thumb',
|
||||||
'name': 'Second Camera',
|
'name': 'Second Camera',
|
||||||
'status': 'done'}
|
'status': 'done'}
|
||||||
|
|
||||||
SYNC_MODULE = {'updated_at': '1970-01-01T01:00:00+00:00',
|
SYNC_MODULE = {'updated_at': '1970-01-01T01:00:00+00:00',
|
||||||
'device_type': 'sync_module',
|
'device_type': 'sync_module',
|
||||||
'notifications': 2,
|
'notifications': 2,
|
||||||
'device_id': 7990,
|
'device_id': 7990,
|
||||||
'status': 'online'}
|
'status': 'online'}
|
||||||
|
|
||||||
FIRST_EVENT = {'camera_name': FIRST_CAMERA['name'],
|
FIRST_EVENT = {'camera_name': FIRST_CAMERA['name'],
|
||||||
'updated_at': '2017-10-10T03:37:37+00:00',
|
'updated_at': '2017-10-10T03:37:37+00:00',
|
||||||
'sync_module_id': None,
|
'sync_module_id': None,
|
||||||
'camera': FIRST_CAMERA['device_id'],
|
'camera': FIRST_CAMERA['device_id'],
|
||||||
'type': 'motion',
|
'type': 'motion',
|
||||||
'duration': None,
|
'duration': None,
|
||||||
'status': None,
|
'status': None,
|
||||||
'created_at': '2017-01-28T19:51:52+00:00',
|
'created_at': '2017-01-28T19:51:52+00:00',
|
||||||
'camera_id': FIRST_CAMERA['device_id'],
|
'camera_id': FIRST_CAMERA['device_id'],
|
||||||
'id': 666777888,
|
'id': 666777888,
|
||||||
'siren_id': None,
|
'siren_id': None,
|
||||||
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
||||||
'notified': True,
|
'notified': True,
|
||||||
'siren': None,
|
'siren': None,
|
||||||
'syncmodule': None,
|
'syncmodule': None,
|
||||||
'video_url': FIRST_CAMERA['thumbnail'] + '.mp4',
|
'video_url': FIRST_CAMERA['thumbnail'] + '.mp4',
|
||||||
'command_id': None,
|
'command_id': None,
|
||||||
'network_id': None,
|
'network_id': None,
|
||||||
'account': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
'account': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
||||||
'video_id': 123000321}
|
'video_id': 123000321}
|
||||||
|
|
||||||
SECOND_EVENT = {'updated_at': '2017-01-28T19:51:29+00:00',
|
SECOND_EVENT = {'updated_at': '2017-01-28T19:51:29+00:00',
|
||||||
'sync_module_id': SYNC_MODULE['device_id'],
|
'sync_module_id': SYNC_MODULE['device_id'],
|
||||||
'camera': None,
|
'camera': None,
|
||||||
'type': 'armed',
|
'type': 'armed',
|
||||||
'duration': None,
|
'duration': None,
|
||||||
'status': None,
|
'status': None,
|
||||||
'created_at': '2017-01-28T19:51:29+00:00',
|
'created_at': '2017-01-28T19:51:29+00:00',
|
||||||
'camera_id': None,
|
'camera_id': None,
|
||||||
'id': 333777555,
|
'id': 333777555,
|
||||||
'siren_id': None,
|
'siren_id': None,
|
||||||
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
|
||||||
'notified': False,
|
'notified': False,
|
||||||
'siren': None,
|
'siren': None,
|
||||||
'syncmodule': SYNC_MODULE['device_id'],
|
'syncmodule': SYNC_MODULE['device_id'],
|
||||||
'command_id': None,
|
'command_id': None,
|
||||||
'network_id': None,
|
'network_id': None,
|
||||||
'account': NETWORKS_RESPONSE['networks'][0]['account_id']}
|
'account': NETWORKS_RESPONSE['networks'][0]['account_id']}
|
||||||
|
|
||||||
"""Fake response content."""
|
"""Fake response content."""
|
||||||
LOGIN_RESPONSE = {}
|
LOGIN_RESPONSE = {}
|
||||||
LOGIN_RESPONSE['region'] = {'ciri': 'Cintra'}
|
LOGIN_RESPONSE['region'] = {'ciri': 'Cintra'}
|
||||||
LOGIN_RESPONSE['networks'] = {
|
LOGIN_RESPONSE['networks'] = {
|
||||||
NETWORKS_RESPONSE['networks'][0]['id']: NETWORKS_RESPONSE['summary']
|
NETWORKS_RESPONSE['networks'][0]['id']: NETWORKS_RESPONSE['summary']
|
||||||
}
|
}
|
||||||
LOGIN_RESPONSE['authtoken'] = {'authtoken': 'foobar7117', 'message': 'auth'}
|
LOGIN_RESPONSE['authtoken'] = {'authtoken': 'foobar7117', 'message': 'auth'}
|
||||||
|
|
||||||
RESPONSE = {}
|
RESPONSE = {}
|
||||||
RESPONSE['account'] = {'notifications': SYNC_MODULE['notifications']}
|
RESPONSE['account'] = {'notifications': SYNC_MODULE['notifications']}
|
||||||
RESPONSE['devices'] = [FIRST_CAMERA, SECOND_CAMERA, SYNC_MODULE]
|
RESPONSE['devices'] = [FIRST_CAMERA, SECOND_CAMERA, SYNC_MODULE]
|
||||||
RESPONSE['network'] = {'armed': NETWORKS_RESPONSE['networks'][0]['armed'],
|
RESPONSE['network'] = {'armed': NETWORKS_RESPONSE['networks'][0]['armed'],
|
||||||
'wifi_strength': 4,
|
'wifi_strength': 4,
|
||||||
'warning': 0,
|
'warning': 0,
|
||||||
'name': NETWORKS_RESPONSE['summary']['name'],
|
'name': NETWORKS_RESPONSE['summary']['name'],
|
||||||
'notifications': SYNC_MODULE['notifications']}
|
'notifications': SYNC_MODULE['notifications']}
|
||||||
RESPONSE['event'] = [FIRST_EVENT, SECOND_EVENT]
|
RESPONSE['event'] = [FIRST_EVENT, SECOND_EVENT]
|
||||||
RESPONSE['syncmodule'] = {'name': 'Vengerberg', 'status': 'online'}
|
RESPONSE['syncmodule'] = {'name': 'Vengerberg', 'status': 'online'}
|
||||||
|
|
||||||
MOCK_BYTES = '\x00\x10JFIF\x00\x01'
|
BAD_RESPONSE = {}
|
||||||
|
BAD_RESPONSE['account'] = {'nothing': 'here'}
|
||||||
IMAGE_TO_WRITE_URL = list()
|
BAD_RESPONSE['devices'] = [{'foo': 'bar', 'device_type': 'camera'},
|
||||||
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
|
{'device_type': 'camera', 'device_id': 2112}]
|
||||||
FIRST_CAMERA['thumbnail'] + '.jpg')
|
BAD_RESPONSE['network'] = {'bar': 'foo'}
|
||||||
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
|
|
||||||
SECOND_CAMERA['thumbnail'] + '.jpg')
|
MOCK_BYTES = '\x00\x10JFIF\x00\x01'
|
||||||
|
|
||||||
FAKE_FILES = list()
|
IMAGE_TO_WRITE_URL = list()
|
||||||
|
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
|
||||||
|
FIRST_CAMERA['thumbnail'] + '.jpg')
|
||||||
def mocked_requests_post(*args, **kwargs):
|
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
|
||||||
"""Mock post request."""
|
SECOND_CAMERA['thumbnail'] + '.jpg')
|
||||||
class MockPostResponse:
|
|
||||||
"""Class for mock post response."""
|
FAKE_FILES = list()
|
||||||
|
|
||||||
def __init__(self, json_data, status_code):
|
|
||||||
"""Initialze mock post response."""
|
def mocked_requests_post(*args, **kwargs):
|
||||||
self.json_data = json_data
|
"""Mock post request."""
|
||||||
self.status_code = status_code
|
class MockPostResponse:
|
||||||
|
"""Class for mock post response."""
|
||||||
def json(self):
|
|
||||||
"""Return json data from post request."""
|
def __init__(self, json_data, status_code):
|
||||||
return self.json_data
|
"""Initialze mock post response."""
|
||||||
|
self.json_data = json_data
|
||||||
# pylint: disable=global-variable-not-assigned
|
self.status_code = status_code
|
||||||
global RESPONSE
|
|
||||||
# pylint: disable=global-variable-not-assigned
|
def json(self):
|
||||||
global NETWORKS_RESPONSE
|
"""Return json data from post request."""
|
||||||
|
return self.json_data
|
||||||
if args[0] is not None:
|
|
||||||
url_tail = args[0].split("/")[-1]
|
# pylint: disable=global-variable-not-assigned
|
||||||
else:
|
global RESPONSE
|
||||||
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
|
# pylint: disable=global-variable-not-assigned
|
||||||
|
global NETWORKS_RESPONSE
|
||||||
if args[0] == const.LOGIN_URL:
|
|
||||||
# Request to login
|
if args[0] is not None:
|
||||||
return MockPostResponse(LOGIN_RESPONSE, 200)
|
url_tail = args[0].split("/")[-1]
|
||||||
elif args[0] == const.LOGIN_BACKUP_URL:
|
else:
|
||||||
return MockPostResponse(LOGIN_RESPONSE, 200)
|
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
|
||||||
elif url_tail == 'arm' or url_tail == 'disarm':
|
|
||||||
# Request to arm/disarm system
|
if args[0] == const.LOGIN_URL:
|
||||||
NETWORKS_RESPONSE['networks'][0]['armed'] = url_tail == 'arm'
|
# Request to login
|
||||||
RESPONSE['network']['armed'] = url_tail == 'arm'
|
return MockPostResponse(LOGIN_RESPONSE, 200)
|
||||||
return MockPostResponse({}, 200)
|
elif args[0] == const.LOGIN_BACKUP_URL:
|
||||||
elif url_tail == 'enable' or url_tail == 'disable':
|
return MockPostResponse(LOGIN_RESPONSE, 200)
|
||||||
# Request to enable/disable motion detection per camera
|
elif url_tail == 'arm' or url_tail == 'disarm':
|
||||||
received_id = args[0].split("/")[-2]
|
# Request to arm/disarm system
|
||||||
all_devices = list()
|
NETWORKS_RESPONSE['networks'][0]['armed'] = url_tail == 'arm'
|
||||||
for element in RESPONSE['devices']:
|
RESPONSE['network']['armed'] = url_tail == 'arm'
|
||||||
all_devices.append(element)
|
return MockPostResponse({}, 200)
|
||||||
current_id = element['device_id']
|
elif url_tail == 'enable' or url_tail == 'disable':
|
||||||
if str(current_id) == received_id:
|
# Request to enable/disable motion detection per camera
|
||||||
element['armed'] = url_tail == 'enable'
|
received_id = args[0].split("/")[-2]
|
||||||
element['enabled'] = url_tail == 'enable'
|
all_devices = list()
|
||||||
RESPONSE['devices'] = all_devices
|
for element in RESPONSE['devices']:
|
||||||
return MockPostResponse({}, 200)
|
all_devices.append(element)
|
||||||
elif url_tail == 'thumbnail':
|
current_id = element['device_id']
|
||||||
# Requesting a new image
|
if str(current_id) == received_id:
|
||||||
received_id = args[0].split("/")[-2]
|
element['armed'] = url_tail == 'enable'
|
||||||
all_devices = list()
|
element['enabled'] = url_tail == 'enable'
|
||||||
for element in RESPONSE['devices']:
|
RESPONSE['devices'] = all_devices
|
||||||
all_devices.append(element)
|
return MockPostResponse({}, 200)
|
||||||
if str(element['device_id']) == received_id:
|
elif url_tail == 'thumbnail':
|
||||||
element['thumbnail'] = NEW_THUMBNAIL
|
# Requesting a new image
|
||||||
RESPONSE['devices'] = all_devices
|
received_id = args[0].split("/")[-2]
|
||||||
return MockPostResponse({}, 200)
|
all_devices = list()
|
||||||
|
for element in RESPONSE['devices']:
|
||||||
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
|
all_devices.append(element)
|
||||||
|
if str(element['device_id']) == received_id:
|
||||||
|
element['thumbnail'] = NEW_THUMBNAIL
|
||||||
def mocked_requests_get(*args, **kwargs):
|
RESPONSE['devices'] = all_devices
|
||||||
"""Mock get request."""
|
return MockPostResponse({}, 200)
|
||||||
class MockGetResponse:
|
|
||||||
"""Class for mock get response."""
|
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
|
||||||
|
|
||||||
def __init__(self, json_data, status_code, raw_data=None):
|
|
||||||
"""Initialize mock get response."""
|
def mocked_requests_get(*args, **kwargs):
|
||||||
self.json_data = json_data
|
"""Mock get request."""
|
||||||
self.status_code = status_code
|
class MockGetResponse:
|
||||||
self.raw_data = raw_data
|
"""Class for mock get response."""
|
||||||
|
|
||||||
def json(self):
|
def __init__(self, json_data, status_code, raw_data=None):
|
||||||
"""Return json data from get request."""
|
"""Initialize mock get response."""
|
||||||
return self.json_data
|
self.json_data = json_data
|
||||||
|
self.status_code = status_code
|
||||||
@property
|
self.raw_data = raw_data
|
||||||
def raw(self):
|
|
||||||
"""Return raw data from get request."""
|
def json(self):
|
||||||
return self.raw_data
|
"""Return json data from get request."""
|
||||||
|
return self.json_data
|
||||||
# pylint: disable=unused-variable
|
|
||||||
(region_id, region), = LOGIN_RESPONSE['region'].items()
|
@property
|
||||||
set_region_id = args[0].split('/')[2].split('.')[0]
|
def raw(self):
|
||||||
if set_region_id == 'rest':
|
"""Return raw data from get request."""
|
||||||
set_region_id = (set_region_id + '.' +
|
return self.raw_data
|
||||||
args[0].split('/')[2].split('.')[1])
|
|
||||||
region_id = 'rest.piri'
|
# pylint: disable=unused-variable
|
||||||
neturl = 'https://' + set_region_id + '.' + const.BLINK_URL + '/networks'
|
(region_id, region), = LOGIN_RESPONSE['region'].items()
|
||||||
if args[0] == neturl:
|
if args[0] != 'use_bad_response':
|
||||||
return MockGetResponse(NETWORKS_RESPONSE, 200)
|
set_region_id = args[0].split('/')[2].split('.')[0]
|
||||||
elif set_region_id != region_id:
|
else:
|
||||||
raise ConnectionError('Received region id ' + region_id +
|
set_region_id = 'ciri'
|
||||||
' Expected ' + set_region_id)
|
|
||||||
elif args[0] in IMAGE_TO_WRITE_URL:
|
if set_region_id == 'rest':
|
||||||
return MockGetResponse({}, 200, raw_data=MOCK_BYTES)
|
set_region_id = (set_region_id + '.' +
|
||||||
else:
|
args[0].split('/')[2].split('.')[1])
|
||||||
return MockGetResponse(RESPONSE, 200)
|
region_id = 'rest.piri'
|
||||||
|
neturl = 'https://' + set_region_id + '.' + const.BLINK_URL + '/networks'
|
||||||
return MockGetResponse({'message': 'ERROR', 'code': 404}, 404)
|
if args[0] == neturl:
|
||||||
|
return MockGetResponse(NETWORKS_RESPONSE, 200)
|
||||||
|
elif set_region_id != region_id:
|
||||||
def mocked_copyfileobj(*args, **kwargs):
|
raise ConnectionError('Received region id ' + region_id +
|
||||||
"""Mock shutil.copyfileobj."""
|
' Expected ' + set_region_id)
|
||||||
class MockCopyFileObj:
|
elif args[0] in IMAGE_TO_WRITE_URL:
|
||||||
"""Class for mock copy file."""
|
return MockGetResponse({}, 200, raw_data=MOCK_BYTES)
|
||||||
|
elif args[0] == 'use_bad_response':
|
||||||
def __init__(self, src, dst):
|
return MockGetResponse(BAD_RESPONSE, 200)
|
||||||
"""Initialize copyfile mock."""
|
else:
|
||||||
self.src = src
|
return MockGetResponse(RESPONSE, 200)
|
||||||
self.dst = dst
|
|
||||||
# pylint: disable=global-variable-not-assigned
|
return MockGetResponse({'message': 'ERROR', 'code': 404}, 404)
|
||||||
global FAKE_FILES
|
|
||||||
mockobj = MockCopyFileObj(args[0], args[1])
|
|
||||||
FAKE_FILES.append(mockobj.src)
|
def mocked_copyfileobj(*args, **kwargs):
|
||||||
return
|
"""Mock shutil.copyfileobj."""
|
||||||
|
class MockCopyFileObj:
|
||||||
|
"""Class for mock copy file."""
|
||||||
def get_test_cameras(base_url):
|
|
||||||
"""Helper function to return cameras named in this file."""
|
def __init__(self, src, dst):
|
||||||
test_cameras = dict()
|
"""Initialize copyfile mock."""
|
||||||
for element in RESPONSE['devices']:
|
self.src = src
|
||||||
if ('device_type' in element and
|
self.dst = dst
|
||||||
element['device_type'] == 'camera'):
|
# pylint: disable=global-variable-not-assigned
|
||||||
test_cameras[element['name']] = {
|
global FAKE_FILES
|
||||||
'device_id': str(element['device_id']),
|
mockobj = MockCopyFileObj(args[0], args[1])
|
||||||
'armed': element['armed'],
|
FAKE_FILES.append(mockobj.src)
|
||||||
'thumbnail': (base_url +
|
return
|
||||||
element['thumbnail'] + '.jpg'),
|
|
||||||
'temperature': element['temp'],
|
|
||||||
'battery': element['battery'],
|
def get_test_cameras(base_url):
|
||||||
'notifications': element['notifications']
|
"""Helper function to return cameras named in this file."""
|
||||||
}
|
test_cameras = dict()
|
||||||
return test_cameras
|
for element in RESPONSE['devices']:
|
||||||
|
if ('device_type' in element and
|
||||||
|
element['device_type'] == 'camera'):
|
||||||
def get_test_id_table():
|
test_cameras[element['name']] = {
|
||||||
"""Helper function to return mock id table."""
|
'device_id': str(element['device_id']),
|
||||||
test_id_table = dict()
|
'armed': element['armed'],
|
||||||
for element in RESPONSE['devices']:
|
'thumbnail': (base_url +
|
||||||
if ('device_type' in element and
|
element['thumbnail'] + '.jpg'),
|
||||||
element['device_type'] == 'camera'):
|
'temperature': element['temp'],
|
||||||
test_id_table[str(element['device_id'])] = element['name']
|
'battery': element['battery'],
|
||||||
return test_id_table
|
'notifications': element['notifications']
|
||||||
|
}
|
||||||
|
return test_cameras
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_id_table():
|
||||||
|
"""Helper function to return mock id table."""
|
||||||
|
test_id_table = dict()
|
||||||
|
for element in RESPONSE['devices']:
|
||||||
|
if ('device_type' in element and
|
||||||
|
element['device_type'] == 'camera'):
|
||||||
|
test_id_table[str(element['device_id'])] = element['name']
|
||||||
|
return test_id_table
|
||||||
|
|||||||
+172
-159
@@ -1,159 +1,172 @@
|
|||||||
"""Tests camera and system functions."""
|
"""Tests camera and system functions."""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import blinkpy
|
import blinkpy
|
||||||
import tests.mock_responses as mresp
|
import tests.mock_responses as mresp
|
||||||
|
|
||||||
USERNAME = 'foobar'
|
USERNAME = 'foobar'
|
||||||
PASSWORD = 'deadbeef'
|
PASSWORD = 'deadbeef'
|
||||||
|
|
||||||
|
|
||||||
class TestBlinkFunctions(unittest.TestCase):
|
class TestBlinkFunctions(unittest.TestCase):
|
||||||
"""Test Blink and BlinkCamera functions in blinkpy."""
|
"""Test Blink and BlinkCamera functions in blinkpy."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Set up Blink module."""
|
"""Set up Blink module."""
|
||||||
self.blink = blinkpy.Blink(username=USERNAME,
|
self.blink = blinkpy.Blink(username=USERNAME,
|
||||||
password=PASSWORD)
|
password=PASSWORD)
|
||||||
(self.region_id, self.region), = mresp.LOGIN_RESPONSE['region'].items()
|
(self.region_id, self.region), = mresp.LOGIN_RESPONSE['region'].items()
|
||||||
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Clean up after test."""
|
"""Clean up after test."""
|
||||||
self.blink = None
|
self.blink = None
|
||||||
self.region = None
|
self.region = None
|
||||||
self.region_id = None
|
self.region_id = None
|
||||||
self.test_urls = None
|
self.test_urls = None
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_set_motion_detect(self, mock_get, mock_post):
|
def test_set_motion_detect(self, mock_get, mock_post):
|
||||||
"""Checks if we can set motion detection."""
|
"""Checks if we can set motion detection."""
|
||||||
self.blink.setup_system()
|
self.blink.setup_system()
|
||||||
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
||||||
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
||||||
for camera_name in test_cameras:
|
for camera_name in test_cameras:
|
||||||
self.blink.cameras[camera_name].set_motion_detect(True)
|
self.blink.cameras[camera_name].set_motion_detect(True)
|
||||||
self.blink.refresh()
|
self.blink.refresh()
|
||||||
self.assertEqual(self.blink.cameras[camera_name].armed, True)
|
self.assertEqual(self.blink.cameras[camera_name].armed, True)
|
||||||
self.blink.cameras[camera_name].set_motion_detect(False)
|
self.blink.cameras[camera_name].set_motion_detect(False)
|
||||||
self.blink.refresh()
|
self.blink.refresh()
|
||||||
self.assertEqual(self.blink.cameras[camera_name].armed, False)
|
self.assertEqual(self.blink.cameras[camera_name].armed, False)
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_last_motion(self, mock_get, mock_post):
|
def test_last_motion(self, mock_get, mock_post):
|
||||||
"""Checks that we can get the last motion info."""
|
"""Checks that we can get the last motion info."""
|
||||||
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
||||||
test_events = mresp.RESPONSE['event']
|
test_events = mresp.RESPONSE['event']
|
||||||
test_video = dict()
|
test_video = dict()
|
||||||
test_image = dict()
|
test_image = dict()
|
||||||
test_time = dict()
|
test_time = dict()
|
||||||
for event in test_events:
|
for event in test_events:
|
||||||
if event['type'] == 'motion':
|
if event['type'] == 'motion':
|
||||||
url = self.test_urls.base_url + event['video_url']
|
url = self.test_urls.base_url + event['video_url']
|
||||||
test_video[event['camera_name']] = url
|
test_video[event['camera_name']] = url
|
||||||
test_image[event['camera_name']] = url[:-3] + 'jpg'
|
test_image[event['camera_name']] = url[:-3] + 'jpg'
|
||||||
test_time[event['camera_name']] = event['created_at']
|
test_time[event['camera_name']] = event['created_at']
|
||||||
|
|
||||||
self.blink.setup_system()
|
self.blink.setup_system()
|
||||||
for name in self.blink.cameras:
|
for name in self.blink.cameras:
|
||||||
camera = self.blink.cameras[name]
|
camera = self.blink.cameras[name]
|
||||||
self.blink.last_motion()
|
self.blink.last_motion()
|
||||||
if name in test_video:
|
if name in test_video:
|
||||||
self.assertEqual(camera.motion['video'], test_video[name])
|
self.assertEqual(camera.motion['video'], test_video[name])
|
||||||
else:
|
else:
|
||||||
self.assertEqual(camera.motion, {})
|
self.assertEqual(camera.motion, {})
|
||||||
if name in test_image:
|
if name in test_image:
|
||||||
self.assertEqual(camera.motion['image'], test_image[name])
|
self.assertEqual(camera.motion['image'], test_image[name])
|
||||||
else:
|
else:
|
||||||
self.assertEqual(camera.motion, {})
|
self.assertEqual(camera.motion, {})
|
||||||
if name in test_video:
|
if name in test_video:
|
||||||
self.assertEqual(camera.motion['time'], test_time[name])
|
self.assertEqual(camera.motion['time'], test_time[name])
|
||||||
else:
|
else:
|
||||||
self.assertEqual(camera.motion, {})
|
self.assertEqual(camera.motion, {})
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_take_new_picture(self, mock_get, mock_post):
|
def test_take_new_picture(self, mock_get, mock_post):
|
||||||
"""Checks if we can take a new picture and retrieve the thumbnail."""
|
"""Checks if we can take a new picture and retrieve the thumbnail."""
|
||||||
self.blink.setup_system()
|
self.blink.setup_system()
|
||||||
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
||||||
test_thumbnail = self.test_urls.base_url + mresp.NEW_THUMBNAIL + '.jpg'
|
test_thumbnail = self.test_urls.base_url + mresp.NEW_THUMBNAIL + '.jpg'
|
||||||
# Snap picture for each camera and check new thumb
|
# Snap picture for each camera and check new thumb
|
||||||
for camera_name in test_cameras:
|
for camera_name in test_cameras:
|
||||||
camera = self.blink.cameras[camera_name]
|
camera = self.blink.cameras[camera_name]
|
||||||
camera.snap_picture()
|
camera.snap_picture()
|
||||||
camera.image_refresh()
|
camera.image_refresh()
|
||||||
self.assertEqual(camera.thumbnail, test_thumbnail)
|
self.assertEqual(camera.thumbnail, test_thumbnail)
|
||||||
|
|
||||||
# Manually set thumbnail, and then globally refresh and check
|
# Manually set thumbnail, and then globally refresh and check
|
||||||
for camera_name in test_cameras:
|
for camera_name in test_cameras:
|
||||||
camera = self.blink.cameras[camera_name]
|
camera = self.blink.cameras[camera_name]
|
||||||
camera.thumbnail = 'Testing'
|
camera.thumbnail = 'Testing'
|
||||||
self.assertEqual(camera.thumbnail, 'Testing')
|
self.assertEqual(camera.thumbnail, 'Testing')
|
||||||
|
|
||||||
self.blink.refresh()
|
self.blink.refresh()
|
||||||
for camera_name in test_cameras:
|
for camera_name in test_cameras:
|
||||||
camera = self.blink.cameras[camera_name]
|
camera = self.blink.cameras[camera_name]
|
||||||
self.assertEqual(camera.thumbnail, test_thumbnail)
|
self.assertEqual(camera.thumbnail, test_thumbnail)
|
||||||
|
|
||||||
def test_camera_update(self):
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
"""Checks that the update function is doing the right thing."""
|
side_effect=mresp.mocked_requests_post)
|
||||||
self.test_urls = blinkpy.BlinkURLHandler('test')
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
test_config = mresp.FIRST_CAMERA
|
side_effect=mresp.mocked_requests_get)
|
||||||
test_camera = blinkpy.blinkpy.BlinkCamera(test_config, self.test_urls)
|
def test_image_with_bad_data(self, mock_get, mock_post):
|
||||||
test_update = mresp.SECOND_CAMERA
|
"""Checks for handling of bad keys."""
|
||||||
test_camera.update(test_update)
|
self.blink.setup_system()
|
||||||
test_image_url = self.test_urls.base_url + test_update['thumbnail']
|
for camera_name in self.blink.cameras:
|
||||||
test_thumbnail = test_image_url + '.jpg'
|
camera = self.blink.cameras[camera_name]
|
||||||
test_clip = test_image_url + '.mp4'
|
camera.snap_picture()
|
||||||
self.assertEqual(test_camera.name, test_update['name'])
|
camera.urls.home_url = "use_bad_response"
|
||||||
self.assertEqual(test_camera.armed, test_update['armed'])
|
self.assertEqual(camera.image_refresh(), None)
|
||||||
self.assertEqual(test_camera.thumbnail, test_thumbnail)
|
|
||||||
self.assertEqual(test_camera.clip, test_clip)
|
def test_camera_update(self):
|
||||||
self.assertEqual(test_camera.temperature, test_update['temp'])
|
"""Checks that the update function is doing the right thing."""
|
||||||
self.assertEqual(test_camera.battery, test_update['battery'])
|
self.test_urls = blinkpy.BlinkURLHandler('test')
|
||||||
self.assertEqual(test_camera.notifications,
|
test_config = mresp.FIRST_CAMERA
|
||||||
test_update['notifications'])
|
test_camera = blinkpy.blinkpy.BlinkCamera(test_config, self.test_urls)
|
||||||
|
test_update = mresp.SECOND_CAMERA
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
test_camera.update(test_update)
|
||||||
side_effect=mresp.mocked_requests_post)
|
test_image_url = self.test_urls.base_url + test_update['thumbnail']
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
test_thumbnail = test_image_url + '.jpg'
|
||||||
side_effect=mresp.mocked_requests_get)
|
test_clip = test_image_url + '.mp4'
|
||||||
def test_camera_thumbs(self, mock_get, mock_post):
|
self.assertEqual(test_camera.name, test_update['name'])
|
||||||
"""Checks to see if we can retrieve camera thumbs."""
|
self.assertEqual(test_camera.armed, test_update['armed'])
|
||||||
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
self.assertEqual(test_camera.thumbnail, test_thumbnail)
|
||||||
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
self.assertEqual(test_camera.clip, test_clip)
|
||||||
self.blink.setup_system()
|
self.assertEqual(test_camera.temperature, test_update['temp'])
|
||||||
for name in self.blink.cameras:
|
self.assertEqual(test_camera.battery, test_update['battery'])
|
||||||
thumb = self.blink.camera_thumbs[name]
|
self.assertEqual(test_camera.notifications,
|
||||||
self.assertEqual(test_cameras[name]['thumbnail'], thumb)
|
test_update['notifications'])
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.copyfileobj',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_copyfileobj)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_get)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
def test_camera_thumbs(self, mock_get, mock_post):
|
||||||
side_effect=mresp.mocked_requests_get)
|
"""Checks to see if we can retrieve camera thumbs."""
|
||||||
def test_image_to_file(self, mock_get, mock_post, mock_copyfileobj):
|
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
|
||||||
"""Checks that we can write an image to file."""
|
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
|
||||||
self.blink.setup_system()
|
self.blink.setup_system()
|
||||||
cameras = self.blink.cameras
|
for name in self.blink.cameras:
|
||||||
filename = '/tmp/test.jpg'
|
thumb = self.blink.camera_thumbs[name]
|
||||||
test_files = list()
|
self.assertEqual(test_cameras[name]['thumbnail'], thumb)
|
||||||
for camera_name in cameras:
|
|
||||||
camera = cameras[camera_name]
|
@mock.patch('blinkpy.blinkpy.copyfileobj',
|
||||||
test_files.append(mresp.MOCK_BYTES)
|
side_effect=mresp.mocked_copyfileobj)
|
||||||
mock_fh = mock.mock_open()
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
with mock.patch('builtins.open', mock_fh, create=True):
|
side_effect=mresp.mocked_requests_post)
|
||||||
camera.image_to_file(camera_name + filename)
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
mock_fh.assert_called_once_with(camera_name + filename, 'wb')
|
side_effect=mresp.mocked_requests_get)
|
||||||
self.assertEqual(test_files, mresp.FAKE_FILES)
|
def test_image_to_file(self, mock_get, mock_post, mock_copyfileobj):
|
||||||
|
"""Checks that we can write an image to file."""
|
||||||
|
self.blink.setup_system()
|
||||||
|
cameras = self.blink.cameras
|
||||||
|
filename = '/tmp/test.jpg'
|
||||||
|
test_files = list()
|
||||||
|
for camera_name in cameras:
|
||||||
|
camera = cameras[camera_name]
|
||||||
|
test_files.append(mresp.MOCK_BYTES)
|
||||||
|
mock_fh = mock.mock_open()
|
||||||
|
with mock.patch('builtins.open', mock_fh, create=True):
|
||||||
|
camera.image_to_file(camera_name + filename)
|
||||||
|
mock_fh.assert_called_once_with(camera_name + filename, 'wb')
|
||||||
|
self.assertEqual(test_files, mresp.FAKE_FILES)
|
||||||
|
|||||||
+173
-163
@@ -1,163 +1,173 @@
|
|||||||
"""
|
"""
|
||||||
Tests the system initialization and attributes of
|
Tests the system initialization and attributes of
|
||||||
the main Blink system. Tests if we properly catch
|
the main Blink system. Tests if we properly catch
|
||||||
any communication related errors at startup.
|
any communication related errors at startup.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import blinkpy
|
import blinkpy
|
||||||
import tests.mock_responses as mresp
|
import tests.mock_responses as mresp
|
||||||
import helpers.constants as const
|
import helpers.constants as const
|
||||||
|
|
||||||
USERNAME = 'foobar'
|
USERNAME = 'foobar'
|
||||||
PASSWORD = 'deadbeef'
|
PASSWORD = 'deadbeef'
|
||||||
|
|
||||||
|
|
||||||
class TestBlinkSetup(unittest.TestCase):
|
class TestBlinkSetup(unittest.TestCase):
|
||||||
"""Test the Blink class in blinkpy."""
|
"""Test the Blink class in blinkpy."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Set up Blink module."""
|
"""Set up Blink module."""
|
||||||
self.blink_no_cred = blinkpy.Blink()
|
self.blink_no_cred = blinkpy.Blink()
|
||||||
self.blink = blinkpy.Blink(username=USERNAME,
|
self.blink = blinkpy.Blink(username=USERNAME,
|
||||||
password=PASSWORD)
|
password=PASSWORD)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Clean up after test."""
|
"""Clean up after test."""
|
||||||
self.blink = None
|
self.blink = None
|
||||||
self.blink_no_cred = None
|
self.blink_no_cred = None
|
||||||
|
|
||||||
def test_initialization(self):
|
def test_initialization(self):
|
||||||
"""Verify we can initialize blink."""
|
"""Verify we can initialize blink."""
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(self.blink._username, USERNAME)
|
self.assertEqual(self.blink._username, USERNAME)
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(self.blink._password, PASSWORD)
|
self.assertEqual(self.blink._password, PASSWORD)
|
||||||
|
|
||||||
def test_no_credentials(self):
|
def test_no_credentials(self):
|
||||||
"""Check that we throw an exception when no username/password."""
|
"""Check that we throw an exception when no username/password."""
|
||||||
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
||||||
self.blink_no_cred.get_auth_token()
|
self.blink_no_cred.get_auth_token()
|
||||||
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
||||||
self.blink_no_cred.setup_system()
|
self.blink_no_cred.setup_system()
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.blink_no_cred._username = USERNAME
|
self.blink_no_cred._username = USERNAME
|
||||||
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
||||||
self.blink_no_cred.get_auth_token()
|
self.blink_no_cred.get_auth_token()
|
||||||
|
|
||||||
def test_no_auth_header(self):
|
def test_no_auth_header(self):
|
||||||
"""Check that we throw an excpetion when no auth header given."""
|
"""Check that we throw an excpetion when no auth header given."""
|
||||||
# pylint: disable=unused-variable
|
# pylint: disable=unused-variable
|
||||||
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
|
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
|
||||||
self.blink.urls = blinkpy.BlinkURLHandler(region_id)
|
self.blink.urls = blinkpy.BlinkURLHandler(region_id)
|
||||||
with self.assertRaises(blinkpy.BlinkException):
|
with self.assertRaises(blinkpy.BlinkException):
|
||||||
self.blink.get_ids()
|
self.blink.get_ids()
|
||||||
with self.assertRaises(blinkpy.BlinkException):
|
with self.assertRaises(blinkpy.BlinkException):
|
||||||
self.blink.get_summary()
|
self.blink.get_summary()
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.getpass.getpass')
|
@mock.patch('blinkpy.blinkpy.getpass.getpass')
|
||||||
def test_manual_login(self, getpwd):
|
def test_manual_login(self, getpwd):
|
||||||
"""Check that we can manually use the login() function."""
|
"""Check that we can manually use the login() function."""
|
||||||
getpwd.return_value = PASSWORD
|
getpwd.return_value = PASSWORD
|
||||||
with mock.patch('builtins.input', return_value=USERNAME):
|
with mock.patch('builtins.input', return_value=USERNAME):
|
||||||
self.blink_no_cred.login()
|
self.blink_no_cred.login()
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(self.blink_no_cred._username, USERNAME)
|
self.assertEqual(self.blink_no_cred._username, USERNAME)
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.assertEqual(self.blink_no_cred._password, PASSWORD)
|
self.assertEqual(self.blink_no_cred._password, PASSWORD)
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_bad_request(self, mock_get, mock_post):
|
def test_bad_request(self, mock_get, mock_post):
|
||||||
"""Check that we raise an Exception with a bad request."""
|
"""Check that we raise an Exception with a bad request."""
|
||||||
with self.assertRaises(blinkpy.BlinkException):
|
with self.assertRaises(blinkpy.BlinkException):
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
blinkpy.blinkpy._request(None, reqtype='bad')
|
blinkpy.blinkpy._request(None, reqtype='bad')
|
||||||
|
|
||||||
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
with self.assertRaises(blinkpy.BlinkAuthenticationException):
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
blinkpy.blinkpy._request(None, reqtype='post')
|
blinkpy.blinkpy._request(None, reqtype='post')
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_full_setup(self, mock_get, mock_post):
|
def test_system_bad_refresh(self, mock_get, mock_post):
|
||||||
"""Check that we can set Blink up properly."""
|
"""Checks for handling of bad keys."""
|
||||||
self.blink.setup_system()
|
self.blink.setup_system()
|
||||||
|
self.blink.urls.home_url = 'use_bad_response'
|
||||||
# Get all test values
|
self.assertEqual(self.blink.refresh(), None)
|
||||||
authtoken = mresp.LOGIN_RESPONSE['authtoken']['authtoken']
|
|
||||||
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
host = region_id + '.' + const.BLINK_URL
|
side_effect=mresp.mocked_requests_post)
|
||||||
network_id = mresp.NETWORKS_RESPONSE['networks'][0]['id']
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
account_id = mresp.NETWORKS_RESPONSE['networks'][0]['account_id']
|
side_effect=mresp.mocked_requests_get)
|
||||||
test_urls = blinkpy.BlinkURLHandler(region_id)
|
def test_full_setup(self, mock_get, mock_post):
|
||||||
test_cameras = mresp.get_test_cameras(test_urls.base_url)
|
"""Check that we can set Blink up properly."""
|
||||||
test_camera_id = mresp.get_test_id_table()
|
self.blink.setup_system()
|
||||||
|
|
||||||
# Check that all links have been set properly
|
# Get all test values
|
||||||
self.assertEqual(self.blink.region_id, region_id)
|
authtoken = mresp.LOGIN_RESPONSE['authtoken']['authtoken']
|
||||||
self.assertEqual(self.blink.urls.base_url, test_urls.base_url)
|
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
|
||||||
self.assertEqual(self.blink.urls.home_url, test_urls.home_url)
|
host = region_id + '.' + const.BLINK_URL
|
||||||
self.assertEqual(self.blink.urls.event_url, test_urls.event_url)
|
network_id = mresp.NETWORKS_RESPONSE['networks'][0]['id']
|
||||||
self.assertEqual(self.blink.urls.network_url, test_urls.network_url)
|
account_id = mresp.NETWORKS_RESPONSE['networks'][0]['account_id']
|
||||||
self.assertEqual(self.blink.urls.networks_url, test_urls.networks_url)
|
test_urls = blinkpy.BlinkURLHandler(region_id)
|
||||||
|
test_cameras = mresp.get_test_cameras(test_urls.base_url)
|
||||||
# Check that all properties have been set after startup
|
test_camera_id = mresp.get_test_id_table()
|
||||||
# pylint: disable=protected-access
|
|
||||||
self.assertEqual(self.blink._token, authtoken)
|
# Check that all links have been set properly
|
||||||
# pylint: disable=protected-access
|
self.assertEqual(self.blink.region_id, region_id)
|
||||||
self.assertEqual(self.blink._host, host)
|
self.assertEqual(self.blink.urls.base_url, test_urls.base_url)
|
||||||
self.assertEqual(self.blink.network_id, str(network_id))
|
self.assertEqual(self.blink.urls.home_url, test_urls.home_url)
|
||||||
self.assertEqual(self.blink.account_id, str(account_id))
|
self.assertEqual(self.blink.urls.event_url, test_urls.event_url)
|
||||||
self.assertEqual(self.blink.region, region)
|
self.assertEqual(self.blink.urls.network_url, test_urls.network_url)
|
||||||
|
self.assertEqual(self.blink.urls.networks_url, test_urls.networks_url)
|
||||||
# Verify we have initialized all the cameras
|
|
||||||
self.assertEqual(self.blink.id_table, test_camera_id)
|
# Check that all properties have been set after startup
|
||||||
for camera in test_cameras:
|
# pylint: disable=protected-access
|
||||||
self.assertTrue(camera in self.blink.cameras)
|
self.assertEqual(self.blink._token, authtoken)
|
||||||
|
# pylint: disable=protected-access
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
self.assertEqual(self.blink._host, host)
|
||||||
side_effect=mresp.mocked_requests_post)
|
self.assertEqual(self.blink.network_id, str(network_id))
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
self.assertEqual(self.blink.account_id, str(account_id))
|
||||||
side_effect=mresp.mocked_requests_get)
|
self.assertEqual(self.blink.region, region)
|
||||||
def test_arm_disarm_system(self, mock_get, mock_post):
|
|
||||||
"""Check that we can arm/disarm the system"""
|
# Verify we have initialized all the cameras
|
||||||
self.blink.setup_system()
|
self.assertEqual(self.blink.id_table, test_camera_id)
|
||||||
self.blink.arm = False
|
for camera in test_cameras:
|
||||||
self.assertIs(self.blink.arm, False)
|
self.assertTrue(camera in self.blink.cameras)
|
||||||
self.blink.arm = True
|
|
||||||
self.assertIs(self.blink.arm, True)
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_get)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
def test_arm_disarm_system(self, mock_get, mock_post):
|
||||||
side_effect=mresp.mocked_requests_get)
|
"""Check that we can arm/disarm the system"""
|
||||||
def test_check_online_status(self, mock_get, mock_post):
|
self.blink.setup_system()
|
||||||
"""Check that we can get our online status."""
|
self.blink.arm = False
|
||||||
self.blink.setup_system()
|
self.assertIs(self.blink.arm, False)
|
||||||
expected_status = const.ONLINE[mresp.RESPONSE['syncmodule']['status']]
|
self.blink.arm = True
|
||||||
self.assertIs(self.blink.online, expected_status)
|
self.assertIs(self.blink.arm, True)
|
||||||
|
|
||||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
side_effect=mresp.mocked_requests_post)
|
side_effect=mresp.mocked_requests_post)
|
||||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
side_effect=mresp.mocked_requests_get)
|
side_effect=mresp.mocked_requests_get)
|
||||||
def test_setup_backup_subdomain(self, mock_get, mock_post):
|
def test_check_online_status(self, mock_get, mock_post):
|
||||||
"""Check that we can use the 'rest.piri' subdomain."""
|
"""Check that we can get our online status."""
|
||||||
test_urls = blinkpy.BlinkURLHandler('rest.piri')
|
self.blink.setup_system()
|
||||||
with mock.patch('helpers.constants.LOGIN_URL',
|
expected_status = const.ONLINE[mresp.RESPONSE['syncmodule']['status']]
|
||||||
return_value=const.LOGIN_URL + 'NO'):
|
self.assertIs(self.blink.online, expected_status)
|
||||||
self.blink.setup_system()
|
|
||||||
self.assertEqual(self.blink.region_id, 'rest.piri')
|
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||||
# pylint: disable=protected-access
|
side_effect=mresp.mocked_requests_post)
|
||||||
self.assertEqual(self.blink._host, 'rest.piri.' + const.BLINK_URL)
|
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||||
self.assertEqual(self.blink.urls.base_url, test_urls.base_url)
|
side_effect=mresp.mocked_requests_get)
|
||||||
self.assertEqual(self.blink.urls.home_url, test_urls.home_url)
|
def test_setup_backup_subdomain(self, mock_get, mock_post):
|
||||||
self.assertEqual(self.blink.urls.event_url, test_urls.event_url)
|
"""Check that we can use the 'rest.piri' subdomain."""
|
||||||
self.assertEqual(self.blink.urls.network_url, test_urls.network_url)
|
test_urls = blinkpy.BlinkURLHandler('rest.piri')
|
||||||
self.assertEqual(self.blink.urls.networks_url, test_urls.networks_url)
|
with mock.patch('helpers.constants.LOGIN_URL',
|
||||||
|
return_value=const.LOGIN_URL + 'NO'):
|
||||||
|
self.blink.setup_system()
|
||||||
|
self.assertEqual(self.blink.region_id, 'rest.piri')
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
self.assertEqual(self.blink._host, 'rest.piri.' + const.BLINK_URL)
|
||||||
|
self.assertEqual(self.blink.urls.base_url, test_urls.base_url)
|
||||||
|
self.assertEqual(self.blink.urls.home_url, test_urls.home_url)
|
||||||
|
self.assertEqual(self.blink.urls.event_url, test_urls.event_url)
|
||||||
|
self.assertEqual(self.blink.urls.network_url, test_urls.network_url)
|
||||||
|
self.assertEqual(self.blink.urls.networks_url, test_urls.networks_url)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ setenv =
|
|||||||
LANG=en_US.UTF-8
|
LANG=en_US.UTF-8
|
||||||
PYTHONPATH = {toxinidir}
|
PYTHONPATH = {toxinidir}
|
||||||
commands =
|
commands =
|
||||||
py.test -v --timeout=30 --duration=10 --cov=blinkpy --cov-report term-missing {posargs}
|
py.test --timeout=30 --duration=10 --cov=blinkpy --cov-report term-missing {posargs}
|
||||||
deps =
|
deps =
|
||||||
-r{toxinidir}/requirements.txt
|
-r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/requirements_test.txt
|
-r{toxinidir}/requirements_test.txt
|
||||||
|
|||||||
Reference in New Issue
Block a user