Skip to content

Commit deba0cb

Browse files
authored
Merge pull request #225 from fronzbot/dev
0.14.3
2 parents 4a4811b + 0c3359a commit deba0cb

23 files changed

+398
-59
lines changed

.coveragerc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[run]
2-
omit =
3-
helpers/*
2+
parallel = true
3+
omit =
44
tests/*
5-
setup.py
5+
setup.py

.flake8

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
ignore = BLK100

.github/workflows/coverage.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: coverage
2+
3+
on:
4+
push:
5+
branches: [ master, dev ]
6+
pull_request:
7+
branches: [ master, dev ]
8+
9+
jobs:
10+
build:
11+
runs-on: ${{ matrix.platform }}
12+
strategy:
13+
max-parallel: 4
14+
matrix:
15+
platform:
16+
- ubuntu-latest
17+
python-version: [3.8]
18+
19+
steps:
20+
- uses: actions/checkout@v2
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v1
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install -r requirements.txt
29+
pip install -r requirements_test.txt
30+
pip install tox
31+
pip install codecov
32+
- name: Test
33+
run: |
34+
tox -r -e cov
35+
- name: Codecov
36+
uses: codecov/[email protected]
37+
with:
38+
flags: unittests
39+
file: ./coverage.xml
40+
name: blinkpy
41+
fail_ci_if_error: true

.github/workflows/lint.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3+
4+
name: Lint
5+
6+
on:
7+
push:
8+
branches: [ master, dev ]
9+
pull_request:
10+
branches: [ master, dev ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
python-version: [3.8]
19+
20+
steps:
21+
- uses: actions/checkout@v2
22+
- name: Set up Python ${{ matrix.python-version }}
23+
uses: actions/setup-python@v1
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install -r requirements.txt
30+
pip install -r requirements_test.txt
31+
pip install tox
32+
- name: Lint
33+
run: |
34+
tox -r -e lint

.github/workflows/publish.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This workflows will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
name: Upload Python Package
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
deploy:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v1
19+
with:
20+
python-version: '3.7'
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install setuptools wheel twine
25+
- name: Build and publish
26+
env:
27+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29+
run: |
30+
python setup.py bdist_wheel
31+
twine upload dist/*

.github/workflows/tests.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: build
2+
3+
on:
4+
push:
5+
branches: [ master, dev ]
6+
pull_request:
7+
branches: [ master, dev ]
8+
9+
jobs:
10+
build:
11+
runs-on: ${{ matrix.platform }}
12+
strategy:
13+
max-parallel: 4
14+
matrix:
15+
platform:
16+
- ubuntu-latest
17+
python-version: [3.5, 3.6, 3.7, 3.8]
18+
19+
steps:
20+
- uses: actions/checkout@v2
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v1
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install -r requirements.txt
29+
pip install -r requirements_test.txt
30+
pip install tox
31+
- name: Test
32+
run: |
33+
tox -r

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
__pycache__/*
55
htmlcov/*
66
.coverage
7+
coverage.xml
78
*.pyc
89
*.egg*/*
910
dist/*

.hound.yml

+4
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ python:
44
ignored_directories:
55
- docs
66

7+
flake8:
8+
enabled: true
9+
config_file: .flake8
10+
711
fail_on_violations: true

.travis.yml

-23
This file was deleted.

CHANGES.rst

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ Changelog
33

44
A list of changes between each release
55

6+
0.14.3 (2020-04-22)
7+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
- Add time check on recorded videos before determining motion
9+
- Fix motion detection variable suck to ``True``
10+
- Add ability to load credentials from a json file
11+
- Only allow ``motion_detected`` variable to trigger if system was armed
12+
- Log response message from server if not attempting a re-authorization
13+
614
0.14.2 (2019-10-12)
715
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
816
- Update dependencies

README.rst

+21-4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,23 @@ The simplest way to use this package from a terminal is to call ``Blink.start()`
5555
5656
If you would like to log in without setting up the cameras or system, you can simply call the ``Blink.login()`` function which will prompt for a username and password and then authenticate with the server. This is useful if you want to avoid use of the ``start()`` function which simply acts as a wrapper for more targeted API methods.
5757

58+
In addition, you can also save your credentials in a json file and initialize Blink with the credential file as follows:
59+
60+
.. code:: python
61+
62+
from blinkpy import blinkpy
63+
blink = blinkpy.Blink(cred_file="path/to/credentials.json")
64+
blink.start()
65+
66+
The credential file must be json formatted with a ``username`` and ``password`` key like follows:
67+
68+
.. code:: json
69+
70+
{
71+
"username": "YOUR USER NAME",
72+
"password": "YOUR PASSWORD"
73+
}
74+
5875
Cameras are instantiated as individual ``BlinkCamera`` classes within a ``BlinkSyncModule`` instance. All of your sync modules are stored within the ``Blink.sync`` dictionary and can be accessed using the name of the sync module as the key (this is the name of your sync module in the Blink App).
5976

6077
The below code will display cameras and their available attributes:
@@ -100,10 +117,10 @@ Example usage, which downloads all videos recorded since July 4th, 2018 at 9:34a
100117
blink.download_videos('/home/blink', since='2018/07/04 09:34')
101118
102119
103-
.. |Build Status| image:: https://travis-ci.org/fronzbot/blinkpy.svg?branch=dev
104-
:target: https://travis-ci.org/fronzbot/blinkpy
105-
.. |Coverage Status| image:: https://coveralls.io/repos/github/fronzbot/blinkpy/badge.svg?branch=dev
106-
:target: https://coveralls.io/github/fronzbot/blinkpy?branch=dev
120+
.. |Build Status| image:: https://github.com/fronzbot/blinkpy/workflows/build/badge.svg
121+
:target: https://github.com/fronzbot/blinkpy/actions?query=workflow%3Abuild
122+
.. |Coverage Status| image:: https://codecov.io/gh/fronzbot/blinkpy/branch/dev/graph/badge.svg
123+
:target: https://codecov.io/gh/fronzbot/blinkpy
107124
.. |PyPi Version| image:: https://img.shields.io/pypi/v/blinkpy.svg
108125
:target: https://pypi.python.org/pypi/blinkpy
109126
.. |Docs| image:: https://readthedocs.org/projects/blinkpy/badge/?version=latest

blinkpy/blinkpy.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import time
1818
import getpass
1919
import logging
20+
import json
2021
from shutil import copyfileobj
2122

2223
from requests.structures import CaseInsensitiveDict
@@ -42,6 +43,7 @@ class Blink():
4243
"""Class to initialize communication."""
4344

4445
def __init__(self, username=None, password=None,
46+
cred_file=None,
4547
refresh_rate=DEFAULT_REFRESH,
4648
motion_interval=DEFAULT_MOTION_INTERVAL,
4749
legacy_subdomain=False):
@@ -50,6 +52,10 @@ def __init__(self, username=None, password=None,
5052
5153
:param username: Blink username (usually email address)
5254
:param password: Blink password
55+
:param cred_file: JSON formatted file to store credentials.
56+
If username and password are given, file
57+
is ignored. Otherwise, username and password
58+
are loaded from file.
5359
:param refresh_rate: Refresh rate of blink information.
5460
Defaults to 15 (seconds)
5561
:param motion_interval: How far back to register motion in minutes.
@@ -62,6 +68,7 @@ def __init__(self, username=None, password=None,
6268
"""
6369
self._username = username
6470
self._password = password
71+
self._cred_file = cred_file
6572
self._token = None
6673
self._auth_header = None
6774
self._host = None
@@ -117,8 +124,25 @@ def start(self):
117124

118125
def login(self):
119126
"""Prompt user for username and password."""
120-
self._username = input("Username:")
121-
self._password = getpass.getpass("Password:")
127+
if self._cred_file is not None and os.path.isfile(self._cred_file):
128+
try:
129+
with open(self._cred_file, 'r') as json_file:
130+
creds = json.load(json_file)
131+
self._username = creds['username']
132+
self._password = creds['password']
133+
except ValueError:
134+
_LOGGER.error("Improperly formated json file %s.",
135+
self._cred_file,
136+
exc_info=True)
137+
return False
138+
except KeyError:
139+
_LOGGER.error("JSON file information incomplete %s.",
140+
exc_info=True)
141+
return False
142+
else:
143+
self._username = input("Username:")
144+
self._password = getpass.getpass("Password:")
145+
122146
if self.get_auth_token():
123147
_LOGGER.debug("Login successful!")
124148
return True

blinkpy/camera.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,7 @@ def image_to_file(self, path):
178178
copyfileobj(response.raw, imgfile)
179179
else:
180180
_LOGGER.error("Cannot write image to file, response %s",
181-
response.status_code,
182-
exc_info=True)
181+
response.status_code)
183182

184183
def video_to_file(self, path):
185184
"""Write video to file.
@@ -190,8 +189,7 @@ def video_to_file(self, path):
190189
response = self._cached_video
191190
if response is None:
192191
_LOGGER.error("No saved video exist for %s.",
193-
self.name,
194-
exc_info=True)
192+
self.name)
195193
return
196194
with open(path, 'wb') as vidfile:
197195
copyfileobj(response.raw, vidfile)

blinkpy/helpers/constants.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
MAJOR_VERSION = 0
66
MINOR_VERSION = 14
7-
PATCH_VERSION = 2
7+
PATCH_VERSION = 3
88

99
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
1010

@@ -60,7 +60,7 @@
6060
'''
6161
OTHER
6262
'''
63-
TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S%Z'
63+
TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S%z'
6464

6565
DEFAULT_MOTION_INTERVAL = 1
6666
DEFAULT_REFRESH = 30

blinkpy/helpers/errors.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
"Authentication header incorrect. Are you sure you received your token?"
1212
)
1313
REQUEST = (4, "Cannot perform request (get/post type incorrect)")
14+
15+
BLINK_ERRORS = [101, 400, 404]

0 commit comments

Comments
 (0)