Compare commits

..
823 Commits
Author SHA1 Message Date
Kevin FronczakandGitHub 1ced64de65 Merge pull request #434 from fronzbot/dev
0.17.0
2021-02-15 10:30:52 -05:00
Kevin Fronczak b41460c569 Add 0.17.0 changes 2021-02-15 10:27:32 -05:00
Kevin Fronczak 9ff02de48b Version bump 2021-02-15 10:16:59 -05:00
Kevin FronczakandGitHub 14cbbacc1b Merge pull request #433 from fronzbot/dependabot/pip/pygments-2.8.0
Bump pygments from 2.7.4 to 2.8.0
2021-02-15 10:14:35 -05:00
dependabot-preview[bot]andGitHub 1cadf3488d Bump pygments from 2.7.4 to 2.8.0
Bumps [pygments](https://github.com/pygments/pygments) from 2.7.4 to 2.8.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.7.4...2.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-15 06:09:58 +00:00
Kevin FronczakandGitHub c78f411014 Merge pull request #432 from fronzbot/add-reauth-back
Add reauth param back into login
2021-02-13 11:38:27 -05:00
Kevin Fronczak ab2db14bc8 Add reauth param back into login...may stop emails
- Also added a debug script because I'm tired of typing the same
  commands over and over again when debugging
2021-02-13 11:33:05 -05:00
Kevin FronczakandGitHub 36ff8e4917 Merge pull request #431 from fronzbot/0.17.0rc0
v0.17.0rc0
2021-02-11 23:55:59 -05:00
Kevin Fronczak f42c49d221 RC Version bump 2021-02-11 23:49:11 -05:00
Kevin FronczakandGitHub 114f8fbfa8 Merge pull request #430 from fronzbot/add-clip-record-function
Add camera record function
2021-02-11 23:46:33 -05:00
Kevin FronczakandGitHub 8bbf03fdb4 Merge pull request #429 from fronzbot/add-logout-endpoint
Add logout endpoint
2021-02-11 23:44:49 -05:00
Kevin Fronczak 5b57982b41 Add record function for camera 2021-02-11 23:41:16 -05:00
Kevin Fronczak ecf7a5b13a Add logout endpoint (among some linting improvements) 2021-02-11 23:34:59 -05:00
Kevin FronczakandGitHub f68951fab7 Merge pull request #428 from fronzbot/update-login
Upgrade login, UUID
2021-02-11 22:42:12 -05:00
Kevin Fronczak 23eec5187d Add gen_uid test 2021-02-11 22:32:15 -05:00
Kevin Fronczak caa3e10648 Fixed errant comment 2021-02-11 22:22:05 -05:00
Kevin FronczakandGitHub 4bc0b80eea Merge pull request #427 from fronzbot/dependabot/pip/pre-commit-2.10.1
Bump pre-commit from 2.9.3 to 2.10.1
2021-02-11 22:17:17 -05:00
Kevin Fronczak 959a7dfa85 Modify uid to prefix with BlinkCamera 2021-02-11 11:55:27 -05:00
Kevin Fronczak 9e793b6748 Upgraded login endpoint, fixed uid generation 2021-02-11 11:21:26 -05:00
dependabot-preview[bot]andGitHub c75e057e83 Bump pre-commit from 2.9.3 to 2.10.1
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.9.3 to 2.10.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.9.3...v2.10.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-08 06:29:34 +00:00
Kevin FronczakandGitHub 6fa4aa6f75 Merge pull request #425 from fronzbot/0.16.5.rc0
0.16.5.rc0
2021-02-05 10:24:00 -05:00
Kevin FronczakandGitHub 89da167404 Update constants.py 2021-02-05 10:22:04 -05:00
Kevin FronczakandGitHub f2520e35fe Merge pull request #424 from fronzbot/fix-vid-download
Add content type to header to fix downloading
2021-02-05 10:21:10 -05:00
Kevin Fronczak aaaaea4dd1 Fix header test 2021-02-05 15:18:09 +00:00
Kevin Fronczak ec67d97809 Add content type to header to fix downloading 2021-02-05 15:11:03 +00:00
Kevin FronczakandGitHub f6118ea4a7 Merge pull request #420 from fronzbot/dependabot/pip/coverage-5.4
Bump coverage from 5.3.1 to 5.4
2021-01-27 07:37:23 -05:00
dependabot-preview[bot]andGitHub d257f676ec Bump coverage from 5.3.1 to 5.4
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.3.1 to 5.4.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.3.1...coverage-5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-27 06:09:36 +00:00
Kevin FronczakandGitHub 58f4a9df57 Merge pull request #419 from fronzbot/dependabot/pip/pytest-6.2.2
Bump pytest from 6.2.1 to 6.2.2
2021-01-26 08:10:02 -05:00
dependabot-preview[bot]andGitHub 9d91ce62d3 Bump pytest from 6.2.1 to 6.2.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.2.1...6.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-26 06:06:01 +00:00
Kevin FronczakandGitHub 511ca99cba Merge pull request #416 from fronzbot/dependabot/pip/pytest-cov-2.11.1
Bump pytest-cov from 2.11.0 to 2.11.1
2021-01-21 09:04:52 -05:00
dependabot-preview[bot]andGitHub 465701810b Bump pytest-cov from 2.11.0 to 2.11.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.11.0 to 2.11.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.11.0...v2.11.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-21 06:06:32 +00:00
Kevin FronczakandGitHub c8c0ed58df Merge pull request #415 from fronzbot/dependabot/pip/pytest-cov-2.11.0
Bump pytest-cov from 2.10.1 to 2.11.0
2021-01-19 07:30:16 -05:00
dependabot-preview[bot]andGitHub cfe3c10cec Bump pytest-cov from 2.10.1 to 2.11.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.1 to 2.11.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.1...v2.11.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-19 06:06:21 +00:00
Kevin FronczakandGitHub 014509bd64 Merge pull request #414 from fronzbot/dependabot/pip/pygments-2.7.4
Bump pygments from 2.7.3 to 2.7.4
2021-01-13 07:53:07 -05:00
dependabot-preview[bot]andGitHub f5d5d34eda Bump pygments from 2.7.3 to 2.7.4
Bumps [pygments](https://github.com/pygments/pygments) from 2.7.3 to 2.7.4.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.7.3...2.7.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-13 06:12:31 +00:00
Kevin FronczakandGitHub 64c8bec614 Merge pull request #405 from fronzbot/dependabot/pip/restructuredtext-lint-1.3.2
Bump restructuredtext-lint from 1.3.1 to 1.3.2
2021-01-05 09:43:00 -05:00
Kevin FronczakandGitHub 1b765035de Merge pull request #408 from fronzbot/dependabot/pip/pre-commit-2.9.3
Bump pre-commit from 2.7.1 to 2.9.3
2021-01-05 09:42:48 -05:00
dependabot-preview[bot]andGitHub 93f46bde6a Bump restructuredtext-lint from 1.3.1 to 1.3.2
Bumps [restructuredtext-lint](https://github.com/twolfson/restructuredtext-lint) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/twolfson/restructuredtext-lint/releases)
- [Changelog](https://github.com/twolfson/restructuredtext-lint/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/twolfson/restructuredtext-lint/compare/1.3.1...1.3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-05 14:37:34 +00:00
dependabot-preview[bot]andGitHub 4a09fcf06f Bump pre-commit from 2.7.1 to 2.9.3
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.7.1 to 2.9.3.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.7.1...v2.9.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-05 14:36:38 +00:00
Kevin FronczakandGitHub 12a2ae1326 Merge pull request #407 from fronzbot/dependabot/pip/pygments-2.7.3
Bump pygments from 2.7.1 to 2.7.3
2021-01-05 09:36:22 -05:00
Kevin FronczakandGitHub 325241d56a Merge pull request #411 from fronzbot/dependabot/pip/coverage-5.3.1
Bump coverage from 5.3 to 5.3.1
2021-01-05 09:36:04 -05:00
Kevin FronczakandGitHub 95664fea1f Merge pull request #410 from fronzbot/dependabot/pip/pytest-6.2.1
Bump pytest from 6.1.1 to 6.2.1
2021-01-05 09:35:22 -05:00
dependabot-preview[bot]andGitHub e2b43f4b06 Bump pytest from 6.1.1 to 6.2.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.1 to 6.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.1...6.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-05 14:29:23 +00:00
Kevin FronczakandGitHub 845c8a2a40 Merge pull request #413 from fronzbot/add-py39
Add py39
2021-01-05 09:27:31 -05:00
Kevin FronczakandGitHub 306f8b6cb4 Update tests.yml 2021-01-05 09:24:04 -05:00
Kevin FronczakandGitHub a704933a35 Update publish.yml 2021-01-05 09:23:29 -05:00
Kevin FronczakandGitHub 8bd09c3726 Delete .gitlab-ci.yml 2021-01-05 09:22:04 -05:00
Kevin FronczakandGitHub 6240364067 Update constants.py 2021-01-05 09:21:36 -05:00
Kevin FronczakandGitHub 9d37cfccd0 Update stale.yml 2021-01-05 09:12:56 -05:00
dependabot-preview[bot]andGitHub 125efd9436 Bump coverage from 5.3 to 5.3.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.3 to 5.3.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.3...coverage-5.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-21 06:32:59 +00:00
dependabot-preview[bot]andGitHub 6701fd39d8 Bump pygments from 2.7.1 to 2.7.3
Bumps [pygments](https://github.com/pygments/pygments) from 2.7.1 to 2.7.3.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.7.1...2.7.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-07 06:18:02 +00:00
Kevin Fronczak d4edf96f83 Dev version bump 2020-11-23 04:34:49 +00:00
Kevin FronczakandGitHub 37350da1b2 Merge pull request #402 from fronzbot/dev
0.16.4
2020-11-22 23:33:15 -05:00
Kevin FronczakandGitHub a2555a6c40 Update for 0.16.4 2020-11-22 23:31:13 -05:00
Kevin Fronczak c01a6ce16b dev version bump 2020-11-23 04:25:16 +00:00
Kevin Fronczak ab38afa105 dev version bump 2020-11-23 04:06:19 +00:00
Kevin FronczakandGitHub ba3c2e3489 Merge pull request #401 from fronzbot/fix-exception-on-refresh
Added test to catch NoneType error on refresh, fixed offending code
2020-11-22 23:04:31 -05:00
Kevin Fronczak 92a2cc2d9a Added test to catch NoneType error on refresh, fixed offending code 2020-11-23 03:30:15 +00:00
Kevin FronczakandGitHub 0842739197 Merge pull request #395 from fronzbot/fix-stream-format
Fix malformatted stream url for blink mini
2020-10-25 10:09:28 -04:00
Kevin Fronczak f09a66c083 Fix malformatted stream url for blink mini 2020-10-25 14:01:03 +00:00
Kevin FronczakandGitHub 88984365fe Update constants.py 2020-10-06 09:31:45 -04:00
Kevin FronczakandGitHub 469b0c257e Merge pull request #389 from fronzbot/fix-liveview-endpoint
Updated liveview endpoint
2020-10-06 09:29:17 -04:00
Kevin FronczakandGitHub a94f59eb53 Merge pull request #388 from fronzbot/fix-mini-thumb-refresh
Generalized image/video download, fixed non-updating image for minis
2020-10-06 09:23:55 -04:00
Kevin Fronczak eb1fbe90d1 Updated liveview endpoint 2020-10-06 13:20:56 +00:00
Kevin Fronczak b5b7498041 Generalized image/video download, fixed non-updating image for minis 2020-10-06 13:16:05 +00:00
Kevin FronczakandGitHub 828b41197b Merge pull request #387 from fronzbot/move-testtools
Move testtools to requirements_test.txt
2020-10-05 16:33:14 -04:00
Kevin Fronczak b0fed670b9 Move testtools to requirements_test.txt 2020-10-05 20:29:13 +00:00
Kevin FronczakandGitHub f13d177615 Merge pull request #371 from fronzbot/dependabot/pip/pre-commit-2.7.1
Bump pre-commit from 2.6.0 to 2.7.1
2020-10-05 09:53:56 -04:00
Kevin FronczakandGitHub fcce28c9c4 Merge pull request #385 from fronzbot/dependabot/pip/pytest-6.1.1
Bump pytest from 6.0.1 to 6.1.1
2020-10-05 09:53:44 -04:00
Kevin FronczakandGitHub e8e9d4e3cd Update .pre-commit-config.yaml 2020-10-05 09:49:16 -04:00
dependabot-preview[bot]andGitHub 59ef398452 Bump pytest from 6.0.1 to 6.1.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.1 to 6.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.1...6.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 13:49:12 +00:00
Kevin FronczakandGitHub 80e39845ce Merge pull request #375 from fronzbot/dependabot/pip/pydocstyle-5.1.1
Bump pydocstyle from 5.0.2 to 5.1.1
2020-10-05 09:47:58 -04:00
Kevin FronczakandGitHub cbab673084 Merge pull request #384 from fronzbot/dependabot/pip/flake8-3.8.4
Bump flake8 from 3.8.3 to 3.8.4
2020-10-05 09:47:44 -04:00
Kevin FronczakandGitHub f27df12e64 Merge pull request #379 from fronzbot/dependabot/pip/pygments-2.7.1
Bump pygments from 2.6.1 to 2.7.1
2020-10-05 09:46:08 -04:00
dependabot-preview[bot]andGitHub bdcb3f6203 Bump pydocstyle from 5.0.2 to 5.1.1
Bumps [pydocstyle](https://github.com/PyCQA/pydocstyle) from 5.0.2 to 5.1.1.
- [Release notes](https://github.com/PyCQA/pydocstyle/releases)
- [Changelog](https://github.com/PyCQA/pydocstyle/blob/master/docs/release_notes.rst)
- [Commits](https://github.com/PyCQA/pydocstyle/compare/5.0.2...5.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 13:44:53 +00:00
dependabot-preview[bot]andGitHub f619b20e2a Bump flake8 from 3.8.3 to 3.8.4
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.3 to 3.8.4.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.3...3.8.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 13:44:52 +00:00
Kevin FronczakandGitHub 69aaee3fc4 Merge branch 'dev' into dependabot/pip/pre-commit-2.7.1 2020-10-05 09:44:28 -04:00
Kevin FronczakandGitHub 7140895c58 Merge pull request #370 from fronzbot/dependabot/pip/pylint-2.6.0
Bump pylint from 2.5.3 to 2.6.0
2020-10-05 09:43:33 -04:00
Kevin FronczakandGitHub 190cef875e Attempt to fix coverage 2020-10-05 09:38:15 -04:00
dependabot-preview[bot]andGitHub 7aef8570a5 Bump pylint from 2.5.3 to 2.6.0
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.5.3 to 2.6.0.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.5.3...pylint-2.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-05 13:24:47 +00:00
Kevin FronczakandGitHub 721a3ad8f2 Merge pull request #386 from fronzbot/add-codecov-token
Add codecov token to workflow to fix upload issue
2020-10-05 09:21:31 -04:00
Kevin FronczakandGitHub 1b1c30bff0 Add codecov token to workflow to fix upload issue 2020-10-05 09:08:15 -04:00
dependabot-preview[bot]andGitHub 8c23087f89 Bump pre-commit from 2.6.0 to 2.7.1
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.6.0 to 2.7.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.6.0...v2.7.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-28 15:10:49 +00:00
Kevin FronczakandGitHub dae2413ed1 Merge pull request #381 from rohitsud/patch-1
Fix readme param and spelling
2020-09-28 11:10:32 -04:00
Kevin FronczakandGitHub cd9792193f Merge pull request #377 from fronzbot/dependabot/pip/coverage-5.3
Bump coverage from 5.2.1 to 5.3
2020-09-28 11:09:35 -04:00
Kevin FronczakandGitHub 75dbd1e498 Merge pull request #368 from fronzbot/dependabot/pip/pytest-cov-2.10.1
Bump pytest-cov from 2.10.0 to 2.10.1
2020-09-27 21:59:53 -04:00
rohitsudandGitHub a374009835 Fix readme param and spelling 2020-09-27 13:06:24 -07:00
dependabot-preview[bot]andGitHub 9a9501635f Bump pygments from 2.6.1 to 2.7.1
Bumps [pygments](https://github.com/pygments/pygments) from 2.6.1 to 2.7.1.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.6.1...2.7.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-18 06:32:37 +00:00
dependabot-preview[bot]andGitHub e00600c955 Bump coverage from 5.2.1 to 5.3
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2.1 to 5.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.2.1...coverage-5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-09-14 06:38:09 +00:00
dependabot-preview[bot]andGitHub 141fea542c Bump pytest-cov from 2.10.0 to 2.10.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.0...v2.10.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-08-17 08:14:22 +00:00
Kevin Fronczak ed4450778d Dev bump 2020-08-02 03:35:42 +00:00
Kevin FronczakandGitHub 19b7eef123 Merge pull request #363 from fronzbot/dev
0.16.3
2020-08-01 23:33:38 -04:00
Kevin FronczakandGitHub 41d59b1df0 Merge pull request #362 from fronzbot/update-changelog
Update changelog for 0.16.3
2020-08-01 23:29:04 -04:00
Kevin FronczakandGitHub fd104c09da Merge pull request #361 from fronzbot/add-user-agent-everywhere
Add user agent to all headers
2020-08-01 23:28:54 -04:00
Kevin Fronczak 6dbed91426 Update changelog for 0.16.3 2020-08-02 03:24:38 +00:00
Kevin Fronczak cb43f17d75 Add user agent to all headers 2020-08-02 03:22:49 +00:00
Kevin FronczakandGitHub 5ebf278ad3 Merge pull request #360 from fronzbot/dev-bump
Dev version bump
2020-08-01 23:13:46 -04:00
Kevin FronczakandGitHub 6bd8d14190 Merge pull request #359 from fronzbot/dev
0.16.2
2020-08-01 23:12:25 -04:00
Kevin Fronczak 7f782533b8 Dev version bump 2020-08-02 03:09:22 +00:00
Kevin FronczakandGitHub 1790c1beae Merge pull request #358 from fronzbot/bugfix-version-bump
Version bump
2020-08-01 23:07:58 -04:00
Kevin Fronczak 09e1c382d3 Version bump 2020-08-02 03:04:09 +00:00
Kevin FronczakandGitHub ceb2270ee5 Merge pull request #357 from fronzbot/simplify-login
Updated headers to include user-agent, removed extra data at login
2020-08-01 23:01:34 -04:00
Kevin Fronczak 986a3c81f3 Updated headers to include user-agent, removed extra data at login 2020-08-02 02:57:26 +00:00
Kevin FronczakandGitHub 11d6bbb916 Merge pull request #354 from fronzbot/dev-rc-bump
Dev rc bump
2020-07-31 22:15:13 -04:00
Kevin FronczakandGitHub b02f6318a7 Merge pull request #353 from fronzbot/update-app-version
Update app version and set reauth to True...should fix login problems
2020-07-31 22:15:02 -04:00
Kevin FronczakandGitHub c1435e74e8 Merge pull request #352 from fronzbot/dependabot/pip/pytest-6.0.1
Bump pytest from 6.0.0 to 6.0.1
2020-07-31 22:13:28 -04:00
Kevin Fronczak b30da661e5 Dev rc bump 2020-08-01 02:12:42 +00:00
Kevin Fronczak 3a22dddc82 Update app version and set reauth to True...should fix login problems 2020-08-01 02:10:25 +00:00
dependabot-preview[bot]andGitHub a19a17d4dc Bump pytest from 6.0.0 to 6.0.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.0...6.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-31 08:16:15 +00:00
Kevin FronczakandGitHub bff6ef92ce Merge pull request #350 from fronzbot/dev-version-bump
Dev bump
2020-07-29 11:38:18 -04:00
Kevin FronczakandGitHub f6ddfbe5cf Merge pull request #349 from fronzbot/dev
0.16.1
2020-07-29 11:32:04 -04:00
Kevin Fronczak 263572eb66 Dev bump 2020-07-29 15:28:13 +00:00
Kevin FronczakandGitHub 3a97a928de Merge pull request #348 from fronzbot/0.16.1-changelog
Updated versions and changelog for 0.16.1
2020-07-29 11:27:26 -04:00
Kevin Fronczak 0322414de1 Updated versions and changelog for 0.16.1 2020-07-29 15:23:59 +00:00
Kevin FronczakandGitHub 1c75e86863 Merge pull request #347 from fronzbot/unpin-reqs
Set min version for reqs instead of pinning
2020-07-29 11:23:11 -04:00
Kevin FronczakandGitHub 0ae71f6367 Merge pull request #345 from fronzbot/dependabot/pip/pytest-6.0.0
Bump pytest from 5.4.3 to 6.0.0
2020-07-29 11:19:38 -04:00
Kevin FronczakandGitHub af7c38695a Merge pull request #344 from fronzbot/dependabot/pip/coverage-5.2.1
Bump coverage from 5.2 to 5.2.1
2020-07-29 11:19:21 -04:00
Kevin Fronczak c741c22876 Set min version for reqs instead of pinning 2020-07-29 15:15:19 +00:00
dependabot-preview[bot]andGitHub 06b9b12eeb Bump pytest from 5.4.3 to 6.0.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.3 to 6.0.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.3...6.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-29 08:05:56 +00:00
dependabot-preview[bot]andGitHub daf7078f98 Bump coverage from 5.2 to 5.2.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2 to 5.2.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.2...coverage-5.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-27 08:17:40 +00:00
Kevin FronczakandGitHub c2db57ecb3 Merge pull request #341 from fronzbot/dev-bump
Dev version bump
2020-07-20 23:01:51 -04:00
Kevin FronczakandGitHub 1b66eddfb4 Merge pull request #340 from fronzbot/dev
0.16.0
2020-07-20 23:01:30 -04:00
Kevin Fronczak 0336c6a8f8 Dev version bump 2020-07-20 02:24:28 +00:00
Kevin Fronczak 22d3fa9565 Merge remote-tracking branch 'origin/master' into dev 2020-07-20 02:19:27 +00:00
Kevin FronczakandGitHub 9d81973b3a Merge pull request #339 from fronzbot/retry-options
Retry options
2020-07-19 21:47:40 -04:00
Kevin Fronczak fe8eac3dc6 Update documentation 2020-07-20 01:42:07 +00:00
Kevin Fronczak 5fc315201a Add tests for retry options 2020-07-20 01:33:11 +00:00
Kevin Fronczak a9d3d5568b Adding retry options to auth class 2020-07-20 01:25:09 +00:00
Kevin FronczakandGitHub f88dbdaeba Merge pull request #338 from fronzbot/fix-auth-tests
Fix broken test and missing try/except
2020-07-19 21:24:50 -04:00
Kevin Fronczak 48028914de Fix broken test and missing try/except 2020-07-20 01:18:41 +00:00
Kevin FronczakandGitHub fcdb70d246 Merge pull request #337 from fronzbot/remove-exec-info
Removed all exc_info parameters during logging
2020-07-19 20:51:38 -04:00
Kevin Fronczak e8589bfa05 Fix test 2020-07-20 00:48:40 +00:00
Kevin Fronczak 854ffbf26a Removed all exc_info parameters during logging 2020-07-20 00:37:30 +00:00
Kevin FronczakandGitHub ca109f703c Merge pull request #336 from fronzbot/dev-bump
Dev version bump
2020-07-19 20:37:22 -04:00
Kevin Fronczak 82d5a7ea51 Dev version bump 2020-07-20 00:34:06 +00:00
Kevin FronczakandGitHub 79ead7b826 Merge pull request #333 from fronzbot/dependabot/pip/pytest-timeout-1.4.2
Bump pytest-timeout from 1.4.1 to 1.4.2
2020-07-16 13:03:03 -04:00
dependabot-preview[bot]andGitHub 6e360b2bb1 Bump pytest-timeout from 1.4.1 to 1.4.2
Bumps [pytest-timeout](https://github.com/pytest-dev/pytest-timeout) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/pytest-dev/pytest-timeout/releases)
- [Commits](https://github.com/pytest-dev/pytest-timeout/compare/1.4.1...1.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-16 08:06:30 +00:00
Kevin FronczakandGitHub 1aaa5b649f Merge pull request #331 from fronzbot/remove-host
Remove host from auth header
2020-07-11 11:24:47 -04:00
Kevin FronczakandGitHub 435f3b9831 Update CHANGES.rst 2020-07-11 10:44:37 -04:00
Kevin FronczakandGitHub bcf0bb5525 Merge pull request #330 from fronzbot/bugfix
Bugfix: remove Host from auth header
2020-07-11 10:42:44 -04:00
Kevin Fronczak 322aae37dc fix test (remove host) 2020-07-11 14:41:44 +00:00
Kevin Fronczak 45cb4028b8 Remove host from auth header 2020-07-11 14:39:45 +00:00
Kevin Fronczak 151d9b7375 Version bump 2020-07-11 14:37:04 +00:00
Kevin Fronczak d393c861d7 bugfix: remove host from auth header 2020-07-11 14:36:37 +00:00
Kevin Fronczak 02c4b2e7e1 Add rst linter to pre-commit and fix flake8 2020-07-11 14:36:06 +00:00
Kevin FronczakandGitHub 77959d6d94 Merge pull request #327 from fronzbot/dependabot/pip/pytest-sugar-0.9.4
Bump pytest-sugar from 0.9.3 to 0.9.4
2020-07-08 22:47:46 -04:00
Kevin FronczakandGitHub ad832c4d2d Merge pull request #326 from fronzbot/dependabot/pip/coverage-5.2
Bump coverage from 5.1 to 5.2
2020-07-08 22:46:54 -04:00
Kevin FronczakandGitHub 0ce2aec139 Merge pull request #328 from fronzbot/remove-unbound-ref
Remove reference to response on exception since it may be unbound
2020-07-08 22:46:29 -04:00
Kevin Fronczak d3761b23ec Remove reference to response on exception since it may be unbound 2020-07-08 17:57:56 +00:00
dependabot-preview[bot]andGitHub cdbd1a4c27 Bump pytest-sugar from 0.9.3 to 0.9.4
Bumps [pytest-sugar](https://github.com/Teemu/pytest-sugar) from 0.9.3 to 0.9.4.
- [Release notes](https://github.com/Teemu/pytest-sugar/releases)
- [Changelog](https://github.com/Teemu/pytest-sugar/blob/master/CHANGES.rst)
- [Commits](https://github.com/Teemu/pytest-sugar/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-07 08:16:07 +00:00
dependabot-preview[bot]andGitHub 2d2e569595 Bump coverage from 5.1 to 5.2
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.1 to 5.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.1...coverage-5.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-07 08:15:43 +00:00
Kevin FronczakandGitHub 391373b304 Merge pull request #324 from fronzbot/http-adapter
Modify session to use HTTPAdapter and handle retries
2020-07-02 14:34:45 -04:00
Kevin Fronczak a030f46b4d Modify session to use HTTPAdapter and handle retries 2020-07-02 18:15:29 +00:00
Kevin FronczakandGitHub f6dc22f241 Merge pull request #323 from fronzbot/image-and-video-timeout
Add different timeout for video and image retrieval
2020-07-02 11:40:31 -04:00
Kevin Fronczak 220638e525 Add different timeout for video and image retrieval 2020-07-02 14:50:38 +00:00
Kevin FronczakandGitHub 24b1aac1be Merge pull request #322 from fronzbot/dependabot/pip/pre-commit-2.6.0
Bump pre-commit from 2.5.1 to 2.6.0
2020-07-02 08:46:50 -04:00
dependabot-preview[bot]andGitHub c4608f4258 Bump pre-commit from 2.5.1 to 2.6.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.5.1 to 2.6.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.5.1...v2.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-02 08:15:35 +00:00
Kevin FronczakandGitHub ca19ea62a4 Merge pull request #321 from fronzbot/dependabot/pip/python-slugify-approx-eq-4.0.1
Update python-slugify requirement from ~=4.0.0 to ~=4.0.1
2020-06-30 12:47:24 -04:00
Kevin FronczakandGitHub 2d8f4d8289 Merge pull request #320 from fronzbot/roll-back
Rolled back to rc8, removed v3 auth functionality (poorly thought out)
2020-06-30 12:46:57 -04:00
Kevin Fronczak 24ca9d9617 Fixed request version, improved setup.py requirement import 2020-06-30 16:40:19 +00:00
dependabot-preview[bot]andGitHub 41aa1839b7 Update python-slugify requirement from ~=4.0.0 to ~=4.0.1
Updates the requirements on [python-slugify](https://github.com/un33k/python-slugify) to permit the latest version.
- [Release notes](https://github.com/un33k/python-slugify/releases)
- [Changelog](https://github.com/un33k/python-slugify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un33k/python-slugify/compare/4.0.0...4.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-30 07:53:51 +00:00
Kevin Fronczak 40354e87a0 Rolled back to rc8, removed v3 auth functionality (poorly thought out) 2020-06-29 17:23:15 +00:00
Kevin FronczakandGitHub 0fc74c3f82 Merge pull request #319 from fronzbot/login-fix
Changed the way the new login method switch is handled
2020-06-29 13:06:01 -04:00
Kevin Fronczak 7b150eb1af Changed the way the new login method switch is handled 2020-06-29 17:01:46 +00:00
Kevin FronczakandGitHub f8db8eb3b6 Merge pull request #318 from fronzbot/login-switch
Add option to use v3 login endpoint
2020-06-29 12:49:56 -04:00
Kevin FronczakandGitHub a34b6dec67 Merge pull request #315 from fronzbot/dependabot/pip/requests-approx-eq-2.24.0
Update requests requirement from ~=2.23.0 to ~=2.24.0
2020-06-29 11:54:10 -04:00
Kevin Fronczak bded3eb156 Add option to use v3 login endpoint 2020-06-29 15:46:43 +00:00
dependabot-preview[bot]andGitHub 9ca73934ce Update requests requirement from ~=2.23.0 to ~=2.24.0
Updates the requirements on [requests](https://github.com/psf/requests) to permit the latest version.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/master/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.23.0...v2.24.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-18 08:04:10 +00:00
Kevin FronczakandGitHub e02b429523 Merge pull request #314 from fronzbot/fix-return-error
Fix error with updating owl information during refresh
2020-06-16 14:46:40 -04:00
Kevin Fronczak 22e4b7dabe Fix error with updating owl information during refresh 2020-06-16 18:42:59 +00:00
Kevin FronczakandGitHub 130b5acf84 Merge pull request #312 from fronzbot/dependabot/pip/pytest-timeout-1.4.1
Bump pytest-timeout from 1.4.0 to 1.4.1
2020-06-16 13:54:52 -04:00
Kevin FronczakandGitHub d0fa303c88 Merge pull request #313 from fronzbot/improve-mini-extraction
Broke out homescreen call to prevent back-to-back api calls
2020-06-16 13:54:37 -04:00
Kevin Fronczak dff0746450 Broke out homescreen call to prevent back-to-back api calls 2020-06-16 17:43:22 +00:00
dependabot-preview[bot]andGitHub 815dfd9a8e Bump pytest-timeout from 1.4.0 to 1.4.1
Bumps [pytest-timeout](https://github.com/pytest-dev/pytest-timeout) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/pytest-dev/pytest-timeout/releases)
- [Commits](https://github.com/pytest-dev/pytest-timeout/compare/1.4.0...1.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-16 07:58:09 +00:00
Kevin FronczakandGitHub b0ea0566a5 Merge pull request #310 from fronzbot/dependabot/pip/pytest-cov-2.10.0
Bump pytest-cov from 2.9.0 to 2.10.0
2020-06-15 10:57:19 -04:00
dependabot-preview[bot]andGitHub 0167900415 Bump pytest-cov from 2.9.0 to 2.10.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.9.0...v2.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-15 14:34:40 +00:00
Kevin FronczakandGitHub 9279ba2aa9 Merge pull request #311 from fronzbot/dependabot/pip/pytest-timeout-1.4.0
Bump pytest-timeout from 1.3.4 to 1.4.0
2020-06-15 10:33:14 -04:00
dependabot-preview[bot]andGitHub 2abfc3e843 Bump pytest-timeout from 1.3.4 to 1.4.0
Bumps [pytest-timeout](https://github.com/pytest-dev/pytest-timeout) from 1.3.4 to 1.4.0.
- [Release notes](https://github.com/pytest-dev/pytest-timeout/releases)
- [Commits](https://github.com/pytest-dev/pytest-timeout/compare/1.3.4...1.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-15 08:34:05 +00:00
Kevin FronczakandGitHub 4ff83585b4 Merge pull request #309 from fronzbot/dev-bump
dev bump
2020-06-14 10:51:47 -04:00
Kevin FronczakandGitHub 3cf2b5e093 dev bump 2020-06-14 10:49:17 -04:00
Kevin FronczakandGitHub 6a7eff6501 Merge pull request #308 from fronzbot/fix-extra-reauth
Removed 'reauth' key from login payload
2020-06-14 10:45:58 -04:00
Kevin Fronczak 3805a41d9f Removed 'reauth' key from login payload 2020-06-14 13:43:58 +00:00
Kevin FronczakandGitHub f8c78fb499 Merge pull request #307 from fronzbot/update-docker-app
Updated docker app to be compatible with 0.16.0 changes
2020-06-13 22:40:35 -04:00
Kevin Fronczak 3314ff85ed Updated docke app to be compatible with 0.16.0 changes 2020-06-14 02:36:57 +00:00
Kevin FronczakandGitHub 67b24eb89a Merge pull request #306 from fronzbot/dev-bump
Dev version bump
2020-06-13 22:18:31 -04:00
Kevin Fronczak d416e42925 Dev version bump 2020-06-14 02:12:43 +00:00
Kevin FronczakandGitHub 17655849ae Merge pull request #305 from fronzbot/disable-owl-option
Add option to skip homescreen check
2020-06-13 22:08:08 -04:00
Kevin Fronczak d9e3761c7b Add option to skip homescreen check 2020-06-14 02:03:22 +00:00
Kevin FronczakandGitHub 382db80584 Merge pull request #304 from fronzbot/codecov-update
Update codecov.yml
2020-06-11 22:57:13 -04:00
Kevin FronczakandGitHub 695dc96340 Update codecov.yml 2020-06-11 22:54:46 -04:00
Kevin FronczakandGitHub 8b1851b647 Merge pull request #303 from fronzbot/support-mini-attached-to-sync
Prevent sync module creation for minis already attached to one
2020-06-11 22:51:24 -04:00
Kevin Fronczak eeaa9cdf6f Prevent sync module creation for minis already attached to one 2020-06-11 23:05:37 +00:00
Kevin FronczakandGitHub 5cd59c049e Merge pull request #302 from fronzbot/dev-bump
Dev version bump
2020-06-10 11:14:03 -04:00
Kevin Fronczak 5d86e0ac9a Dev version bump 2020-06-10 15:10:17 +00:00
Kevin FronczakandGitHub d9136e611f Merge pull request #297 from fronzbot/dependabot/pip/pre-commit-2.5.1
Bump pre-commit from 2.5.0 to 2.5.1
2020-06-10 11:03:38 -04:00
Kevin FronczakandGitHub 5ca1aca3c0 Merge pull request #301 from fronzbot/fix-mini-attributes
Add type check on temperature conversion
2020-06-10 11:03:14 -04:00
Kevin Fronczak 08632ec9ce Add type check on temperature conversion 2020-06-10 14:58:28 +00:00
Kevin FronczakandGitHub 45ba46e637 Merge pull request #300 from fronzbot/blink-mini-arm-support
Add blink mini arm/disarm support
2020-06-10 10:20:42 -04:00
Kevin Fronczak e51740ca89 Removed blink mini arm overload 2020-06-10 14:16:16 +00:00
Kevin Fronczak eb7d7d9601 Add blink mini arm/disarm support
- Updates endpoint for arm/disarm so it's consistent across device types
2020-06-10 14:13:42 +00:00
Kevin FronczakandGitHub c4b70f963c Merge pull request #299 from fronzbot/fix-sync-arm
Fixed missing sync module arm method
2020-06-10 10:13:00 -04:00
Kevin Fronczak b73d122b15 Fixed missing sync module arm method 2020-06-10 14:06:42 +00:00
dependabot-preview[bot]andGitHub db072b9dea Bump pre-commit from 2.5.0 to 2.5.1
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.5.0 to 2.5.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.5.0...v2.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-10 08:27:36 +00:00
Kevin FronczakandGitHub 5c56c903e8 Merge pull request #294 from fronzbot/dev-bump
Dev version bump
2020-06-09 13:54:34 -04:00
Kevin Fronczak 0758fa66d3 Dev version bump 2020-06-09 17:50:31 +00:00
Kevin FronczakandGitHub 6edb89a606 Merge pull request #292 from fronzbot/dependabot/pip/pre-commit-2.5.0
Bump pre-commit from 2.4.0 to 2.5.0
2020-06-09 13:41:13 -04:00
Kevin FronczakandGitHub 7f15827791 Merge pull request #291 from fronzbot/dependabot/pip/flake8-3.8.3
Bump flake8 from 3.8.2 to 3.8.3
2020-06-09 13:40:54 -04:00
Kevin FronczakandGitHub 93d498aafb Merge pull request #290 from fronzbot/add-minis
Add support for Blink Minis
2020-06-09 13:38:40 -04:00
Kevin Fronczak b8da6e2197 Add unsupported notifications, updated Mini thumbnail endpoint 2020-06-09 16:53:33 +00:00
Kevin Fronczak 4f00aac7a2 Fixed missing camera init from owl, cleaned up camera a bit 2020-06-09 15:25:57 +00:00
Kevin Fronczak 7dd32a0dad Make sure cameras are properly merged, initilize minis properly 2020-06-09 13:30:29 +00:00
dependabot-preview[bot]andGitHub eb8f0f6437 Bump pre-commit from 2.4.0 to 2.5.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.4.0...v2.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-09 08:12:59 +00:00
dependabot-preview[bot]andGitHub 8fcd579a69 Bump flake8 from 3.8.2 to 3.8.3
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.2 to 3.8.3.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.2...3.8.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-09 08:12:37 +00:00
Kevin Fronczak 6479423c6c Fix test 2020-06-09 04:33:11 +00:00
Kevin Fronczak be1a5bf92f Update liveview for mini 2020-06-09 04:10:47 +00:00
Kevin Fronczak 2788ab58ea First cut at blink mini support 2020-06-09 04:04:07 +00:00
Kevin FronczakandGitHub 31de65f155 Merge pull request #289 from fronzbot/add-liveview
Add get_liveview command to camera module
2020-06-08 13:20:03 -04:00
Kevin Fronczak fd2e4ed9a4 Add get_liveview command to camera module 2020-06-08 17:05:54 +00:00
Kevin FronczakandGitHub b029c32744 Merge pull request #288 from fronzbot/use-new-endpoints
Update camera retrieval method (no more homescreen use)
2020-06-08 12:30:59 -04:00
Kevin Fronczak df88be56e9 Change sync get network info method 2020-06-08 16:20:13 +00:00
Kevin Fronczak 816f09b002 Update camera retrieval method (no more homescreen use) 2020-06-08 16:08:19 +00:00
Kevin FronczakandGitHub 507f350ec2 Merge pull request #283 from fronzbot/dependabot/pip/pytest-5.4.3
Bump pytest from 5.4.2 to 5.4.3
2020-06-08 09:48:34 -04:00
Kevin FronczakandGitHub 7067c05c6b Merge pull request #287 from fronzbot/dependabot/pip/pylint-2.5.3
Bump pylint from 2.5.2 to 2.5.3
2020-06-08 09:48:22 -04:00
dependabot-preview[bot]andGitHub 338a10c8a2 Bump pylint from 2.5.2 to 2.5.3
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.5.2 to 2.5.3.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.5.2...pylint-2.5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-08 08:23:41 +00:00
Kevin FronczakandGitHub 44beddac18 Merge branch 'dev' into dependabot/pip/pytest-5.4.3 2020-06-05 22:09:15 -04:00
Kevin FronczakandGitHub 534b5ad6e0 Merge pull request #282 from fronzbot/dependabot/pip/restructuredtext-lint-1.3.1
Bump restructuredtext-lint from 1.3.0 to 1.3.1
2020-06-05 22:09:02 -04:00
Kevin FronczakandGitHub 04ad77ad42 Merge branch 'dev' into dependabot/pip/pytest-5.4.3 2020-06-05 18:38:23 -04:00
Kevin FronczakandGitHub 476042a6e6 Merge branch 'dev' into dependabot/pip/restructuredtext-lint-1.3.1 2020-06-05 18:07:00 -04:00
Kevin FronczakandGitHub d40787499e Merge pull request #285 from fronzbot/add-more-endpoints
Add more api endpoints
2020-06-05 18:06:45 -04:00
Kevin FronczakandGitHub 9e53ebfb05 Merge branch 'dev' into add-more-endpoints 2020-06-05 18:01:56 -04:00
Kevin Fronczak 0455210598 Changed paypal donate to buy me a coffee link 2020-06-05 21:56:11 +00:00
Kevin Fronczak 4d66d8e0c4 Add more api endpoints 2020-06-05 21:54:47 +00:00
dependabot-preview[bot]andGitHub 020b6d9855 Bump pytest from 5.4.2 to 5.4.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.2 to 5.4.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.2...5.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-03 08:22:21 +00:00
dependabot-preview[bot]andGitHub 1d9efabfd6 Bump restructuredtext-lint from 1.3.0 to 1.3.1
Bumps [restructuredtext-lint](https://github.com/twolfson/restructuredtext-lint) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/twolfson/restructuredtext-lint/releases)
- [Changelog](https://github.com/twolfson/restructuredtext-lint/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/twolfson/restructuredtext-lint/compare/1.3.0...1.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-03 08:21:45 +00:00
Kevin FronczakandGitHub b8fc4934e2 Merge pull request #280 from fronzbot/add-user-endpoint
Add new endpoint to get user info
2020-05-30 13:15:16 -04:00
Kevin FronczakandGitHub 37743f78d5 Merge branch 'dev' into add-user-endpoint 2020-05-30 13:12:50 -04:00
Kevin Fronczak 27cddaac70 Add new endpoint to get user info 2020-05-30 16:37:36 +00:00
Kevin FronczakandGitHub 9d828a254c Merge pull request #278 from fronzbot/improve-documentation
Improve documentation
2020-05-28 15:06:11 -04:00
Kevin Fronczak 8bc4544eeb Add rst linter to pre-commit and fix flake8 2020-05-28 18:59:37 +00:00
Kevin Fronczak cec801c39c Add CONTRIBUTING.rst to lint check 2020-05-28 18:57:12 +00:00
Kevin Fronczak 2abf195391 Documentation overhaul 2020-05-28 18:33:36 +00:00
Kevin FronczakandGitHub e6469aea5f Merge pull request #277 from fronzbot/dev-bump
Dev bump to 0.16.0-rc3
2020-05-27 19:43:57 -04:00
Kevin Fronczak 470ab17813 Dev bump to 0.16.0-rc3 2020-05-27 23:33:02 +00:00
Kevin FronczakandGitHub 42e444c0e0 Merge pull request #275 from fronzbot/add-errored-property
Add is_errored property to Auth class
2020-05-27 19:30:14 -04:00
Kevin FronczakandGitHub 2baae9ea45 Merge branch 'dev' into add-errored-property 2020-05-27 19:28:02 -04:00
Kevin FronczakandGitHub 789724a6a3 Merge pull request #276 from fronzbot/dev-bump
Bump dev version
2020-05-27 19:26:51 -04:00
Kevin Fronczak e53439141a Bump dev version 2020-05-27 23:23:50 +00:00
Kevin Fronczak d5ec39113e Add is_errored property to Auth class 2020-05-27 23:19:59 +00:00
Kevin FronczakandGitHub 58117b3daf Merge pull request #274 from fronzbot/remove-auto-refresh
Only refresh token on unauthorized response from request
2020-05-27 19:19:33 -04:00
Kevin FronczakandGitHub 558c190512 Merge branch 'dev' into remove-auto-refresh 2020-05-27 19:17:00 -04:00
Kevin Fronczak 9e124ce5cc Only refresh token on unauthorized response from request 2020-05-27 23:05:51 +00:00
Kevin FronczakandGitHub 396824d38c Merge pull request #273 from fronzbot/add-camera-arm-property
Add arm property to camera, deprecate motion enable method
2020-05-27 17:55:28 -04:00
Kevin FronczakandGitHub cc860c3d03 Merge branch 'dev' into add-camera-arm-property 2020-05-27 17:49:29 -04:00
Kevin FronczakandGitHub 6a5256e9b1 Merge pull request #272 from fronzbot/catch-none-response
Catch all None responses from http requests
2020-05-27 17:48:32 -04:00
Kevin Fronczak 00c2c2cc29 Add arm property to camera, deprecate motion enable method 2020-05-27 21:44:07 +00:00
Kevin Fronczak 4775bda51c Catch all None responses from http requests 2020-05-27 21:27:08 +00:00
Kevin FronczakandGitHub 38fed26742 Merge pull request #269 from fronzbot/increase-timeout
Increase timeout from 2s to 5s
2020-05-26 17:24:20 -04:00
Kevin FronczakandGitHub 99235fbc80 Merge branch 'dev' into increase-timeout 2020-05-26 17:04:33 -04:00
Kevin FronczakandGitHub feef686767 Merge pull request #268 from fronzbot/catch-json-decode-error
Handle json decode error
2020-05-26 17:04:03 -04:00
Kevin Fronczak 1e00f657a7 Increase timeout from 2s to 5s 2020-05-26 21:00:15 +00:00
Kevin Fronczak 672fca6dbf Handle json decode error 2020-05-26 20:44:24 +00:00
Kevin FronczakandGitHub bc85779272 Merge pull request #265 from fronzbot/update-string-format
Update string formatting
2020-05-25 22:05:58 -04:00
Kevin FronczakandGitHub 669fb008d1 Merge branch 'dev' into update-string-format 2020-05-25 22:00:28 -04:00
Kevin FronczakandGitHub 7281241edd Merge pull request #266 from fronzbot/fix-codecov
Update codecov.yml
2020-05-25 22:00:06 -04:00
Kevin Fronczak 9394964688 Update codecov.yml 2020-05-26 01:54:04 +00:00
Kevin Fronczak d8c80c24fc Update string formatting 2020-05-26 01:47:05 +00:00
Kevin FronczakandGitHub 12f7e65d0a Merge pull request #262 from fronzbot/dependabot/pip/pytest-cov-2.9.0
Bump pytest-cov from 2.8.1 to 2.9.0
2020-05-25 21:03:28 -04:00
Kevin FronczakandGitHub d31cb60a17 Merge branch 'dev' into dependabot/pip/pytest-cov-2.9.0 2020-05-25 11:50:04 -04:00
Kevin FronczakandGitHub 1b8bae3d25 Merge pull request #263 from fronzbot/dependabot/pip/flake8-3.8.2
Bump flake8 from 3.8.1 to 3.8.2
2020-05-25 11:49:42 -04:00
Kevin FronczakandGitHub 598b2e4235 Merge branch 'dev' into dependabot/pip/pytest-cov-2.9.0 2020-05-25 09:59:37 -04:00
Kevin FronczakandGitHub 569249a6f4 Merge branch 'dev' into dependabot/pip/flake8-3.8.2 2020-05-25 09:59:27 -04:00
Kevin FronczakandGitHub 754d441111 Merge pull request #264 from fronzbot/dev-bump
Dev version bump
2020-05-25 09:59:12 -04:00
Kevin FronczakandGitHub 4ca9cc21fe Merge branch 'dev' into dependabot/pip/pytest-cov-2.9.0 2020-05-25 09:56:39 -04:00
Kevin Fronczak 2fc3e735c5 Dev version bump 2020-05-25 13:55:42 +00:00
Kevin FronczakandGitHub 80d886bfb1 Merge pull request #261 from fronzbot/refactor-auth
Total refactoring of auth logic
2020-05-25 09:48:08 -04:00
Kevin Fronczak 359d6930b4 Improved availablility handling for sync module 2020-05-25 13:40:48 +00:00
Kevin Fronczak 8fe67ea574 More test coverage 2020-05-25 13:00:26 +00:00
dependabot-preview[bot]andGitHub ca60d99e90 Bump flake8 from 3.8.1 to 3.8.2
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.1 to 3.8.2.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.1...3.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-25 08:36:59 +00:00
dependabot-preview[bot]andGitHub f0445683ca Bump pytest-cov from 2.8.1 to 2.9.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.8.1 to 2.9.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.8.1...v2.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-25 08:36:41 +00:00
Kevin Fronczak 61e18ee0a8 Simplify mock_responses file 2020-05-25 04:39:27 +00:00
Kevin Fronczak 9cb55dff66 Updated tests 2020-05-25 04:36:22 +00:00
Kevin Fronczak f7bc4c7f93 Move all login handling to auth class
- Update quick start guide with new flow
- If token given at startup don't bother with logging in (token will be
  auto-refreshed on failed server request anyways)
- Update to v4 login by default (2FA endpoint)
2020-05-25 01:51:04 +00:00
Kevin Fronczak 7fc63e5f23 Add cred_file parameter back into Blink class 2020-05-24 16:16:16 +00:00
Kevin Fronczak af279b337d Total refactoring of auth logic
- Still need major test updates
- Still needs more thorough testing
- Want to add an option to override login endpoint
2020-05-24 04:09:23 +00:00
Kevin FronczakandGitHub 384c2f372b Merge pull request #255 from fronzbot/dependabot/pip/pytest-5.4.2
Bump pytest from 5.4.1 to 5.4.2
2020-05-16 21:57:48 -04:00
dependabot-preview[bot]andGitHub 6abb14ceeb Bump pytest from 5.4.1 to 5.4.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.1 to 5.4.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.1...5.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-17 01:53:01 +00:00
Kevin FronczakandGitHub 6a0be737d3 Merge pull request #258 from fronzbot/add-commit-hooks
Add commit hooks
2020-05-16 21:51:49 -04:00
Kevin Fronczak 611a167c30 Update dev instructions with venv and pre-commit 2020-05-17 00:54:19 +00:00
Kevin Fronczak 0f9301742a Add pre-commit hooks 2020-05-17 00:49:13 +00:00
Kevin FronczakandGitHub baa2b8cd49 Merge pull request #256 from fronzbot/dependabot/pip/flake8-3.8.1
Bump flake8 from 3.7.9 to 3.8.1
2020-05-16 19:00:20 -04:00
dependabot-preview[bot]andGitHub 30681cd243 Bump flake8 from 3.7.9 to 3.8.1
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.7.9 to 3.8.1.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.7.9...3.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-12 08:33:08 +00:00
Kevin FronczakandGitHub b5c9a51e9c Fix version, fix bad required version...doh 2020-05-08 17:40:45 -04:00
Kevin FronczakandGitHub f6575ea05f Dev version bump 2020-05-08 17:38:10 -04:00
Kevin FronczakandGitHub 295833efbf Merge pull request #254 from fronzbot/master
Merge changes.rst
2020-05-08 17:37:10 -04:00
Kevin FronczakandGitHub 5e98f59cdb Update for release 0.15.0 2020-05-08 17:35:54 -04:00
Kevin FronczakandGitHub 77649e0991 Merge pull request #253 from fronzbot/dev
v0.15.0
2020-05-08 17:28:18 -04:00
Kevin FronczakandGitHub 5c9ced057b Merge pull request #251 from fronzbot/dependabot/pip/restructuredtext-lint-1.3.0
Bump restructuredtext-lint from 1.0.1 to 1.3.0
2020-05-08 17:26:01 -04:00
dependabot-preview[bot]andGitHub 7a2b3b9967 Bump restructuredtext-lint from 1.0.1 to 1.3.0
Bumps [restructuredtext-lint](https://github.com/twolfson/restructuredtext-lint) from 1.0.1 to 1.3.0.
- [Release notes](https://github.com/twolfson/restructuredtext-lint/releases)
- [Changelog](https://github.com/twolfson/restructuredtext-lint/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/twolfson/restructuredtext-lint/compare/1.0.1...1.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-08 21:24:01 +00:00
Kevin FronczakandGitHub 4582600900 Merge pull request #252 from fronzbot/dependabot/pip/pygments-2.6.1
Bump pygments from 2.2.0 to 2.6.1
2020-05-08 17:22:54 -04:00
dependabot-preview[bot]andGitHub 78ec104392 Bump pygments from 2.2.0 to 2.6.1
Bumps [pygments](https://github.com/pygments/pygments) from 2.2.0 to 2.6.1.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.2.0...2.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-08 21:03:32 +00:00
Kevin FronczakandGitHub f15f00e8c5 Merge pull request #250 from fronzbot/dependabot/pip/pytest-sugar-0.9.3
Bump pytest-sugar from 0.9.2 to 0.9.3
2020-05-08 17:02:23 -04:00
Kevin FronczakandGitHub e953a2f918 Version bump 2020-05-08 17:02:07 -04:00
Kevin FronczakandGitHub 9d6075c0f7 Merge branch 'dev' into dependabot/pip/pytest-sugar-0.9.3 2020-05-08 16:58:37 -04:00
Kevin FronczakandGitHub 90ad0c7cc9 Merge pull request #249 from fronzbot/dependabot/pip/pytest-timeout-1.3.4
Bump pytest-timeout from 1.3.3 to 1.3.4
2020-05-08 16:57:52 -04:00
dependabot-preview[bot]andGitHub 62a74db683 Bump pytest-sugar from 0.9.2 to 0.9.3
Bumps [pytest-sugar](https://github.com/Teemu/pytest-sugar) from 0.9.2 to 0.9.3.
- [Release notes](https://github.com/Teemu/pytest-sugar/releases)
- [Changelog](https://github.com/Teemu/pytest-sugar/blob/master/CHANGES.rst)
- [Commits](https://github.com/Teemu/pytest-sugar/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-08 08:14:08 +00:00
dependabot-preview[bot]andGitHub 12b5dfdfd7 Bump pytest-timeout from 1.3.3 to 1.3.4
Bumps [pytest-timeout](https://github.com/pytest-dev/pytest-timeout) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/pytest-dev/pytest-timeout/releases)
- [Commits](https://github.com/pytest-dev/pytest-timeout/compare/1.3.3...1.3.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-08 08:13:45 +00:00
Kevin FronczakandGitHub 255812defc Merge pull request #246 from fronzbot/pin-requirements
Pin test requirements
2020-05-07 09:07:12 -04:00
Kevin FronczakandGitHub 7b2e015eed Pin test requirements 2020-05-07 09:04:42 -04:00
Kevin FronczakandGitHub a8605bd91f Dev version bump 2020-05-06 18:05:32 -04:00
Kevin FronczakandGitHub e3f9f4b0c1 Merge pull request #245 from fronzbot/add-device-id-param
Add device id param
2020-05-06 18:00:43 -04:00
Kevin Fronczak ec476bb9d6 quick codecov threshold fix...maybe 2020-05-06 11:19:45 -04:00
Kevin Fronczak 60cbcb7717 Update login methods to ensure platform is refreshed 2020-05-06 11:12:56 -04:00
Kevin Fronczak 4b11a8b16a Add ability to have unique device name per application 2020-05-06 10:59:01 -04:00
Kevin FronczakandGitHub dfb90b8c86 Dev version bump 2020-05-06 10:43:09 -04:00
Kevin FronczakandGitHub 2f0cec2724 Merge pull request #243 from fronzbot/dependabot/pip/pylint-2.5.2
Bump pylint from 2.5.1 to 2.5.2
2020-05-06 10:42:29 -04:00
Kevin FronczakandGitHub 887a1d0a2b Merge pull request #244 from fronzbot/fix-typos
Fix typos
2020-05-06 10:42:11 -04:00
Kevin FronczakandGitHub 1d65d558e8 Fix typo 2020-05-06 10:39:34 -04:00
Kevin FronczakandGitHub d49a1fe36c Fix typo, remove Python Version info 2020-05-06 10:37:25 -04:00
dependabot-preview[bot]andGitHub 33f0e16e7a Bump pylint from 2.5.1 to 2.5.2
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.5.1 to 2.5.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.5.1...pylint-2.5.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-06 08:37:35 +00:00
Kevin FronczakandGitHub 86aae07367 Merge pull request #242 from fronzbot/add-2FA
Add 2FA Support
2020-05-05 22:51:45 -04:00
Kevin Fronczak 1e86e7eb79 Add unit tests for new methods 2020-05-05 22:45:48 -04:00
Kevin Fronczak 0c7737cd7f Update README 2020-05-05 15:38:45 -04:00
Kevin Fronczak 0c79620baa Updated login method to allow for email verification and 2FA in future 2020-05-05 15:28:38 -04:00
Kevin FronczakandGitHub 9bc20cc82e Merge pull request #241 from fronzbot/refactor-login-logic
Refactor login logic in preperation for 2FA
2020-05-05 13:56:39 -04:00
Kevin Fronczak c51551afc5 Add skeleton for 2FA 2020-05-05 13:56:04 -04:00
Kevin Fronczak f80a93f8e1 Refactor login logic in preperation for 2FA 2020-05-05 12:46:48 -04:00
Kevin FronczakandGitHub 853c596167 Merge pull request #240 from fronzbot/dependabot/pip/pylint-2.5.1
Bump pylint from 2.5.0 to 2.5.1
2020-05-05 08:10:58 -04:00
dependabot-preview[bot]andGitHub 819e383b05 Bump pylint from 2.5.0 to 2.5.1
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.5.0 to 2.5.1.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.5.0...pylint-2.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-05 08:29:12 +00:00
Kevin FronczakandGitHub 724734847a Merge pull request #239 from fronzbot/codecov-threshold
Fix codecov threshold
2020-05-04 14:44:53 -04:00
Kevin Fronczak cdd01c5186 Fix codecov threshold 2020-05-04 14:38:47 -04:00
Kevin FronczakandGitHub 5a5c34b6a1 Merge pull request #238 from fronzbot/add-black
Add black
2020-05-04 14:37:50 -04:00
Kevin Fronczak 28271efbe6 Remove hound. 2020-05-04 14:30:48 -04:00
Kevin Fronczak 1dbb8d4b21 Add black badge 2020-05-04 14:28:14 -04:00
Kevin Fronczak e1bbbb5c7e Add black formatting style 2020-05-04 14:23:02 -04:00
Kevin FronczakandGitHub addc32e3e6 Merge pull request #237 from fronzbot/deprecate-py35
Remove Python 3.5.3 support
2020-05-04 13:41:11 -04:00
Kevin Fronczak b201c95e8d Remove Python 3.5.3 support 2020-05-04 13:37:32 -04:00
Kevin FronczakandGitHub 19b2541c81 Merge pull request #236 from fronzbot/remove-flake8-filewq
Remove .flake8 file
2020-05-04 13:31:57 -04:00
Kevin Fronczak 6a2650dda0 Remove .flake8 file 2020-05-04 13:28:37 -04:00
Kevin FronczakandGitHub c122c4ecfb Merge pull request #235 from fronzbot/dependabot/pip/pylint-2.5.0
Bump pylint from 2.4.4 to 2.5.0
2020-05-04 13:21:22 -04:00
Kevin Fronczak 43ed6f1600 Fix lint errors 2020-05-04 13:14:52 -04:00
Kevin FronczakandGitHub fae1e1a554 Merge pull request #230 from fronzbot/dependabot/pip/python-dateutil-approx-eq-2.8.1
Update python-dateutil requirement from ~=2.8.0 to ~=2.8.1
2020-05-04 12:39:11 -04:00
Kevin Fronczak 4587268ecb Bump dateutil to 2.8.1 2020-05-04 12:32:40 -04:00
dependabot-preview[bot]andGitHub e0ff5c484a Update python-dateutil requirement from ~=2.8.0 to ~=2.8.1
Updates the requirements on [python-dateutil](https://github.com/dateutil/dateutil) to permit the latest version.
- [Release notes](https://github.com/dateutil/dateutil/releases)
- [Changelog](https://github.com/dateutil/dateutil/blob/master/NEWS)
- [Commits](https://github.com/dateutil/dateutil/compare/2.8.0...2.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 16:28:09 +00:00
Kevin FronczakandGitHub bc4956c64b Merge pull request #234 from fronzbot/dependabot/pip/python-slugify-approx-eq-4.0.0
Update python-slugify requirement from ~=3.0.2 to ~=4.0.0
2020-05-04 12:26:45 -04:00
Kevin Fronczak cc5fbcd3a7 Bump slugify to 4.0.0 2020-05-04 12:19:30 -04:00
dependabot-preview[bot]andGitHub db23acd46c Update python-slugify requirement from ~=3.0.2 to ~=4.0.0
Updates the requirements on [python-slugify](https://github.com/un33k/python-slugify) to permit the latest version.
- [Release notes](https://github.com/un33k/python-slugify/releases)
- [Changelog](https://github.com/un33k/python-slugify/blob/master/CHANGELOG.md)
- [Commits](https://github.com/un33k/python-slugify/compare/3.0.2...4.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 16:17:35 +00:00
Kevin FronczakandGitHub 973374f6a1 Merge pull request #227 from fronzbot/dependabot/pip/testtools-2.4.0
Bump testtools from 2.3.0 to 2.4.0
2020-05-04 12:16:25 -04:00
dependabot-preview[bot]andGitHub 13e2262c2f Bump pylint from 2.4.4 to 2.5.0
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.4.4 to 2.5.0.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/master/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/pylint-2.4.4...pylint-2.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 16:13:02 +00:00
Kevin FronczakandGitHub 69775188a6 Merge pull request #228 from fronzbot/dependabot/pip/coverage-5.1
Bump coverage from 4.5.4 to 5.1
2020-05-04 12:12:10 -04:00
Kevin FronczakandGitHub 0554e4e159 Merge pull request #229 from fronzbot/dependabot/pip/pytest-5.4.1
Bump pytest from 5.3.5 to 5.4.1
2020-05-04 12:11:44 -04:00
dependabot-preview[bot]andGitHub f576c97c1d Bump coverage from 4.5.4 to 5.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 4.5.4 to 5.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-4.5.4...coverage-5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 15:59:53 +00:00
dependabot-preview[bot]andGitHub e6c842072c Bump pytest from 5.3.5 to 5.4.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.3.5 to 5.4.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.3.5...5.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 15:59:16 +00:00
dependabot-preview[bot]andGitHub bf87f3676d Bump testtools from 2.3.0 to 2.4.0
Bumps [testtools](https://github.com/testing-cabal/testtools) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/testing-cabal/testtools/releases)
- [Changelog](https://github.com/testing-cabal/testtools/blob/master/NEWS)
- [Commits](https://github.com/testing-cabal/testtools/compare/2.3.0...2.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 15:52:19 +00:00
Kevin FronczakandGitHub a87581638c Merge pull request #231 from fronzbot/dependabot/pip/requests-2.23.0
Bump requests from 2.22.0 to 2.23.0
2020-05-04 11:51:09 -04:00
Kevin Fronczak 42ed18fcd5 Bump requests to 2.23.0 2020-05-04 11:45:54 -04:00
Kevin FronczakandGitHub a66c926475 Merge pull request #232 from fronzbot/stale-bot
Create stale.yml
2020-05-04 11:40:53 -04:00
Kevin FronczakandGitHub 6a481aaa74 Update stale.yml 2020-05-04 11:33:22 -04:00
dependabot-preview[bot]andGitHub 72d97f4944 Bump requests from 2.22.0 to 2.23.0
Bumps [requests](https://github.com/psf/requests) from 2.22.0 to 2.23.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/master/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.22.0...v2.23.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-05-04 15:30:44 +00:00
Kevin FronczakandGitHub 1694187b39 Merge pull request #233 from fronzbot/pip-downgrade-workflows
Fix setup.py use of internal pip structure
2020-05-04 11:29:30 -04:00
Kevin Fronczak a531a8e8a3 Update setup.py to not rely on internal pip functions 2020-05-04 11:05:46 -04:00
Kevin FronczakandGitHub 44d5bb65ae Exempt stuff added to projects and milestones 2020-05-04 10:21:06 -04:00
Kevin FronczakandGitHub c64f5cfb23 Downgrade pip again 2020-05-04 10:17:13 -04:00
Kevin FronczakandGitHub 19a29bc3a1 Create stale.yml 2020-05-04 10:12:41 -04:00
Kevin FronczakandGitHub 6159987928 Downgrade pip 2020-05-04 09:57:23 -04:00
Kevin FronczakandGitHub 8a8c4ea20b Change to SemVer for dev versions (now rc) 2020-05-04 09:31:41 -04:00
Kevin FronczakandGitHub e43d2f9a88 Dev version bump 2020-04-22 10:37:43 -04:00
Kevin FronczakandGitHub deba0cbba6 Merge pull request #225 from fronzbot/dev
0.14.3
2020-04-22 10:22:48 -04:00
Kevin FronczakandGitHub 0c3359abcf Changes for release 0.14.3 2020-04-22 10:20:42 -04:00
Kevin FronczakandGitHub a76069174d Version bump to 0.14.3 2020-04-22 10:17:21 -04:00
Kevin FronczakandGitHub 19c9178db7 Merge pull request #223 from fronzbot/fronzbot-patch-1
Update README.rst
2020-04-15 11:51:55 -04:00
Kevin FronczakandGitHub 2ebf2db04d Update README.rst 2020-04-15 11:47:38 -04:00
Kevin FronczakandGitHub 26de89c1b9 Merge pull request #222 from fronzbot/no-camera-enabled-bug
Log response code and message if not trying to re-authorize
2020-04-15 11:26:14 -04:00
Kevin Fronczak 8f68aad238 Create codecov.yml for confugration 2020-04-15 11:21:38 -04:00
Kevin Fronczak 7b586e2947 Log response code and message if not trying to re-authorize (fixes #213) 2020-04-15 11:10:13 -04:00
Kevin FronczakandGitHub 800ddeaf7a Dev version bump 2020-04-15 11:09:46 -04:00
Kevin FronczakandGitHub 4ed2e3dab5 dev version update for pre-release 2020-04-13 20:50:39 -04:00
Kevin FronczakandGitHub 2b9c82b432 Merge pull request #221 from fronzbot/mask-motion-with-arm
Mask motion detection with sync module arm status
2020-04-13 20:48:49 -04:00
Kevin Fronczak 3e7c9f3d5c Mask motion detection with sync module arm status 2020-04-13 20:42:55 -04:00
Kevin FronczakandGitHub 8d0b51ed9c Merge pull request #220 from fronzbot/fix-video-saving
Only store motion clip if motion occurred since last refresh
2020-04-13 20:31:02 -04:00
Kevin Fronczak c178fa5457 Only store motion clip if motion occured since last refresh 2020-04-13 20:02:13 -04:00
Kevin FronczakandGitHub 532ad92714 Merge pull request #219 from fronzbot/json-creds
Load credentials from json file
2020-04-13 19:17:34 -04:00
Kevin Fronczak deb0a682d8 revert tox 2020-04-13 19:05:56 -04:00
Kevin Fronczak 12e22dee8e Load credentials from json file 2020-04-13 18:53:37 -04:00
Kevin FronczakandGitHub ae0f954632 Merge pull request #218 from fronzbot/fix-codecov
Update coverage action
2020-04-13 17:02:40 -04:00
Kevin Fronczak b92941538b Update coverage action 2020-04-13 16:59:53 -04:00
Kevin FronczakandGitHub ce13444427 Merge pull request #217 from fronzbot/bugfix-205
Remove exc_info fixes #205
2020-04-13 16:48:10 -04:00
Kevin FronczakandGitHub 9c461c4cfa Remove exc_info fixes #205 2020-04-13 16:45:36 -04:00
Kevin FronczakandGitHub 23858c2912 Merge pull request #216 from fronzbot/Github-Actions
Migrate to github actions
2020-04-13 16:41:42 -04:00
Kevin FronczakandGitHub 2284a56c82 Delete .travis.yml 2020-04-13 16:37:46 -04:00
Kevin FronczakandGitHub 323143cb2b Fix name 2020-04-13 16:32:50 -04:00
Kevin FronczakandGitHub d6064a9aac Create coverage.yml 2020-04-13 16:32:33 -04:00
Kevin FronczakandGitHub a982aa595f Remove coverage 2020-04-13 16:31:48 -04:00
Kevin FronczakandGitHub 54c52a7f1e Update tests.yml 2020-04-13 16:30:32 -04:00
Kevin FronczakandGitHub bdb8cedf64 Update tests.yml 2020-04-13 16:29:15 -04:00
Kevin FronczakandGitHub 554b18adfe Update README.rst 2020-04-13 16:24:50 -04:00
Kevin FronczakandGitHub 5619af2a00 Update build badge 2020-04-13 16:24:27 -04:00
Kevin FronczakandGitHub 957003aeb1 Rename workflow 2020-04-13 16:22:49 -04:00
Kevin FronczakandGitHub 6fc64a486e Create publish.yml 2020-04-13 16:18:40 -04:00
Kevin FronczakandGitHub 534e3fb34e Reduce to only one VM 2020-04-13 16:14:17 -04:00
Kevin FronczakandGitHub 9ab346ed91 Create tests.yml 2020-04-13 16:11:09 -04:00
Kevin FronczakandGitHub 1bf5dda803 Create lint.yml 2020-04-13 16:02:14 -04:00
Kevin FronczakandGitHub 6cd8fd8ab2 Merge pull request #215 from fronzbot/codecov
Migrate from coveralls to codecov
2020-04-09 15:20:09 -04:00
Kevin Fronczak a689839616 Update codecov badge 2020-04-09 15:16:19 -04:00
Kevin Fronczak 783aa5e547 Migrate from coveralls to codecov 2020-04-09 15:07:30 -04:00
Kevin FronczakandGitHub a6ff2fa0df Merge pull request #214 from fronzbot/bugfix-motion
Fix motion detection getting stuck 'on'
2020-04-09 15:05:44 -04:00
Kevin Fronczak eb498bfb22 Pin coverage in traviswq 2020-04-09 15:01:33 -04:00
Kevin Fronczak 2ebbe46ada Change time conversion to something that supports older python versions 2020-04-09 14:51:06 -04:00
Kevin Fronczak 2f4e8fcade Ignore flake8-black errors 2020-04-09 14:14:47 -04:00
Kevin Fronczak efe05525e4 Fix tests, pin coverage due to sqlite problems 2020-04-09 14:11:19 -04:00
Kevin Fronczak 4122ae8f64 Added time check on latest video 2020-04-08 18:45:59 -04:00
Kevin FronczakandGitHub 5d296cc836 Merge pull request #203 from fronzbot/merge-v0.14.2-into-dev
Merge v0.14.2 into dev
2019-10-12 14:48:45 -04:00
Kevin Fronczak fa50e315a9 dev version bump 2019-10-12 14:42:34 -04:00
Kevin FronczakandGitHub 4a4811bee2 Merge pull request #202 from fronzbot/release-0.14.2
Release 0.14.2
2019-10-12 14:38:35 -04:00
Kevin Fronczak ad7ece4d45 Fixed version.wq 2019-10-12 14:32:26 -04:00
Kevin Fronczak 17d1aa9690 Update changelog, bumped version 2019-10-12 14:31:20 -04:00
Kevin FronczakandGitHub b00839ecb3 Merge pull request #198 from 3ch01c/docker
Add Docker example files
2019-10-12 14:01:25 -04:00
Kevin Fronczak 4900ea8ba6 Add app to tox check 2019-10-12 13:41:57 -04:00
Kevin Fronczak 4fb16398e4 Restructured to allow for future expansion
- Removed docker_compose
2019-10-12 13:27:14 -04:00
Jack Miner a1fc0c5a2b Added TIMEDELTA environment variable to configure how far back to download videos. Wrapped long lines to make linter happy. 2019-09-22 11:43:22 -06:00
Jack Miner 6adb252cdd dockerized 2019-09-14 02:01:44 -06:00
Kevin FronczakandGitHub 3637bbad8d Merge pull request #196 from fronzbot/req
Update python slugify version, better versioning
2019-09-09 11:12:45 -04:00
Kevin FronczakandGitHub 694efe71f8 Update python slugify version, better versioning 2019-09-02 10:29:14 -04:00
Kevin FronczakandGitHub 315735bc2f Merge pull request #192 from fronzbot/dev-version-bump
Dev verison bump
2019-06-20 13:56:16 -04:00
Kevin Fronczak db6403b468 Dev verison bump 2019-06-20 13:44:11 -04:00
Kevin FronczakandGitHub 92dda40e84 Merge pull request #191 from fronzbot/0.14.1
0.14.1
2019-06-20 13:41:22 -04:00
Kevin Fronczak 6c8fc0abce Updated changes 2019-06-20 13:34:59 -04:00
Kevin Fronczak 2d74b12d43 Version bump 2019-06-20 13:32:46 -04:00
Kevin FronczakandGitHub 197695ee40 Merge pull request #190 from fronzbot/dev-version-bump
Dev version bump
2019-06-20 13:24:24 -04:00
Kevin Fronczak 490c42550d Dev version bump
- Added Py3.8 to supported versions
2019-06-20 12:42:01 -04:00
Kevin FronczakandGitHub 7367eb6e87 Merge pull request #187 from fronzbot/upgrade-login
Upgraded login urls to use rest-region subdomain
2019-06-18 10:55:32 -04:00
Kevin FronczakandGitHub 414b647dc8 Merge pull request #189 from fronzbot/timeout
Improved timeout, prevent blocking on startup when unable to login
2019-06-17 11:54:17 -04:00
Kevin FronczakandGitHub 57882bb811 Merge pull request #188 from fronzbot/remove-thumbnail-method
Remove thumbnail from homescreen method
2019-06-17 11:17:15 -04:00
Kevin Fronczak bb76f09f31 Fix dev version (will add to different PR) 2019-06-17 11:15:46 -04:00
Kevin Fronczak 741cf489c8 Fix tests for improved login routine 2019-06-17 11:11:07 -04:00
Kevin Fronczak 7ce332b3ca Improved timeout, prevent blocking on startup when unable to login 2019-06-17 11:07:16 -04:00
Kevin Fronczak 8b7a491c89 Remove thumbnail from homescreen method 2019-06-17 10:20:23 -04:00
Kevin Fronczak 604eebd1b7 Upgraded login urls to use rest-region subdomain 2019-06-17 10:04:34 -04:00
Kevin FronczakandGitHub c2f44b3dfd Merge pull request #183 from fronzbot/dev-version-bump
Dev version bump
2019-05-24 09:38:56 -04:00
Kevin FronczakandGitHub f4480da276 Merge pull request #180 from fronzbot/dev
0.14.0
2019-05-23 16:56:46 -04:00
Kevin Fronczak ccad3dcb0c Dev version bump 2019-05-23 16:53:02 -04:00
Kevin FronczakandGitHub 7767d3af65 Merge pull request #182 from fronzbot/update-changes
Update CHANGES.rst
2019-05-23 16:51:54 -04:00
Kevin FronczakandGitHub 79e699ba78 Update CHANGES.rst 2019-05-23 16:42:12 -04:00
Kevin FronczakandGitHub b28d6f4eb4 Merge pull request #181 from fronzbot/version-bump
Version bump
2019-05-23 16:40:14 -04:00
Kevin FronczakandGitHub d021f48c67 Update CHANGES.rst 2019-05-23 16:15:07 -04:00
Kevin Fronczak 1e71af28dd Version bump 2019-05-23 16:06:56 -04:00
Kevin FronczakandGitHub cb5867d430 Merge pull request #179 from fronzbot/bugfix
Blink instantiation bugfix
2019-05-23 14:45:26 -04:00
Kevin Fronczak bb887936b6 Blink instantiation bugfix 2019-05-23 14:35:27 -04:00
Kevin FronczakandGitHub 720d520398 Merge pull request #175 from fronzbot/update-subdomains
Change subdomain from rest.region to rest-region
2019-05-21 23:56:25 -04:00
Kevin FronczakandGitHub 8fb1116641 Merge branch 'dev' into update-subdomains 2019-05-21 23:37:00 -04:00
Kevin FronczakandGitHub c319762152 Merge pull request #178 from fronzbot/dev-bump
dev version bump
2019-05-21 23:35:25 -04:00
Kevin Fronczak 726d8b8c65 dev version bump 2019-05-21 23:14:26 -04:00
Kevin FronczakandGitHub 683650e2c2 Merge pull request #177 from fronzbot/fix-motion-detect
Fix motion detect
2019-05-21 23:13:15 -04:00
Kevin Fronczak 50b1a35168 Update tests 2019-05-21 22:46:11 -04:00
Kevin Fronczak b88a5feddf Change default interval to one minute 2019-05-21 22:38:49 -04:00
Kevin Fronczak 93472e38de Added in motion interval to allow for looking at historic motion events.
- Good debug utility
- Helps iron out rapid motion events, or missed events due to quick
calls to refresh method
2019-05-21 22:36:46 -04:00
Kevin Fronczak 85c14ede8d Move constants into helpers/constants.py 2019-05-21 22:23:31 -04:00
Kevin Fronczak 58ce109518 Use UTC for time conversions 2019-05-21 22:09:36 -04:00
Kevin Fronczak cf65648293 Add legacy flag to be able to use old 'rest.region' subdomain 2019-05-20 21:15:08 -04:00
Kevin FronczakandGitHub d46e7ed96d Merge pull request #176 from fronzbot/slug
Slugify filenames in video download to ensure OS interoperability
2019-05-20 20:43:28 -04:00
Kevin Fronczak 00395b3825 Slugify filenames in video download to ensure OS interoperability 2019-05-20 11:04:58 -04:00
Kevin FronczakandGitHub f67f0dd6a2 Dev version bump 2019-05-20 00:00:57 -04:00
Kevin FronczakandGitHub d90cd3309f Update README.rst 2019-05-19 18:00:42 -04:00
Kevin Fronczak 130aa8382a Change subdomain from rest.region to rest-region 2019-05-18 18:23:46 -04:00
Kevin FronczakandGitHub e836a6fa58 Merge pull request #174 from fronzbot/fix-battery-voltage
Change battery percentage to state
2019-05-18 18:17:38 -04:00
Kevin Fronczak 92d89b9fe5 Change battery percentage to state 2019-05-18 12:42:01 -04:00
Kevin FronczakandGitHub c10fb432f7 Merge pull request #173 from fronzbot/reduce-throttling
Remove throttling from critical api methods
2019-05-18 12:23:25 -04:00
Kevin Fronczak 37b729b597 Remove throttling from critical api methods 2019-05-18 12:15:57 -04:00
Kevin FronczakandGitHub 749c68bb8a Merge pull request #172 from fronzbot/fix-video-api
Changed log to print
2019-05-18 11:57:46 -04:00
Kevin Fronczak dcf0ce6394 Fix lint issue 2019-05-18 11:51:58 -04:00
Kevin Fronczak 102190e61b Changed log to print 2019-05-18 11:41:17 -04:00
Kevin FronczakandGitHub a7340c97ca Merge pull request #171 from fronzbot/fix-video-api
Added changed video download endpoint
2019-05-18 11:40:23 -04:00
Kevin Fronczak 43c1162634 Added vieo endpoint key changes to motion detect logic 2019-05-18 10:54:24 -04:00
Kevin Fronczak 4db7a33ef3 Added changed video download endpoint 2019-05-18 10:48:58 -04:00
Kevin FronczakandGitHub bfdc1e47bd Dev version bump 2019-03-01 22:00:37 -05:00
Kevin FronczakandGitHub afdd73118d Merge pull request #165 from fronzbot/dev
0.13.1
2019-03-01 21:59:29 -05:00
Kevin FronczakandGitHub 5511af6244 Version bump 2019-03-01 21:51:03 -05:00
Kevin FronczakandGitHub d629d9fa3a Update CHANGES.rst 2019-03-01 21:50:36 -05:00
Kevin FronczakandGitHub 3e22d83962 Merge pull request #164 from fronzbot/throttle-hotfix
Remove throttle from network_status
2019-03-01 21:45:59 -05:00
Kevin Fronczak 57b05daad7 Remove throttle from network_status 2019-03-01 21:40:27 -05:00
Kevin FronczakandGitHub 419eb51b66 Dev version bump 2019-03-01 21:06:12 -05:00
Kevin FronczakandGitHub 0262f14a53 Merge pull request #163 from fronzbot/dev
0.13.0
2019-03-01 21:04:36 -05:00
Kevin FronczakandGitHub c4b255d3bf Version bump 2019-03-01 20:54:52 -05:00
Kevin FronczakandGitHub 13b7debb33 Update CHANGES.rst 2019-03-01 20:54:21 -05:00
Kevin FronczakandGitHub a203c4a29f Merge pull request #162 from fronzbot/new-login-api
Added ability to have multiple backup api endpoints for logging in
2019-03-01 20:34:03 -05:00
Kevin Fronczak d8bac39c52 Added ability to have multiple backup api endpoints for logging in 2019-03-01 16:03:22 -05:00
Kevin FronczakandGitHub f1c06198b2 Merge pull request #161 from fronzbot/throttle-refresh
Throttle refresh
2019-03-01 15:22:30 -05:00
Kevin Fronczak 95b45f507a Change api throttle time to 2 seconds 2019-03-01 15:11:23 -05:00
Kevin Fronczak 54bfb99d60 Added simple throttle for refresh to prevent too many force calls 2019-03-01 15:10:28 -05:00
Kevin FronczakandGitHub 9dda477e3d Merge pull request #160 from fronzbot/api-change
Api change
2019-03-01 14:55:38 -05:00
Kevin Fronczak 2ca6b9edda -_- 2019-03-01 14:25:46 -05:00
Kevin Fronczak b22764614d Upgrade pylint to 2.3.0 2019-03-01 14:08:22 -05:00
Kevin Fronczak 09c168f6e8 Remove blank line at EOF 2019-03-01 13:53:13 -05:00
Kevin Fronczak 414eabd3ae Add test for get_camera method. Downgrade travis lint to 3.5.3 2019-03-01 13:52:13 -05:00
Kevin Fronczak b536bd7eb5 Build back to 3.6, forgot dist for lint 3.7 2019-03-01 13:40:10 -05:00
Kevin Fronczak 532a8d5071 lint and build python version now 3.7 2019-03-01 13:36:19 -05:00
Kevin Fronczak 793797e3a7 Fixed issues with new endpoint 2019-03-01 13:09:03 -05:00
Kevin Fronczak 602b6160ab New method to retrieve cameras due to api change 2019-03-01 11:35:30 -05:00
Kevin FronczakandGitHub aff95ba9e9 Merge pull request #158 from fronzbot/throttle-api-calls
Added throttles to api calls
2019-02-26 10:06:49 -05:00
Kevin Fronczak 74aad2af1c Added throttles to api calls 2019-02-26 09:53:49 -05:00
Kevin FronczakandGitHub b96ad8b4e4 Merge pull request #157 from fronzbot/throttle-decorator
Adds throttle decorator
2019-02-17 20:27:15 -08:00
Kevin Fronczak a8b731fe21 Adds throttle decorator 2019-02-17 23:19:28 -05:00
Kevin FronczakandGitHub ff8f091a74 Merge pull request #154 from fronzbot/dev
0.12.1
2019-01-31 18:22:09 -08:00
Kevin Fronczak 147b6143b0 Dev version bump 2019-01-31 21:21:17 -05:00
Kevin FronczakandGitHub 2835ccf7d2 Version bump 2019-01-31 21:18:02 -05:00
Kevin FronczakandGitHub 4deb53eab8 Update CHANGES.rst 2019-01-31 21:17:30 -05:00
Kevin FronczakandGitHub 1c49b1a943 Merge pull request #153 from fronzbot/revert-logging
Remove logging improvements because they sucked
2019-01-31 18:16:10 -08:00
Kevin Fronczak 67cd4ab962 fix lint 2019-01-31 21:08:55 -05:00
Kevin Fronczak 1a2017b337 Remove logging improvements because they sucked 2019-01-31 21:02:06 -05:00
Kevin Fronczak 7775898078 Update Changes 2019-01-31 20:43:56 -05:00
Kevin FronczakandGitHub 8f0bd1224d Dev version bump 2019-01-31 20:06:30 -05:00
Kevin FronczakandGitHub 77e200f6a5 Merge pull request #152 from fronzbot/dev
0.12.0
2019-01-31 17:05:03 -08:00
Kevin Fronczak d880998c43 Version bump 2019-01-31 19:58:15 -05:00
Kevin FronczakandGitHub fbd82030bb Merge pull request #151 from fronzbot/fix-log-format
Added log formatter
2019-01-31 16:42:47 -08:00
Kevin Fronczak 162b409c52 Added log formatter 2019-01-31 19:33:29 -05:00
Kevin FronczakandGitHub 8e2d2e81e8 Merge pull request #150 from fronzbot/fix-logging
Add improved logging functionality.
2019-01-31 11:10:15 -08:00
Kevin FronczakandGitHub 5504dfa94e Merge branch 'dev' into fix-logging 2019-01-31 10:58:56 -08:00
Kevin FronczakandGitHub d5f866bd34 Merge pull request #149 from fronzbot/add-download-videos
Add download videos routine
2019-01-31 10:56:08 -08:00
Kevin FronczakandGitHub 02937c0ef5 Added more info to README 2019-01-31 13:41:26 -05:00
Kevin Fronczak ae5d73e197 Fix for lint errors 2019-01-31 13:24:14 -05:00
Kevin Fronczak 15da35a6bc Add improved logging functionality. 2019-01-31 13:18:53 -05:00
Kevin Fronczak 9738f84457 Add download videos routine 2019-01-31 12:56:08 -05:00
Kevin FronczakandGitHub 663a128469 Merge pull request #148 from fronzbot/backup-temp
Set calibrated temperature to default to temperature if endpoint fails
2019-01-30 13:24:21 -08:00
Kevin FronczakandGitHub bc14ab053c Merge branch 'dev' into backup-temp 2019-01-30 13:01:53 -08:00
Kevin FronczakandGitHub 3b897f6dbc Merge pull request #147 from fronzbot/better-logging
Add repeat log handling filter.
2019-01-29 20:34:08 -08:00
Kevin Fronczak 92f908928d Set calibrated temperature to default to temperature if endpoint fails 2019-01-29 23:13:31 -05:00
Kevin Fronczak da537773a7 Add repeat log handling filter.
- Added exc_info=True to some errors for traceback logging
2019-01-29 23:09:28 -05:00
Kevin FronczakandGitHub 778592c6cf Merge pull request #146 from fronzbot/typo
Fix typo in video url
2019-01-28 11:15:52 -08:00
Kevin Fronczak 0e33457ed0 Fix typo in video url 2019-01-28 14:10:13 -05:00
Kevin FronczakandGitHub abcf2ae1a1 Merge pull request #145 from fronzbot/dont-poop-on-failures
Dont poop on failures
2019-01-26 18:06:50 -08:00
Kevin Fronczak 28fb53029c Fixed recurssion error by adding is_retry property to get_auth_token 2019-01-26 20:56:10 -05:00
Kevin Fronczak d809cbcb3d Stashing commit. Getting RecursonError on failed login. 2019-01-26 20:14:50 -05:00
Kevin Fronczak 8dea1a4312 Added try/excepts around methods that would bomb setup if api fails 2019-01-26 19:41:01 -05:00
Kevin FronczakandGitHub 45f7dd6cbb Merge pull request #144 from fronzbot/api-doc-strings
Api doc strings
2019-01-26 13:41:21 -08:00
Kevin Fronczak ac28dddd8b Finished adding docstrings, added version attr to Blink class 2019-01-26 16:20:48 -05:00
Kevin Fronczak aa58383318 Started adding doctrings. 2019-01-26 16:07:59 -05:00
Kevin FronczakandGitHub b0698f246a Merge pull request #143 from fronzbot/fix-video-api
Fix video api to re-enable motion detection
2019-01-26 12:55:32 -08:00
Kevin Fronczak 46c5d5eb3c Added check videos tests
- Moved motion detection setting to happen prior to return to prevent
motion detect sticking upon api failure
2019-01-26 15:40:02 -05:00
Kevin Fronczak 1922b2535c Fix linting errors 2019-01-26 14:45:11 -05:00
Kevin Fronczak 4297290fba Fix broken tests 2019-01-26 14:35:28 -05:00
Kevin Fronczak 1daf5d22af Fix lint, remove some camera tests 2019-01-25 20:51:14 -05:00
Kevin Fronczak 8fd989e991 Motion detection now working, removed get_videos method 2019-01-25 20:44:31 -05:00
Kevin Fronczak 559cc4a5ac First cut at fixing video api 2019-01-25 13:51:07 -05:00
Kevin FronczakandGitHub 66a66c9bd3 Dev version bump 2019-01-23 11:05:34 -05:00
Kevin FronczakandGitHub f3a8036649 Merge pull request #141 from fronzbot/dev
0.11.2
2019-01-23 08:05:05 -08:00
Kevin FronczakandGitHub 5c6e4364e8 Update CHANGES.rst 2019-01-23 10:57:18 -05:00
Kevin FronczakandGitHub fd64f41b22 Update constants.py 2019-01-23 10:55:39 -05:00
Kevin FronczakandGitHub 0d7aac3458 Merge pull request #140 from fronzbot/hotfix
Added some error handling for video method due to api changes
2019-01-23 07:54:19 -08:00
Kevin Fronczak 0bebcd8303 Added some error handling for video method due to api changes 2019-01-23 10:48:51 -05:00
Kevin Fronczak ff35c56c9a Dev version bump 2019-01-02 12:24:30 -05:00
Kevin FronczakandGitHub 853ccbce79 Merge pull request #136 from fronzbot/dev
0.11.1
2019-01-02 09:19:08 -08:00
Kevin Fronczak 8153fab887 Version bump 2019-01-02 11:59:27 -05:00
Kevin FronczakandGitHub 216541288e Merge pull request #135 from fronzbot/link-fix
Fixed link formatting
2019-01-02 08:53:08 -08:00
Kevin FronczakandGitHub a855cceb05 Merge pull request #134 from fronzbot/calibrated-temperature
Add calibrated temperature property (fixes #133)
2019-01-02 08:52:56 -08:00
Kevin Fronczak d9991d5acd Fixed link formatting (fixes #132) 2019-01-02 11:45:48 -05:00
Kevin Fronczak 2ee2ae7d4e Add calibrated temperature property (fixes #133) 2019-01-02 11:35:40 -05:00
Kevin FronczakandGitHub 04c2be9087 Add changes from source repo 2018-11-29 15:23:28 -05:00
Kevin Fronczak 34fc9bc527 dev version bump 2018-11-23 20:32:12 -05:00
Kevin FronczakandGitHub 1a24e1896f Merge pull request #129 from fronzbot/dev
0.11.0
2018-11-23 20:27:40 -05:00
Kevin Fronczak 1d67764dc8 version bump 2018-11-23 20:09:46 -05:00
Kevin Fronczak 8f250d204f Fixed docs for real 2018-11-23 20:08:21 -05:00
Kevin Fronczak 643ae8c387 trying again 2018-11-23 19:44:25 -05:00
Kevin Fronczak f9615a2d90 fix docs again 2018-11-23 19:39:23 -05:00
Kevin Fronczak f7a3b1d0ef Update docs 2018-11-23 19:37:38 -05:00
Kevin FronczakandGitHub 94aed43d2e Merge pull request #128 from fronzbot/fix-sync-refresh
Fix broken sync refresh
2018-11-23 19:25:39 -05:00
Kevin Fronczak 90f30deea8 Fix broken sync refresh 2018-11-23 19:20:18 -05:00
Kevin FronczakandGitHub 1bbc71ef17 Merge pull request #125 from fronzbot/multi-sync-support
Support for Multiple Sync Modules
2018-11-23 18:23:03 -05:00
Kevin Fronczak c84a0deb5f Add sync parent to attributes 2018-11-23 18:08:58 -05:00
Kevin Fronczak ece65a9158 Fix linting errors 2018-11-23 17:52:12 -05:00
Kevin Fronczak 5a8af75a5b Added cameras dict to blink to keep track of ALL cameras 2018-11-23 17:47:44 -05:00
Kevin Fronczak 84f987d29c Updated to reflect multi-sync unit support 2018-11-23 16:46:20 -05:00
Kevin Fronczak ed25745deb Added case insesnitive dict, changed sync module name to network name
(to mimic app)
2018-11-23 16:36:17 -05:00
Kevin Fronczak a1fd05735e Initial support for multiple sync modules 2018-11-23 14:22:54 -05:00
Kevin FronczakandGitHub 5a9f8f6dfc Merge pull request #124 from fronzbot/improve-contribution-doc
Improve contribution instructions
2018-11-21 10:08:31 -05:00
Kevin FronczakandGitHub 2639055372 Merge pull request #123 from fronzbot/update-readme
Update README.rst
2018-11-21 10:03:18 -05:00
Kevin FronczakandGitHub c53b2bd777 Improve contribution instructions 2018-11-21 10:02:12 -05:00
Kevin FronczakandGitHub db29bae140 Broke out blink home assistant links 2018-11-21 09:38:23 -05:00
Kevin FronczakandGitHub 52f1fde47a Bad link format 2018-11-21 09:37:27 -05:00
Kevin FronczakandGitHub e705fbd403 Update README.rst 2018-11-21 09:36:36 -05:00
Kevin FronczakandGitHub 2d437b4462 Merge pull request #122 from fronzbot/dev-bump
Dev version bump
2018-11-20 21:53:09 -05:00
Kevin FronczakandGitHub ae946dbb53 Merge pull request #121 from fronzbot/dev
0.10.3
2018-11-20 21:47:42 -05:00
Kevin Fronczak ea2b22dbf0 Dev version bump 2018-11-20 21:46:38 -05:00
Kevin Fronczak 7ee57b2c6b Version bump 2018-11-20 21:40:18 -05:00
Kevin FronczakandGitHub ccd393a533 Merge pull request #120 from fronzbot/fix-bad-logging
Logging fixes
2018-11-20 21:26:32 -05:00
Kevin Fronczak 1b571c7d4b Fix logging string format 2018-11-20 21:21:42 -05:00
Kevin Fronczak 4b91fcb615 Improved video page debug logging 2018-11-20 21:20:35 -05:00
Kevin Fronczak 1e0d069dcd Fix linting errors 2018-11-20 21:16:41 -05:00
Kevin Fronczak 92088779e0 Added debug logging 2018-11-20 21:15:01 -05:00
Kevin Fronczak a6e02433b6 Fix #113 2018-11-20 21:12:12 -05:00
Kevin FronczakandGitHub 1aa5dc1c71 Merge pull request #119 from md-reddevil/dev
Use network_status instead of homescreen
2018-11-19 12:49:47 -05:00
Kevin Fronczak 3c78923853 Fix linting error (line was too long) 2018-11-19 12:46:01 -05:00
Kevin Fronczak d17183a152 Fixed broken sync module test 2018-11-19 12:42:54 -05:00
2e5e343913 Update blinkpy/sync_module.py fix linting
Co-Authored-By: md-reddevil <16707502+md-reddevil@users.noreply.github.com>
2018-11-18 14:06:21 +02:00
md-reddevilandGitHub cec6035d23 fix tests after API changes 2018-11-18 14:01:22 +02:00
md-reddevil bdc760608e fix indentation 2018-11-17 18:20:28 +02:00
md-reddevil 4f41899338 fix indentation 2018-11-17 18:18:57 +02:00
md-reddevil 557f21b637 Use network_status instead of homescreen
Use network_status to check if System is armed or disarmed
2018-11-17 18:12:26 +02:00
Kevin FronczakandGitHub 4241b50002 Merge pull request #118 from md-reddevil/dev
API: Fix Command Status method add a new method to manage correctly the System status
2018-11-14 09:01:10 -05:00
md-reddevilandGitHub 8b0507f1a7 fix indentation for method request_command_status 2018-11-14 15:57:46 +02:00
md-reddevilandGitHub d62429189e Fix formatting issue in api.py 2018-11-14 11:04:40 +02:00
md-reddevilandGitHub c83b173a17 update description of the networks method 2018-11-14 09:55:17 +02:00
md-reddevilandGitHub 9c1974c227 Add method to request the Network/System status
Home screen method returns just the information about last added System(network). The method "request_network_status", should replace the homescreen method in order to obtain all the information about a system.
2018-11-14 09:39:44 +02:00
md-reddevilandGitHub c621ba3150 fix check command status 2018-11-14 09:34:25 +02:00
Kevin FronczakandGitHub 7710e3f972 Errant whitespace 2018-10-30 21:08:43 -04:00
Kevin Fronczak a4f65c1102 dev version bump 2018-10-30 20:24:39 -04:00
Kevin FronczakandGitHub 80c6444c2e Merge pull request #112 from fronzbot/dev
0.10.2
2018-10-30 20:22:08 -04:00
Kevin Fronczak 2022b80f9d Version bump 2018-10-30 20:16:37 -04:00
Kevin FronczakandGitHub 7e9900c5f5 Merge pull request #111 from fronzbot/fix-typo
Reformatted log message when multiple networks detected.
2018-10-30 20:07:03 -04:00
Kevin Fronczak 132df9e8c4 Fixed wrong string format 2018-10-30 19:58:13 -04:00
Kevin Fronczak 07e3549306 Reformatted log message when multiple networks detected. 2018-10-30 19:48:08 -04:00
Kevin FronczakandGitHub e0fa0a0cde Merge pull request #110 from fronzbot/upgrade-requests
Upgraded requests due to security issue prior to 2.20.0
2018-10-30 19:47:38 -04:00
Kevin Fronczak 31771ca87d Upgraded requests due to security issue prior to 2.20.0 2018-10-30 19:42:35 -04:00
Kevin FronczakandGitHub 1b898398a7 Fix rst lint error 2018-10-26 11:09:43 -04:00
Kevin FronczakandGitHub d8fcb679cd Add python versioning badge 2018-10-26 11:05:00 -04:00
Kevin Fronczak 72a5ccb769 dev version bump 2018-10-18 13:20:34 -04:00
Kevin FronczakandGitHub e872fc9ce5 Merge pull request #105 from fronzbot/dev
0.10.1
2018-10-18 13:19:49 -04:00
Kevin Fronczak 51961474b6 Version bump 2018-10-18 13:10:42 -04:00
Kevin FronczakandGitHub 8be35dab30 Merge pull request #104 from fronzbot/fix-warning
Changed 'warning' to 'info' in camera
2018-10-18 13:05:17 -04:00
Kevin FronczakandGitHub 0ab17aede8 Merge pull request #103 from fronzbot/reauth-bug-fix
Reauth bug fix
2018-10-18 13:01:52 -04:00
Kevin Fronczak 6db8a151f8 Changed 'warning' to 'info' and added an error if trying to save video
that doesn't exist
2018-10-18 12:58:43 -04:00
Kevin Fronczak 1a12eb367f Added additional re-auth attempt in try/except 2018-10-18 12:49:18 -04:00
Kevin Fronczak f61f68a5c2 Fix reauthorization bug 2018-10-18 12:23:23 -04:00
Kevin FronczakandGitHub 0781d79ca7 Update bug_report.md 2018-10-17 11:18:29 -04:00
Kevin FronczakandGitHub 4ffdf499c9 Update PULL_REQUEST_TEMPLATE.md 2018-10-17 10:28:40 -04:00
Kevin FronczakandGitHub f8f318c203 Update bug_report.md 2018-10-17 10:26:28 -04:00
Kevin Fronczak 59540818f9 Add feature request template 2018-10-17 10:24:52 -04:00
Kevin Fronczak b2b531ad3c Add issue template 2018-10-17 10:22:59 -04:00
Kevin FronczakandGitHub 4e6957a772 Merge pull request #100 from fronzbot/dev
Release 0.10.0
2018-10-16 17:43:21 -04:00
Kevin FronczakandGitHub e747fb1010 Merge branch 'master' into dev 2018-10-16 17:28:34 -04:00
Kevin FronczakandGitHub 9d110cdd72 Merge pull request #99 from fronzbot/0.10.0
Version bump
2018-10-16 16:53:51 -04:00
Kevin Fronczak 6fa0eacff3 Fix trailing whitespace 2018-10-16 16:26:47 -04:00
Kevin Fronczak 7ce924f52e Version bump 2018-10-16 16:24:39 -04:00
Kevin FronczakandGitHub 91b3c2a64b Merge pull request #98 from fronzbot/update-travis
Added py38 to tox and travis
2018-10-16 16:19:11 -04:00
Kevin FronczakandGitHub 97579400b1 Merge pull request #97 from fronzbot/multi-network-support
Adds multi-network handling (Thanks @dgomes and @dib0 )
2018-10-16 16:17:48 -04:00
Kevin Fronczak 63b01dde14 Removed condition on py38-dev 2018-10-16 15:43:02 -04:00
Kevin Fronczak d9b996ab02 Added py38 2018-10-16 15:41:12 -04:00
Kevin Fronczak 3af105edf5 Check for 'None' clip before saving to cache 2018-10-16 15:26:15 -04:00
Kevin Fronczak 5057592b0d Fix blink_functions test 2018-10-16 13:52:09 -04:00
Kevin Fronczak 13bb819e07 Added network checking 2018-10-16 13:28:44 -04:00
Kevin Fronczak eefa9252e5 [WIP] Adding in network checking 2018-10-16 12:27:57 -04:00
Kevin FronczakandGitHub c5b84ac357 Merge pull request #96 from fronzbot/update-changes-rst
Add changes from PR #94
2018-10-16 11:42:12 -04:00
Kevin Fronczak 787256ce66 Fixed bad linkwq 2018-10-16 11:28:18 -04:00
Kevin Fronczak 2f1877267f Add changes from PR #94 2018-10-16 11:23:31 -04:00
Kevin FronczakandGitHub 9c34fc9281 Merge pull request #94 from fronzbot/breakout-api-calls
Improve API calls
2018-10-16 11:18:52 -04:00
Kevin Fronczak 1b9bba7c3d Modified tests, added homescreen thumbnail backup Fixes #93 2018-10-15 20:52:05 -04:00
Kevin FronczakandGitHub 123867ecd8 Merge pull request #95 from fronzbot/update-changes
Updated CHANGES to reflect recent releases
2018-10-14 08:54:01 -04:00
Kevin Fronczak 26d900897b Updated CHANGES to reflect recent releases 2018-10-14 00:27:59 -04:00
Kevin Fronczak f7a5b5cc03 Tests now working
- Simplified tests a bit
2018-10-14 00:12:44 -04:00
Kevin Fronczak 7fd822caf2 Removed old api calls, using new api module
- Tests currently broken
- wifi_strength is now a number of bars rather than dBm level
- camera no longer has armed or status attributes
- added serial numbers for sync and cameras
2018-10-13 20:38:01 -04:00
Kevin Fronczak 01c6f0b12b Add all requests to single api file 2018-10-13 16:49:31 -04:00
Kevin FronczakandGitHub 62c89a925e Dev version bump 2018-09-28 15:00:51 -04:00
Kevin FronczakandGitHub 07e1759819 Merge pull request #85 from fronzbot/v0.9.0
V0.9.0
2018-09-27 21:46:04 -04:00
Kevin FronczakandGitHub 8fac6c5bc0 Merge branch 'master' into v0.9.0 2018-09-27 21:42:05 -04:00
Kevin Fronczak bd4307af58 Version bump 2018-09-27 21:33:53 -04:00
Kevin FronczakandGitHub bd6e3bb4e3 Merge pull request #84 from fronzbot/better-docstrings
Added docstrings, removed docs/_build
2018-09-27 16:17:07 -04:00
Kevin Fronczak c2630a43e1 Added docstrings, removed docs/_build 2018-09-27 16:13:19 -04:00
Kevin FronczakandGitHub 2e6fb97cc5 Merge pull request #83 from fronzbot/use-sessions
Use sessions for requests
2018-09-27 15:19:11 -04:00
Kevin Fronczak 674dae4440 Fix lint error 2018-09-27 15:15:25 -04:00
Kevin Fronczak a1082812bb Modified tests to pass with session
- Added session mock
- Removed post and get mocks
- Modified the throttling for events and summary
    - Now they're throttled, but it's overridden during a system refresh
- Store the login url in a protected variable
2018-09-27 15:10:48 -04:00
Kevin Fronczak 9d838fe4eb Added session for requests
- fixed refresh issue throttling summary and events
2018-09-27 12:35:15 -04:00
Kevin FronczakandGitHub fe0aef69e4 Merge pull request #82 from fronzbot/refactor
Refactor blinkpy code
2018-09-27 11:15:17 -04:00
Kevin Fronczak 1b1235210e Split up tests, added cache test 2018-09-27 11:07:31 -04:00
Kevin Fronczak 451d725946 Update functionality in README 2018-09-26 13:02:48 -04:00
Kevin Fronczak 9d5ae9552a Check if first init, if so force cache update 2018-09-26 12:45:29 -04:00
Kevin Fronczak c3c558e934 Fix broken refresh throttle 2018-09-26 12:24:45 -04:00
Kevin Fronczak a570413e66 Fixed broken tests...probably should re-write them 2018-09-26 12:11:41 -04:00
Kevin Fronczak 3e23374b32 Modified requests so cameras only talk to sync 2018-09-26 11:09:51 -04:00
Kevin Fronczak 1c6a5eb6c6 Fixed tests. Need to improve mocking in functions test. 2018-09-25 16:02:59 -04:00
Kevin Fronczak 40e9e4bd6c Fixed camera tests 2018-09-25 14:31:23 -04:00
Kevin Fronczak e1ff851068 First cut of refactoring 2018-09-25 14:16:14 -04:00
Kevin FronczakandGitHub 8a4e507f22 Merge pull request #81 from fronzbot/add-refresh-rate
Add refresh rate and image caching
2018-09-25 12:23:41 -04:00
Kevin Fronczak cd7b5bfabc Fixing travis errors with new python versions 2018-09-25 12:15:19 -04:00
Kevin Fronczak 346882f1ff Remove Python 3.4 from travis, add py38-dev 2018-09-25 12:07:40 -04:00
Kevin Fronczak 5bc2466da2 Add py37 to tox.ini 2018-09-25 12:04:22 -04:00
Kevin Fronczak 672f59ab4e Added image and video caching 2018-09-25 12:03:32 -04:00
Kevin Fronczak ae26a9e371 Added refresh rate throttling 2018-09-25 11:07:40 -04:00
Kevin FronczakandGitHub 37fc047174 Merge pull request #80 from fronzbot/v0.8.3
V0.8.3
2018-09-24 22:31:12 -04:00
Kevin FronczakandGitHub 6343965bbc Merge branch 'master' into v0.8.3 2018-09-24 22:30:56 -04:00
Kevin Fronczak 411da60bb2 version_bump 2018-09-24 22:30:17 -04:00
Kevin Fronczak 72c36d8381 revert tests 2018-09-24 22:27:42 -04:00
Kevin Fronczak b0974c1ab2 reverting to 0.8.1 style thumbnail retreival 2018-09-24 22:25:43 -04:00
Kevin Fronczak a76eac085a Fix thumbnail since we aren't using homescreen anymore 2018-09-24 22:12:07 -04:00
Kevin FronczakandGitHub 5319714a37 Merge pull request #79 from fronzbot/v0.8.2
V0.8.2
2018-09-24 21:36:44 -04:00
Kevin FronczakandGitHub 5d9105655f Merge branch 'master' into v0.8.2 2018-09-24 21:32:02 -04:00
Kevin Fronczak b98c03b96b version bump 2018-09-24 21:30:23 -04:00
Kevin FronczakandGitHub ec703ae4b0 Merge pull request #78 from fronzbot/sort-motion-clips
Changed motion check to look at sorted date list
2018-09-24 21:29:01 -04:00
Kevin Fronczak 9ce09b4761 Fix thumbnails grabbing wrong date 2018-09-24 21:24:21 -04:00
Kevin Fronczak 6d002fc8b0 record_dates needs to default to dict, not list 2018-09-24 20:59:16 -04:00
Kevin Fronczak 7228340677 Changed motion check to look at sorted date list
- Previous method using clips resulted in an unsorted array, so the
newest clip wasn't always added during check
2018-09-24 20:26:36 -04:00
Kevin FronczakandGitHub 9335a37feb Merge pull request #77 from fronzbot/v0.8.1
v0.8.1
2018-09-24 13:35:48 -04:00
Kevin Fronczak 371348533f Fix trailing whitespace 2018-09-24 13:30:56 -04:00
Kevin Fronczak 26f6defe60 Version bump 2018-09-24 13:27:10 -04:00
Kevin FronczakandGitHub 52bc4af1f0 Merge pull request #76 from fronzbot/better-motion
Fix motion detection
2018-09-24 13:25:14 -04:00
Kevin Fronczak 8c94305804 Fix motion detection
- Use an array of recent video clips to determine if motion has been
detected.
- Reset the value every system refresh
2018-09-24 13:17:15 -04:00
Kevin FronczakandGitHub 0eb57698bd Merge pull request #72 from fronzbot/lint-upgrade
Update linter versions
2018-08-09 09:43:51 -04:00
Kevin FronczakandGitHub 7b0db80edd Disable no-else-return 2018-08-09 09:37:57 -04:00
Kevin FronczakandGitHub 0e63e97a57 Remove whitespace 2018-08-09 09:27:36 -04:00
Kevin FronczakandGitHub e4a21964d2 Fix useless-import-alias 2018-08-09 09:26:22 -04:00
Kevin FronczakandGitHub 39ad37f23b Fix pylint errors
- change if comparison to fix (consider-using-in)
- Disabled no else-if-return check
2018-08-09 09:25:42 -04:00
Kevin FronczakandGitHub 34bc61e1c3 Fix pylint warnings
- Remove object from class declarations
- Remove useless returns from functions
2018-08-09 09:21:49 -04:00
Kevin FronczakandGitHub e6a7c367b3 Merge branch 'dev' into lint-upgrade 2018-08-09 07:35:26 -04:00
Kevin FronczakandGitHub 66afd33b79 Merge pull request #71 from fronzbot/upgrade-pytest
Pytest 3.7.1
2018-08-09 07:28:51 -04:00
Kevin FronczakandGitHub cf617d720e Update linter versions 2018-08-09 07:27:12 -04:00
Kevin FronczakandGitHub 4f2eca08e0 Update requirements_test.txt 2018-08-09 07:21:05 -04:00
Kevin FronczakandGitHub 2972780c18 Merge pull request #69 from fronzbot/dev-version-bump
Dev version bump
2018-05-21 11:47:52 -04:00
Kevin Fronczak 9c3f3f2f98 Version bump 2018-05-21 11:44:05 -04:00
Kevin FronczakandGitHub 0d83a7fcb1 Merge pull request #68 from fronzbot/v0.8.0
V0.8.0
2018-05-21 11:40:14 -04:00
Kevin FronczakandGitHub 80f4ca7c4f Merge branch 'master' into v0.8.0 2018-05-21 11:36:34 -04:00
Kevin Fronczak 96e7fce304 Version bump 2018-05-21 11:34:09 -04:00
Kevin FronczakandGitHub 13a358c07c Merge pull request #67 from fronzbot/celcius-support
Add celcius property for cameras
2018-05-21 11:26:43 -04:00
Kevin Fronczak 389745533c Add celcius property for cameras 2018-05-21 11:12:32 -04:00
Kevin FronczakandGitHub 65dd547a32 Merge pull request #65 from fronzbot/battery-percent
Added new request url for camera config
2018-05-21 11:03:25 -04:00
Kevin Fronczak 91a877da79 Fix tests, updated changes in changelog 2018-05-21 10:54:32 -04:00
Kevin Fronczak d357215e0e Added new request url for camera config
- Adds support for battery voltage level
- Added new camera properties (wifi_strength, motion_detected)
- Store full camera config from request into dict
2018-05-21 00:16:24 -04:00
Kevin FronczakandGitHub ff47dc4731 Merge pull request #63 from fronzbot/release-0.7.1
v0.7.1
2018-05-09 11:15:56 -04:00
Kevin Fronczak fedea74256 Version bump 2018-05-09 11:08:35 -04:00
Kevin FronczakandGitHub 66a6701a66 Merge pull request #62 from fronzbot/gitlab
Add gitlab support, py3.7 checks.  Also removes py34 tests
2018-05-09 10:46:13 -04:00
Kevin Fronczak 5bdfd6da52 Add gitlab support, py3.7 checks. Also removes py34 tests 2018-05-09 10:29:33 -04:00
Kevin FronczakandGitHub a8f90400b2 Merge pull request #61 from fronzbot/pip-fix
Fixed import error for pip version 10
2018-05-09 10:21:43 -04:00
Kevin Fronczak 3348386a4c Style fixes 2018-05-09 10:05:03 -04:00
Kevin Fronczak 1b53c4a0dd Hound should ignore setup.py 2018-05-09 10:02:58 -04:00
Kevin Fronczak 24158638ef Fix hound 2018-05-09 10:00:13 -04:00
Kevin Fronczak 901cbfc9d1 Fixed import error for pip version 10 2018-05-09 09:49:41 -04:00
Kevin FronczakandGitHub 9f85068a0d Merge pull request #59 from fronzbot/dev-version-bump
dev version bump
2018-02-08 17:02:38 -05:00
Kevin FronczakandGitHub 90b83544f4 Update constants.py 2018-02-08 16:53:03 -05:00
Kevin FronczakandGitHub 1d8e8e53d9 Update CHANGES.rst 2018-02-08 16:52:17 -05:00
Kevin FronczakandGitHub 46a0a433ec Merge pull request #58 from fronzbot/master
Rebase with master
2018-02-08 16:51:05 -05:00
Kevin FronczakandGitHub d38d30471a Update CHANGES.rst 2018-02-08 16:46:21 -05:00
Kevin FronczakandGitHub 5aad8ea641 Merge pull request #57 from fronzbot/dev
v0.7.0
2018-02-08 16:44:37 -05:00
Kevin FronczakandGitHub 74f4bd7763 Version bump 2018-02-08 16:35:37 -05:00
Kevin FronczakandGitHub 51dd69a51f Merge pull request #56 from fronzbot/camera-attributes
Camera attributes
2018-02-08 16:22:14 -05:00
Kevin FronczakandGitHub 950e7d4971 Merge pull request #55 from fronzbot/auth-at-login
Added authentication to login function and deprecated setup_system
2018-02-08 16:18:19 -05:00
Kevin Fronczak 623b694c78 Added attributes property to camera object 2018-02-08 16:16:23 -05:00
Kevin Fronczak 7162ea24cc Added authentication to login function and deprecated setup_system 2018-02-08 15:31:26 -05:00
Kevin FronczakandGitHub 968b77b8bd Merge pull request #53 from fronzbot/logging-support
Added logging
2018-02-08 14:59:46 -05:00
Kevin Fronczak 6e00b126d1 Added logging 2018-02-08 14:49:10 -05:00
Kevin FronczakandGitHub 003ceb0944 Merge pull request #50 from b10m/active_vs_armed
Handle the armed status better
2018-02-03 09:53:43 -05:00
Kevin Fronczak ce6dec50cd Fixed requirement issue causing tox failure
- Updated camera test to check for new status change
- Added updated to CHANGES.rst
2018-02-03 09:50:08 -05:00
B10m 87643ddcab Reflect changes in tests 2018-02-03 01:11:27 +01:00
B10m 017d8aa6c0 Handle the armed status better
Blink allows users to arm/disarm individual cameras. This is pretty useful for
inside and outside cameras, for instance.

The 'armed' information in the JSON however, merely indicates whether the
*system* is armed, not whether the camera itself is armed. This value, which is
the same as blink.arm, does not indicate whether the camera has motion
detection enabled.

In the JSON, the true status information lies in the 'active' key. The value
can be 'armed', 'disarmed' or 'disabled'. This commit reflects that value
in the armed property.
2018-02-03 00:32:20 +01:00
Kevin FronczakandGitHub 87b83465b3 Merge pull request #48 from fronzbot/update-readme
Add doc badge
2018-01-20 23:26:57 -05:00
Kevin Fronczak a1900f0130 Add doc badge 2018-01-20 23:26:03 -05:00
Kevin FronczakandGitHub cf9ecff529 Merge pull request #47 from fronzbot/docs
Updated theme
2018-01-20 23:18:14 -05:00
Kevin Fronczak db3dee81e9 Updated theme 2018-01-20 23:17:06 -05:00
Kevin FronczakandGitHub 798032be08 Merge pull request #46 from fronzbot/docs
Add documentation
2018-01-20 23:01:44 -05:00
Kevin Fronczak d6834dca06 Ignore docs for Hound 2018-01-20 22:57:38 -05:00
Kevin Fronczak 933cd7229a Add documentation 2018-01-20 22:53:02 -05:00
Kevin FronczakandGitHub 8e51a86971 Merge pull request #45 from fronzbot/video-clip-support
Added ability to download recent video clip
2018-01-20 20:22:36 -05:00
Kevin Fronczak 8ab44041eb Added ability to download recent video clip 2018-01-20 20:13:33 -05:00
Kevin Fronczak 79191d757a Changed coveralls badge to dev branch 2018-01-20 20:03:28 -05:00
Kevin FronczakandGitHub 7d01f54d73 Merge pull request #44 from fronzbot/update-api
Update Blink API Calls
2018-01-20 20:00:55 -05:00
Kevin Fronczak 63c0e11cc9 Fix linting error 2018-01-20 19:57:06 -05:00
Kevin Fronczak 7347d03f93 Added case-sensitive test, logged all changes 2018-01-20 19:53:27 -05:00
Kevin Fronczak fffb10d7e6 Refactored unit tests for special functions 2018-01-20 19:41:15 -05:00
Kevin Fronczak 91b3de1444 Refactored requests, expanded video retreival
- Removed blinkpy.last_motion()
- blinkpy.get_summary() changed to blinkpy.summary property
2018-01-20 16:53:38 -05:00
Kevin Fronczak 8340f2f78a WIP Simplified unit tests 2018-01-20 15:38:37 -05:00
Kevin Fronczak e65840d269 Fix lint 2018-01-20 11:43:46 -05:00
Kevin Fronczak c245bc24a6 Added video retrieval 2018-01-20 11:35:01 -05:00
Kevin Fronczak 71ebc3dc8a Updated links to retrieve images 2018-01-20 10:42:14 -05:00
Kevin FronczakandGitHub 7ade321dd3 Merge pull request #43 from fronzbot/update-travis
Update travis to use 3.6 for linting and build
2018-01-20 09:19:45 -05:00
Kevin Fronczak 19c0114eea Update travis to use 3.6 for linting and build 2018-01-20 09:15:09 -05:00
Kevin Fronczak 968c0cf8fc Fixed typos 2018-01-19 14:52:40 -05:00
Kevin Fronczak f8d4874f2f Updated README badges to dev branch, improved setup script 2018-01-19 14:47:12 -05:00
Kevin Fronczak 261d6293dd Fix lint, upgrade pylint to 1.8.1 2018-01-19 14:38:16 -05:00
Kevin Fronczak 988265fd9f Removed API warning 2018-01-19 11:45:08 -05:00
Kevin Fronczak ba03894e94 Refactored code in prep for API overhaul 2018-01-19 11:41:26 -05:00
Kevin FronczakandGitHub 556c28d4b9 Update README.rst 2017-12-29 20:09:34 -05:00
Kevin FronczakandGitHub 9d2a8c6b69 Update README.rst 2017-07-05 13:33:05 -04:00
Kevin FronczakandGitHub 89b517f47e Merge pull request #39 from fronzbot/pylint-upgrade
Upgrade to pylint==1.7.2
2017-07-05 13:31:45 -04:00
Kevin Fronczak 150016f543 Fixed underline too short 2017-07-05 13:24:22 -04:00
Kevin Fronczak 5df599be15 Upgrade to pylint==1.7.2
Also added PyPi badge to readme
2017-07-05 13:16:12 -04:00
Kevin FronczakandGitHub 0fd4b4b274 Merge pull request #37 from fronzbot/case_insensitive_cameras
Added case handling on camera dict
2017-06-18 18:47:41 -04:00
Kevin FronczakandGitHub dd744053f4 Fixed issue link 2017-06-18 18:41:21 -04:00
Kevin Fronczak be68c0d714 Added case handling on camera dict 2017-06-18 18:37:19 -04:00
Kevin FronczakandGitHub 2a4b0d3f4b Merge pull request #33 from fronzbot/fronzbot-patch-1
Update README.rst
2017-05-15 18:24:17 -04:00
Kevin FronczakandGitHub 46dd002e5d Update README.rst 2017-05-15 18:18:59 -04:00
Kevin FronczakandGitHub 04bc0ace3f Update README.rst
Fixed incorrect example code
2017-05-15 18:17:46 -04:00
Kevin FronczakandGitHub fa6cc49343 Merge pull request #32 from fronzbot/rst-linter
Added rst checking
2017-05-13 20:26:12 -04:00
Kevin Fronczak 231d191556 Added rst checking
Added reStructuredText checking so that the README is actually readable when uploaded to PyPi
2017-05-13 20:14:32 -04:00
Kevin FronczakandGitHub b6c8141042 Merge pull request #31 from fronzbot/upgrade-tests
Upgrade tests
2017-05-13 18:34:10 -04:00
Kevin Fronczak ae209a37f7 Pass lint version bumps 2017-05-13 18:27:01 -04:00
Kevin Fronczak 0d07ae1b4c Upgrade tests
-  pylint to 1.7.1
-  pydocstyle to 2.0.0
-  Added bdist_wheel test to ensure packaging working properly
2017-05-13 12:44:36 -04:00
Kevin FronczakandGitHub cfeed4f432 Merge pull request #30 from fronzbot/v0.6.0
v0.6.0
2017-05-12 16:09:45 -04:00
Kevin Fronczak 6ca243c05c Version bump 2017-05-12 16:03:50 -04:00
Kevin FronczakandGitHub cfa2f0f1bc Merge pull request #29 from fronzbot/better-battery-report
Added battery_string property to camera
2017-05-12 15:53:00 -04:00
Kevin Fronczak d4456555b3 Updated README 2017-05-12 15:46:53 -04:00
Kevin Fronczak 01babca0f4 Added battery_string property to camera
Ability to detect if battery is "OK" or "Low"
2017-05-12 15:42:18 -04:00
Kevin FronczakandGitHub 123444ddf6 Merge pull request #27 from fronzbot/reauth-tests
Reauth tests
2017-05-12 15:08:44 -04:00
Kevin Fronczak aeeb894ad9 Added reauth test 2017-05-12 14:46:13 -04:00
Kevin Fronczak d290fe4096 Added test for reauth
Test to check that we throw an exception if we cannot reauth (to ensure we don't get stuck in a loop)
2017-05-12 14:03:35 -04:00
Kevin FronczakandGitHub 565e3e1b9d Merge pull request #24 from tySwift93/development
Add Token Reauthorization
2017-05-12 10:39:27 -04:00
tySwift93andGitHub b23fe8319b Removed a single space to make lint happy once more
PLEASE BE HAPPY
2017-05-10 19:47:22 -04:00
tySwift93andGitHub eb41b4285e Lint is the bane of my existence 2017-05-10 19:42:20 -04:00
tySwift93andGitHub ab684f64ff Lint is killing me 2017-05-10 19:27:12 -04:00
tySwift93andGitHub abea28ef00 Undo my attempt at fixing code coverage 2017-05-10 19:23:26 -04:00
tySwift93andGitHub 8934645c4d One final attempt to get coverage to work...
I'm just hoping something sticks!
2017-05-10 19:20:26 -04:00
tySwift93andGitHub 68d64665a6 Trying to fix test coverage really quickly... 2017-05-10 19:03:39 -04:00
tySwift93andGitHub 5099d0e67e Update the changes made to _request method
Forgot to include 'return'
2017-05-10 18:51:34 -04:00
tySwift93andGitHub 7a3ba3ae03 Minor change that will hopefully trigger Hound 2017-05-10 10:18:27 -04:00
Kevin FronczakandGitHub 80272b1e27 Merge pull request #25 from fronzbot/hound
Create .hound.yml
2017-05-10 09:11:42 -04:00
Kevin FronczakandGitHub 8d807289ae Create .hound.yml 2017-05-10 09:04:56 -04:00
ttrushin cb946209a2 Has it become obvious that I have never used pylint before?...Please work now... 2017-05-09 16:09:44 -04:00
ttrushin 890b58d0ce Another attempt to fix pylint-related issues 2017-05-09 16:01:31 -04:00
ttrushin 6623f2559d Hopefully fixed pylint-related issues 2017-05-09 15:46:18 -04:00
ttrushin b395eba4f3 Fixed misspelling yet again... 2017-05-09 15:28:03 -04:00
ttrushin c13f3d5b77 Fixed tests, fixed misspelling, and fixed a small error in _request method 2017-05-09 15:15:31 -04:00
ttrushin 13c7373917 Added auto-reauthorization (token refresh) when a request fails due to an expired token 2017-05-09 14:47:31 -04:00
Kevin FronczakandGitHub b0cb3dda37 Merge pull request #22 from fronzbot/dev
Merge 0.6.0.dev0 branch
2017-04-15 17:38:36 -04:00
Kevin FronczakandGitHub a0ab6700d8 Update CHANGES.rst 2017-03-21 10:01:24 -04:00
Kevin FronczakandGitHub ebf4cb53b5 Merge pull request #21 from fronzbot/cleanup
Cleanup and Coverage Increase
2017-03-20 15:57:43 -04:00
Kevin Fronczak 9fa2e967dc Removed redundant functions, increased test coverage 2017-03-20 15:53:53 -04:00
Kevin Fronczak f853b410e7 Merge branch 'dev' of github.com:fronzbot/blinkpy into cleanup
Conflicts:
	helpers/constants.py
2017-03-20 14:06:35 -04:00
Kevin Fronczak 874f717bd1 Fixed formatting 2017-03-20 14:05:40 -04:00
Kevin Fronczak 479a41c900 Had to update version due to messing up the module distribution 2017-03-20 14:05:39 -04:00
Kevin Fronczak a0a1e2837c Fixed coveralls badge 2017-03-20 14:05:39 -04:00
Kevin FronczakandGitHub bd783385de Merge pull request #20 from fronzbot/fronzbot-api-formatting
Fixed formatting
2017-03-20 13:37:23 -04:00
Kevin FronczakandGitHub 5f19b3e47b Fixed formatting 2017-03-20 13:22:12 -04:00
Kevin FronczakandGitHub c7fe0a5b5c Merge pull request #19 from fronzbot/constant-fix
Fixed copy-paste error
2017-03-14 15:11:38 -04:00
Kevin FronczakandGitHub 5eb1b663f4 Fixed copy-paste error 2017-03-14 15:11:22 -04:00
Kevin FronczakandGitHub 1e194385b8 Merge pull request #18 from fronzbot/dev-version-bump
Bump version to dev
2017-03-14 15:10:12 -04:00
Kevin FronczakandGitHub 731fb87012 Bump version to dev 2017-03-14 15:09:35 -04:00
Kevin FronczakandGitHub 5e1634dbfa Merge pull request #17 from fronzbot/master
Pulling in updates from master to dev branch
2017-03-14 15:07:56 -04:00
Kevin Fronczak 7d366386da Had to update version due to messing up the module distribution 2017-03-12 22:06:39 -04:00
Kevin Fronczak b4a03778d3 Fixed coveralls badge 2017-03-12 20:04:42 -04:00
64 changed files with 4764 additions and 1510 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
[run]
omit =
helpers/*
parallel = true
omit =
tests/*
setup.py
setup.py
+29
View File
@@ -0,0 +1,29 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1.
2.
3.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Home Assistant version (if applicable):** <HA Version Number>
**`blinkpy` version (not needed if filling out Home Assistant version):**
**Log Output/Additional Information**
If using home-assistant, please paste the output of the log showing your error below. If not, please include any additional useful information.
```
PASTE LOG OUTPUT HERE
```
+14
View File
@@ -0,0 +1,14 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context about the feature request (such as API endpoint responses, etc).
+2 -2
View File
@@ -5,5 +5,5 @@
## Checklist:
- [ ] Local tests with `tox` run successfully **PR cannot be meged unless tests pass**
- [ ] If user-facing functionality changed, README.rst updated
- [ ] Tests added to verify new code works
- [ ] Changes tested locally to ensure platform still works as intended
- [ ] Tests added to verify new code works
+31
View File
@@ -0,0 +1,31 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- Priority
- bug
- help wanted
- feature request
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs within seven days. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue is now being closed due to inactivity.
+42
View File
@@ -0,0 +1,42 @@
name: coverage
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
jobs:
build:
runs-on: ${{ matrix.platform }}
strategy:
max-parallel: 4
matrix:
platform:
- ubuntu-latest
python-version: [3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
pip install tox
pip install codecov
- name: Test
run: |
tox -r -e cov
- name: Codecov
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: unittests
file: ./coverage.xml
name: blinkpy
fail_ci_if_error: true
+34
View File
@@ -0,0 +1,34 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Lint
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
pip install tox
- name: Lint
run: |
tox -r -e lint
+31
View File
@@ -0,0 +1,31 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Python Package
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py bdist_wheel
twine upload dist/*
+33
View File
@@ -0,0 +1,33 @@
name: build
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
jobs:
build:
runs-on: ${{ matrix.platform }}
strategy:
max-parallel: 4
matrix:
platform:
- ubuntu-latest
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
pip install tox
- name: Test
run: |
tox -r
+7
View File
@@ -1,10 +1,17 @@
.pytest_cache/*
.cache/*
.tox/*
__pycache__/*
htmlcov/*
.coverage
.coverage.*
coverage.xml
*.pyc
*.egg*/*
dist/*
.sh
build/*
docs/_build
*.log
venv
.session*
+22
View File
@@ -0,0 +1,22 @@
repos:
- repo: https://github.com/psf/black
rev: 19.10b0
hooks:
- id: black
args:
- --safe
- --quiet
files: ^((blinkpy|tests)/.+)?[^/]+\.py$
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.5.0
- pydocstyle==5.1.1
files: ^(blinkpy|tests)/.+\.py$
- repo: https://github.com/Lucas-C/pre-commit-hooks-markup
rev: v1.0.0
hooks:
- id: rst-linter
files: /.+\.rst$
-18
View File
@@ -1,18 +0,0 @@
matrix:
fast_finish: true
include:
- python: "3.4.2"
env: TOXENV=py34
- python: "3.4.2"
env: TOXENV=lint
- python: "3.5"
env: TOXENV=py35
- python: "3.6"
env: TOXENV=py36
- python: "3.6-dev"
env: TOXENV=py36
install: pip install -U tox coveralls
language: python
script: tox
after_success: coveralls
+44 -42
View File
@@ -1,5 +1,5 @@
# BlinkMonitorProtocol
Unofficial documentation for the Client API of the Blink Wire-Free HD Home Monitoring and Alert System.
Unofficial documentation for the Client API of the Blink Wire-Free HD Home Monitoring &amp; Alert System.
Copied from https://github.com/MattTW/BlinkMonitorProtocol
@@ -7,10 +7,7 @@ I am not affiliated with the company in any way - this documentation is strictly
The Client API is a straightforward REST API using JSON and HTTPS.
## 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.
##Login
## Login
Client login to the Blink Servers.
@@ -19,20 +16,25 @@ Client login to the Blink Servers.
> "password" : "*your blink password*",
> "client_specifier" : "iPhone 9.2 | 2.2 | 222",
> "email" : "*your blink login/email*"
>}' --compressed https://prod.immedia-semi.com/login
>}' --compressed https://rest.prod.immedia-semi.com/login
**Response:**
>{"authtoken":{"authtoken":"*an auth token*","message":"auth"}}
>{"authtoken":{"authtoken":"*an auth token*","message":"auth"},"networks":{"*network id*":{"name":"*name*","onboarded":true}},"region":{"*regioncode for endpoint*":"*region name"}}
**Notes:**
The authtoken value is passed in a header in future calls.
The region code for endpoint is required to form the URL of the REST endpoint for future calls.
Depending on the region you are registered you will need to change the REST endpoints below:
- from `https://rest.prod.immedia-semi.com`
- to `https://rest.prde.immedia-semi.com` if e.g. your device is registered in Germany
Please note that at this moment it seems that all regions are not implemented equally: not all endpoints are available in all regions
##Networks
## Networks
Obtain information about the Blink networks defined for the logged in user.
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/networks
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/networks
**Response:**
JSON response containing information including Network ID and Account ID.
@@ -41,12 +43,12 @@ JSON response containing information including Network ID and Account ID.
Network ID is needed to issue arm/disarm calls
##Sync Modules
## Sync Modules
Obtain information about the Blink Sync Modules on the given network.
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/syncmodules
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/syncmodules
**Response:**
JSON response containing information about the known state of the Sync module, most notably if it is online
@@ -55,12 +57,12 @@ 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.
##Arm
## Arm
Arm the given network (start recording/reporting motion events)
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/arm
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/arm
**Response:**
JSON response containing information about the arm command request, including the command/request ID
@@ -68,12 +70,12 @@ JSON response containing information about the arm command request, including th
**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.
##Disarm
## Disarm
Disarm the given network (stop recording/reporting motion events)
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/disarm
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/disarm
**Response:**
JSON response containing information about the disarm command request, including the command/request ID
@@ -82,12 +84,12 @@ 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.
##Command Status
## Command Status
Get status info on the given command
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/command/*command_id*
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/command/*command_id*
**Response:**
JSON response containing state information of the given command, most notably whether it has completed and was successful.
@@ -98,12 +100,12 @@ After an arm/disarm command, the client appears to poll this URL every second or
**Known Commands:**
lv_relay, arm, disarm, thumbnail, clip
##Home Screen
## Home Screen
Return information displayed on the home screen of the mobile client
**Request:**
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/homescreen
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/homescreen
**Response:**
JSON response containing information that the mobile client displays on the home page, including: status, armed state, links to thumbnails for each camera, etc.
@@ -111,12 +113,12 @@ JSON response containing information that the mobile client displays on the home
**Notes:**
Not necessary to as part of issuing arm/disarm commands, but contains good summary info.
##Events, thumbnails & video captures
## Events, thumbnails & video captures
**Request**
Get events for a given network (sync module) -- Need network ID from home
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/events/network/*network__id*
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/events/network/*network__id*
**Response**
A json list of evets incluing URL's. Replace the "mp4" with "jpg" extension to get the thumbnail of each clip
@@ -144,7 +146,7 @@ Note that you replace the 'mp4' with a 'jpg' to get the thumbnail
**Request**
Captures a new thumbnail for a camera
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/thumbnail
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/thumbnail
**Response**
Command information.
@@ -152,17 +154,17 @@ Command information.
**Request**
Captures a new video for a camera
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/clip
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/clip
**Response**
Command information.
##Video Information
## Video Information
**Request**
Get the total number of videos in the system
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/count
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/count
**Response**
JSON response containing the total video count.
@@ -170,7 +172,7 @@ JSON response containing the total video count.
**Request**
Gets a paginated set of video information
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/page/0
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/page/0
**Response**
JSON response containing a set of video information, including: camera name, creation time, thumbnail URI, size, length
@@ -178,7 +180,7 @@ JSON response containing a set of video information, including: camera name, cre
**Request**
Gets information for a specific video by ID
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/video/*video_id*
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/video/*video_id*
**Response**
JSON response containing video information
@@ -186,7 +188,7 @@ JSON response containing video information
**Request**
Gets a list of unwatched videos
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/unwatched
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/unwatched
**Response**
JSON response containing unwatched video information
@@ -194,7 +196,7 @@ JSON response containing unwatched video information
**Request**
Deletes a video
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/api/v2/video/*video_id*/delete
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/api/v2/video/*video_id*/delete
**Response**
Unknown - not tested
@@ -202,17 +204,17 @@ Unknown - not tested
**Request**
Deletes all videos
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/api/v2/videos/deleteall
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/api/v2/videos/deleteall
**Response**
Unknown - not tested
##Cameras
## Cameras
**Request**
Gets a list of cameras
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/cameras
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/cameras
**Response**
JSON response containing camera information
@@ -220,7 +222,7 @@ JSON response containing camera information
**Request**
Gets information for one camera
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*
**Response**
JSON response containing camera information
@@ -228,7 +230,7 @@ JSON response containing camera information
**Request**
Gets camera sensor information
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/signals
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/signals
**Response**
JSON response containing camera sensor information, such as wifi strength, temperature, and battery level
@@ -236,7 +238,7 @@ JSON response containing camera sensor information, such as wifi strength, tempe
**Request**
Enables motion detection for one camera
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/enable
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/enable
**Response**
JSON response containing camera information
@@ -244,7 +246,7 @@ JSON response containing camera information
**Request**
Disables motion detection for one camera
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/disable
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/disable
**Response**
JSON response containing camera information
@@ -252,12 +254,12 @@ 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.
##Miscellaneous
## Miscellaneous
**Request**
Gets information about devices that have connected to the blink service
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/account/clients
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/account/clients
**Response**
JSON response containing client information, including: type, name, connection time, user ID
@@ -265,7 +267,7 @@ JSON response containing client information, including: type, name, connection t
**Request**
Gets information about supported regions
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/regions
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/regions
**Response**
JSON response containing region information
@@ -273,7 +275,7 @@ JSON response containing region information
**Request**
Gets information about system health
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/health
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/health
**Response**
"all ports tested are open"
@@ -281,7 +283,7 @@ Gets information about system health
**Request**
Gets information about programs
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v1/networks/*network_id*/programs
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v1/networks/*network_id*/programs
**Response**
Unknown.
+359
View File
@@ -0,0 +1,359 @@
=========
Changelog
=========
A list of changes between each release
0.17.0 (2021-02-15)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Bugfixes:**
- Fix video downloading bug (`#424 <https://github.com/fronzbot/blinkpy/pull/424>`__)
- Fix repeated authorization email bug (`#432 <https://github.com/fronzbot/blinkpy/pull/432>`__ and `#428 <https://github.com/fronzbot/blinkpy/pull/428>`__)
**New Features:**
- Add logout method (`#429 <https://github.com/fronzbot/blinkpy/pull/429>`__)
- Add camera record method (`#430 <https://github.com/fronzbot/blinkpy/pull/430>`__)
**Other:**
- Add debug script to main repo to help with general debug
- Upgrade login endpoint from v4 to v5
- Add python 3.9 support
- Bump coverage to 5.4
- Bump pytest to 6.2.2
- Bump pytest-cov to 2.11.1
- Bump pygments to 2.8.0
- Bump pre-commit to 2.10.1
- Bump restructuredtext-lint to 1.3.2
0.16.4 (2020-11-22)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Bugfixes:**
- Updated liveview endpoint (`#389 <https://github.com/fronzbot/blinkpy/pull/389>`__)
- Fixed mini thumbnail not updating (`#388 <https://github.com/fronzbot/blinkpy/pull/388>`__)
- Add exception catch to prevent NoneType error on refresh, added test to check behavior as well (`#401 <https://github.com/fronzbot/blinkpy/pull/401>`__)
- Unrelated: had to add two force methods to refresh for testing purposes. Should not change normal usage.
- Fix malformed stream url (`#395 <https://github.com/fronzbot/blinkpy/pull/395>`__)
**All:**
- Moved testtools to requirements_test.txt (`#387 <https://github.com/fronzbot/blinkpy/pull/387>`__)
- Bumped pytest to 6.1.1
- Bumped flake8 to 3.8.4
- Fixed README spelling ((`#381 <https://github.com/fronzbot/blinkpy/pull/381>`__) via @rohitsud)
- Bumped pygments to 2.7.1
- Bumped coverage to 5.3
- Bumped pydocstyle to 5.1.1
- Bumped pre-commit to 2.7.1
- Bumped pylint to 2.6.0
- Bumped pytest-cov to 2.10.1
0.16.3 (2020-08-02)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Add user-agent to all headers
0.16.2 (2020-08-01)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Add user-agent to header at login
- Remove extra data parameters at login (not-needed)
- Bump pytest to 6.0.1
0.16.1 (2020-07-29)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Unpin requirements, set minimum version instead
- Bump coverage to 5.2.1
- Bump pytest to 6.0.0
0.16.0 (2020-07-20)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Breaking Changes:**
- Add arm property to camera, deprecate motion enable method (`#273 <https://github.com/fronzbot/blinkpy/pull/273>`__)
- Complete refactoring of auth logic (breaks all pre-0.16.0 setups!) (`#261 <https://github.com/fronzbot/blinkpy/pull/261>`__)
**New Features:**
- Add is_errored property to Auth class (`#275 <https://github.com/fronzbot/blinkpy/pull/275>`__)
- Add new endpoint to get user infor (`#280 <https://github.com/fronzbot/blinkpy/pull/280>`__)
- Add get_liveview command to camera module (`#289 <https://github.com/fronzbot/blinkpy/pull/289>`__)
- Add blink Mini Camera support (`#290 <https://github.com/fronzbot/blinkpy/pull/290>`__)
- Add option to skip homescreen check (`#305 <https://github.com/fronzbot/blinkpy/pull/305>`__)
- Add different timeout for video and image retrieval (`#323 <https://github.com/fronzbot/blinkpy/pull/323>`__)
- Modifiy session to use HTTPAdapter and handle retries (`#324 <https://github.com/fronzbot/blinkpy/pull/324>`__)
- Add retry option overrides (`#339 <https://github.com/fronzbot/blinkpy/pull/339>`__)
**All changes:**
Please see the change list in the (`Release Notes <https://github.com/fronzbot/releases/tag/v0.16.0>`__)
0.15.1 (2020-07-11)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Bugfix: remove "Host" from auth header (`#330 <https://github.com/fronzbot/blinkpy/pull/330>`__)
0.15.0 (2020-05-08)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Breaking Changes:**
- Removed support for Python 3.5 (3.6 is now the minimum supported version)
- Deprecated ``Blink.login()`` method. Please only use the ``Blink.start()`` method for logging in.
**New Functions**
- Add ``device_id`` override when logging in (for debug and to differentiate applications) (`#245 <https://github.com/fronzbot/blinkpy/pull/245>`__)
This can be used by instantiating the Blink class with the ``device_id`` parameter.
**All Changes:**
- Fix setup.py use of internal pip structure (`#233 <https://github.com/fronzbot/blinkpy/pull/233>`__)
- Update python-slugify requirement from ~=3.0.2 to ~=4.0.0 (`#234 <https://github.com/fronzbot/blinkpy/pull/234>`__)
- Update python-dateutil requirement from ~=2.8.0 to ~=2.8.1 (`#230 <https://github.com/fronzbot/blinkpy/pull/230>`__)
- Bump requests from 2.22.0 to 2.23.0 (`#231 <https://github.com/fronzbot/blinkpy/pull/231>`__)
- Refactor login logic in preparation for 2FA (`#241 <https://github.com/fronzbot/blinkpy/pull/241>`__)
- Add 2FA Support (`#242 <https://github.com/fronzbot/blinkpy/pull/242>`__) (fixes (`#210 <https://github.com/fronzbot/blinkpy/pull/210>`__))
- Re-set key_required and available variables after setup (`#245 <https://github.com/fronzbot/blinkpy/pull/245>`__)
- Perform system refresh after setup (`#245 <https://github.com/fronzbot/blinkpy/pull/245>`__)
- Fix typos (`#244 <https://github.com/fronzbot/blinkpy/pull/244>`__)
0.14.3 (2020-04-22)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Add time check on recorded videos before determining motion
- Fix motion detection variable suck to ``True``
- Add ability to load credentials from a json file
- Only allow ``motion_detected`` variable to trigger if system was armed
- Log response message from server if not attempting a re-authorization
0.14.2 (2019-10-12)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Update dependencies
- Dockerize `(@3ch01c <https://github.com/fronzbot/blinkpy/pull/198>__)`
0.14.1 (2019-06-20)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix timeout problems blocking blinkpy startup
- Updated login urls using ``rest-region`` subdomain
- Removed deprecated thumbanil recovery from homescreen
0.14.0 (2019-05-23)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Breaking Changes:**
- ``BlinkCamera.battery`` no longer reports a percentage, instead it returns a string representing the state of the battery.
- Previous logic for calculating percentage was incorrect
- raw battery voltage can be accessed via ``BlinkCamera.battery_voltage``
**Bug Fixes:**
- Updated video endpoint (fixes broken motion detection)
- Removed throttling from critical api methods which prevented proper operation of multi-sync unit setups
- Slugify downloaded video names to allow for OS interoperability
- Added one minute offset (``Blink.motion_interval``) when checking for recent motion to allow time for events to propagate to server prior to refresh call.
**Everything else:**
- Changed all urls to use ``rest-region`` rather than ``rest.region``. Ability to revert to old method is enabled by instantiating ``Blink()`` with the ``legacy_subdomain`` variable set to ``True``.
- Added debug mode to ``blinkpy.download_videos`` routine to simply print the videos prepped for download, rather than actually saving them.
- Use UTC for time conversions, rather than local timezone
0.13.1 (2019-03-01)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Remove throttle decorator from network status request
0.13.0 (2019-03-01)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Breaking change:**
Wifi status reported in dBm again, instead of bars (which is great). Also, the old ``get_camera_info`` method has changed and requires a ``camera_id`` parameter.
- Adds throttle decorator
- Decorate following functions with 4s throttle (call method with ``force=True`` to override):
- request_network_status
- request_syncmodule
- request_system_arm
- request_system_disarm
- request_sync_events
- request_new_image
- request_new_video
- request_video_count
- request_cameras
- request_camera_info
- request_camera_sensors
- request_motion_detection_enable
- request_motion_detection_disable
- Use the updated homescreen api endpoint to retrieve camera information. The old method to retrieve all cameras at once seems to not exist, and this was the only solution I could figure out and confirm to work.
- Adds throttle decorator to refresh function to prevent too many frequent calls with ``force_cache`` flag set to ``True``. This additional throttle can be overridden with the ``force=True`` argument passed to the refresh function.
- Add ability to cycle through login api endpoints to anticipate future endpoint deprecation
0.12.1 (2019-01-31)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Remove logging improvements since they were incompatible with home-assistant logging
0.12.0 (2019-01-31)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix video api endpoint, re-enables motion detection
- Add improved logging capability
- Add download video method
- Prevent blinkpy from failing at setup due to api error
0.11.2 (2019-01-23)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Hotfix to prevent platform from stalling due to API change
- Motion detection and video recovery broken until new API endpoint discovered
0.11.1 (2019-01-02)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fixed incorrect backup login url
- Added calibrated temperature property for cameras
0.11.0 (2018-11-23)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Added support for multiple sync modules
0.10.3 (2018-11-18)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Use networks endpoint rather than homecreen to retrieve arm/disarm status (`@md-reddevil <https://github.com/fronzbot/blinkpy/pull/119>`__)
- Fix incorrect command status endpoint (`@md-reddevil <https://github.com/fronzbot/blinkpy/pull/118>`__)
- Add extra debug logging
- Remove error prior to re-authorization (only log error when re-auth failed)
0.10.2 (2018-10-30)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Set minimum required version of the requests library to 2.20.0 due to vulnerability in earlier releases.
- When multiple networks detected, changed log level to ``warning`` from ``error``
0.10.1 (2018-10-18)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix re-authorization bug (fixes `#101 <https://github.com/fronzbot/blinkpy/issues/#101>`__)
- Log an error if saving video that doesn't exist
0.10.0 (2018-10-16)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Moved all API calls to own module for easier maintainability
- Added network ids to sync module and cameras to allow for multi-network use
- Removed dependency on video existance prior to camera setup (fixes `#93 <https://github.com/fronzbot/blinkpy/issues/#93>`__)
- Camera wifi_strength now reported in wifi "bars" rather than dBm due to API endpoint change
- Use homescreen thumbnail as fallback in case it's not in the camera endpoint
- Removed "armed" and "status" attributes from camera (status of camera only reported by "motion_enabled" now)
- Added serial number attributes to sync module and cameras
- Check network_id from login response and verify that network is onboarded (fixes `#90 <https://github.com/fronzbot/#90>`__)
- Check if retrieved clip is "None" prior to storing in cache
0.9.0 (2018-09-27)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Complete code refactoring to enable future multi-sync module support
- Add image and video caching to the cameras
- Add internal throttling of system refresh
- Use session for http requests
**Breaking change:**
- Cameras now accessed through sync module ``Blink.sync.cameras``
0.8.1 (2018-09-24)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Update requirements_test.txt
- Update linter versions
- Fix pylint warnings
- Remove object from class declarations
- Remove useless returns from functions
- Fix pylint errors
- change if comparison to fix (consider-using-in)
- Disabled no else-if-return check
- Fix useless-import-alias
- Disable no-else-return
- Fix motion detection
- Use an array of recent video clips to determine if motion has been detected.
- Reset the value every system refresh
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
- Changed Blink.cameras dictionary to be case-insensitive (fixes `#35 <https://github.com/fronzbot/blinkpy/issues/35>`__)
- Changed api endpoint for video extraction (fixes `#35 <https://github.com/fronzbot/blinkpy/issues/35>`__ and `#41 <https://github.com/fronzbot/blinkpy/issues/41>`__)
- Removed last_motion() function from Blink class
- Refactored code for better organization
- Moved some request calls out of @property methods (enables future CLI support)
- Renamed get_summary() method to summary and changed to @property
- Added ability to download most recent video clip
- Improved camera arm/disarm handling (`@b10m <https://github.com/fronzbot/blinkpy/pull/50>`__)
- Added authentication to ``login()`` function and deprecated ``setup_system()`` in favor of ``start()``
- Added ``attributes`` dictionary to camera object
0.6.0 (2017-05-12)
~~~~~~~~~~~~~~~~~~
- 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!)
- Added auto-reauthorization (token refresh) when a request fails due to an expired token (`@tySwift93 <https://github.com/fronzbot/blinkpy/pull/24>`__)
- Added battery level string to reduce confusion with the way Blink reports battery level as integer from 0 to 3
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
-83
View File
@@ -1,83 +0,0 @@
# Contributing to blinkpy
Everyone is welcome to contribute to blinkpy! The process to get started is described below.
## Fork the Repository
You can do this right in gituhb: just click the 'fork' button at the top right.
## Setup Local Repository
```shell
$ git clone https://github.com/<YOUR_GIT_USERNAME>/blinkpy.git
$ cd blinkpy
$ git remote add upstream https://github.com/fronzbot/blinkpy.git
```
## Create a Local Branch
First, you will want to create a new branch to hold your changes:
``git checkout -b <your-branch-name>``
Next, you need to make sure you pull from the 'dev' branch:
``git pull origin dev``
## Make changes
Now you can make changes to your code. It is worthwhile to test your code as you progress (see the **Testing** section)
## Commit Your Changes
To commit changes to your branch, simply add the files you want and the commit them to the branch. After that, you can push to your fork on GitHub:
```shell
$ git add .
$ git commit -m "Put your commit text here. Please be concise, but descriptive."
$ git push origin HEAD
```
## Testing
It is important to test the code to make sure your changes don't break anything major and that they pass PEP8 style conventions.
FIrst, you need to locally install ``tox``
```shell
$ pip3 install tox
```
You can then run all of the tests with the following command:
```shell
$ tox
```
### Tips
If you only want to see if you can pass the local tests, you can run ``tox -e py34``. If you just want to check for style violations, you can run ``tox -e lint``. Regardless, when you submit a pull request, your code MUST pass both the unit tests, and the linters.
If you need to change anything in ``requirements.txt`` for any reason, you'll want to regenerate the virtual envrionments used by ``tox`` by running with the ``-r`` flag: ``tox -r``
Please do not locally disable any linter warnings within the ``blinkpy.py`` module itself (it's ok to do this in any of the ``test_*.py`` files)
# Catching Up With Reality
If your code is taking a while to develop, you may be behind the ``dev`` branch, in which case you need to catch up before creating your pull-request. To do this you can run ``git rebase`` as follows (running this on your local branch):
```shell
$ git fetch upstream dev
$ git rebase upstream/dev
```
If rebase detects conflicts, repeat the following process until all changes have been resolved:
1. ``git status`` shows you the filw with a conflict. You will need to edit that file and resolve the lines between ``<<<< | >>>>`.
2. Add the modified file: ``git add <file>`` or ``git add .``.
3. Continue rebase: ``git rebase --continue``.
4. Repeat until all conflicts resolved.
# Creating a Pull Request
Please follow these steps to create a pull request against the ``dev`` branch: [Creating a Pull Request](https://help.github.com/articles/creating-a-pull-request/)
# Monitor Build Status
Once you create your PR, you can monitor the status of your build [here](https://travis-ci.org/fronzbot/blinkpy), Your code will be tested to ensure it passes and won't cause any problems after merging.
+109
View File
@@ -0,0 +1,109 @@
========================
Contributing to blinkpy
========================
Everyone is welcome to contribute to blinkpy! The process to get started is described below.
Fork the Repository
-------------------
You can do this right in github: just click the 'fork' button at the top right.
Start Developing
-----------------
1. Setup Local Repository
.. code:: bash
$ git clone https://github.com/<YOUR_GIT_USERNAME>/blinkpy.git
$ cd blinkpy
$ git remote add upstream https://github.com/fronzbot/blinkpy.git
2. Create virtualenv and install dependencies
.. code:: bash
$ python -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
$ pip install -r requirements_test.txt
$ pre-commit install
3. Create a Local Branch
First, you will want to create a new branch to hold your changes:
``git checkout -b <your-branch-name>``
4. Make changes
Now you can make changes to your code. It is worthwhile to test your code as you progress (see the **Testing** section)
5. Commit Your Changes
To commit changes to your branch, simply add the files you want and the commit them to the branch. After that, you can push to your fork on GitHub:
.. code:: bash
$ git add .
$ git commit
$ git push origin HEAD
6. Submit your pull request on GitHub
- On GitHub, navigate to the `blinkpy <https://github.com/fronzbot/blinkpy>`__ repository.
- In the "Branch" menu, choose the branch that contains your commits (from your fork).
- To the right of the Branch menu, click New pull request.
- The base branch dropdown menu should read ``dev``. Use the compare branch drop-down menu to choose the branch you made your changes in.
- Type a title and complete the provided description for your pull request.
- Click Create pull request.
- More detailed instructions can be found here: `Creating a Pull Request` <https://help.github.com/articles/creating-a-pull-request>`__
7. Prior to merge approval
Finally, the ``blinkpy`` repository uses continuous integration tools to run tests prior to merging. If there are any problems, you will see a red 'X' next to your pull request.
Testing
-------
It is important to test the code to make sure your changes don't break anything major and that they pass PEP8 style conventions.
First, you need to locally install ``tox``
.. code:: bash
$ pip install tox
You can then run all of the tests with the following command:
.. code:: bash
$ tox
**Tips**
If you only want to see if you can pass the local tests, you can run ``tox -e py37`` (or whatever python version you have installed. Only ``py36``, ``py37``, and ``py38`` will be accepted). If you just want to check for style violations, you can run ``tox -e lint``. Regardless, when you submit a pull request, your code MUST pass both the unit tests, and the linters.
If you need to change anything in ``requirements.txt`` for any reason, you'll want to regenerate the virtual envrionments used by ``tox`` by running with the ``-r`` flag: ``tox -r``
If you want to run a single test (perhaps you only changed a small thing in one file) you can run ``tox -e py37 -- tests/<testname>.py -x``. This will run the test ``<testname>.py`` and stop testing upon the first failure, making it easier to figure out why a particular test might be failing. The test structure mimics the library structure, so if you changed something in ``sync_module.py``, the associated test file would be in ``test_sync_module.py`` (ie. the filename is prepended with ``test_``.
Catching Up With Reality
-------------------------
If your code is taking a while to develop, you may be behind the ``dev`` branch, in which case you need to catch up before creating your pull-request. To do this you can run ``git rebase`` as follows (running this on your local branch):
.. code:: bash
$ git fetch upstream dev
$ git rebase upstream/dev
If rebase detects conflicts, repeat the following process until all changes have been resolved:
1. ``git status`` shows you the filw with a conflict. You will need to edit that file and resolve the lines between ``<<<< | >>>>``.
2. Add the modified file: ``git add <file>`` or ``git add .``.
3. Continue rebase: ``git rebase --continue``.
4. Repeat until all conflicts resolved.
+12
View File
@@ -0,0 +1,12 @@
FROM python:3.7-alpine
LABEL maintainer="Kevin Fronczak <kfronczak@gmail.com>"
VOLUME /media
RUN python -m pip install --upgrade pip
RUN pip3 install blinkpy
COPY app/ .
ENTRYPOINT ["python", "./app.py"]
CMD []
-1
View File
@@ -2,4 +2,3 @@ include README.rst
include LICENSE.md
include API.md
include tests/*.py
include helpers/*.py
+153 -83
View File
@@ -1,9 +1,12 @@
blinkpy |Build Status| |Coverage Status|
============
A Python library for the Blink Camera system
blinkpy |Build Status| |Coverage Status| |Docs| |PyPi Version| |Codestyle|
=============================================================================================
A Python library for the Blink Camera system (Python 3.6+)
Disclaimer:
~~~~~~~~~~~~~~~
Like the library? Consider buying me a cup of coffee!
`Buy me a Coffee! <https://buymeacoffee.com/kevinfronczak>`__
**Disclaimer:**
Published under the MIT license - See LICENSE file for more details.
"Blink Wire-Free HS Home Monitoring & Alert Systems" is a trademark owned by Immedia Inc., see www.blinkforhome.com for more information.
@@ -14,112 +17,179 @@ Original protocol hacking by MattTW : https://github.com/MattTW/BlinkMonitorProt
API calls faster than 60 seconds is not recommended as it can overwhelm Blink's servers. Please use this module responsibly.
Installation
================
``pip3 install blinkpy``
-------------
``pip install blinkpy``
Installing Development Version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To install the current development version, perform the following steps. Note that the following will create a blinkpy directory in your home area:
.. code:: bash
$ cd ~
$ git clone https://github.com/fronzbot/blinkpy.git
$ cd blinkpy
$ rm -rf build dist
$ python3 setup.py bdist_wheel
$ pip3 install --upgrade dist/*.whl
If you'd like to contribute to this library, please read the `contributing instructions <https://github.com/fronzbot/blinkpy/blob/dev/CONTRIBUTING.rst>`__.
For more information on how to use this library, please `read the docs <https://blinkpy.readthedocs.io/en/latest/>`__.
Purpose
===========
This library was built with the intention of allowing easy communication with Blink camera systems, specifically so I can add a module into homeassistant https://home-assistant.io
-------
This library was built with the intention of allowing easy communication with Blink camera systems, specifically to support the `Blink component <https://home-assistant.io/components/blink>`__ in `homeassistant <https://home-assistant.io/>`__.
Usage
=========
In terms of usage, you just need to instantiate the module with a username and password
Quick Start
=============
The simplest way to use this package from a terminal is to call ``Blink.start()`` which will prompt for your Blink username and password and then log you in. In addition, http requests are throttled internally via use of the ``Blink.refresh_rate`` variable, which can be set at initialization and defaults to 30 seconds.
.. code:: python
import blinkpy
blink = blinkpy.Blink(username='YOUR USER NAME', password='YOUR PASSWORD')
from blinkpy.blinkpy import Blink
blink = Blink()
blink.start()
If you leave out either of those parameters, you need to call the login function which will prompt for your username and password
This flow will prompt you for your username and password. Once entered, if you likely will need to send a 2FA key to the blink servers (this pin is sent to your email address). When you receive this pin, enter at the prompt and the Blink library will proceed with setup.
Starting blink without a prompt
-------------------------------
In some cases, having an interactive command-line session is not desired. In this case, you will need to set the ``Blink.auth.no_prompt`` value to ``True``. In addition, since you will not be prompted with a username and password, you must supply the login data to the blink authentication handler. This is best done by instantiating your own auth handler with a dictionary containing at least your username and password.
.. code:: python
import blinkpy
blink = blinkpy.Blink()
blink.login()
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
blink = Blink()
# Can set no_prompt when initializing auth handler
auth = Auth({"username": <your username>, "password": <your password>}, no_prompt=True)
blink.auth = auth
blink.start()
Once the login information is entered, you can run the `setup_system()` function which will attempt to authenticate with Blink servers using your username and password, obtain network ids, and create a list of cameras.
The cameras are of a BlinkCamera class, of which the following parameters can be used (the code below creates a Blink object and iterates through each camera found)
Since you will not be prompted for any 2FA pin, you must call the ``blink.auth.send_auth_key`` function. There are two required parameters: the ``blink`` object as well as the ``key`` you received from Blink for 2FA:
.. code:: python
import blinkpy
auth.send_auth_key(blink, <your key>)
blink.setup_post_verify()
Supplying credentials from file
--------------------------------
Other use cases may involved loading credentials from a file. This file must be ``json`` formatted and contain a minimum of ``username`` and ``password``. A built in function in the ``blinkpy.helpers.util`` module can aid in loading this file. Note, if ``no_prompt`` is desired, a similar flow can be followed as above.
.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
from blinkpy.helpers.util import json_load
blink = Blink()
auth = Auth(json_load("<File Location>"))
blink.auth = auth
blink.start()
Saving credentials
-------------------
This library also allows you to save your credentials to use in future sessions. Saved information includes authentication tokens as well as unique ids which should allow for a more streamlined experience and limits the frequency of login requests. This data can be saved as follows (it can then be loaded by following the instructions above for supplying credentials from a file):
.. code:: python
blink.save("<File location>")
Getting cameras
----------------
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).
The below code will display cameras and their available attributes:
.. code:: python
for name, camera in blink.cameras.items():
print(name) # Name of the camera
print(camera.attributes) # Print available attributes of camera
The most recent images and videos can be accessed as a bytes-object via internal variables. These can be updated with calls to ``Blink.refresh()`` but will only make a request if motion has been detected or other changes have been found. This can be overridden with the ``force`` flag, but this should be used for debugging only since it overrides the internal request throttling.
.. code:: python
blink = blinkpy.Blink(username='YOUR USER NAME', password='YOUR PASSWORD')
blink.setup_system()
for camera in blink.cameras:
print(camera.name) # Name of the camera
print(camera.id) # Integer id of the camera (assigned by Blink)
print(camera.armed) # Whether the device is armed/disarmed (ie. detecting motion)
print(camera.clip) # Link to last motion clip captured
print(camera.thumbnail) # Link to current camera thumbnail
print(camera.temperature) # Current camera temperature (not super accurate, but might be useful for someone)
print(camera.battery) # Current battery level... I think the value ranges from 0-3, but not quite sure yet.
print(camera.notifications) # Number of unread notifications (ie. motion alerts that haven't been viewed)
print(camera.motion) # Dictionary containing values for keys ['video', 'image', 'time']
# which correspond to last motion recorded, thumbnail of last motion, and timestamp of last motion
camera = blink.cameras['SOME CAMERA NAME']
blink.refresh(force=True) # force a cache update USE WITH CAUTION
camera.image_from_cache.raw # bytes-like image object (jpg)
camera.video_from_cache.raw # bytes-like video object (mp4)
Class Descriptions
===================
.. code:: python
class Blink()
* ``Blink.cameras`` Returns a dictionary of ``BlinkCamera`` objects where the key corresponds to the camera name and the value is the actual BlinkCamera object.
* ``Blink.network_id`` Returns the current network id.
* ``Blink.account_id`` Returns the account id.
* ``Blink.events`` Returns a list of events recorded by blink. This information will contain links to any motion caught by an armed camera..
* ``Blink.online`` Returns online status of sync module (True = online, False = offline).
* ``Blink.last_motion()`` Finds last motion information for each camera and stores it in the ``BlinkCamera.motion`` field.
* ``Blink.arm`` Set to True to arm, False to disarm. Can be used to see the status of the system as well.
* ``Blink.refresh()`` Forces a refresh of all camera information.
* ``Blink.get_summary()`` Returns json formatted summary of the system.
* ``Blink.get_cameras()`` Finds all cameras in the system and creates ``BlinkCamera`` objects to represent them.
* ``Blink.set_links()`` Gives each BlinkCamera object the links needed to find recent images and videos.
* ``Blink.login()`` Prompts user for login information.
* ``Blink.get_auth_token()`` Uses login information to retrieve authorization token from Blink for further communication.
* ``Blink.get_ids()`` Retrieves the network_id and account_id from Blink in order to access video and image pages on their server.
* ``Blink.setup_system()`` A wrapper script that calls:
.. code:: python
Blink.get_auth_token()
Blink.get_ids()
Blink.get_camers()
Blink.set_links()
The ``blinkpy`` api also allows for saving images and videos to a file and snapping a new picture from the camera remotely:
.. code:: python
class BlinkCamera(config, urls)
The ``BlinkCamera`` class expects to receive:
camera = blink.cameras['SOME CAMERA NAME']
camera.snap_picture() # Take a new picture with the camera
blink.refresh() # Get new information from server
camera.image_to_file('/local/path/for/image.jpg')
camera.video_to_file('/local/path/for/video.mp4')
* A dictionary ``config`` that contains the camera name, device id, armed status, thumbnail url, camera temperature, camery battery level, number of notifications, and region id
* A ``BlinkURLHandler`` object that contains all the links necessary for communication.
Ultimately, this class is just a wrapper for each individual camera in order to make communication with individual cameras less clunky. The following properties/methods are availiable (in addition to the ones mentioned earlier):
* ``BlinkCamera.snap_picture()`` Takes an image with the camera and saves it as the new thumbnail. The ``Blink.refresh()`` method should be called after this if you want to store the new thumbnail link.
* ``BlinkCamera.set_motion_detect(enable=True/False)`` Sending True to this function will enable motion detection for the camera. Setting to False will disable motion detection.
* ``BlinkCamera.image_to_file(path)`` This will write the current thumbnail to the location indicated in 'path'
* ``BlinkCamera.image_refresh()`` Refreshes the current thumbnail.
Arming Blink
-------------
Methods exist to arm/disarm the sync module, as well as enable/disable motion detection for individual cameras. This is done as follows:
.. code:: python
class BlinkURLHandler(region_id)
The ``BlinkURLHandler`` class expects to be initialized with the region id found in the ``Blink.get_auth_token()`` function. The class will then create the necessary links required for various communication.
.. |Build Status| image:: https://travis-ci.org/fronzbot/blinkpy.svg?branch=master
:target: https://travis-ci.org/fronzbot/blinkpy
.. |Coverage Status| image:: https://coveralls.io/repos/github/fronzbot/blinkpy/badge.svg?branch=master
:target: https://coveralls.io/r/fronzbot/blinkpy?branch=master
# Arm a sync module
blink.sync["SYNC MODULE NAME"].arm = True
# Disarm a sync module
blink.sync["SYNC MODULE NAME"].disarm = False
# Print arm status of a sync module - a system refresh should be performed first
blink.refresh()
sync = blink.sync["SYNC MODULE NAME"]
print(f"{sync.name} status: {sync.arm}")
Similar methods exist for individual cameras:
.. code:: python
camera = blink.cameras["SOME CAMERA NAME"]
# Enable motion detection on a camera
camera.arm = True
# Disable motion detection on a camera
camera.arm = False
# Print arm status of a sync module - a system refresh should be performed first
blink.refresh()
print(f"{camera.name} status: {camera.arm}")
Download videos
----------------
You can also use this library to download all videos from the server. In order to do this, you must specify a ``path``. You may also specifiy a how far back in time to go to retrieve videos via the ``since=`` variable (a simple string such as ``"2017/09/21"`` is sufficient), as well as how many pages to traverse via the ``stop=`` variable. Note that by default, the library will search the first ten pages which is sufficient in most use cases. Additionally, you can specify one or more cameras via the ``camera=`` property. This can be a single string indicating the name of the camera, or a list of camera names. By default, it is set to the string ``'all'`` to grab videos from all cameras.
Example usage, which downloads all videos recorded since July 4th, 2018 at 9:34am to the ``/home/blink`` directory:
.. code:: python
blink.download_videos('/home/blink', since='2018/07/04 09:34')
.. |Build Status| image:: https://github.com/fronzbot/blinkpy/workflows/build/badge.svg
:target: https://github.com/fronzbot/blinkpy/actions?query=workflow%3Abuild
.. |Coverage Status| image:: https://codecov.io/gh/fronzbot/blinkpy/branch/dev/graph/badge.svg
:target: https://codecov.io/gh/fronzbot/blinkpy
.. |PyPi Version| image:: https://img.shields.io/pypi/v/blinkpy.svg
:target: https://pypi.python.org/pypi/blinkpy
.. |Docs| image:: https://readthedocs.org/projects/blinkpy/badge/?version=latest
:target: http://blinkpy.readthedocs.io/en/latest/?badge=latest
.. |Codestyle| image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
-5
View File
@@ -1,5 +0,0 @@
"""Init file for blinkpy."""
from blinkpy.blinkpy import Blink
from blinkpy.blinkpy import BlinkAuthenticationException
from blinkpy.blinkpy import BlinkException
from blinkpy.blinkpy import BlinkURLHandler
+1
View File
@@ -0,0 +1 @@
"""Python init file for app.py."""
+39
View File
@@ -0,0 +1,39 @@
"""Script to run blinkpy as an app."""
from os import environ
from datetime import datetime, timedelta
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
from blinkpy.helpers.util import json_load
CREDFILE = environ.get("CREDFILE")
TIMEDELTA = timedelta(environ.get("TIMEDELTA", 1))
def get_date():
"""Return now - timedelta for blinkpy."""
return (datetime.now() - TIMEDELTA).isoformat()
def download_videos(blink, save_dir="/media"):
"""Make request to download videos."""
blink.download_videos(save_dir, since=get_date())
def start():
"""Startup blink app."""
blink = Blink()
blink.auth = Auth(json_load(CREDFILE))
blink.start()
return blink
def main():
"""Run the app."""
blink = start()
download_videos(blink)
blink.save(CREDFILE)
if __name__ == "__main__":
main()
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
docker build -t fronzbot/blinkpy:latest ./
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# bash run.sh [username] [password]
if [ "$#" -ne 2 ]; then
echo ""
echo "ERROR: Requries Blink username and password as arguments."
echo "bash run.sh [username] [password]"
echo ""
exit 1
fi
set -ex
USER=fronzbot
IMAGE=blinkpy
CONFIG=$HOME/blinkpy_media
USERNAME=$1
PASSWORD=$2
mkdir -p $CONFIG
result=$(docker images -q $IMAGE)
if [ $result ]; then
docker rm $IMAGE
fi
docker run -it --name ${IMAGE} \
-v $CONFIG:/media \
-e USERNAME=${USERNAME} \
-e PASSWORD=${PASSWORD} \
$USER/$IMAGE \
/bin/bash
-476
View File
@@ -1,476 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
blinkpy by Kevin Fronczak - A Blink camera Python library.
https://github.com/fronzbot/blinkpy
Original protocol hacking by MattTW :
https://github.com/MattTW/BlinkMonitorProtocol
Published under the MIT license - See LICENSE file for more details.
"Blink Wire-Free HS Home Monitoring & Alert Systems" is a trademark
owned by Immedia Inc., see www.blinkforhome.com for more information.
I am in no way affiliated with Blink, nor Immedia Inc.
"""
import json
import getpass
from shutil import copyfileobj
import requests
import helpers.errors as ERROR
from helpers.constants import (BLINK_URL, LOGIN_URL,
LOGIN_BACKUP_URL,
DEFAULT_URL, ONLINE)
def _request(url, data=None, headers=None, reqtype='get',
stream=False, json_resp=True):
"""Wrapper function for request."""
if reqtype is 'post' and json_resp:
response = requests.post(url, headers=headers,
data=data).json()
elif reqtype is 'post' and not json_resp:
response = requests.post(url, headers=headers,
data=data)
elif reqtype is 'get' and json_resp:
response = requests.get(url, headers=headers,
stream=stream).json()
elif reqtype is 'get' and not json_resp:
response = requests.get(url, headers=headers,
stream=stream)
else:
raise BlinkException(ERROR.REQUEST)
if json_resp and 'code' in response:
raise BlinkAuthenticationException(
(response['code'], response['message']))
return response
# pylint: disable=super-init-not-called
class BlinkException(Exception):
"""Class to throw general blink exception."""
def __init__(self, errcode):
"""Initialize BlinkException."""
self.errid = errcode[0]
self.message = errcode[1]
class BlinkAuthenticationException(BlinkException):
"""Class to throw authentication exception."""
pass
class BlinkURLHandler(object):
"""Class that handles Blink URLS."""
def __init__(self, region_id):
"""Initialize the urls."""
self.base_url = 'https://' + region_id + '.' + BLINK_URL
self.home_url = self.base_url + '/homescreen'
self.event_url = self.base_url + '/events/network/'
self.network_url = self.base_url + '/network/'
self.networks_url = self.base_url + '/networks'
class BlinkCamera(object):
"""Class to initialize individual camera."""
def __init__(self, config, urls):
"""Initiailize BlinkCamera."""
self.urls = urls
self._id = str(config['device_id'])
self._name = config['name']
self._status = config['armed']
self._thumb = self.urls.base_url + config['thumbnail'] + '.jpg'
self._clip = self.urls.base_url + config['thumbnail'] + '.mp4'
self._temperature = config['temp']
self._battery = config['battery']
self._notifications = config['notifications']
self._motion = {}
self._header = None
self._image_link = None
self._arm_link = None
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
def armed(self):
"""Return camera arm 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):
"""Take a picture with camera to create a new thumbnail."""
_request(self._image_link, headers=self._header, reqtype='post')
def set_motion_detect(self, enable):
"""Set motion detection."""
url = self._arm_link
if enable:
_request(url + 'enable', headers=self._header, reqtype='post')
else:
_request(url + 'disable', headers=self._header, reqtype='post')
def update(self, values):
"""Update camera information."""
self._name = values['name']
self._status = values['armed']
self._thumb = self.urls.base_url + values['thumbnail'] + '.jpg'
self._clip = self.urls.base_url + values['thumbnail'] + '.mp4'
self._temperature = values['temp']
self._battery = values['battery']
self._notifications = values['notifications']
def image_refresh(self):
"""Refresh current thumbnail."""
url = self.urls.home_url
response = _request(url, headers=self._header,
reqtype='get')['devices']
for element in response:
try:
if str(element['device_id']) == self._id:
self._thumb = (self.urls.base_url +
element['thumbnail'] + '.jpg')
return self._thumb
except KeyError:
pass
return None
def image_to_file(self, path):
"""Write image to file."""
thumb = self.image_refresh()
response = _request(thumb, headers=self._header,
reqtype='get', stream=True, json_resp=False)
if response.status_code == 200:
with open(path, 'wb') as imgfile:
copyfileobj(response.raw, imgfile)
class Blink(object):
"""Class to initialize communication and sync module."""
def __init__(self, username=None, password=None):
"""Initialize Blink system."""
self._username = username
self._password = password
self._token = None
self._auth_header = None
self._network_id = None
self._account_id = None
self._region = None
self._region_id = None
self._host = None
self._events = []
self._cameras = {}
self._idlookup = {}
self.urls = None
@property
def cameras(self):
"""Return camera/id pairs."""
return self._cameras
@property
def camera_thumbs(self):
"""Return camera thumbnails."""
self.refresh()
data = {}
for name, camera in self._cameras.items():
data[name] = camera.thumbnail
return data
@property
def id_table(self):
"""Return id/camera pairs."""
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
def events(self):
"""Get all events on server."""
url = self.urls.event_url + self._network_id
headers = self._auth_header
self._events = _request(url, headers=headers,
reqtype='get')['event']
return self._events
@property
def online(self):
"""Return boolean system online status."""
url = self.urls.network_url + self._network_id + '/syncmodules'
headers = self._auth_header
return ONLINE[_request(url, headers=headers,
reqtype='get')['syncmodule']['status']]
def last_motion(self):
"""Find last motion of each camera."""
recent = self.events
for element in recent:
try:
camera_id = str(element['camera_id'])
camera_name = self._idlookup[camera_id]
camera = self._cameras[camera_name]
if element['type'] == 'motion':
url = self.urls.base_url + element['video_url']
camera.motion = {'video': url,
'image': url[:-3] + 'jpg',
'time': element['created_at']}
except KeyError:
pass
@property
def arm(self):
"""Return status of sync module: armed/disarmed."""
return self.get_summary()['network']['armed']
@arm.setter
def arm(self, value):
"""Arm or disarm system."""
if value:
value_to_append = 'arm'
else:
value_to_append = 'disarm'
url = self.urls.network_url + self._network_id + '/' + value_to_append
_request(url, headers=self._auth_header, reqtype='post')
def refresh(self):
"""Get all blink cameras and pulls their most recent status."""
response = self.get_summary()['devices']
for name in self._cameras:
camera = self._cameras[name]
for element in response:
try:
if str(element['device_id']) == camera.id:
camera.update(element)
except KeyError:
pass
def get_summary(self):
"""Get a full summary of device information."""
url = self.urls.home_url
headers = self._auth_header
if self._auth_header is None:
raise BlinkException(ERROR.AUTH_TOKEN)
return _request(url, headers=headers, reqtype='get')
def get_cameras(self):
"""Find and creates cameras."""
response = self.get_summary()['devices']
for element in response:
if ('device_type' in element and
element['device_type'] == 'camera'):
# Add region to config
element['region_id'] = self._region_id
device = BlinkCamera(element, self.urls)
self._cameras[device.name] = device
self._idlookup[device.id] = device.name
def set_links(self):
"""Set access links and required headers for each camera in system."""
for name in self._cameras:
camera = self._cameras[name]
network_id_url = self.urls.network_url + self._network_id
image_url = network_id_url + '/camera/' + camera.id + '/thumbnail'
arm_url = network_id_url + '/camera/' + camera.id + '/'
camera.image_link = image_url
camera.arm_link = arm_url
camera.header = self._auth_header
def setup_system(self):
"""
Wrapper for various setup functions.
Method logs in and sets auth token, urls, and ids for future requests.
"""
if self._username is None or self._password is None:
raise BlinkAuthenticationException(ERROR.AUTHENTICATE)
self.get_auth_token()
self.get_ids()
self.get_cameras()
self.set_links()
def login(self):
"""Prompt user for username and password."""
self._username = input("Username:")
self._password = getpass.getpass("Password:")
def get_auth_token(self):
"""Retrieve the authentication token from Blink."""
if not isinstance(self._username, str):
raise BlinkAuthenticationException(ERROR.USERNAME)
if not isinstance(self._password, str):
raise BlinkAuthenticationException(ERROR.PASSWORD)
headers = {'Host': DEFAULT_URL,
'Content-Type': 'application/json'}
data = json.dumps({
"email": self._username,
"password": self._password,
"client_specifier": "iPhone 9.2 | 2.2 | 222"
})
response = _request(LOGIN_URL, headers=headers,
data=data, json_resp=False, reqtype='post')
if response.status_code is 200:
response = response.json()
(self._region_id, self._region), = response['region'].items()
else:
response = _request(LOGIN_BACKUP_URL, headers=headers,
data=data, reqtype='post')
self._region_id = 'rest.piri'
self._region = "UNKNOWN"
self._host = self._region_id + '.' + BLINK_URL
self._token = response['authtoken']['authtoken']
self._auth_header = {'Host': self._host,
'TOKEN_AUTH': self._token}
self.urls = BlinkURLHandler(self._region_id)
def get_ids(self):
"""Set the network ID and Account ID."""
url = self.urls.networks_url
headers = self._auth_header
if self._auth_header is None:
raise BlinkException(ERROR.AUTH_TOKEN)
response = _request(url, headers=headers, reqtype='get')
self._network_id = str(response['networks'][0]['id'])
self._account_id = str(response['networks'][0]['account_id'])
+1
View File
@@ -0,0 +1 @@
"""Init file for blinkpy."""
+322
View File
@@ -0,0 +1,322 @@
"""Implements known blink API calls."""
import logging
from json import dumps
from blinkpy.helpers.util import get_time, Throttle
from blinkpy.helpers.constants import DEFAULT_URL, TIMEOUT, DEFAULT_USER_AGENT
_LOGGER = logging.getLogger(__name__)
MIN_THROTTLE_TIME = 5
def request_login(
auth, url, login_data, is_retry=False,
):
"""
Login request.
:param auth: Auth instance.
:param url: Login url.
:login_data: Dictionary containing blink login data.
"""
headers = {
"Host": DEFAULT_URL,
"Content-Type": "application/json",
"user-agent": DEFAULT_USER_AGENT,
}
data = dumps(
{
"email": login_data["username"],
"password": login_data["password"],
"unique_id": login_data["uid"],
"device_identifier": login_data["device_id"],
"client_name": "Computer",
"reauth": True,
}
)
return auth.query(
url=url,
headers=headers,
data=data,
json_resp=False,
reqtype="post",
is_retry=is_retry,
)
def request_verify(auth, blink, verify_key):
"""Send verification key to blink servers."""
url = f"{blink.urls.base_url}/api/v4/account/{blink.account_id}/client/{blink.client_id}/pin/verify"
data = dumps({"pin": verify_key})
return auth.query(
url=url, headers=auth.header, data=data, json_resp=False, reqtype="post",
)
def request_logout(blink):
"""Logout of blink servers."""
url = f"{blink.urls.base_url}/api/v4/account/{blink.account_id}/client/{blink.client_id}/logout"
return http_post(blink, url=url)
def request_networks(blink):
"""Request all networks information."""
url = f"{blink.urls.base_url}/networks"
return http_get(blink, url)
def request_network_update(blink, network):
"""
Request network update.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}/update"
return http_post(blink, url)
def request_user(blink):
"""Get user information from blink servers."""
url = f"{blink.urls.base_url}/user"
return http_get(blink, url)
def request_network_status(blink, network):
"""
Request network information.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}"
return http_get(blink, url)
def request_syncmodule(blink, network):
"""
Request sync module info.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}/syncmodules"
return http_get(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_system_arm(blink, network):
"""
Arm system.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/api/v1/accounts/{blink.account_id}/networks/{network}/state/arm"
return http_post(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_system_disarm(blink, network):
"""
Disarm system.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/api/v1/accounts/{blink.account_id}/networks/{network}/state/disarm"
return http_post(blink, url)
def request_command_status(blink, network, command_id):
"""
Request command status.
:param blink: Blink instance.
:param network: Sync module network id.
:param command_id: Command id to check.
"""
url = f"{blink.urls.base_url}/network/{network}/command/{command_id}"
return http_get(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_homescreen(blink):
"""Request homescreen info."""
url = f"{blink.urls.base_url}/api/v3/accounts/{blink.account_id}/homescreen"
return http_get(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_sync_events(blink, network):
"""
Request events from sync module.
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/events/network/{network}"
return http_get(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_new_image(blink, network, camera_id):
"""
Request to capture new thumbnail for camera.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request new image from.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/thumbnail"
return http_post(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_new_video(blink, network, camera_id):
"""
Request to capture new video clip.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request new video from.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/clip"
return http_post(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_video_count(blink):
"""Request total video count."""
url = f"{blink.urls.base_url}/api/v2/videos/count"
return http_get(blink, url)
def request_videos(blink, time=None, page=0):
"""
Perform a request for videos.
:param blink: Blink instance.
:param time: Get videos since this time. In epoch seconds.
:param page: Page number to get videos from.
"""
timestamp = get_time(time)
url = f"{blink.urls.base_url}/api/v1/accounts/{blink.account_id}/media/changed?since={timestamp}&page={page}"
return http_get(blink, url)
def request_cameras(blink, network):
"""
Request all camera information.
:param Blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}/cameras"
return http_get(blink, url)
def request_camera_info(blink, network, camera_id):
"""
Request camera info for one camera.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request info from.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/config"
return http_get(blink, url)
def request_camera_usage(blink):
"""
Request camera status.
:param blink: Blink instance.
"""
url = f"{blink.urls.base_url}/api/v1/camera/usage"
return http_get(blink, url)
def request_camera_liveview(blink, network, camera_id):
"""
Request camera liveview.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request liveview from.
"""
url = f"{blink.urls.base_url}/api/v5/accounts/{blink.account_id}/networks/{network}/cameras/{camera_id}/liveview"
return http_post(blink, url)
def request_camera_sensors(blink, network, camera_id):
"""
Request camera sensor info for one camera.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to request sesnor info from.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/signals"
return http_get(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_motion_detection_enable(blink, network, camera_id):
"""
Enable motion detection for a camera.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to enable.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/enable"
return http_post(blink, url)
@Throttle(seconds=MIN_THROTTLE_TIME)
def request_motion_detection_disable(blink, network, camera_id):
"""Disable motion detection for a camera.
:param blink: Blink instance.
:param network: Sync module network id.
:param camera_id: Camera ID of camera to disable.
"""
url = f"{blink.urls.base_url}/network/{network}/camera/{camera_id}/disable"
return http_post(blink, url)
def http_get(blink, url, stream=False, json=True, is_retry=False, timeout=TIMEOUT):
"""
Perform an http get request.
:param url: URL to perform get request.
:param stream: Stream response? True/FALSE
:param json: Return json response? TRUE/False
:param is_retry: Is this part of a re-auth attempt?
"""
_LOGGER.debug("Making GET request to %s", url)
return blink.auth.query(
url=url,
headers=blink.auth.header,
reqtype="get",
stream=stream,
json_resp=json,
is_retry=is_retry,
)
def http_post(blink, url, is_retry=False, timeout=TIMEOUT):
"""
Perform an http post request.
:param url: URL to perfom post request.
:param is_retry: Is this part of a re-auth attempt?
"""
_LOGGER.debug("Making POST request to %s", url)
return blink.auth.query(
url=url, headers=blink.auth.header, reqtype="post", is_retry=is_retry
)
+269
View File
@@ -0,0 +1,269 @@
"""Login handler for blink."""
import logging
from functools import partial
from requests import Request, Session, exceptions
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from blinkpy import api
from blinkpy.helpers import util
from blinkpy.helpers.constants import (
BLINK_URL,
DEFAULT_USER_AGENT,
LOGIN_ENDPOINT,
TIMEOUT,
)
_LOGGER = logging.getLogger(__name__)
class Auth:
"""Class to handle login communication."""
def __init__(self, login_data=None, no_prompt=False):
"""
Initialize auth handler.
:param login_data: dictionary for login data
must contain the following:
- username
- password
:param no_prompt: Should any user input prompts
be supressed? True/FALSE
"""
if login_data is None:
login_data = {}
self.data = login_data
self.token = login_data.get("token", None)
self.host = login_data.get("host", None)
self.region_id = login_data.get("region_id", None)
self.client_id = login_data.get("client_id", None)
self.account_id = login_data.get("account_id", None)
self.login_response = None
self.is_errored = False
self.no_prompt = no_prompt
self.session = self.create_session()
@property
def login_attributes(self):
"""Return a dictionary of login attributes."""
self.data["token"] = self.token
self.data["host"] = self.host
self.data["region_id"] = self.region_id
self.data["client_id"] = self.client_id
self.data["account_id"] = self.account_id
return self.data
@property
def header(self):
"""Return authorization header."""
if self.token is None:
return None
return {
"TOKEN_AUTH": self.token,
"user-agent": DEFAULT_USER_AGENT,
"content-type": "application/json",
}
def create_session(self, opts=None):
"""Create a session for blink communication."""
if opts is None:
opts = {}
backoff = opts.get("backoff", 1)
retries = opts.get("retries", 3)
retry_list = opts.get("retry_list", [429, 500, 502, 503, 504])
sess = Session()
assert_status_hook = [
lambda response, *args, **kwargs: response.raise_for_status()
]
sess.hooks["response"] = assert_status_hook
retry = Retry(
total=retries, backoff_factor=backoff, status_forcelist=retry_list
)
adapter = HTTPAdapter(max_retries=retry)
sess.mount("https://", adapter)
sess.mount("http://", adapter)
sess.get = partial(sess.get, timeout=TIMEOUT)
return sess
def prepare_request(self, url, headers, data, reqtype):
"""Prepare a request."""
req = Request(reqtype.upper(), url, headers=headers, data=data)
return req.prepare()
def validate_login(self):
"""Check login information and prompt if not available."""
self.data["username"] = self.data.get("username", None)
self.data["password"] = self.data.get("password", None)
if not self.no_prompt:
self.data = util.prompt_login_data(self.data)
self.data = util.validate_login_data(self.data)
def login(self, login_url=LOGIN_ENDPOINT):
"""Attempt login to blink servers."""
self.validate_login()
_LOGGER.info("Attempting login with %s", login_url)
response = api.request_login(self, login_url, self.data, is_retry=False,)
try:
if response.status_code == 200:
return response.json()
raise LoginError
except AttributeError as error:
raise LoginError from error
def logout(self, blink):
"""Log out."""
return api.request_logout(blink)
def refresh_token(self):
"""Refresh auth token."""
self.is_errored = True
try:
_LOGGER.info("Token expired, attempting automatic refresh.")
self.login_response = self.login()
self.extract_login_info()
self.is_errored = False
except LoginError as error:
_LOGGER.error("Login endpoint failed. Try again later.")
raise TokenRefreshFailed from error
except (TypeError, KeyError) as error:
_LOGGER.error("Malformed login response: %s", self.login_response)
raise TokenRefreshFailed from error
return True
def extract_login_info(self):
"""Extract login info from login response."""
self.region_id = self.login_response["account"]["tier"]
self.host = f"{self.region_id}.{BLINK_URL}"
self.token = self.login_response["auth"]["token"]
self.client_id = self.login_response["account"]["client_id"]
self.account_id = self.login_response["account"]["account_id"]
def startup(self):
"""Initialize tokens for communication."""
self.validate_login()
if None in self.login_attributes.values():
self.refresh_token()
def validate_response(self, response, json_resp):
"""Check for valid response."""
if not json_resp:
self.is_errored = False
return response
self.is_errored = True
try:
if response.status_code in [101, 401]:
raise UnauthorizedError
if response.status_code == 404:
raise exceptions.ConnectionError
json_data = response.json()
except KeyError:
pass
except (AttributeError, ValueError) as error:
raise BlinkBadResponse from error
self.is_errored = False
return json_data
def query(
self,
url=None,
data=None,
headers=None,
reqtype="get",
stream=False,
json_resp=True,
is_retry=False,
timeout=TIMEOUT,
):
"""
Perform server requests.
:param url: URL to perform request
:param data: Data to send
:param headers: Headers to send
:param reqtype: Can be 'get' or 'post' (default: 'get')
:param stream: Stream response? True/FALSE
:param json_resp: Return JSON response? TRUE/False
:param is_retry: Is this part of a re-auth attempt? True/FALSE
"""
req = self.prepare_request(url, headers, data, reqtype)
try:
response = self.session.send(req, stream=stream, timeout=timeout)
return self.validate_response(response, json_resp)
except (exceptions.ConnectionError, exceptions.Timeout):
_LOGGER.error(
"Connection error. Endpoint %s possibly down or throttled.", url,
)
except BlinkBadResponse:
code = None
reason = None
try:
code = response.status_code
reason = response.reason
except AttributeError:
pass
_LOGGER.error(
"Expected json response from %s, but received: %s: %s",
url,
code,
reason,
)
except UnauthorizedError:
try:
if not is_retry:
self.refresh_token()
return self.query(
url=url,
data=data,
headers=self.header,
reqtype=reqtype,
stream=stream,
json_resp=json_resp,
is_retry=True,
timeout=timeout,
)
_LOGGER.error("Unable to access %s after token refresh.", url)
except TokenRefreshFailed:
_LOGGER.error("Unable to refresh token.")
return None
def send_auth_key(self, blink, key):
"""Send 2FA key to blink servers."""
if key is not None:
response = api.request_verify(self, blink, key)
try:
json_resp = response.json()
blink.available = json_resp["valid"]
if not json_resp["valid"]:
_LOGGER.error("%s", json_resp["message"])
return False
except (KeyError, TypeError):
_LOGGER.error("Did not receive valid response from server.")
return False
return True
def check_key_required(self):
"""Check if 2FA key is required."""
try:
if self.login_response["account"]["client_verification_required"]:
return True
except (KeyError, TypeError):
pass
return False
class TokenRefreshFailed(Exception):
"""Class to throw failed refresh exception."""
class LoginError(Exception):
"""Class to throw failed login exception."""
class BlinkBadResponse(Exception):
"""Class to throw bad json response exception."""
class UnauthorizedError(Exception):
"""Class to throw an unauthorized access error."""
+357
View File
@@ -0,0 +1,357 @@
# -*- coding: utf-8 -*-
"""
blinkpy is an unofficial api for the Blink security camera system.
repo url: https://github.com/fronzbot/blinkpy
Original protocol hacking by MattTW :
https://github.com/MattTW/BlinkMonitorProtocol
Published under the MIT license - See LICENSE file for more details.
"Blink Wire-Free HS Home Monitoring & Alert Systems" is a trademark
owned by Immedia Inc., see www.blinkforhome.com for more information.
blinkpy is in no way affiliated with Blink, nor Immedia Inc.
"""
import os.path
import time
import logging
from shutil import copyfileobj
from requests.structures import CaseInsensitiveDict
from dateutil.parser import parse
from slugify import slugify
from blinkpy import api
from blinkpy.sync_module import BlinkSyncModule, BlinkOwl
from blinkpy.helpers import util
from blinkpy.helpers.constants import (
DEFAULT_MOTION_INTERVAL,
DEFAULT_REFRESH,
MIN_THROTTLE_TIME,
TIMEOUT_MEDIA,
)
from blinkpy.helpers.constants import __version__
from blinkpy.auth import Auth, TokenRefreshFailed, LoginError
_LOGGER = logging.getLogger(__name__)
class Blink:
"""Class to initialize communication."""
def __init__(
self,
refresh_rate=DEFAULT_REFRESH,
motion_interval=DEFAULT_MOTION_INTERVAL,
no_owls=False,
):
"""
Initialize Blink system.
:param refresh_rate: Refresh rate of blink information.
Defaults to 15 (seconds)
:param motion_interval: How far back to register motion in minutes.
Defaults to last refresh time.
Useful for preventing motion_detected property
from de-asserting too quickly.
:param no_owls: Disable searching for owl entries (blink mini cameras only known entity). Prevents an uneccessary API call if you don't have these in your network.
"""
self.auth = Auth()
self.account_id = None
self.client_id = None
self.network_ids = []
self.urls = None
self.sync = CaseInsensitiveDict({})
self.last_refresh = None
self.refresh_rate = refresh_rate
self.networks = []
self.cameras = CaseInsensitiveDict({})
self.video_list = CaseInsensitiveDict({})
self.motion_interval = motion_interval
self.version = __version__
self.available = False
self.key_required = False
self.homescreen = {}
self.no_owls = no_owls
@util.Throttle(seconds=MIN_THROTTLE_TIME)
def refresh(self, force=False, force_cache=False):
"""
Perform a system refresh.
:param force: Used to override throttle, resets refresh
:param force_cache: Used to force update without overriding throttle
"""
if self.check_if_ok_to_update() or force or force_cache:
if not self.available:
self.setup_post_verify()
self.get_homescreen()
for sync_name, sync_module in self.sync.items():
_LOGGER.debug("Attempting refresh of sync %s", sync_name)
sync_module.refresh(force_cache=(force or force_cache))
if not force_cache:
# Prevents rapid clearing of motion detect property
self.last_refresh = int(time.time())
return True
return False
def start(self):
"""Perform full system setup."""
try:
self.auth.startup()
self.setup_login_ids()
self.setup_urls()
self.get_homescreen()
except (LoginError, TokenRefreshFailed, BlinkSetupError):
_LOGGER.error("Cannot setup Blink platform.")
self.available = False
return False
self.key_required = self.auth.check_key_required()
if self.key_required:
if self.auth.no_prompt:
return True
self.setup_prompt_2fa()
return self.setup_post_verify()
def setup_prompt_2fa(self):
"""Prompt for 2FA."""
email = self.auth.data["username"]
pin = input(f"Enter code sent to {email}: ")
result = self.auth.send_auth_key(self, pin)
self.key_required = not result
def setup_post_verify(self):
"""Initialize blink system after verification."""
try:
self.setup_networks()
networks = self.setup_network_ids()
cameras = self.setup_camera_list()
except BlinkSetupError:
self.available = False
return False
for name, network_id in networks.items():
sync_cameras = cameras.get(network_id, {})
self.setup_sync_module(name, network_id, sync_cameras)
self.cameras = self.merge_cameras()
self.available = True
self.key_required = False
return True
def setup_sync_module(self, name, network_id, cameras):
"""Initialize a sync module."""
self.sync[name] = BlinkSyncModule(self, name, network_id, cameras)
self.sync[name].start()
def get_homescreen(self):
"""Get homecreen information."""
if self.no_owls:
_LOGGER.debug("Skipping owl extraction.")
self.homescreen = {}
return
self.homescreen = api.request_homescreen(self)
def setup_owls(self):
"""Check for mini cameras."""
network_list = []
camera_list = []
try:
for owl in self.homescreen["owls"]:
name = owl["name"]
network_id = str(owl["network_id"])
if network_id in self.network_ids:
camera_list.append(
{network_id: {"name": name, "id": network_id, "type": "mini"}}
)
continue
if owl["onboarded"]:
network_list.append(str(network_id))
self.sync[name] = BlinkOwl(self, name, network_id, owl)
self.sync[name].start()
except KeyError:
# No sync-less devices found
pass
self.network_ids.extend(network_list)
return camera_list
def setup_camera_list(self):
"""Create camera list for onboarded networks."""
all_cameras = {}
response = api.request_camera_usage(self)
try:
for network in response["networks"]:
camera_network = str(network["network_id"])
if camera_network not in all_cameras:
all_cameras[camera_network] = []
for camera in network["cameras"]:
all_cameras[camera_network].append(
{"name": camera["name"], "id": camera["id"]}
)
mini_cameras = self.setup_owls()
for camera in mini_cameras:
for network, camera_info in camera.items():
all_cameras[network].append(camera_info)
return all_cameras
except (KeyError, TypeError):
_LOGGER.error("Unable to retrieve cameras from response %s", response)
raise BlinkSetupError
def setup_login_ids(self):
"""Retrieve login id numbers from login response."""
self.client_id = self.auth.client_id
self.account_id = self.auth.account_id
def setup_urls(self):
"""Create urls for api."""
try:
self.urls = util.BlinkURLHandler(self.auth.region_id)
except TypeError:
_LOGGER.error(
"Unable to extract region is from response %s", self.auth.login_response
)
raise BlinkSetupError
def setup_networks(self):
"""Get network information."""
response = api.request_networks(self)
try:
self.networks = response["summary"]
except (KeyError, TypeError):
raise BlinkSetupError
def setup_network_ids(self):
"""Create the network ids for onboarded networks."""
all_networks = []
network_dict = {}
try:
for network, status in self.networks.items():
if status["onboarded"]:
all_networks.append(f"{network}")
network_dict[status["name"]] = network
except AttributeError:
_LOGGER.error(
"Unable to retrieve network information from %s", self.networks
)
raise BlinkSetupError
self.network_ids = all_networks
return network_dict
def check_if_ok_to_update(self):
"""Check if it is ok to perform an http request."""
current_time = int(time.time())
last_refresh = self.last_refresh
if last_refresh is None:
last_refresh = 0
if current_time >= (last_refresh + self.refresh_rate):
return True
return False
def merge_cameras(self):
"""Merge all sync camera dicts into one."""
combined = CaseInsensitiveDict({})
for sync in self.sync:
combined = util.merge_dicts(combined, self.sync[sync].cameras)
return combined
def save(self, file_name):
"""Save login data to file."""
util.json_save(self.auth.login_attributes, file_name)
def download_videos(self, path, since=None, camera="all", stop=10, debug=False):
"""
Download all videos from server since specified time.
:param path: Path to write files. /path/<cameraname>_<recorddate>.mp4
:param since: Date and time to get videos from.
Ex: "2018/07/28 12:33:00" to retrieve videos since
July 28th 2018 at 12:33:00
:param camera: Camera name to retrieve. Defaults to "all".
Use a list for multiple cameras.
:param stop: Page to stop on (~25 items per page. Default page 10).
:param debug: Set to TRUE to prevent downloading of items.
Instead of downloading, entries will be printed to log.
"""
if since is None:
since_epochs = self.last_refresh
else:
parsed_datetime = parse(since, fuzzy=True)
since_epochs = parsed_datetime.timestamp()
formatted_date = util.get_time(time_to_convert=since_epochs)
_LOGGER.info("Retrieving videos since %s", formatted_date)
if not isinstance(camera, list):
camera = [camera]
for page in range(1, stop):
response = api.request_videos(self, time=since_epochs, page=page)
_LOGGER.debug("Processing page %s", page)
try:
result = response["media"]
if not result:
raise KeyError
except (KeyError, TypeError):
_LOGGER.info("No videos found on page %s. Exiting.", page)
break
self._parse_downloaded_items(result, camera, path, debug)
def _parse_downloaded_items(self, result, camera, path, debug):
"""Parse downloaded videos."""
for item in result:
try:
created_at = item["created_at"]
camera_name = item["device_name"]
is_deleted = item["deleted"]
address = item["media"]
except KeyError:
_LOGGER.info("Missing clip information, skipping...")
continue
if camera_name not in camera and "all" not in camera:
_LOGGER.debug("Skipping videos for %s.", camera_name)
continue
if is_deleted:
_LOGGER.debug("%s: %s is marked as deleted.", camera_name, address)
continue
clip_address = f"{self.urls.base_url}{address}"
filename = f"{camera_name}-{created_at}"
filename = f"{slugify(filename)}.mp4"
filename = os.path.join(path, filename)
if not debug:
if os.path.isfile(filename):
_LOGGER.info("%s already exists, skipping...", filename)
continue
response = api.http_get(
self,
url=clip_address,
stream=True,
json=False,
timeout=TIMEOUT_MEDIA,
)
with open(filename, "wb") as vidfile:
copyfileobj(response.raw, vidfile)
_LOGGER.info("Downloaded video to %s", filename)
else:
print(
(
f"Camera: {camera_name}, Timestamp: {created_at}, "
"Address: {address}, Filename: {filename}"
)
)
class BlinkSetupError(Exception):
"""Class to handle setup errors."""
+275
View File
@@ -0,0 +1,275 @@
"""Defines Blink cameras."""
from shutil import copyfileobj
import logging
from blinkpy import api
from blinkpy.helpers.constants import TIMEOUT_MEDIA
_LOGGER = logging.getLogger(__name__)
class BlinkCamera:
"""Class to initialize individual camera."""
def __init__(self, sync):
"""Initiailize BlinkCamera."""
self.sync = sync
self.name = None
self.camera_id = None
self.network_id = None
self.thumbnail = None
self.serial = None
self.motion_enabled = None
self.battery_voltage = None
self.clip = None
self.temperature = None
self.temperature_calibrated = None
self.battery_state = None
self.motion_detected = None
self.wifi_strength = None
self.last_record = None
self._cached_image = None
self._cached_video = None
self.camera_type = ""
@property
def attributes(self):
"""Return dictionary of all camera attributes."""
attributes = {
"name": self.name,
"camera_id": self.camera_id,
"serial": self.serial,
"temperature": self.temperature,
"temperature_c": self.temperature_c,
"temperature_calibrated": self.temperature_calibrated,
"battery": self.battery,
"battery_voltage": self.battery_voltage,
"thumbnail": self.thumbnail,
"video": self.clip,
"motion_enabled": self.motion_enabled,
"motion_detected": self.motion_detected,
"wifi_strength": self.wifi_strength,
"network_id": self.sync.network_id,
"sync_module": self.sync.name,
"last_record": self.last_record,
}
return attributes
@property
def battery(self):
"""Return battery as string."""
return self.battery_state
@property
def temperature_c(self):
"""Return temperature in celcius."""
try:
return round((self.temperature - 32) / 9.0 * 5.0, 1)
except TypeError:
return None
@property
def image_from_cache(self):
"""Return the most recently cached image."""
if self._cached_image:
return self._cached_image
return None
@property
def video_from_cache(self):
"""Return the most recently cached video."""
if self._cached_video:
return self._cached_video
return None
@property
def arm(self):
"""Return arm status of camera."""
return self.motion_enabled
@arm.setter
def arm(self, value):
"""Set camera arm status."""
if value:
return api.request_motion_detection_enable(
self.sync.blink, self.network_id, self.camera_id
)
return api.request_motion_detection_disable(
self.sync.blink, self.network_id, self.camera_id
)
def record(self):
"""Initiate clip recording."""
return api.request_new_video(self.sync.blink, self.network_id, self.camera_id)
def get_media(self, media_type="image"):
"""Download media (image or video)."""
url = self.thumbnail
if media_type.lower() == "video":
url = self.clip
return api.http_get(
self.sync.blink, url=url, stream=True, json=False, timeout=TIMEOUT_MEDIA,
)
def snap_picture(self):
"""Take a picture with camera to create a new thumbnail."""
return api.request_new_image(self.sync.blink, self.network_id, self.camera_id)
def set_motion_detect(self, enable):
"""Set motion detection."""
_LOGGER.warning(
"Method is deprecated as of v0.16.0 and will be removed in a future version. Please use the BlinkCamera.arm property instead."
)
if enable:
return api.request_motion_detection_enable(
self.sync.blink, self.network_id, self.camera_id
)
return api.request_motion_detection_disable(
self.sync.blink, self.network_id, self.camera_id
)
def update(self, config, force_cache=False, **kwargs):
"""Update camera info."""
self.extract_config_info(config)
self.get_sensor_info()
self.update_images(config, force_cache=force_cache)
def extract_config_info(self, config):
"""Extract info from config."""
self.name = config.get("name", "unknown")
self.camera_id = str(config.get("id", "unknown"))
self.network_id = str(config.get("network_id", "unknown"))
self.serial = config.get("serial", None)
self.motion_enabled = config.get("enabled", "unknown")
self.battery_voltage = config.get("battery_voltage", None)
self.battery_state = config.get("battery_state", None)
self.temperature = config.get("temperature", None)
self.wifi_strength = config.get("wifi_strength", None)
def get_sensor_info(self):
"""Retrieve calibrated temperatue from special endpoint."""
resp = api.request_camera_sensors(
self.sync.blink, self.network_id, self.camera_id
)
try:
self.temperature_calibrated = resp["temp"]
except (TypeError, KeyError):
self.temperature_calibrated = self.temperature
_LOGGER.warning("Could not retrieve calibrated temperature.")
def update_images(self, config, force_cache=False):
"""Update images for camera."""
new_thumbnail = None
thumb_addr = None
if config.get("thumbnail", False):
thumb_addr = config["thumbnail"]
else:
_LOGGER.warning("Could not find thumbnail for camera %s", self.name)
if thumb_addr is not None:
new_thumbnail = f"{self.sync.urls.base_url}{thumb_addr}.jpg"
try:
self.motion_detected = self.sync.motion[self.name]
except KeyError:
self.motion_detected = False
clip_addr = None
try:
clip_addr = self.sync.last_record[self.name]["clip"]
self.last_record = self.sync.last_record[self.name]["time"]
self.clip = f"{self.sync.urls.base_url}{clip_addr}"
except KeyError:
pass
# If the thumbnail or clip have changed, update the cache
update_cached_image = False
if new_thumbnail != self.thumbnail or self._cached_image is None:
update_cached_image = True
self.thumbnail = new_thumbnail
update_cached_video = False
if self._cached_video is None or self.motion_detected:
update_cached_video = True
if new_thumbnail is not None and (update_cached_image or force_cache):
self._cached_image = self.get_media()
if clip_addr is not None and (update_cached_video or force_cache):
self._cached_video = self.get_media(media_type="video")
def get_liveview(self):
"""Get livewview rtsps link."""
response = api.request_camera_liveview(
self.sync.blink, self.sync.network_id, self.camera_id
)
return response["server"]
def image_to_file(self, path):
"""
Write image to file.
:param path: Path to write file
"""
_LOGGER.debug("Writing image from %s to %s", self.name, path)
response = self.get_media()
if response.status_code == 200:
with open(path, "wb") as imgfile:
copyfileobj(response.raw, imgfile)
else:
_LOGGER.error(
"Cannot write image to file, response %s", response.status_code
)
def video_to_file(self, path):
"""
Write video to file.
:param path: Path to write file
"""
_LOGGER.debug("Writing video from %s to %s", self.name, path)
response = self.get_media(media_type="video")
if response is None:
_LOGGER.error("No saved video exist for %s.", self.name)
return
with open(path, "wb") as vidfile:
copyfileobj(response.raw, vidfile)
class BlinkCameraMini(BlinkCamera):
"""Define a class for a Blink Mini camera."""
def __init__(self, sync):
"""Initialize a Blink Mini cameras."""
super().__init__(sync)
self.camera_type = "mini"
@property
def arm(self):
"""Return camera arm status."""
return self.sync.arm
@arm.setter
def arm(self, value):
"""Set camera arm status."""
_LOGGER.warning(
"Individual camera motion detection enable/disable for Blink Mini cameras is unsupported at this time."
)
def snap_picture(self):
"""Snap picture for a blink mini camera."""
url = f"{self.sync.urls.base_url}/api/v1/accounts/{self.sync.blink.account_id}/networks/{self.network_id}/owls/{self.camera_id}/thumbnail"
return api.http_post(self.sync.blink, url)
def get_sensor_info(self):
"""Get sensor info for blink mini camera."""
def get_liveview(self):
"""Get liveview link."""
url = f"{self.sync.urls.base_url}/api/v1/accounts/{self.sync.blink.account_id}/networks/{self.network_id}/owls/{self.camera_id}/liveview"
response = api.http_post(self.sync.blink, url)
server = response["server"]
server_split = server.split(":")
server_split[0] = "rtsps:"
link = "".join(server_split)
return link
+1
View File
@@ -0,0 +1 @@
"""Init file for blinkpy helper functions."""
+71
View File
@@ -0,0 +1,71 @@
"""Generates constants for use in blinkpy."""
import os
MAJOR_VERSION = 0
MINOR_VERSION = 17
PATCH_VERSION = 0
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER = (3, 6, 0)
PROJECT_NAME = "blinkpy"
PROJECT_PACKAGE_NAME = "blinkpy"
PROJECT_LICENSE = "MIT"
PROJECT_AUTHOR = "Kevin Fronczak"
PROJECT_COPYRIGHT = f" 2017, {PROJECT_AUTHOR}"
PROJECT_URL = "https://github.com/fronzbot/blinkpy"
PROJECT_EMAIL = "kfronczak@gmail.com"
PROJECT_DESCRIPTION = "A Blink camera Python library " "running on Python 3."
PROJECT_LONG_DESCRIPTION = (
"blinkpy is an open-source "
"unofficial API for the Blink Camera "
"system with the intention for easy "
"integration into various home "
"automation platforms."
)
if os.path.exists("README.rst"):
PROJECT_LONG_DESCRIPTION = open("README.rst").read()
PROJECT_CLASSIFIERS = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Home Automation",
]
PROJECT_GITHUB_USERNAME = "fronzbot"
PROJECT_GITHUB_REPOSITORY = "blinkpy"
PYPI_URL = f"https://pypi.python.org/pypi/{PROJECT_PACKAGE_NAME}"
"""
URLS
"""
BLINK_URL = "immedia-semi.com"
DEFAULT_URL = f"rest-prod.{BLINK_URL}"
BASE_URL = f"https://{DEFAULT_URL}"
LOGIN_ENDPOINT = f"{BASE_URL}/api/v5/account/login"
"""
Dictionaries
"""
ONLINE = {"online": True, "offline": False}
"""
OTHER
"""
DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
DEVICE_ID = "Blinkpy"
TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
DEFAULT_MOTION_INTERVAL = 1
DEFAULT_REFRESH = 30
MIN_THROTTLE_TIME = 2
SIZE_NOTIFICATION_KEY = 152
SIZE_UID = 16
TIMEOUT = 10
TIMEOUT_MEDIA = 90
+15
View File
@@ -0,0 +1,15 @@
"""Module to define error types."""
USERNAME = (0, "Username must be a string")
PASSWORD = (1, "Password must be a string")
AUTHENTICATE = (
2,
"Cannot authenticate since either password or username has not been set",
)
AUTH_TOKEN = (
3,
"Authentication header incorrect. Are you sure you received your token?",
)
REQUEST = (4, "Cannot perform request (get/post type incorrect)")
BLINK_ERRORS = [400, 404]
+150
View File
@@ -0,0 +1,150 @@
"""Useful functions for blinkpy."""
import json
import logging
import time
import secrets
from calendar import timegm
from functools import wraps
from getpass import getpass
import dateutil.parser
from blinkpy.helpers import constants as const
_LOGGER = logging.getLogger(__name__)
def json_load(file_name):
"""Load json credentials from file."""
try:
with open(file_name, "r") as json_file:
data = json.load(json_file)
return data
except FileNotFoundError:
_LOGGER.error("Could not find %s", file_name)
except json.decoder.JSONDecodeError:
_LOGGER.error("File %s has improperly formatted json", file_name)
return None
def json_save(data, file_name):
"""Save data to file location."""
with open(file_name, "w") as json_file:
json.dump(data, json_file, indent=4)
def gen_uid(size, uid_format=False):
"""Create a random sring."""
if uid_format:
token = f"BlinkCamera_{secrets.token_hex(4)}-{secrets.token_hex(2)}-{secrets.token_hex(2)}-{secrets.token_hex(2)}-{secrets.token_hex(6)}"
else:
token = secrets.token_hex(size)
return token
def time_to_seconds(timestamp):
"""Convert TIMESTAMP_FORMAT time to seconds."""
try:
dtime = dateutil.parser.isoparse(timestamp)
except ValueError:
_LOGGER.error("Incorrect timestamp format for conversion: %s.", timestamp)
return False
return timegm(dtime.timetuple())
def get_time(time_to_convert=None):
"""Create blink-compatible timestamp."""
if time_to_convert is None:
time_to_convert = time.time()
return time.strftime(const.TIMESTAMP_FORMAT, time.gmtime(time_to_convert))
def merge_dicts(dict_a, dict_b):
"""Merge two dictionaries into one."""
duplicates = [val for val in dict_a if val in dict_b]
if duplicates:
_LOGGER.warning(
("Duplicates found during merge: %s. " "Renaming is recommended."),
duplicates,
)
return {**dict_a, **dict_b}
def prompt_login_data(data):
"""Prompt user for username and password."""
if data["username"] is None:
data["username"] = input("Username:")
if data["password"] is None:
data["password"] = getpass("Password:")
return data
def validate_login_data(data):
"""Check for missing keys."""
data["uid"] = data.get("uid", gen_uid(const.SIZE_UID, uid_format=True))
data["device_id"] = data.get("device_id", const.DEVICE_ID)
return data
class BlinkException(Exception):
"""Class to throw general blink exception."""
def __init__(self, errcode):
"""Initialize BlinkException."""
super().__init__()
self.errid = errcode[0]
self.message = errcode[1]
class BlinkAuthenticationException(BlinkException):
"""Class to throw authentication exception."""
class BlinkURLHandler:
"""Class that handles Blink URLS."""
def __init__(self, region_id):
"""Initialize the urls."""
if region_id is None:
raise TypeError
self.subdomain = f"rest-{region_id}"
self.base_url = f"https://{self.subdomain}.{const.BLINK_URL}"
self.home_url = f"{self.base_url}/homescreen"
self.event_url = f"{self.base_url}/events/network"
self.network_url = f"{self.base_url}/network"
self.networks_url = f"{self.base_url}/networks"
self.video_url = f"{self.base_url}/api/v2/videos"
_LOGGER.debug("Setting base url to %s.", self.base_url)
class Throttle:
"""Class for throttling api calls."""
def __init__(self, seconds=10):
"""Initialize throttle class."""
self.throttle_time = seconds
self.last_call = 0
def __call__(self, method):
"""Throttle caller method."""
def throttle_method():
"""Call when method is throttled."""
return None
@wraps(method)
def wrapper(*args, **kwargs):
"""Wrap that checks for throttling."""
force = kwargs.pop("force", False)
now = int(time.time())
last_call_delta = now - self.last_call
if force or last_call_delta > self.throttle_time:
result = method(*args, *kwargs)
self.last_call = now
return result
return throttle_method()
return wrapper
+296
View File
@@ -0,0 +1,296 @@
"""Defines a sync module for Blink."""
import logging
from requests.structures import CaseInsensitiveDict
from blinkpy import api
from blinkpy.camera import BlinkCamera, BlinkCameraMini
from blinkpy.helpers.util import time_to_seconds
from blinkpy.helpers.constants import ONLINE
_LOGGER = logging.getLogger(__name__)
class BlinkSyncModule:
"""Class to initialize sync module."""
def __init__(self, blink, network_name, network_id, camera_list):
"""
Initialize Blink sync module.
:param blink: Blink class instantiation
"""
self.blink = blink
self.network_id = network_id
self.region_id = blink.auth.region_id
self.name = network_name
self.serial = None
self.status = "offline"
self.sync_id = None
self.host = None
self.summary = None
self.network_info = None
self.events = []
self.cameras = CaseInsensitiveDict({})
self.motion_interval = blink.motion_interval
self.motion = {}
self.last_record = {}
self.camera_list = camera_list
self.available = False
@property
def attributes(self):
"""Return sync attributes."""
attr = {
"name": self.name,
"id": self.sync_id,
"network_id": self.network_id,
"serial": self.serial,
"status": self.status,
"region_id": self.region_id,
}
return attr
@property
def urls(self):
"""Return device urls."""
return self.blink.urls
@property
def online(self):
"""Return boolean system online status."""
try:
return ONLINE[self.status]
except KeyError:
_LOGGER.error("Unknown sync module status %s", self.status)
self.available = False
return False
@property
def arm(self):
"""Return status of sync module: armed/disarmed."""
try:
return self.network_info["network"]["armed"]
except (KeyError, TypeError):
self.available = False
return None
@arm.setter
def arm(self, value):
"""Arm or disarm camera."""
if value:
return api.request_system_arm(self.blink, self.network_id)
return api.request_system_disarm(self.blink, self.network_id)
def start(self):
"""Initialize the system."""
response = self.sync_initialize()
if not response:
return False
try:
self.sync_id = self.summary["id"]
self.serial = self.summary["serial"]
self.status = self.summary["status"]
except KeyError:
_LOGGER.error("Could not extract some sync module info: %s", response)
is_ok = self.get_network_info()
self.check_new_videos()
if not is_ok or not self.update_cameras():
return False
self.available = True
return True
def sync_initialize(self):
"""Initialize a sync module."""
response = api.request_syncmodule(self.blink, self.network_id)
try:
self.summary = response["syncmodule"]
self.network_id = self.summary["network_id"]
except (TypeError, KeyError):
_LOGGER.error(
"Could not retrieve sync module information with response: %s", response
)
return False
return response
def update_cameras(self, camera_type=BlinkCamera):
"""Update cameras from server."""
try:
for camera_config in self.camera_list:
if "name" not in camera_config:
break
blink_camera_type = camera_config.get("type", "")
name = camera_config["name"]
self.motion[name] = False
owl_info = self.get_owl_info(name)
if blink_camera_type == "mini":
camera_type = BlinkCameraMini
self.cameras[name] = camera_type(self)
camera_info = self.get_camera_info(
camera_config["id"], owl_info=owl_info
)
self.cameras[name].update(camera_info, force_cache=True, force=True)
except KeyError:
_LOGGER.error("Could not create camera instances for %s", self.name)
return False
return True
def get_owl_info(self, name):
"""Extract owl information."""
try:
for owl in self.blink.homescreen["owls"]:
if owl["name"] == name:
return owl
except (TypeError, KeyError):
pass
return None
def get_events(self, **kwargs):
"""Retrieve events from server."""
force = kwargs.pop("force", False)
response = api.request_sync_events(self.blink, self.network_id, force=force)
try:
return response["event"]
except (TypeError, KeyError):
_LOGGER.error("Could not extract events: %s", response)
return False
def get_camera_info(self, camera_id, **kwargs):
"""Retrieve camera information."""
owl = kwargs.get("owl_info", None)
if owl is not None:
return owl
response = api.request_camera_info(self.blink, self.network_id, camera_id)
try:
return response["camera"][0]
except (TypeError, KeyError):
_LOGGER.error("Could not extract camera info: %s", response)
return {}
def get_network_info(self):
"""Retrieve network status."""
self.network_info = api.request_network_update(self.blink, self.network_id)
try:
if self.network_info["network"]["sync_module_error"]:
raise KeyError
except (TypeError, KeyError):
self.available = False
return False
return True
def refresh(self, force_cache=False):
"""Get all blink cameras and pulls their most recent status."""
if not self.get_network_info():
return
self.check_new_videos()
for camera_name in self.cameras.keys():
camera_id = self.cameras[camera_name].camera_id
camera_info = self.get_camera_info(
camera_id, owl_info=self.get_owl_info(camera_name)
)
self.cameras[camera_name].update(camera_info, force_cache=force_cache)
self.available = True
def check_new_videos(self):
"""Check if new videos since last refresh."""
try:
interval = self.blink.last_refresh - self.motion_interval * 60
except TypeError:
# This is the first start, so refresh hasn't happened yet.
# No need to check for motion.
return False
resp = api.request_videos(self.blink, time=interval, page=1)
for camera in self.cameras.keys():
self.motion[camera] = False
try:
info = resp["media"]
except (KeyError, TypeError):
_LOGGER.warning("Could not check for motion. Response: %s", resp)
return False
for entry in info:
try:
name = entry["device_name"]
clip = entry["media"]
timestamp = entry["created_at"]
if self.check_new_video_time(timestamp):
self.motion[name] = True and self.arm
self.last_record[name] = {"clip": clip, "time": timestamp}
except KeyError:
_LOGGER.debug("No new videos since last refresh.")
return True
def check_new_video_time(self, timestamp):
"""Check if video has timestamp since last refresh."""
return time_to_seconds(timestamp) > self.blink.last_refresh
class BlinkOwl(BlinkSyncModule):
"""Representation of a sync-less device."""
def __init__(self, blink, name, network_id, response):
"""Initialize a sync-less object."""
cameras = [{"name": name, "id": response["id"]}]
super().__init__(blink, name, network_id, cameras)
self.sync_id = response["id"]
self.serial = response["serial"]
self.status = response["enabled"]
if not self.serial:
self.serial = f"{network_id}-{self.sync_id}"
def sync_initialize(self):
"""Initialize a sync-less module."""
self.summary = {
"id": self.sync_id,
"name": self.name,
"serial": self.serial,
"status": self.status,
"onboarded": True,
"account_id": self.blink.account_id,
"network_id": self.network_id,
}
return self.summary
def update_cameras(self, camera_type=BlinkCameraMini):
"""Update sync-less cameras."""
return super().update_cameras(camera_type=BlinkCameraMini)
def get_camera_info(self, camera_id, **kwargs):
"""Retrieve camera information."""
try:
for owl in self.blink.homescreen["owls"]:
if owl["name"] == self.name:
self.status = owl["enabled"]
return owl
except (TypeError, KeyError):
pass
return None
def get_network_info(self):
"""Get network info for sync-less module."""
return True
@property
def network_info(self):
"""Format owl response to resemble sync module."""
return {
"network": {
"id": self.network_id,
"name": self.name,
"armed": self.status,
"sync_module_error": False,
"account_id": self.blink.account_id,
}
}
@network_info.setter
def network_info(self, value):
"""Set network_info property."""
+15
View File
@@ -0,0 +1,15 @@
codecov:
branch: dev
coverage:
status:
project:
default:
target: 80%
threshold: 2%
patch:
default:
target: 60%
threshold: 5%
comment: true
require_ci_to_pass: yes
+77
View File
@@ -0,0 +1,77 @@
"""Login testing script."""
import sys
import os
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
from blinkpy.helpers.util import json_load, json_save
save_session = False
print("")
print("Blink Login Debug Script ...")
print(" ... Loading previous session information.")
cwd = os.getcwd()
print(f" ... Looking in {cwd}.")
session_path = os.path.join(cwd, ".session_debug")
session = json_load(session_path)
try:
auth_file = session["file"]
except (TypeError, KeyError):
print(" ... Please input location of auth file")
auth_file = input(" Must contain username and password: ")
save_session = True
data = json_load(auth_file)
if data is None:
print(f" ... Please fix file contents of {auth_file}.")
print(" ... Exiting.")
sys.exit(1)
try:
username = data["username"]
password = data["password"]
except KeyError:
print(f" ... File contents of {auth_file} incorrect.")
print(" ... Require username and password at minimum.")
print(" ... Exiting.")
sys.exit(1)
if save_session:
print(f" ... Saving session file to {session_path}.")
json_save({"file": auth_file}, session_path)
blink = Blink()
auth = Auth(data)
blink.auth = auth
print(" ... Starting Blink.")
print("")
blink.start()
print("")
print(" ... Printing login response.")
print("")
print(blink.auth.login_response)
print("")
print(" ... Printing login attributes.")
print("")
print(blink.auth.login_attributes)
print("")
input(" ... Press any key to continue: ")
print(" ... Deactivating auth token.")
blink.auth.token = "foobar"
print(f"\t - blink.auth.token = {blink.auth.token}")
print(" ... Attempting login.")
print("")
blink.start()
print("")
print(" ... Printing login response.")
print("")
print(blink.auth.login_response)
print("")
print(" ... Printing login attributes.")
print("")
print(blink.auth.login_attributes)
print("")
rint(" ... Done.")
print("")
+1
View File
@@ -0,0 +1 @@
../CHANGES.rst
+1
View File
@@ -0,0 +1 @@
../CONTRIBUTING.rst
+20
View File
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = blinkpy
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+1
View File
@@ -0,0 +1 @@
../README.rst
+104
View File
@@ -0,0 +1,104 @@
=======================
Advanced Library Usage
=======================
Usage of this library was designed with the `Home Assistant <https://home-assistant.io>`__ project in mind. With that said, this library is flexible to be used in other scripts where advanced usage not covered in the Quick Start guide may be required. This usage guide will attempt to cover as many use cases as possible.
Throttling
--------------
In general, attempting too many requests to the Blink servers will result in your account being throttled. Where possible, adding a delay between calls is ideal. For use cases where this is not an acceptable solution, the ``blinkpy.helpers.util`` module contains a ``Throttle`` class that can be used as a decorator for calls. There are many examples of usage within the ``blinkpy.api`` module. A simple example of usage is covered below, where the decorated method is prevented from executing again until 10s has passed. Note that if the method call is throttled by the decorator, the method will return `None`.
.. code:: python
from blinkpy.helpers.util import Throttle
@Throttle(seconds=10)
def my_method(*args):
"""Some method to be throttled."""
return True
Custom Sessions
-----------------
By default, the ``blink.auth.Auth`` class creates its own websession via its ``create_session`` method. This is done when the class is initialized and is accessible via the ``Auth.session`` property. To override with a custom websession, the following code can accomplish that:
.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
blink = Blink()
blink.auth = Auth()
blink.auth.session = YourCustomSession
Custom Retry Logic
--------------------
The built-in auth session via the ``create_session`` method allows for customizable retry intervals and conditions. These parameters are:
- retries
- backoff
- retry_list
``retries`` is the total number of retry attempts that each http request can do before timing out. ``backoff`` is a parameter that allows for non-linear retry times such that the time between retries is backoff*(2^(retries) - 1). ``retry_list`` is simply a list of status codes to force a retry. By default ``retries=3``, ``backoff=1``, and ``retry_list=[429, 500, 502, 503, 504]``. To override them, you need to add you overrides to a dictionary and use that to create a new session with the ``opts`` variable in the ``create_session`` method. The following example can serve as a guide where only the number of retries and backoff factor are overridden:
.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
blink = Blink()
blink.auth = Auth()
opts = {"retries": 10, "backoff": 2}
blink.auth.session = blink.auth.create_session(opts=opts)
Custom HTTP requests
---------------------
In addition to custom sessions, custom blink server requests can be performed. This give you the ability to bypass the built-in ``Auth.query`` method. It also allows flexibility by giving you the option to pass your own url, rather than be limited to what is currently implemented in the ``blinkpy.api`` module.
**Send custom url**
This prepares a standard "GET" request.
.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
blink = Blink()
blink.auth = Auth()
url = some_api_endpoint_string
request = blink.auth.prepare_request(url, blink.auth.header, None, "get")
response = blink.auth.session.send(request)
**Overload query method**
Another option is to create your own ``Auth`` class with a custom ``query`` method to avoid the built-in response checking. This allows you to use the built in ``blinkpy.api`` endpoints, but also gives you flexibility to send your own urls.
.. code:: python
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
from blinkpy import api
class CustomAuth(Auth):
def query(
self,
url=None,
data=None,
headers=self.header,
reqtype="get",
stream=False,
json_resp=True,
**kwargs
):
req = self.prepare_request(url, headers, data, reqtype)
return self.session.send(req, stream=stream)
blink = blink.Blink()
blink.auth = CustomAuth()
# Send custom GET query
response = blink.auth.query(url=some_custom_url)
# Call built-in networks api endpoint
response = api.request_networks(blink)
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# blinkpy documentation build configuration file, created by
# sphinx-quickstart on Sat Jan 20 22:20:16 2018.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
import sphinx_rtd_theme
from blinkpy.helpers.constants import __version__
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'blinkpy'
copyright = '2018, Kevin Fronczak'
author = 'Kevin Fronczak'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'blinkpydoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'blinkpy.tex', 'blinkpy Documentation',
'Kevin Fronczak', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'blinkpy', 'blinkpy Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'blinkpy', 'blinkpy Documentation',
author, 'blinkpy', 'One line description of project.',
'Miscellaneous'),
]
+26
View File
@@ -0,0 +1,26 @@
.. blinkpy documentation master file, created by
sphinx-quickstart on Sat Jan 20 22:20:16 2018.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to blinkpy's documentation!
===================================
.. toctree::
:maxdepth: 1
:caption: Contents:
:glob:
README
advanced
CONTRIBUTING
modules/*
CHANGES
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
+36
View File
@@ -0,0 +1,36 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=blinkpy
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
+41
View File
@@ -0,0 +1,41 @@
.. _core_module:
===========================
Blinkpy Library Reference
===========================
blinkpy.py
-----------
.. automodule:: blinkpy.blinkpy
:members:
auth.py
--------
.. automodule:: blinkpy.auth
:members:
sync_module.py
----------------
.. automodule:: blinkpy.sync_module
:members:
camera.py
-----------
.. automodule:: blinkpy.camera
:members:
api.py
---------
.. automodule:: blinkpy.api
:members:
helpers/util.py
----------------
.. automodule:: blinkpy.helpers.util
:members:
-3
View File
@@ -1,3 +0,0 @@
"""Init file for blinkpy helper functions."""
from helpers import constants
from helpers import errors
-55
View File
@@ -1,55 +0,0 @@
'''
constants.py
Generates constants for use in blinkpy
'''
import os
MAJOR_VERSION = 0
MINOR_VERSION = 5
PATCH_VERSION = 0
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 4, 2)
PROJECT_NAME = 'blinkpy'
PROJECT_PACKAGE_NAME = 'blinkpy'
PROJECT_LICENSE = 'MIT'
PROJECT_AUTHOR = 'Kevin Fronczak'
PROJECT_COPYRIGHT = ' 2017, {}'.format(PROJECT_AUTHOR)
PROJECT_URL = 'https://github.com/fronzbot/blinkpy'
PROJECT_EMAIL = 'kfronczak@gmail.com'
PROJECT_DESCRIPTION = ('A Blink camera Python library '
'running on Python 3.')
PROJECT_LONG_DESCRIPTION = ('blinkpy is an open-source '
'unofficial API for the Blink Camera '
'system with the intention for easy '
'integration into various home '
'automation platforms.')
if os.path.exists('README.rst'):
PROJECT_LONG_DESCRIPTION = open('README.rst').read()
PROJECT_CLASSIFIERS = [
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3.4',
'Topic :: Home Automation'
]
PROJECT_GITHUB_USERNAME = 'home-assistant'
PROJECT_GITHUB_REPOSITORY = 'home-assistant'
PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
'''
URLS
'''
BLINK_URL = 'immedia-semi.com'
LOGIN_URL = 'https://prod.' + BLINK_URL + '/login'
LOGIN_BACKUP_URL = 'https://rest.piri/' + BLINK_URL + '/login'
BASE_URL = 'https://prod.' + BLINK_URL
DEFAULT_URL = 'prod.' + BLINK_URL
'''
Dictionaries
'''
ONLINE = {'online': True, 'offline': False}
-6
View File
@@ -1,6 +0,0 @@
USERNAME = (0, "Username must be a string")
PASSWORD = (1, "Password must be a string")
AUTHENTICATE = (2, "Cannot authenticate since either password or username has not been set")
AUTH_TOKEN = (3, "Authentication header incorrect. Are you sure you logged in and received your token?")
REQUEST = (4, "Cannot perform request (get/post type incorrect)")
+10 -1
View File
@@ -7,11 +7,17 @@ reports=no
# unused-argument - generic callbacks and setup methods create a lot of warnings
# too-many-* - are not enforced for the sake of readability
# too-few-* - same as too-many-*
# no-else-return - I don't see any reason to enforce this. both forms are readable
# no-self-use - stupid and only annoying
# unexpected-keyword-arg - doesn't allow for use of **kwargs, which is dumb
disable=
format,
bad-continuation,
locally-disabled,
unused-argument,
duplicate-code,
implicit-str-concat,
too-many-arguments,
too-many-branches,
too-many-instance-attributes,
@@ -20,4 +26,7 @@ disable=
too-many-return-statements,
too-many-statements,
too-many-lines,
too-few-public-methods,
too-few-public-methods,
no-else-return,
no-self-use,
unexpected-keyword-arg,
+3 -5
View File
@@ -1,5 +1,3 @@
pytest>=2.9.2
pytest-cov>=2.3.1
pytest-timeout>=1.0.0
requests>=2.12.4
testtools
python-dateutil>=2.8.1
requests>=2.24.0
python-slugify>=4.0.1
+14 -3
View File
@@ -1,3 +1,14 @@
flake8==3.3
pylint==1.6.5
pydocstyle==1.1.1
black==19.10b0
coverage==5.4
flake8==3.8.4
flake8-docstrings==1.5.0
pre-commit==2.10.1
pylint==2.6.0
pydocstyle==5.1.1
pytest==6.2.2
pytest-cov==2.11.1
pytest-sugar==0.9.4
pytest-timeout==1.4.2
restructuredtext-lint==1.3.2
pygments==2.8.0
testtools>=2.4.0
+18
View File
@@ -0,0 +1,18 @@
[flake8]
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
doctests = True
# To work with Black
max-line-length = 88
# E501: line too long
# W503: Line break occurred before a binary operator
# E203: Whitespace before ':'
# D202 No blank lines allowed after function docstring
# W504 line break after binary operator
ignore =
E501,
W503,
E203,
D202,
W504,
+41 -20
View File
@@ -1,23 +1,44 @@
"""Setup file for blinkpy."""
# -*- coding: utf-8 -*-
from setuptools import setup
from helpers.constants import (__version__, PROJECT_PACKAGE_NAME,
PROJECT_LICENSE, PROJECT_URL,
PROJECT_EMAIL, PROJECT_DESCRIPTION,
PROJECT_CLASSIFIERS, PROJECT_AUTHOR,
PROJECT_LONG_DESCRIPTION)
from os.path import abspath, dirname
from setuptools import setup, find_packages
from blinkpy.helpers.constants import (
__version__,
PROJECT_PACKAGE_NAME,
PROJECT_LICENSE,
PROJECT_URL,
PROJECT_EMAIL,
PROJECT_DESCRIPTION,
PROJECT_CLASSIFIERS,
PROJECT_AUTHOR,
)
PROJECT_VERSION = __version__
THIS_DIR = abspath(dirname(__file__))
with open(f"{THIS_DIR}/requirements.txt") as req_file:
REQUIRES = [line.rstrip() for line in req_file]
PACKAGES = find_packages(exclude=["tests*", "docs"])
with open("{}/README.rst".format(THIS_DIR), encoding="utf-8") as readme_file:
LONG_DESCRIPTION = readme_file.read()
setup(
name = PROJECT_PACKAGE_NAME,
version = __version__,
description = PROJECT_DESCRIPTION,
long_description = PROJECT_LONG_DESCRIPTION,
author = PROJECT_AUTHOR,
author_email = PROJECT_EMAIL,
license = PROJECT_LICENSE,
url = PROJECT_URL,
platforms = 'any',
py_modules = ['blinkpy'],
install_requires = ['requests>=2,<3'],
test_suite = 'tests',
classifiers = PROJECT_CLASSIFIERS
)
name=PROJECT_PACKAGE_NAME,
version=PROJECT_VERSION,
description=PROJECT_DESCRIPTION,
long_description=LONG_DESCRIPTION,
author=PROJECT_AUTHOR,
author_email=PROJECT_EMAIL,
license=PROJECT_LICENSE,
url=PROJECT_URL,
platforms="any",
py_modules=["blinkpy"],
packages=PACKAGES,
include_package_data=True,
install_requires=REQUIRES,
test_suite="tests",
classifiers=PROJECT_CLASSIFIERS,
)
+21 -274
View File
@@ -1,274 +1,21 @@
"""
Mock responses that mimic actual responses from Blink servers.
This file should be updated any time the Blink server responses
change so we can make sure blinkpy can still communicate.
"""
import helpers.constants as const
NETWORKS_RESPONSE = {}
NETWORKS_RESPONSE['summary'] = {'onboarded': True, 'name': 'Nilfgaard'}
NETWORKS_RESPONSE['networks'] = [{
'network_key': None,
'name': NETWORKS_RESPONSE['summary']['name'],
'account_id': 1989,
'id': 9898,
'encryption_key': None,
'armed': True,
'ping_interval': 60,
'video_destination': 'server',
'arm_string': 'Armed',
'feature_plan_id': None
}]
NEW_THUMBNAIL = '/NEW/THUMBNAIL/YAY'
FIRST_CAMERA = {'device_type': 'camera',
'notifications': 1,
'battery': 2,
'active': 'enabled',
'enabled': True,
'temp': 70,
'updated_at': '2017-01-01T01:23:45+00:00',
'lfr_strength': 3,
'armed': True,
'device_id': 2112,
'wifi_strength': 5,
'thumbnail': '/this/is/url1/thumb',
'name': 'First Camera',
'status': 'done'}
SECOND_CAMERA = {'device_type': 'camera',
'notifications': 0,
'battery': 3,
'active': 'disabled',
'enabled': False,
'temp': 82,
'updated_at': '2017-12-21T01:21:12+00:00',
'lfr_strength': 1,
'armed': False,
'device_id': 1221,
'wifi_strength': 1,
'thumbnail': '/this/is/url2/thumb',
'name': 'Second Camera',
'status': 'done'}
SYNC_MODULE = {'updated_at': '1970-01-01T01:00:00+00:00',
'device_type': 'sync_module',
'notifications': 2,
'device_id': 7990,
'status': 'online'}
FIRST_EVENT = {'camera_name': FIRST_CAMERA['name'],
'updated_at': '2017-10-10T03:37:37+00:00',
'sync_module_id': None,
'camera': FIRST_CAMERA['device_id'],
'type': 'motion',
'duration': None,
'status': None,
'created_at': '2017-01-28T19:51:52+00:00',
'camera_id': FIRST_CAMERA['device_id'],
'id': 666777888,
'siren_id': None,
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
'notified': True,
'siren': None,
'syncmodule': None,
'video_url': FIRST_CAMERA['thumbnail'] + '.mp4',
'command_id': None,
'network_id': None,
'account': NETWORKS_RESPONSE['networks'][0]['account_id'],
'video_id': 123000321}
SECOND_EVENT = {'updated_at': '2017-01-28T19:51:29+00:00',
'sync_module_id': SYNC_MODULE['device_id'],
'camera': None,
'type': 'armed',
'duration': None,
'status': None,
'created_at': '2017-01-28T19:51:29+00:00',
'camera_id': None,
'id': 333777555,
'siren_id': None,
'account_id': NETWORKS_RESPONSE['networks'][0]['account_id'],
'notified': False,
'siren': None,
'syncmodule': SYNC_MODULE['device_id'],
'command_id': None,
'network_id': None,
'account': NETWORKS_RESPONSE['networks'][0]['account_id']}
"""Fake response content."""
LOGIN_RESPONSE = {}
LOGIN_RESPONSE['region'] = {'ciri': 'Cintra'}
LOGIN_RESPONSE['networks'] = {
NETWORKS_RESPONSE['networks'][0]['id']: NETWORKS_RESPONSE['summary']
}
LOGIN_RESPONSE['authtoken'] = {'authtoken': 'foobar7117', 'message': 'auth'}
RESPONSE = {}
RESPONSE['account'] = {'notifications': SYNC_MODULE['notifications']}
RESPONSE['devices'] = [FIRST_CAMERA, SECOND_CAMERA, SYNC_MODULE]
RESPONSE['network'] = {'armed': NETWORKS_RESPONSE['networks'][0]['armed'],
'wifi_strength': 4,
'warning': 0,
'name': NETWORKS_RESPONSE['summary']['name'],
'notifications': SYNC_MODULE['notifications']}
RESPONSE['event'] = [FIRST_EVENT, SECOND_EVENT]
RESPONSE['syncmodule'] = {'name': 'Vengerberg', 'status': 'online'}
MOCK_BYTES = '\x00\x10JFIF\x00\x01'
IMAGE_TO_WRITE_URL = list()
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
FIRST_CAMERA['thumbnail'] + '.jpg')
IMAGE_TO_WRITE_URL.append('https://ciri.' + const.BLINK_URL +
SECOND_CAMERA['thumbnail'] + '.jpg')
FAKE_FILES = list()
def mocked_requests_post(*args, **kwargs):
"""Mock post request."""
class MockPostResponse:
"""Class for mock post response."""
def __init__(self, json_data, status_code):
"""Initialze mock post response."""
self.json_data = json_data
self.status_code = status_code
def json(self):
"""Return json data from post request."""
return self.json_data
# pylint: disable=global-variable-not-assigned
global RESPONSE
# pylint: disable=global-variable-not-assigned
global NETWORKS_RESPONSE
if args[0] is not None:
url_tail = args[0].split("/")[-1]
else:
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
if args[0] == const.LOGIN_URL:
# Request to login
return MockPostResponse(LOGIN_RESPONSE, 200)
elif args[0] == const.LOGIN_BACKUP_URL:
return MockPostResponse(LOGIN_RESPONSE, 200)
elif url_tail == 'arm' or url_tail == 'disarm':
# Request to arm/disarm system
NETWORKS_RESPONSE['networks'][0]['armed'] = url_tail == 'arm'
RESPONSE['network']['armed'] = url_tail == 'arm'
return MockPostResponse({}, 200)
elif url_tail == 'enable' or url_tail == 'disable':
# Request to enable/disable motion detection per camera
received_id = args[0].split("/")[-2]
all_devices = list()
for element in RESPONSE['devices']:
all_devices.append(element)
current_id = element['device_id']
if str(current_id) == received_id:
element['armed'] = url_tail == 'enable'
element['enabled'] = url_tail == 'enable'
RESPONSE['devices'] = all_devices
return MockPostResponse({}, 200)
elif url_tail == 'thumbnail':
# Requesting a new image
received_id = args[0].split("/")[-2]
all_devices = list()
for element in RESPONSE['devices']:
all_devices.append(element)
if str(element['device_id']) == received_id:
element['thumbnail'] = NEW_THUMBNAIL
RESPONSE['devices'] = all_devices
return MockPostResponse({}, 200)
return MockPostResponse({'message': 'ERROR', 'code': 404}, 404)
def mocked_requests_get(*args, **kwargs):
"""Mock get request."""
class MockGetResponse:
"""Class for mock get response."""
def __init__(self, json_data, status_code, raw_data=None):
"""Initialize mock get response."""
self.json_data = json_data
self.status_code = status_code
self.raw_data = raw_data
def json(self):
"""Return json data from get request."""
return self.json_data
@property
def raw(self):
"""Return raw data from get request."""
return self.raw_data
# pylint: disable=unused-variable
(region_id, region), = LOGIN_RESPONSE['region'].items()
set_region_id = args[0].split('/')[2].split('.')[0]
if set_region_id == 'rest':
set_region_id = (set_region_id + '.' +
args[0].split('/')[2].split('.')[1])
region_id = 'rest.piri'
neturl = 'https://' + set_region_id + '.' + const.BLINK_URL + '/networks'
if args[0] == neturl:
return MockGetResponse(NETWORKS_RESPONSE, 200)
elif set_region_id != region_id:
raise ConnectionError('Received region id ' + region_id +
' Expected ' + set_region_id)
elif args[0] in IMAGE_TO_WRITE_URL:
return MockGetResponse({}, 200, raw_data=MOCK_BYTES)
else:
return MockGetResponse(RESPONSE, 200)
return MockGetResponse({'message': 'ERROR', 'code': 404}, 404)
def mocked_copyfileobj(*args, **kwargs):
"""Mock shutil.copyfileobj."""
class MockCopyFileObj:
"""Class for mock copy file."""
def __init__(self, src, dst):
"""Initialize copyfile mock."""
self.src = src
self.dst = dst
# pylint: disable=global-variable-not-assigned
global FAKE_FILES
mockobj = MockCopyFileObj(args[0], args[1])
FAKE_FILES.append(mockobj.src)
return
def get_test_cameras(base_url):
"""Helper function to return cameras named in this file."""
test_cameras = dict()
for element in RESPONSE['devices']:
if ('device_type' in element and
element['device_type'] == 'camera'):
test_cameras[element['name']] = {
'device_id': str(element['device_id']),
'armed': element['armed'],
'thumbnail': (base_url +
element['thumbnail'] + '.jpg'),
'temperature': element['temp'],
'battery': element['battery'],
'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
"""Simple mock responses definitions."""
class MockResponse:
"""Class for mock request response."""
def __init__(self, json_data, status_code, raw_data=None):
"""Initialize mock get response."""
self.json_data = json_data
self.status_code = status_code
self.raw_data = raw_data
self.reason = "foobar"
def json(self):
"""Return json data from get_request."""
return self.json_data
@property
def raw(self):
"""Return raw data from get request."""
return self.raw_data
+306
View File
@@ -0,0 +1,306 @@
"""Test login handler."""
import unittest
from unittest import mock
from requests import exceptions
from blinkpy.auth import (
Auth,
LoginError,
TokenRefreshFailed,
BlinkBadResponse,
UnauthorizedError,
)
import blinkpy.helpers.constants as const
import tests.mock_responses as mresp
USERNAME = "foobar"
PASSWORD = "deadbeef"
class TestAuth(unittest.TestCase):
"""Test the Auth class in blinkpy."""
def setUp(self):
"""Set up Login Handler."""
self.auth = Auth()
def tearDown(self):
"""Clean up after test."""
self.auth = None
@mock.patch("blinkpy.helpers.util.gen_uid")
@mock.patch("blinkpy.auth.util.getpass")
def test_empty_init(self, getpwd, genuid):
"""Test initialization with no params."""
auth = Auth()
self.assertDictEqual(auth.data, {})
getpwd.return_value = "bar"
genuid.return_value = 1234
with mock.patch("builtins.input", return_value="foo"):
auth.validate_login()
expected_data = {
"username": "foo",
"password": "bar",
"uid": 1234,
"device_id": const.DEVICE_ID,
}
self.assertDictEqual(auth.data, expected_data)
@mock.patch("blinkpy.helpers.util.gen_uid")
@mock.patch("blinkpy.auth.util.getpass")
def test_barebones_init(self, getpwd, genuid):
"""Test basebones initialization."""
login_data = {"username": "foo", "password": "bar"}
auth = Auth(login_data)
self.assertDictEqual(auth.data, login_data)
getpwd.return_value = "bar"
genuid.return_value = 1234
with mock.patch("builtins.input", return_value="foo"):
auth.validate_login()
expected_data = {
"username": "foo",
"password": "bar",
"uid": 1234,
"device_id": const.DEVICE_ID,
}
self.assertDictEqual(auth.data, expected_data)
def test_full_init(self):
"""Test full initialization."""
login_data = {
"username": "foo",
"password": "bar",
"token": "token",
"host": "host",
"region_id": "region_id",
"client_id": "client_id",
"account_id": "account_id",
"uid": 1234,
"notification_key": 4321,
"device_id": "device_id",
}
auth = Auth(login_data)
self.assertEqual(auth.token, "token")
self.assertEqual(auth.host, "host")
self.assertEqual(auth.region_id, "region_id")
self.assertEqual(auth.client_id, "client_id")
self.assertEqual(auth.account_id, "account_id")
auth.validate_login()
self.assertDictEqual(auth.login_attributes, login_data)
def test_bad_response_code(self):
"""Check bad response code from server."""
self.auth.is_errored = False
fake_resp = mresp.MockResponse({"code": 404}, 404)
with self.assertRaises(exceptions.ConnectionError):
self.auth.validate_response(fake_resp, True)
self.assertTrue(self.auth.is_errored)
self.auth.is_errored = False
fake_resp = mresp.MockResponse({"code": 101}, 401)
with self.assertRaises(UnauthorizedError):
self.auth.validate_response(fake_resp, True)
self.assertTrue(self.auth.is_errored)
def test_good_response_code(self):
"""Check good response code from server."""
fake_resp = mresp.MockResponse({"foo": "bar"}, 200)
self.auth.is_errored = True
self.assertEqual(self.auth.validate_response(fake_resp, True), {"foo": "bar"})
self.assertFalse(self.auth.is_errored)
def test_response_not_json(self):
"""Check response when not json."""
fake_resp = "foobar"
self.auth.is_errored = True
self.assertEqual(self.auth.validate_response(fake_resp, False), "foobar")
self.assertFalse(self.auth.is_errored)
def test_response_bad_json(self):
"""Check response when not json but expecting json."""
self.auth.is_errored = False
with self.assertRaises(BlinkBadResponse):
self.auth.validate_response(None, True)
self.assertTrue(self.auth.is_errored)
def test_header(self):
"""Test header data."""
self.auth.token = "bar"
expected_header = {
"TOKEN_AUTH": "bar",
"user-agent": const.DEFAULT_USER_AGENT,
"content-type": "application/json",
}
self.assertDictEqual(self.auth.header, expected_header)
def test_header_no_token(self):
"""Test header without token."""
self.auth.token = None
self.assertEqual(self.auth.header, None)
@mock.patch("blinkpy.auth.Auth.validate_login", return_value=None)
@mock.patch("blinkpy.auth.api.request_login")
def test_login(self, mock_req, mock_validate):
"""Test login handling."""
fake_resp = mresp.MockResponse({"foo": "bar"}, 200)
mock_req.return_value = fake_resp
self.assertEqual(self.auth.login(), {"foo": "bar"})
@mock.patch("blinkpy.auth.Auth.validate_login", return_value=None)
@mock.patch("blinkpy.auth.api.request_login")
def test_login_bad_response(self, mock_req, mock_validate):
"""Test login handling when bad response."""
fake_resp = mresp.MockResponse({"foo": "bar"}, 404)
mock_req.return_value = fake_resp
self.auth.is_errored = False
with self.assertRaises(LoginError):
self.auth.login()
with self.assertRaises(TokenRefreshFailed):
self.auth.refresh_token()
self.assertTrue(self.auth.is_errored)
@mock.patch("blinkpy.auth.Auth.login")
def test_refresh_token(self, mock_login):
"""Test refresh token method."""
mock_login.return_value = {
"account": {"account_id": 5678, "client_id": 1234, "tier": "test"},
"auth": {"token": "foobar"},
}
self.assertTrue(self.auth.refresh_token())
self.assertEqual(self.auth.region_id, "test")
self.assertEqual(self.auth.token, "foobar")
self.assertEqual(self.auth.client_id, 1234)
self.assertEqual(self.auth.account_id, 5678)
@mock.patch("blinkpy.auth.Auth.login")
def test_refresh_token_failed(self, mock_login):
"""Test refresh token failed."""
mock_login.return_value = {}
self.auth.is_errored = False
with self.assertRaises(TokenRefreshFailed):
self.auth.refresh_token()
self.assertTrue(self.auth.is_errored)
def test_check_key_required(self):
"""Check key required method."""
self.auth.login_response = {}
self.assertFalse(self.auth.check_key_required())
self.auth.login_response = {"account": {"client_verification_required": False}}
self.assertFalse(self.auth.check_key_required())
self.auth.login_response = {"account": {"client_verification_required": True}}
self.assertTrue(self.auth.check_key_required())
@mock.patch("blinkpy.auth.api.request_logout")
def test_logout(self, mock_req):
"""Test logout method."""
mock_blink = MockBlink(None)
mock_req.return_value = True
self.assertTrue(self.auth.logout(mock_blink))
@mock.patch("blinkpy.auth.api.request_verify")
def test_send_auth_key(self, mock_req):
"""Check sending of auth key."""
mock_blink = MockBlink(None)
mock_req.return_value = mresp.MockResponse({"valid": True}, 200)
self.assertTrue(self.auth.send_auth_key(mock_blink, 1234))
self.assertTrue(mock_blink.available)
mock_req.return_value = mresp.MockResponse(None, 200)
self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))
mock_req.return_value = mresp.MockResponse({}, 200)
self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))
self.assertTrue(self.auth.send_auth_key(mock_blink, None))
@mock.patch("blinkpy.auth.api.request_verify")
def test_send_auth_key_fail(self, mock_req):
"""Check handling of auth key failure."""
mock_blink = MockBlink(None)
mock_req.return_value = mresp.MockResponse(None, 200)
self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))
mock_req.return_value = mresp.MockResponse({}, 200)
self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))
@mock.patch("blinkpy.auth.Auth.validate_response")
@mock.patch("blinkpy.auth.Auth.refresh_token")
def test_query_retry(self, mock_refresh, mock_validate):
"""Check handling of request retry."""
self.auth.session = MockSession()
mock_validate.side_effect = [UnauthorizedError, "foobar"]
mock_refresh.return_value = True
self.assertEqual(self.auth.query(url="http://example.com"), "foobar")
@mock.patch("blinkpy.auth.Auth.validate_response")
@mock.patch("blinkpy.auth.Auth.refresh_token")
def test_query_retry_failed(self, mock_refresh, mock_validate):
"""Check handling of failed retry request."""
self.auth.session = MockSession()
mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse]
mock_refresh.return_value = True
self.assertEqual(self.auth.query(url="http://example.com"), None)
mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
self.assertEqual(self.auth.query(url="http://example.com"), None)
def test_default_session(self):
"""Test default session creation."""
sess = self.auth.create_session()
adapter = sess.adapters["https://"]
self.assertEqual(adapter.max_retries.total, 3)
self.assertEqual(adapter.max_retries.backoff_factor, 1)
self.assertEqual(
adapter.max_retries.status_forcelist, [429, 500, 502, 503, 504]
)
def test_custom_session_full(self):
"""Test full custom session creation."""
opts = {"backoff": 2, "retries": 10, "retry_list": [404]}
sess = self.auth.create_session(opts=opts)
adapter = sess.adapters["https://"]
self.assertEqual(adapter.max_retries.total, 10)
self.assertEqual(adapter.max_retries.backoff_factor, 2)
self.assertEqual(adapter.max_retries.status_forcelist, [404])
def test_custom_session_partial(self):
"""Test partial custom session creation."""
opts1 = {"backoff": 2}
opts2 = {"retries": 5}
opts3 = {"retry_list": [101, 202]}
sess1 = self.auth.create_session(opts=opts1)
sess2 = self.auth.create_session(opts=opts2)
sess3 = self.auth.create_session(opts=opts3)
adapt1 = sess1.adapters["https://"]
adapt2 = sess2.adapters["https://"]
adapt3 = sess3.adapters["https://"]
self.assertEqual(adapt1.max_retries.total, 3)
self.assertEqual(adapt1.max_retries.backoff_factor, 2)
self.assertEqual(adapt1.max_retries.status_forcelist, [429, 500, 502, 503, 504])
self.assertEqual(adapt2.max_retries.total, 5)
self.assertEqual(adapt2.max_retries.backoff_factor, 1)
self.assertEqual(adapt2.max_retries.status_forcelist, [429, 500, 502, 503, 504])
self.assertEqual(adapt3.max_retries.total, 3)
self.assertEqual(adapt3.max_retries.backoff_factor, 1)
self.assertEqual(adapt3.max_retries.status_forcelist, [101, 202])
class MockSession:
"""Object to mock a session."""
def send(self, *args, **kwargs):
"""Mock send function."""
return None
class MockBlink:
"""Object to mock basic blink class."""
def __init__(self, login_response):
"""Initialize mock blink class."""
self.available = False
self.login_response = login_response
-101
View File
@@ -1,101 +0,0 @@
"""
Tests the camera initialization and attributes of
individual BlinkCamera instantiations.
"""
import unittest
from unittest import mock
import blinkpy
import tests.mock_responses as mresp
USERNAME = 'foobar'
PASSWORD = 'deadbeef'
class TestBlinkCameraSetup(unittest.TestCase):
"""Test the Blink class in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink = blinkpy.Blink(username=USERNAME,
password=PASSWORD)
def tearDown(self):
"""Clean up after test."""
self.blink = None
@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):
"""Tests all property set/recall."""
test_value = 'foobar'
test_region_id = list(mresp.LOGIN_RESPONSE['region'].keys())[0]
self.blink.setup_system()
for name in self.blink.cameras:
camera = self.blink.cameras[name]
camera.name = test_value
camera.clip = test_value + '.mp4'
camera.thumbnail = test_value + '.jpg'
camera.temperature = 10
camera.battery = 0
camera.notifications = 100
camera.image_link = test_value + '/image.jpg'
camera.arm_link = test_value + '/arm'
camera.header = {'foo': 'bar'}
camera.motion = {'bar': 'foo'}
self.assertEqual(camera.clip, test_value + '.mp4')
self.assertEqual(camera.name, test_value)
self.assertEqual(camera.thumbnail, test_value + '.jpg')
self.assertEqual(camera.temperature, 10)
self.assertEqual(camera.battery, 0)
self.assertEqual(camera.notifications, 100)
self.assertEqual(camera.image_link, test_value + '/image.jpg')
self.assertEqual(camera.arm_link, test_value + '/arm')
self.assertEqual(camera.header, {'foo': 'bar'})
self.assertEqual(camera.motion, {'bar': 'foo'})
self.assertEqual(camera.region_id, test_region_id)
@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_values_from_setup(self, mock_get, mock_post):
"""Tests all property values after camera setup."""
self.blink.setup_system()
# Get expected test values
test_network_id = str(mresp.NETWORKS_RESPONSE['networks'][0]['id'])
# pylint: disable=unused-variable
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
# pylint: disable=protected-access
expected_header = self.blink._auth_header
test_urls = blinkpy.BlinkURLHandler(region_id)
test_cameras = mresp.get_test_cameras(test_urls.base_url)
test_net_id_url = test_urls.network_url + test_network_id
for name in self.blink.cameras:
camera = self.blink.cameras[name]
self.assertEqual(name, camera.name)
if name in test_cameras:
self.assertEqual(camera.id,
test_cameras[name]['device_id'])
self.assertEqual(camera.armed,
test_cameras[name]['armed'])
self.assertEqual(camera.thumbnail,
test_cameras[name]['thumbnail'])
self.assertEqual(camera.temperature,
test_cameras[name]['temperature'])
self.assertEqual(camera.battery,
test_cameras[name]['battery'])
self.assertEqual(camera.notifications,
test_cameras[name]['notifications'])
else:
self.fail("Camera wasn't initialized: " + name)
expected_arm_link = test_net_id_url + '/camera/' + camera.id + '/'
expected_image_link = expected_arm_link + 'thumbnail'
self.assertEqual(camera.image_link, expected_image_link)
self.assertEqual(camera.arm_link, expected_arm_link)
self.assertEqual(camera.header, expected_header)
+130 -159
View File
@@ -1,159 +1,130 @@
"""Tests camera and system functions."""
import unittest
from unittest import mock
import blinkpy
import tests.mock_responses as mresp
USERNAME = 'foobar'
PASSWORD = 'deadbeef'
class TestBlinkFunctions(unittest.TestCase):
"""Test Blink and BlinkCamera functions in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink = blinkpy.Blink(username=USERNAME,
password=PASSWORD)
(self.region_id, self.region), = mresp.LOGIN_RESPONSE['region'].items()
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
def tearDown(self):
"""Clean up after test."""
self.blink = None
self.region = None
self.region_id = None
self.test_urls = None
@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_set_motion_detect(self, mock_get, mock_post):
"""Checks if we can set motion detection."""
self.blink.setup_system()
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
for camera_name in test_cameras:
self.blink.cameras[camera_name].set_motion_detect(True)
self.blink.refresh()
self.assertEqual(self.blink.cameras[camera_name].armed, True)
self.blink.cameras[camera_name].set_motion_detect(False)
self.blink.refresh()
self.assertEqual(self.blink.cameras[camera_name].armed, False)
@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_last_motion(self, mock_get, mock_post):
"""Checks that we can get the last motion info."""
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
test_events = mresp.RESPONSE['event']
test_video = dict()
test_image = dict()
test_time = dict()
for event in test_events:
if event['type'] == 'motion':
url = self.test_urls.base_url + event['video_url']
test_video[event['camera_name']] = url
test_image[event['camera_name']] = url[:-3] + 'jpg'
test_time[event['camera_name']] = event['created_at']
self.blink.setup_system()
for name in self.blink.cameras:
camera = self.blink.cameras[name]
self.blink.last_motion()
if name in test_video:
self.assertEqual(camera.motion['video'], test_video[name])
else:
self.assertEqual(camera.motion, {})
if name in test_image:
self.assertEqual(camera.motion['image'], test_image[name])
else:
self.assertEqual(camera.motion, {})
if name in test_video:
self.assertEqual(camera.motion['time'], test_time[name])
else:
self.assertEqual(camera.motion, {})
@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_take_new_picture(self, mock_get, mock_post):
"""Checks if we can take a new picture and retrieve the thumbnail."""
self.blink.setup_system()
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
test_thumbnail = self.test_urls.base_url + mresp.NEW_THUMBNAIL + '.jpg'
# Snap picture for each camera and check new thumb
for camera_name in test_cameras:
camera = self.blink.cameras[camera_name]
camera.snap_picture()
camera.image_refresh()
self.assertEqual(camera.thumbnail, test_thumbnail)
# Manually set thumbnail, and then globally refresh and check
for camera_name in test_cameras:
camera = self.blink.cameras[camera_name]
camera.thumbnail = 'Testing'
self.assertEqual(camera.thumbnail, 'Testing')
self.blink.refresh()
for camera_name in test_cameras:
camera = self.blink.cameras[camera_name]
self.assertEqual(camera.thumbnail, test_thumbnail)
def test_camera_update(self):
"""Checks that the update function is doing the right thing."""
self.test_urls = blinkpy.BlinkURLHandler('test')
test_config = mresp.FIRST_CAMERA
test_camera = blinkpy.blinkpy.BlinkCamera(test_config, self.test_urls)
test_update = mresp.SECOND_CAMERA
test_camera.update(test_update)
test_image_url = self.test_urls.base_url + test_update['thumbnail']
test_thumbnail = test_image_url + '.jpg'
test_clip = test_image_url + '.mp4'
self.assertEqual(test_camera.name, test_update['name'])
self.assertEqual(test_camera.armed, test_update['armed'])
self.assertEqual(test_camera.thumbnail, test_thumbnail)
self.assertEqual(test_camera.clip, test_clip)
self.assertEqual(test_camera.temperature, test_update['temp'])
self.assertEqual(test_camera.battery, test_update['battery'])
self.assertEqual(test_camera.notifications,
test_update['notifications'])
@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_thumbs(self, mock_get, mock_post):
"""Checks to see if we can retrieve camera thumbs."""
self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
test_cameras = mresp.get_test_cameras(self.test_urls.base_url)
self.blink.setup_system()
for name in self.blink.cameras:
thumb = self.blink.camera_thumbs[name]
self.assertEqual(test_cameras[name]['thumbnail'], thumb)
@mock.patch('blinkpy.blinkpy.copyfileobj',
side_effect=mresp.mocked_copyfileobj)
@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_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)
"""Tests camera and system functions."""
import unittest
from unittest import mock
import logging
from blinkpy import blinkpy
from blinkpy.sync_module import BlinkSyncModule
from blinkpy.camera import BlinkCamera
from blinkpy.helpers.util import get_time, BlinkURLHandler
class MockSyncModule(BlinkSyncModule):
"""Mock blink sync module object."""
def get_network_info(self):
"""Mock network info method."""
return True
class MockCamera(BlinkCamera):
"""Mock blink camera object."""
def update(self, config, force_cache=False, **kwargs):
"""Mock camera update method."""
class TestBlinkFunctions(unittest.TestCase):
"""Test Blink and BlinkCamera functions in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink = blinkpy.Blink()
self.blink.urls = BlinkURLHandler("test")
def tearDown(self):
"""Clean up after test."""
self.blink = None
def test_merge_cameras(self):
"""Test merge camera functionality."""
first_dict = {"foo": "bar", "test": 123}
next_dict = {"foobar": 456, "bar": "foo"}
self.blink.sync["foo"] = BlinkSyncModule(self.blink, "foo", 1, [])
self.blink.sync["bar"] = BlinkSyncModule(self.blink, "bar", 2, [])
self.blink.sync["foo"].cameras = first_dict
self.blink.sync["bar"].cameras = next_dict
result = self.blink.merge_cameras()
expected = {"foo": "bar", "test": 123, "foobar": 456, "bar": "foo"}
self.assertEqual(expected, result)
@mock.patch("blinkpy.blinkpy.api.request_videos")
def test_download_video_exit(self, mock_req):
"""Test we exit method when provided bad response."""
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
blink.last_refresh = 0
mock_req.return_value = {}
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"INFO:blinkpy.blinkpy:No videos found on page 1. Exiting.",
]
with self.assertLogs() as dl_log:
blink.download_videos("/tmp")
self.assertEqual(dl_log.output, expected_log)
@mock.patch("blinkpy.blinkpy.api.request_videos")
def test_parse_downloaded_items(self, mock_req):
"""Test ability to parse downloaded items list."""
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
generic_entry = {
"created_at": "1970",
"device_name": "foo",
"deleted": True,
"media": "/bar.mp4",
}
result = [generic_entry]
mock_req.return_value = {"media": result}
blink.last_refresh = 0
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"DEBUG:blinkpy.blinkpy:foo: /bar.mp4 is marked as deleted.",
]
with self.assertLogs() as dl_log:
blink.download_videos("/tmp", stop=2)
self.assertEqual(dl_log.output, expected_log)
@mock.patch("blinkpy.blinkpy.api.request_videos")
def test_parse_camera_not_in_list(self, mock_req):
"""Test ability to parse downloaded items list."""
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
generic_entry = {
"created_at": "1970",
"device_name": "foo",
"deleted": True,
"media": "/bar.mp4",
}
result = [generic_entry]
mock_req.return_value = {"media": result}
blink.last_refresh = 0
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"DEBUG:blinkpy.blinkpy:Skipping videos for foo.",
]
with self.assertLogs() as dl_log:
blink.download_videos("/tmp", camera="bar", stop=2)
self.assertEqual(dl_log.output, expected_log)
@mock.patch("blinkpy.blinkpy.api.request_network_update")
@mock.patch("blinkpy.auth.Auth.query")
def test_refresh(self, mock_req, mock_update):
"""Test ability to refresh system."""
mock_update.return_value = {"network": {"sync_module_error": False}}
mock_req.return_value = None
self.blink.last_refresh = 0
self.blink.available = True
self.blink.sync["foo"] = MockSyncModule(self.blink, "foo", 1, [])
self.blink.cameras = {"bar": MockCamera(self.blink.sync)}
self.blink.sync["foo"].cameras = self.blink.cameras
self.assertTrue(self.blink.refresh())
-163
View File
@@ -1,163 +0,0 @@
"""
Tests the system initialization and attributes of
the main Blink system. Tests if we properly catch
any communication related errors at startup.
"""
import unittest
from unittest import mock
import blinkpy
import tests.mock_responses as mresp
import helpers.constants as const
USERNAME = 'foobar'
PASSWORD = 'deadbeef'
class TestBlinkSetup(unittest.TestCase):
"""Test the Blink class in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink_no_cred = blinkpy.Blink()
self.blink = blinkpy.Blink(username=USERNAME,
password=PASSWORD)
def tearDown(self):
"""Clean up after test."""
self.blink = None
self.blink_no_cred = None
def test_initialization(self):
"""Verify we can initialize blink."""
# pylint: disable=protected-access
self.assertEqual(self.blink._username, USERNAME)
# pylint: disable=protected-access
self.assertEqual(self.blink._password, PASSWORD)
def test_no_credentials(self):
"""Check that we throw an exception when no username/password."""
with self.assertRaises(blinkpy.BlinkAuthenticationException):
self.blink_no_cred.get_auth_token()
with self.assertRaises(blinkpy.BlinkAuthenticationException):
self.blink_no_cred.setup_system()
# pylint: disable=protected-access
self.blink_no_cred._username = USERNAME
with self.assertRaises(blinkpy.BlinkAuthenticationException):
self.blink_no_cred.get_auth_token()
def test_no_auth_header(self):
"""Check that we throw an excpetion when no auth header given."""
# pylint: disable=unused-variable
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
self.blink.urls = blinkpy.BlinkURLHandler(region_id)
with self.assertRaises(blinkpy.BlinkException):
self.blink.get_ids()
with self.assertRaises(blinkpy.BlinkException):
self.blink.get_summary()
@mock.patch('blinkpy.blinkpy.getpass.getpass')
def test_manual_login(self, getpwd):
"""Check that we can manually use the login() function."""
getpwd.return_value = PASSWORD
with mock.patch('builtins.input', return_value=USERNAME):
self.blink_no_cred.login()
# pylint: disable=protected-access
self.assertEqual(self.blink_no_cred._username, USERNAME)
# pylint: disable=protected-access
self.assertEqual(self.blink_no_cred._password, PASSWORD)
@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_bad_request(self, mock_get, mock_post):
"""Check that we raise an Exception with a bad request."""
with self.assertRaises(blinkpy.BlinkException):
# pylint: disable=protected-access
blinkpy.blinkpy._request(None, reqtype='bad')
with self.assertRaises(blinkpy.BlinkAuthenticationException):
# pylint: disable=protected-access
blinkpy.blinkpy._request(None, reqtype='post')
@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_full_setup(self, mock_get, mock_post):
"""Check that we can set Blink up properly."""
self.blink.setup_system()
# Get all test values
authtoken = mresp.LOGIN_RESPONSE['authtoken']['authtoken']
(region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
host = region_id + '.' + const.BLINK_URL
network_id = mresp.NETWORKS_RESPONSE['networks'][0]['id']
account_id = mresp.NETWORKS_RESPONSE['networks'][0]['account_id']
test_urls = blinkpy.BlinkURLHandler(region_id)
test_cameras = mresp.get_test_cameras(test_urls.base_url)
test_camera_id = mresp.get_test_id_table()
# Check that all links have been set properly
self.assertEqual(self.blink.region_id, region_id)
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)
# Check that all properties have been set after startup
# pylint: disable=protected-access
self.assertEqual(self.blink._token, authtoken)
# pylint: disable=protected-access
self.assertEqual(self.blink._host, host)
self.assertEqual(self.blink.network_id, str(network_id))
self.assertEqual(self.blink.account_id, str(account_id))
self.assertEqual(self.blink.region, region)
# Verify we have initialized all the cameras
self.assertEqual(self.blink.id_table, test_camera_id)
for camera in test_cameras:
self.assertTrue(camera in self.blink.cameras)
@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_arm_disarm_system(self, mock_get, mock_post):
"""Check that we can arm/disarm the system"""
self.blink.setup_system()
self.blink.arm = False
self.assertIs(self.blink.arm, False)
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.get',
side_effect=mresp.mocked_requests_get)
def test_check_online_status(self, mock_get, mock_post):
"""Check that we can get our online status."""
self.blink.setup_system()
expected_status = const.ONLINE[mresp.RESPONSE['syncmodule']['status']]
self.assertIs(self.blink.online, expected_status)
@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_setup_backup_subdomain(self, mock_get, mock_post):
"""Check that we can use the 'rest.piri' subdomain."""
test_urls = blinkpy.BlinkURLHandler('rest.piri')
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)
+297
View File
@@ -0,0 +1,297 @@
"""
Test full system.
Tests the system initialization and attributes of
the main Blink system. Tests if we properly catch
any communication related errors at startup.
"""
import unittest
from unittest import mock
from blinkpy.blinkpy import Blink, BlinkSetupError
from blinkpy.sync_module import BlinkOwl
from blinkpy.helpers.constants import __version__
class TestBlinkSetup(unittest.TestCase):
"""Test the Blink class in blinkpy."""
def setUp(self):
"""Initialize blink test object."""
self.blink = Blink()
self.blink.available = True
def tearDown(self):
"""Cleanup blink test object."""
self.blink = None
def test_initialization(self):
"""Verify we can initialize blink."""
blink = Blink()
self.assertEqual(blink.version, __version__)
def test_network_id_failure(self):
"""Check that with bad network data a setup error is raised."""
self.blink.networks = None
with self.assertRaises(BlinkSetupError):
self.blink.setup_network_ids()
def test_multiple_networks(self):
"""Check that we handle multiple networks appropriately."""
self.blink.networks = {
"0000": {"onboarded": False, "name": "foo"},
"5678": {"onboarded": True, "name": "bar"},
"1234": {"onboarded": False, "name": "test"},
}
self.blink.setup_network_ids()
self.assertTrue("5678" in self.blink.network_ids)
def test_multiple_onboarded_networks(self):
"""Check that we handle multiple networks appropriately."""
self.blink.networks = {
"0000": {"onboarded": False, "name": "foo"},
"5678": {"onboarded": True, "name": "bar"},
"1234": {"onboarded": True, "name": "test"},
}
self.blink.setup_network_ids()
self.assertTrue("0000" not in self.blink.network_ids)
self.assertTrue("5678" in self.blink.network_ids)
self.assertTrue("1234" in self.blink.network_ids)
@mock.patch("blinkpy.blinkpy.time.time")
def test_throttle(self, mock_time):
"""Check throttling functionality."""
now = self.blink.refresh_rate + 1
mock_time.return_value = now
self.assertEqual(self.blink.last_refresh, None)
self.assertEqual(self.blink.check_if_ok_to_update(), True)
self.assertEqual(self.blink.last_refresh, None)
with mock.patch(
"blinkpy.sync_module.BlinkSyncModule.refresh", return_value=True
), mock.patch("blinkpy.blinkpy.Blink.get_homescreen", return_value=True):
self.blink.refresh(force=True)
self.assertEqual(self.blink.last_refresh, now)
self.assertEqual(self.blink.check_if_ok_to_update(), False)
self.assertEqual(self.blink.last_refresh, now)
def test_sync_case_insensitive_dict(self):
"""Check that we can access sync modules ignoring case."""
self.blink.sync["test"] = 1234
self.assertEqual(self.blink.sync["test"], 1234)
self.assertEqual(self.blink.sync["TEST"], 1234)
self.assertEqual(self.blink.sync["tEsT"], 1234)
@mock.patch("blinkpy.api.request_camera_usage")
@mock.patch("blinkpy.api.request_homescreen")
def test_setup_cameras(self, mock_home, mock_req):
"""Check retrieval of camera information."""
mock_home.return_value = {}
mock_req.return_value = {
"networks": [
{
"network_id": 1234,
"cameras": [
{"id": 5678, "name": "foo"},
{"id": 5679, "name": "bar"},
],
},
{"network_id": 4321, "cameras": [{"id": 0000, "name": "test"}]},
]
}
result = self.blink.setup_camera_list()
self.assertEqual(
result,
{
"1234": [{"name": "foo", "id": 5678}, {"name": "bar", "id": 5679}],
"4321": [{"name": "test", "id": 0000}],
},
)
@mock.patch("blinkpy.api.request_camera_usage")
def test_setup_cameras_failure(self, mock_home):
"""Check that on failure we raise a setup error."""
mock_home.return_value = {}
with self.assertRaises(BlinkSetupError):
self.blink.setup_camera_list()
mock_home.return_value = None
with self.assertRaises(BlinkSetupError):
self.blink.setup_camera_list()
def test_setup_urls(self):
"""Check setup of URLS."""
self.blink.auth.region_id = "test"
self.blink.setup_urls()
self.assertEqual(self.blink.urls.subdomain, "rest-test")
def test_setup_urls_failure(self):
"""Check that on failure we raise a setup error."""
self.blink.auth.region_id = None
with self.assertRaises(BlinkSetupError):
self.blink.setup_urls()
@mock.patch("blinkpy.api.request_networks")
def test_setup_networks(self, mock_networks):
"""Check setup of networks."""
mock_networks.return_value = {"summary": "foobar"}
self.blink.setup_networks()
self.assertEqual(self.blink.networks, "foobar")
@mock.patch("blinkpy.api.request_networks")
def test_setup_networks_failure(self, mock_networks):
"""Check that on failure we raise a setup error."""
mock_networks.return_value = {}
with self.assertRaises(BlinkSetupError):
self.blink.setup_networks()
mock_networks.return_value = None
with self.assertRaises(BlinkSetupError):
self.blink.setup_networks()
@mock.patch("blinkpy.blinkpy.Auth.send_auth_key")
def test_setup_prompt_2fa(self, mock_key):
"""Test setup with 2fa prompt."""
self.blink.auth.data["username"] = "foobar"
self.blink.key_required = True
mock_key.return_value = True
with mock.patch("builtins.input", return_value="foo"):
self.blink.setup_prompt_2fa()
self.assertFalse(self.blink.key_required)
mock_key.return_value = False
with mock.patch("builtins.input", return_value="foo"):
self.blink.setup_prompt_2fa()
self.assertTrue(self.blink.key_required)
@mock.patch("blinkpy.blinkpy.Blink.setup_camera_list")
@mock.patch("blinkpy.api.request_networks")
@mock.patch("blinkpy.blinkpy.Blink.setup_owls")
def test_setup_post_verify(self, mock_owl, mock_networks, mock_camera):
"""Test setup after verification."""
self.blink.available = False
self.blink.key_required = True
mock_owl.return_value = True
mock_networks.return_value = {
"summary": {"foo": {"onboarded": False, "name": "bar"}}
}
mock_camera.return_value = []
self.assertTrue(self.blink.setup_post_verify())
self.assertTrue(self.blink.available)
self.assertFalse(self.blink.key_required)
@mock.patch("blinkpy.api.request_networks")
def test_setup_post_verify_failure(self, mock_networks):
"""Test failed setup after verification."""
self.blink.available = False
mock_networks.return_value = {}
self.assertFalse(self.blink.setup_post_verify())
self.assertFalse(self.blink.available)
def test_merge_cameras(self):
"""Test merging of cameras."""
self.blink.sync = {
"foo": MockSync({"test": 123, "foo": "bar"}),
"bar": MockSync({"fizz": "buzz", "bar": "foo"}),
}
combined = self.blink.merge_cameras()
self.assertEqual(combined["test"], 123)
self.assertEqual(combined["foo"], "bar")
self.assertEqual(combined["fizz"], "buzz")
self.assertEqual(combined["bar"], "foo")
@mock.patch("blinkpy.blinkpy.BlinkOwl.start")
def test_initialize_blink_minis(self, mock_start):
"""Test blink mini initialization."""
mock_start.return_value = True
self.blink.homescreen = {
"owls": [
{
"enabled": False,
"id": 1,
"name": "foo",
"network_id": 2,
"onboarded": True,
"status": "online",
"thumbnail": "/foo/bar",
"serial": "1234",
},
{
"enabled": True,
"id": 3,
"name": "bar",
"network_id": 4,
"onboarded": True,
"status": "online",
"thumbnail": "/foo/bar",
"serial": "abcd",
},
]
}
self.blink.sync = {}
self.blink.setup_owls()
self.assertEqual(self.blink.sync["foo"].__class__, BlinkOwl)
self.assertEqual(self.blink.sync["bar"].__class__, BlinkOwl)
self.assertEqual(self.blink.sync["foo"].arm, False)
self.assertEqual(self.blink.sync["bar"].arm, True)
self.assertEqual(self.blink.sync["foo"].name, "foo")
self.assertEqual(self.blink.sync["bar"].name, "bar")
def test_blink_mini_cameras_returned(self):
"""Test that blink mini cameras are found if attached to sync module."""
self.blink.network_ids = ["1234"]
self.blink.homescreen = {
"owls": [
{
"id": 1,
"name": "foo",
"network_id": 1234,
"onboarded": True,
"enabled": True,
"status": "online",
"thumbnail": "/foo/bar",
"serial": "abc123",
}
]
}
result = self.blink.setup_owls()
self.assertEqual(self.blink.network_ids, ["1234"])
self.assertEqual(
result, [{"1234": {"name": "foo", "id": "1234", "type": "mini"}}]
)
self.blink.no_owls = True
self.blink.network_ids = []
self.blink.get_homescreen()
result = self.blink.setup_owls()
self.assertEqual(self.blink.network_ids, [])
self.assertEqual(result, [])
@mock.patch("blinkpy.api.request_camera_usage")
def test_blink_mini_attached_to_sync(self, mock_usage):
"""Test that blink mini cameras are properly attached to sync module."""
self.blink.network_ids = ["1234"]
self.blink.homescreen = {
"owls": [
{
"id": 1,
"name": "foo",
"network_id": 1234,
"onboarded": True,
"enabled": True,
"status": "online",
"thumbnail": "/foo/bar",
"serial": "abc123",
}
]
}
mock_usage.return_value = {"networks": [{"cameras": [], "network_id": 1234}]}
result = self.blink.setup_camera_list()
self.assertEqual(
result, {"1234": [{"name": "foo", "id": "1234", "type": "mini"}]}
)
class MockSync:
"""Mock sync module class."""
def __init__(self, cameras):
"""Initialize fake class."""
self.cameras = cameras
+185
View File
@@ -0,0 +1,185 @@
"""
Test all camera attributes.
Tests the camera initialization and attributes of
individual BlinkCamera instantiations once the
Blink system is set up.
"""
import unittest
from unittest import mock
from blinkpy.blinkpy import Blink
from blinkpy.helpers.util import BlinkURLHandler
from blinkpy.sync_module import BlinkSyncModule
from blinkpy.camera import BlinkCamera, BlinkCameraMini
CAMERA_CFG = {
"camera": [
{
"battery_voltage": 90,
"motion_alert": True,
"wifi_strength": -30,
"temperature": 68,
}
]
}
@mock.patch("blinkpy.auth.Auth.query")
class TestBlinkCameraSetup(unittest.TestCase):
"""Test the Blink class in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink = Blink()
self.blink.urls = BlinkURLHandler("test")
self.blink.sync["test"] = BlinkSyncModule(self.blink, "test", 1234, [])
self.camera = BlinkCamera(self.blink.sync["test"])
self.camera.name = "foobar"
self.blink.sync["test"].cameras["foobar"] = self.camera
def tearDown(self):
"""Clean up after test."""
self.blink = None
self.camera = None
def test_camera_update(self, mock_resp):
"""Test that we can properly update camera properties."""
config = {
"name": "new",
"id": 1234,
"network_id": 5678,
"serial": "12345678",
"enabled": False,
"battery_voltage": 90,
"battery_state": "ok",
"temperature": 68,
"wifi_strength": 4,
"thumbnail": "/thumb",
}
self.camera.last_record = ["1"]
self.camera.sync.last_record = {
"new": {"clip": "/test.mp4", "time": "1970-01-01T00:00:00"}
}
mock_resp.side_effect = [
{"temp": 71},
"test",
"foobar",
]
self.camera.update(config)
self.assertEqual(self.camera.name, "new")
self.assertEqual(self.camera.camera_id, "1234")
self.assertEqual(self.camera.network_id, "5678")
self.assertEqual(self.camera.serial, "12345678")
self.assertEqual(self.camera.motion_enabled, False)
self.assertEqual(self.camera.battery, "ok")
self.assertEqual(self.camera.temperature, 68)
self.assertEqual(self.camera.temperature_c, 20)
self.assertEqual(self.camera.temperature_calibrated, 71)
self.assertEqual(self.camera.wifi_strength, 4)
self.assertEqual(
self.camera.thumbnail, "https://rest-test.immedia-semi.com/thumb.jpg"
)
self.assertEqual(
self.camera.clip, "https://rest-test.immedia-semi.com/test.mp4"
)
self.assertEqual(self.camera.image_from_cache, "test")
self.assertEqual(self.camera.video_from_cache, "foobar")
def test_no_thumbnails(self, mock_resp):
"""Tests that thumbnail is 'None' if none found."""
mock_resp.return_value = "foobar"
self.camera.last_record = ["1"]
config = {
"name": "new",
"id": 1234,
"network_id": 5678,
"serial": "12345678",
"enabled": False,
"battery_voltage": 90,
"battery_state": "ok",
"temperature": 68,
"wifi_strength": 4,
"thumbnail": "",
}
self.camera.sync.homescreen = {"devices": []}
self.assertEqual(self.camera.temperature_calibrated, None)
with self.assertLogs() as logrecord:
self.camera.update(config, force=True)
self.assertEqual(self.camera.thumbnail, None)
self.assertEqual(self.camera.last_record, ["1"])
self.assertEqual(self.camera.temperature_calibrated, 68)
self.assertEqual(
logrecord.output,
[
(
"WARNING:blinkpy.camera:Could not retrieve calibrated "
"temperature."
),
("WARNING:blinkpy.camera:Could not find thumbnail for camera new"),
],
)
def test_no_video_clips(self, mock_resp):
"""Tests that we still proceed with camera setup with no videos."""
mock_resp.return_value = "foobar"
config = {
"name": "new",
"id": 1234,
"network_id": 5678,
"serial": "12345678",
"enabled": False,
"battery_voltage": 90,
"battery_state": "ok",
"temperature": 68,
"wifi_strength": 4,
"thumbnail": "/foobar",
}
self.camera.sync.homescreen = {"devices": []}
self.camera.update(config, force_cache=True)
self.assertEqual(self.camera.clip, None)
self.assertEqual(self.camera.video_from_cache, None)
def test_camera_arm_status(self, mock_resp):
"""Test arming and disarming camera."""
self.camera.motion_enabled = None
self.assertFalse(self.camera.arm)
self.camera.motion_enabled = False
self.assertFalse(self.camera.arm)
self.camera.motion_enabled = True
self.assertTrue(self.camera.arm)
@mock.patch("blinkpy.camera.api.request_motion_detection_enable")
@mock.patch("blinkpy.camera.api.request_motion_detection_disable")
def test_motion_detection_enable_disable(self, mock_dis, mock_en, mock_rep):
"""Test setting motion detection enable properly."""
mock_dis.return_value = "disable"
mock_en.return_value = "enable"
self.assertEqual(self.camera.set_motion_detect(True), "enable")
self.assertEqual(self.camera.set_motion_detect(False), "disable")
def test_missing_attributes(self, mock_resp):
"""Test that attributes return None if missing."""
self.camera.temperature = None
self.camera.serial = None
attr = self.camera.attributes
self.assertEqual(attr["serial"], None)
self.assertEqual(attr["temperature"], None)
self.assertEqual(attr["temperature_c"], None)
def test_mini_missing_attributes(self, mock_resp):
"""Test that attributes return None if missing."""
camera = BlinkCameraMini(self.blink.sync)
self.blink.sync.network_id = None
self.blink.sync.name = None
attr = camera.attributes
for key in attr:
self.assertEqual(attr[key], None)
def test_camera_stream(self, mock_resp):
"""Test that camera stream returns correct url."""
mock_resp.return_value = {"server": "rtsps://foo.bar"}
mini_camera = BlinkCameraMini(self.blink.sync["test"])
self.assertEqual(self.camera.get_liveview(), "rtsps://foo.bar")
self.assertEqual(mini_camera.get_liveview(), "rtsps://foo.bar")
+294
View File
@@ -0,0 +1,294 @@
"""Tests camera and system functions."""
import unittest
from unittest import mock
from blinkpy.blinkpy import Blink
from blinkpy.helpers.util import BlinkURLHandler
from blinkpy.sync_module import BlinkSyncModule, BlinkOwl
from blinkpy.camera import BlinkCamera, BlinkCameraMini
@mock.patch("blinkpy.auth.Auth.query")
class TestBlinkSyncModule(unittest.TestCase):
"""Test BlinkSyncModule functions in blinkpy."""
def setUp(self):
"""Set up Blink module."""
self.blink = Blink(motion_interval=0)
self.blink.last_refresh = 0
self.blink.urls = BlinkURLHandler("test")
self.blink.sync["test"] = BlinkSyncModule(self.blink, "test", "1234", [])
self.camera = BlinkCamera(self.blink.sync)
self.mock_start = [
{
"syncmodule": {
"id": 1234,
"network_id": 5678,
"serial": "12345678",
"status": "foobar",
}
},
{"event": True},
{},
{},
None,
{"devicestatus": {}},
]
self.blink.sync["test"].network_info = {"network": {"armed": True}}
def tearDown(self):
"""Clean up after test."""
self.blink = None
self.camera = None
self.mock_start = None
def test_bad_status(self, mock_resp):
"""Check that we mark module unavaiable on bad status."""
self.blink.sync["test"].status = None
self.blink.sync["test"].available = True
self.assertFalse(self.blink.sync["test"].online)
self.assertFalse(self.blink.sync["test"].available)
def test_bad_arm(self, mock_resp):
"""Check that we mark module unavaiable if bad arm status."""
self.blink.sync["test"].network_info = None
self.blink.sync["test"].available = True
self.assertEqual(self.blink.sync["test"].arm, None)
self.assertFalse(self.blink.sync["test"].available)
self.blink.sync["test"].network_info = {}
self.blink.sync["test"].available = True
self.assertEqual(self.blink.sync["test"].arm, None)
self.assertFalse(self.blink.sync["test"].available)
def test_get_events(self, mock_resp):
"""Test get events function."""
mock_resp.return_value = {"event": True}
self.assertEqual(self.blink.sync["test"].get_events(), True)
def test_get_events_fail(self, mock_resp):
"""Test handling of failed get events function."""
mock_resp.return_value = None
self.assertFalse(self.blink.sync["test"].get_events())
mock_resp.return_value = {}
self.assertFalse(self.blink.sync["test"].get_events())
def test_get_camera_info(self, mock_resp):
"""Test get camera info function."""
mock_resp.return_value = {"camera": ["foobar"]}
self.assertEqual(self.blink.sync["test"].get_camera_info("1234"), "foobar")
def test_get_camera_info_fail(self, mock_resp):
"""Test handling of failed get camera info function."""
mock_resp.return_value = None
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), {})
mock_resp.return_value = {}
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), {})
mock_resp.return_value = {"camera": None}
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), {})
def test_get_network_info(self, mock_resp):
"""Test network retrieval."""
mock_resp.return_value = {"network": {"sync_module_error": False}}
self.assertTrue(self.blink.sync["test"].get_network_info())
mock_resp.return_value = {"network": {"sync_module_error": True}}
self.assertFalse(self.blink.sync["test"].get_network_info())
def test_get_network_info_failure(self, mock_resp):
"""Test failed network retrieval."""
mock_resp.return_value = {}
self.blink.sync["test"].available = True
self.assertFalse(self.blink.sync["test"].get_network_info())
self.assertFalse(self.blink.sync["test"].available)
self.blink.sync["test"].available = True
mock_resp.return_value = None
self.assertFalse(self.blink.sync["test"].get_network_info())
self.assertFalse(self.blink.sync["test"].available)
def test_check_new_videos_startup(self, mock_resp):
"""Test that check_new_videos does not block startup."""
sync_module = self.blink.sync["test"]
self.blink.last_refresh = None
self.assertFalse(sync_module.check_new_videos())
def test_check_new_videos(self, mock_resp):
"""Test recent video response."""
mock_resp.return_value = {
"media": [
{
"device_name": "foo",
"media": "/foo/bar.mp4",
"created_at": "1990-01-01T00:00:00+00:00",
}
]
}
sync_module = self.blink.sync["test"]
sync_module.cameras = {"foo": None}
sync_module.blink.last_refresh = 0
self.assertEqual(sync_module.motion, {})
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(
sync_module.last_record["foo"],
{"clip": "/foo/bar.mp4", "time": "1990-01-01T00:00:00+00:00"},
)
self.assertEqual(sync_module.motion, {"foo": True})
mock_resp.return_value = {"media": []}
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(sync_module.motion, {"foo": False})
self.assertEqual(
sync_module.last_record["foo"],
{"clip": "/foo/bar.mp4", "time": "1990-01-01T00:00:00+00:00"},
)
def test_check_new_videos_old_date(self, mock_resp):
"""Test videos return response with old date."""
mock_resp.return_value = {
"media": [
{
"device_name": "foo",
"media": "/foo/bar.mp4",
"created_at": "1970-01-01T00:00:00+00:00",
}
]
}
sync_module = self.blink.sync["test"]
sync_module.cameras = {"foo": None}
sync_module.blink.last_refresh = 1000
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(sync_module.motion, {"foo": False})
def test_check_no_motion_if_not_armed(self, mock_resp):
"""Test that motion detection is not set if module unarmed."""
mock_resp.return_value = {
"media": [
{
"device_name": "foo",
"media": "/foo/bar.mp4",
"created_at": "1990-01-01T00:00:00+00:00",
}
]
}
sync_module = self.blink.sync["test"]
sync_module.cameras = {"foo": None}
sync_module.blink.last_refresh = 1000
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(sync_module.motion, {"foo": True})
sync_module.network_info = {"network": {"armed": False}}
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(sync_module.motion, {"foo": False})
def test_check_multiple_videos(self, mock_resp):
"""Test motion found even with multiple videos."""
mock_resp.return_value = {
"media": [
{
"device_name": "foo",
"media": "/foo/bar.mp4",
"created_at": "1970-01-01T00:00:00+00:00",
},
{
"device_name": "foo",
"media": "/bar/foo.mp4",
"created_at": "1990-01-01T00:00:00+00:00",
},
{
"device_name": "foo",
"media": "/foobar.mp4",
"created_at": "1970-01-01T00:00:01+00:00",
},
]
}
sync_module = self.blink.sync["test"]
sync_module.cameras = {"foo": None}
sync_module.blink.last_refresh = 1000
self.assertTrue(sync_module.check_new_videos())
self.assertEqual(sync_module.motion, {"foo": True})
expected_result = {
"foo": {"clip": "/bar/foo.mp4", "time": "1990-01-01T00:00:00+00:00"}
}
self.assertEqual(sync_module.last_record, expected_result)
def test_check_new_videos_failed(self, mock_resp):
"""Test method when response is unexpected."""
mock_resp.side_effect = [None, "just a string", {}]
sync_module = self.blink.sync["test"]
sync_module.cameras = {"foo": None}
sync_module.motion["foo"] = True
self.assertFalse(sync_module.check_new_videos())
self.assertFalse(sync_module.motion["foo"])
sync_module.motion["foo"] = True
self.assertFalse(sync_module.check_new_videos())
self.assertFalse(sync_module.motion["foo"])
sync_module.motion["foo"] = True
self.assertFalse(sync_module.check_new_videos())
self.assertFalse(sync_module.motion["foo"])
def test_sync_start(self, mock_resp):
"""Test sync start function."""
mock_resp.side_effect = self.mock_start
self.blink.sync["test"].start()
self.assertEqual(self.blink.sync["test"].name, "test")
self.assertEqual(self.blink.sync["test"].sync_id, 1234)
self.assertEqual(self.blink.sync["test"].network_id, 5678)
self.assertEqual(self.blink.sync["test"].serial, "12345678")
self.assertEqual(self.blink.sync["test"].status, "foobar")
def test_unexpected_summary(self, mock_resp):
"""Test unexpected summary response."""
self.mock_start[0] = None
mock_resp.side_effect = self.mock_start
self.assertFalse(self.blink.sync["test"].start())
def test_summary_with_no_network_id(self, mock_resp):
"""Test handling of bad summary."""
self.mock_start[0]["syncmodule"] = None
mock_resp.side_effect = self.mock_start
self.assertFalse(self.blink.sync["test"].start())
def test_summary_with_only_network_id(self, mock_resp):
"""Test handling of sparse summary."""
self.mock_start[0]["syncmodule"] = {"network_id": 8675309}
mock_resp.side_effect = self.mock_start
self.blink.sync["test"].start()
self.assertEqual(self.blink.sync["test"].network_id, 8675309)
def test_unexpected_camera_info(self, mock_resp):
"""Test unexpected camera info response."""
self.blink.sync["test"].cameras["foo"] = None
self.mock_start[5] = None
mock_resp.side_effect = self.mock_start
self.blink.sync["test"].start()
self.assertEqual(self.blink.sync["test"].cameras, {"foo": None})
def test_missing_camera_info(self, mock_resp):
"""Test missing key from camera info response."""
self.blink.sync["test"].cameras["foo"] = None
self.mock_start[5] = {}
self.blink.sync["test"].start()
self.assertEqual(self.blink.sync["test"].cameras, {"foo": None})
def test_sync_attributes(self, mock_resp):
"""Test sync attributes."""
self.assertEqual(self.blink.sync["test"].attributes["name"], "test")
self.assertEqual(self.blink.sync["test"].attributes["network_id"], "1234")
def test_owl_start(self, mock_resp):
"""Test owl camera instantiation."""
response = {
"name": "foo",
"id": 2,
"serial": "foobar123",
"enabled": True,
"network_id": 1,
"thumbnail": "/foo/bar",
}
self.blink.last_refresh = None
self.blink.homescreen = {"owls": [response]}
owl = BlinkOwl(self.blink, "foo", 1234, response)
self.assertTrue(owl.start())
self.assertTrue("foo" in owl.cameras)
self.assertEqual(owl.cameras["foo"].__class__, BlinkCameraMini)
+150
View File
@@ -0,0 +1,150 @@
"""Test various api functions."""
import unittest
from unittest import mock
import time
from blinkpy.helpers.util import json_load, Throttle, time_to_seconds, gen_uid
class TestUtil(unittest.TestCase):
"""Test the helpers/util module."""
def setUp(self):
"""Initialize the blink module."""
def tearDown(self):
"""Tear down blink module."""
def test_throttle(self):
"""Test the throttle decorator."""
calls = []
@Throttle(seconds=5)
def test_throttle():
calls.append(1)
now = int(time.time())
now_plus_four = now + 4
now_plus_six = now + 6
test_throttle()
self.assertEqual(1, len(calls))
# Call again, still shouldn't fire
test_throttle()
self.assertEqual(1, len(calls))
# Call with force
test_throttle(force=True)
self.assertEqual(2, len(calls))
# Call without throttle, shouldn't fire
test_throttle()
self.assertEqual(2, len(calls))
# Fake time as 4 seconds from now
with mock.patch("time.time", return_value=now_plus_four):
test_throttle()
self.assertEqual(2, len(calls))
# Fake time as 6 seconds from now
with mock.patch("time.time", return_value=now_plus_six):
test_throttle()
self.assertEqual(3, len(calls))
def test_throttle_per_instance(self):
"""Test that throttle is done once per instance of class."""
class Tester:
"""A tester class for throttling."""
def test(self):
"""Test the throttle."""
return True
tester = Tester()
throttled = Throttle(seconds=1)(tester.test)
self.assertEqual(throttled(), True)
self.assertEqual(throttled(), None)
def test_throttle_multiple_objects(self):
"""Test that function is throttled even if called by multiple objects."""
@Throttle(seconds=5)
def test_throttle_method():
return True
class Tester:
"""A tester class for throttling."""
def test(self):
"""Test function for throttle."""
return test_throttle_method()
tester1 = Tester()
tester2 = Tester()
self.assertEqual(tester1.test(), True)
self.assertEqual(tester2.test(), None)
def test_throttle_on_two_methods(self):
"""Test that throttle works for multiple methods."""
class Tester:
"""A tester class for throttling."""
@Throttle(seconds=3)
def test1(self):
"""Test function for throttle."""
return True
@Throttle(seconds=5)
def test2(self):
"""Test function for throttle."""
return True
tester = Tester()
now = time.time()
now_plus_4 = now + 4
now_plus_6 = now + 6
self.assertEqual(tester.test1(), True)
self.assertEqual(tester.test2(), True)
self.assertEqual(tester.test1(), None)
self.assertEqual(tester.test2(), None)
with mock.patch("time.time", return_value=now_plus_4):
self.assertEqual(tester.test1(), True)
self.assertEqual(tester.test2(), None)
with mock.patch("time.time", return_value=now_plus_6):
self.assertEqual(tester.test1(), None)
self.assertEqual(tester.test2(), True)
def test_time_to_seconds(self):
"""Test time to seconds conversion."""
correct_time = "1970-01-01T00:00:05+00:00"
wrong_time = "1/1/1970 00:00:03"
self.assertEqual(time_to_seconds(correct_time), 5)
self.assertFalse(time_to_seconds(wrong_time))
def test_json_load_bad_data(self):
"""Check that bad file is handled."""
self.assertEqual(json_load("fake.file"), None)
with mock.patch("builtins.open", mock.mock_open(read_data="")):
self.assertEqual(json_load("fake.file"), None)
def test_gen_uid(self):
"""Test gen_uid formatting."""
val1 = gen_uid(8)
val2 = gen_uid(8, uid_format=True)
self.assertEqual(len(val1), 16)
self.assertTrue(val2.startswith("BlinkCamera_"))
val2_cut = val2.split("_")
val2_split = val2_cut[1].split("-")
self.assertEqual(len(val2_split[0]), 8)
self.assertEqual(len(val2_split[1]), 4)
self.assertEqual(len(val2_split[2]), 4)
self.assertEqual(len(val2_split[3]), 4)
self.assertEqual(len(val2_split[4]), 12)
+41 -7
View File
@@ -1,24 +1,58 @@
[tox]
envlist = py34, py35, py36, lint
envlist = build, py36, py37, py38, py39, lint
skip_missing_interpreters = True
skipsdist = True
[testenv]
setenv =
LANG=en_US.UTF-8
PYTHONPATH = {toxinidir}
commands =
py.test -v --timeout=30 --duration=10 --cov=blinkpy --cov-report term-missing {posargs}
pytest --timeout=9 --durations=10 --cov=blinkpy --cov-report term-missing {posargs}
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
[testenv:lint]
[testenv:cov]
setenv =
LANG=en_US.UTF-8
PYTHONPATH = {toxinidir}
commands =
pytest --timeout=9 --durations=10 --cov=blinkpy --cov-report=xml {posargs}
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
[testenv:pylint]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
basepython = python3
ignore_errors = True
commands =
pylint --rcfile={toxinidir}/pylintrc blinkpy.py tests
flake8 blinkpy.py tests
pydocstyle blinkpy.py tests
pylint --rcfile={toxinidir}/pylintrc blinkpy tests app
[testenv:lint]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements_test.txt
basepython = python3
commands =
flake8 blinkpy tests app
pydocstyle blinkpy tests app
black --check --diff blinkpy tests app
rst-lint README.rst CHANGES.rst CONTRIBUTING.rst
[testenv:build]
recreate = True
skip_install = True
whitelist_externals =
/bin/sh
/bin/rm
deps =
-r{toxinidir}/requirements_test.txt
commands =
/bin/rm -rf build dist
python setup.py bdist_wheel
/bin/sh -c "pip install --upgrade dist/*.whl"
py.test tests