Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d83a7fcb1 | ||
|
|
80f4ca7c4f | ||
|
|
96e7fce304 | ||
|
|
13a358c07c | ||
|
|
389745533c | ||
|
|
65dd547a32 | ||
|
|
91a877da79 | ||
|
|
d357215e0e | ||
|
|
ff47dc4731 | ||
|
|
fedea74256 | ||
|
|
66a6701a66 | ||
|
|
5bdfd6da52 | ||
|
|
a8f90400b2 | ||
|
|
3348386a4c | ||
|
|
1b53c4a0dd | ||
|
|
24158638ef | ||
|
|
901cbfc9d1 | ||
|
|
9f85068a0d | ||
|
|
90b83544f4 | ||
|
|
1d8e8e53d9 | ||
|
|
46a0a433ec |
@@ -0,0 +1,25 @@
|
||||
image: python
|
||||
|
||||
stages:
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- curl -O https://bootstrap.pypa.io/get-pip.py
|
||||
- python get-pip.py
|
||||
- pip install tox
|
||||
|
||||
python35:
|
||||
image: python:3.5
|
||||
stage: test
|
||||
script: tox -e py35
|
||||
|
||||
python36:
|
||||
image: python:3.6
|
||||
stage: test
|
||||
script: tox -e py36
|
||||
|
||||
lint:
|
||||
image: python:3.6
|
||||
stage: test
|
||||
script: tox -e lint
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
python:
|
||||
enabled: true
|
||||
ignore_file: setup.py
|
||||
ignored_directories:
|
||||
- docs
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,6 @@
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: "3.4.2"
|
||||
env: TOXENV=py34
|
||||
- python: "3.6"
|
||||
env: TOXENV=lint
|
||||
- python: "3.5"
|
||||
@@ -13,6 +11,8 @@ matrix:
|
||||
env: TOXENV=py36
|
||||
- python: "3.6"
|
||||
env: TOXENV=build
|
||||
- python: "3.7-dev"
|
||||
env: TOXENV=py37
|
||||
|
||||
install: pip install -U tox coveralls
|
||||
language: python
|
||||
|
||||
+11
@@ -3,6 +3,17 @@ Changelog
|
||||
|
||||
A list of changes between each release
|
||||
|
||||
0.8.0 (2018-05-21)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Added support for battery voltage level (fixes `#64 <https://github.com/fronzbot/blinkpy/issues/64>`_)
|
||||
- Added motion detection per camera
|
||||
- Added fully accessible camera configuration dict
|
||||
- Added celcius property to camera (fixes `#60 <https://github.com/fronzbot/blinkpy/issues/60>`_)
|
||||
|
||||
0.7.1 (2018-05-09)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Fixed pip 10 import issue during setup (`@fronzbot <https://github.com/fronzbot/blinkpy/pull/61>`_)
|
||||
|
||||
0.7.0 (2018-02-08)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Fixed style errors for bumped pydocstring and pylint versions
|
||||
|
||||
+49
-6
@@ -107,13 +107,17 @@ class BlinkCamera(object):
|
||||
config['thumbnail'])
|
||||
self.clip = "{}{}".format(self.urls.base_url, config['video'])
|
||||
self.temperature = config['temp']
|
||||
self.battery = config['battery']
|
||||
self._battery_string = config['battery']
|
||||
self.notifications = config['notifications']
|
||||
self.motion = {}
|
||||
self.motion = dict()
|
||||
self.header = None
|
||||
self.image_link = None
|
||||
self.arm_link = None
|
||||
self.region_id = config['region_id']
|
||||
self.battery_voltage = -180
|
||||
self.motion_detected = None
|
||||
self.wifi_strength = None
|
||||
self.camera_config = dict()
|
||||
|
||||
@property
|
||||
def attributes(self):
|
||||
@@ -124,10 +128,13 @@ class BlinkCamera(object):
|
||||
'status': self._status,
|
||||
'armed': self.armed,
|
||||
'temperature': self.temperature,
|
||||
'temperature_c': self.temperature_c,
|
||||
'battery': self.battery,
|
||||
'thumbnail': self.thumbnail,
|
||||
'video': self.clip,
|
||||
'notifications': self.notifications,
|
||||
'motion_detected': self.motion_detected,
|
||||
'wifi_strength': self.wifi_strength,
|
||||
'network_id': self.blink.network_id
|
||||
}
|
||||
return attributes
|
||||
@@ -142,16 +149,26 @@ class BlinkCamera(object):
|
||||
"""Return camera arm status."""
|
||||
return True if self._status == 'armed' else False
|
||||
|
||||
@property
|
||||
def battery(self):
|
||||
"""Return battery level as percentage."""
|
||||
return round(self.battery_voltage / 180 * 100)
|
||||
|
||||
@property
|
||||
def battery_string(self):
|
||||
"""Return string indicating battery status."""
|
||||
status = "Unknown"
|
||||
if self.battery > 1 and self.battery <= 3:
|
||||
if self._battery_string > 1 and self._battery_string <= 3:
|
||||
status = "OK"
|
||||
elif self.battery >= 0:
|
||||
elif self._battery_string >= 0:
|
||||
status = "Low"
|
||||
return status
|
||||
|
||||
@property
|
||||
def temperature_c(self):
|
||||
"""Return temperature in celcius."""
|
||||
return round((self.temperature - 32) / 9.0 * 5.0, 1)
|
||||
|
||||
def snap_picture(self):
|
||||
"""Take a picture with camera to create a new thumbnail."""
|
||||
_request(self.blink, url=self.image_link,
|
||||
@@ -175,10 +192,26 @@ class BlinkCamera(object):
|
||||
self.urls.base_url, values['thumbnail'])
|
||||
self.clip = "{}{}".format(
|
||||
self.urls.base_url, values['video'])
|
||||
self.temperature = values['temp']
|
||||
self.battery = values['battery']
|
||||
self._battery_string = values['battery']
|
||||
self.notifications = values['notifications']
|
||||
|
||||
try:
|
||||
cfg = self.blink.camera_config_request(self.id)
|
||||
self.camera_config = cfg
|
||||
except requests.exceptions.RequestException as err:
|
||||
_LOGGER.warning("Could not get config for %s with id %s",
|
||||
self.name, self.id)
|
||||
_LOGGER.warning("Exception raised: %s", err)
|
||||
|
||||
try:
|
||||
self.battery_voltage = cfg['camera'][0]['battery_voltage']
|
||||
self.motion_detected = cfg['camera'][0]['motion_alert']
|
||||
self.wifi_strength = cfg['camera'][0]['wifi_strength']
|
||||
self.temperature = cfg['camera'][0]['temperature']
|
||||
except KeyError:
|
||||
_LOGGER.warning("Problem extracting config for camera %s",
|
||||
self.name)
|
||||
|
||||
def image_refresh(self):
|
||||
"""Refresh current thumbnail."""
|
||||
url = self.urls.home_url
|
||||
@@ -327,6 +360,7 @@ class Blink(object):
|
||||
videos.append(this_page)
|
||||
|
||||
for page in videos:
|
||||
_LOGGER.debug("Retrieved video page %s", page)
|
||||
for entry in page:
|
||||
camera_name = entry['camera_name']
|
||||
clip_addr = entry['address']
|
||||
@@ -365,6 +399,7 @@ class Blink(object):
|
||||
device = BlinkCamera(element, self)
|
||||
self.cameras[device.name] = device
|
||||
self._idlookup[device.id] = device.name
|
||||
self.refresh()
|
||||
|
||||
def set_links(self):
|
||||
"""Set access links and required headers for each camera in system."""
|
||||
@@ -497,3 +532,11 @@ class Blink(object):
|
||||
self.network_id)
|
||||
headers = self._auth_header
|
||||
return _request(self, url=url, headers=headers, reqtype='get')
|
||||
|
||||
def camera_config_request(self, camera_id):
|
||||
"""Retrieve more info about Blink config."""
|
||||
url = "{}/network/{}/camera/{}/config".format(self.urls.base_url,
|
||||
self.network_id,
|
||||
str(camera_id))
|
||||
headers = self._auth_header
|
||||
return _request(self, url=url, headers=headers, reqtype='get')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import os
|
||||
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 7
|
||||
MINOR_VERSION = 8
|
||||
PATCH_VERSION = 0
|
||||
|
||||
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from os.path import abspath, dirname, join
|
||||
from setuptools import setup, find_packages
|
||||
from pip.req import parse_requirements
|
||||
# Fixes import error due to breaking change in pip 10
|
||||
# https://stackoverflow.com/a/49867265
|
||||
# pip > 10
|
||||
try:
|
||||
from pip._internal.req import parse_requirements
|
||||
# pip < 10
|
||||
except ImportError:
|
||||
from pip.req import parse_requirements
|
||||
from blinkpy.helpers.constants import (
|
||||
__version__, PROJECT_PACKAGE_NAME, PROJECT_LICENSE, PROJECT_URL,
|
||||
PROJECT_EMAIL, PROJECT_DESCRIPTION, PROJECT_CLASSIFIERS, PROJECT_AUTHOR,
|
||||
|
||||
+33
-10
@@ -15,6 +15,17 @@ import tests.mock_responses as mresp
|
||||
USERNAME = 'foobar'
|
||||
PASSWORD = 'deadbeef'
|
||||
|
||||
CAMERA_CFG = {
|
||||
'camera': [
|
||||
{
|
||||
'battery_voltage': 90,
|
||||
'motion_alert': True,
|
||||
'wifi_strength': -30,
|
||||
'temperature': 68
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class TestBlinkCameraSetup(unittest.TestCase):
|
||||
"""Test the Blink class in blinkpy."""
|
||||
@@ -35,6 +46,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
'notifications': 2,
|
||||
'region_id': 'test'
|
||||
}
|
||||
|
||||
self.blink.urls = blinkpy.BlinkURLHandler('test')
|
||||
self.blink.network_id = '0000'
|
||||
|
||||
@@ -42,11 +54,13 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
"""Clean up after test."""
|
||||
self.blink = None
|
||||
|
||||
@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
|
||||
return_value=CAMERA_CFG)
|
||||
@mock.patch('blinkpy.blinkpy.requests.post',
|
||||
side_effect=mresp.mocked_requests_post)
|
||||
@mock.patch('blinkpy.blinkpy.requests.get',
|
||||
side_effect=mresp.mocked_requests_get)
|
||||
def test_camera_properties(self, mock_get, mock_post):
|
||||
def test_camera_properties(self, mock_get, mock_post, mock_cfg):
|
||||
"""Tests all property set/recall."""
|
||||
self.blink.urls = blinkpy.BlinkURLHandler('test')
|
||||
|
||||
@@ -56,7 +70,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
|
||||
for name in self.blink.cameras:
|
||||
camera = self.blink.cameras[name]
|
||||
|
||||
camera.update(self.camera_config)
|
||||
self.assertEqual(camera.id, '1111')
|
||||
self.assertEqual(camera.name, 'foobar')
|
||||
self.assertEqual(camera.armed, False)
|
||||
@@ -68,11 +82,15 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
camera.clip,
|
||||
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
|
||||
)
|
||||
self.assertEqual(camera.temperature, 70)
|
||||
self.assertEqual(camera.battery, 3)
|
||||
self.assertEqual(camera.temperature, 68)
|
||||
self.assertEqual(camera.temperature_c, 20.0)
|
||||
self.assertEqual(camera.battery, 50)
|
||||
self.assertEqual(camera.battery_string, "OK")
|
||||
self.assertEqual(camera.notifications, 2)
|
||||
self.assertEqual(camera.region_id, 'test')
|
||||
self.assertEqual(camera.motion_detected, True)
|
||||
self.assertEqual(camera.wifi_strength, -30)
|
||||
|
||||
camera_config = self.camera_config
|
||||
camera_config['active'] = 'armed'
|
||||
camera_config['thumbnail'] = '/test2/image'
|
||||
@@ -80,7 +98,6 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
camera_config['temp'] = 60
|
||||
camera_config['battery'] = 0
|
||||
camera_config['notifications'] = 4
|
||||
|
||||
for name in self.blink.cameras:
|
||||
camera = self.blink.cameras[name]
|
||||
camera.update(camera_config)
|
||||
@@ -93,8 +110,8 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
camera.clip,
|
||||
"https://rest.test.{}/test2/clip.mp4".format(BLINK_URL)
|
||||
)
|
||||
self.assertEqual(camera.temperature, 60)
|
||||
self.assertEqual(camera.battery, 0)
|
||||
self.assertEqual(camera.temperature, 68)
|
||||
self.assertEqual(camera.battery, 50)
|
||||
self.assertEqual(camera.battery_string, "Low")
|
||||
self.assertEqual(camera.notifications, 4)
|
||||
camera_config['battery'] = -10
|
||||
@@ -107,7 +124,9 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.blink.cameras['foobar'] = camera_object
|
||||
self.assertEqual(camera_object, self.blink.cameras['fOoBaR'])
|
||||
|
||||
def test_camera_attributes(self):
|
||||
@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
|
||||
return_value=CAMERA_CFG)
|
||||
def test_camera_attributes(self, mock_cfg):
|
||||
"""Tests camera attributes."""
|
||||
self.blink.urls = blinkpy.BlinkURLHandler('test')
|
||||
|
||||
@@ -117,6 +136,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
|
||||
for name in self.blink.cameras:
|
||||
camera = self.blink.cameras[name]
|
||||
camera.update(self.camera_config)
|
||||
camera_attr = camera.attributes
|
||||
self.assertEqual(camera_attr['device_id'], '1111')
|
||||
self.assertEqual(camera_attr['name'], 'foobar')
|
||||
@@ -129,7 +149,10 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
camera_attr['video'],
|
||||
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
|
||||
)
|
||||
self.assertEqual(camera_attr['temperature'], 70)
|
||||
self.assertEqual(camera_attr['battery'], 3)
|
||||
self.assertEqual(camera_attr['temperature'], 68)
|
||||
self.assertEqual(camera_attr['temperature_c'], 20.0)
|
||||
self.assertEqual(camera_attr['battery'], 50)
|
||||
self.assertEqual(camera_attr['notifications'], 2)
|
||||
self.assertEqual(camera_attr['network_id'], '0000')
|
||||
self.assertEqual(camera_attr['motion_detected'], True)
|
||||
self.assertEqual(camera_attr['wifi_strength'], -30)
|
||||
|
||||
@@ -61,9 +61,17 @@ class TestBlinkFunctions(unittest.TestCase):
|
||||
'/test/thumb')
|
||||
|
||||
@mock.patch('blinkpy.blinkpy._request')
|
||||
def test_get_cameras(self, req):
|
||||
@mock.patch('blinkpy.blinkpy.Blink._video_request')
|
||||
def test_get_cameras(self, vid_req, req):
|
||||
"""Test camera extraction."""
|
||||
req.return_value = {'devices': [self.config]}
|
||||
vid_req.return_value = [
|
||||
{
|
||||
'camera_name': 'foobar',
|
||||
'address': '/new.mp4',
|
||||
'thumbnail': '/new'
|
||||
}
|
||||
]
|
||||
self.blink.get_cameras()
|
||||
self.assertTrue('foobar' in self.blink.cameras)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user