Compare commits

...
26 Commits
Author SHA1 Message Date
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
10 changed files with 151 additions and 32 deletions
+14 -6
View File
@@ -1,11 +1,12 @@
"""Script to run blinkpy as an app."""
from os import environ
from datetime import datetime, timedelta
from blinkpy import blinkpy
from blinkpy.blinkpy import Blink
from blinkpy.auth import Auth
from blinkpy.helpers.util import json_load
USERNAME = environ.get("USERNAME")
PASSWORD = environ.get("PASSWORD")
CREDFILE = environ.get("CREDFILE")
TIMEDELTA = timedelta(environ.get("TIMEDELTA", 1))
@@ -21,11 +22,18 @@ def download_videos(blink, save_dir="/media"):
def start():
"""Startup blink app."""
blink = blinkpy.Blink(username=USERNAME, password=PASSWORD)
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__":
BLINK = start()
download_videos(BLINK)
main()
+1 -1
View File
@@ -32,7 +32,7 @@ def request_login(
"client_name": "Computer",
"client_type": "android",
"os_version": "5.1.1",
"reauth": "true",
"reauth": "false",
}
)
return auth.query(
+28 -6
View File
@@ -40,7 +40,10 @@ class Blink:
"""Class to initialize communication."""
def __init__(
self, refresh_rate=DEFAULT_REFRESH, motion_interval=DEFAULT_MOTION_INTERVAL,
self,
refresh_rate=DEFAULT_REFRESH,
motion_interval=DEFAULT_MOTION_INTERVAL,
no_owls=False,
):
"""
Initialize Blink system.
@@ -51,6 +54,7 @@ class Blink:
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
@@ -68,6 +72,7 @@ class Blink:
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):
@@ -95,6 +100,7 @@ class Blink:
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
@@ -128,7 +134,6 @@ class Blink:
sync_cameras = cameras.get(network_id, {})
self.setup_sync_module(name, network_id, sync_cameras)
self.setup_owls()
self.cameras = self.merge_cameras()
self.available = True
@@ -140,15 +145,27 @@ class Blink:
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."""
response = api.request_homescreen(self)
self.homescreen = response
network_list = []
camera_list = []
try:
for owl in response["owls"]:
for owl in self.homescreen["owls"]:
name = owl["name"]
network_id = owl["network_id"]
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)
@@ -158,6 +175,7 @@ class Blink:
pass
self.network_ids.extend(network_list)
return camera_list
def setup_camera_list(self):
"""Create camera list for onboarded networks."""
@@ -172,6 +190,10 @@ class Blink:
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)
+9 -1
View File
@@ -29,6 +29,7 @@ class BlinkCamera:
self.last_record = None
self._cached_image = None
self._cached_video = None
self.camera_type = ""
@property
def attributes(self):
@@ -229,6 +230,11 @@ class BlinkCamera:
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."""
@@ -237,7 +243,9 @@ class BlinkCameraMini(BlinkCamera):
@arm.setter
def arm(self, value):
"""Set camera arm status."""
self.sync.arm = value
_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."""
+1 -1
View File
@@ -4,7 +4,7 @@ import os
MAJOR_VERSION = 0
MINOR_VERSION = 16
PATCH_VERSION = "0-rc4"
PATCH_VERSION = "0-rc8"
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
+28 -6
View File
@@ -124,16 +124,33 @@ class BlinkSyncModule:
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.cameras[name] = camera_type(self)
self.motion[name] = False
camera_info = self.get_camera_info(camera_config["id"])
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 KeyError:
pass
return None
def get_events(self, **kwargs):
"""Retrieve events from server."""
force = kwargs.pop("force", False)
@@ -144,14 +161,17 @@ class BlinkSyncModule:
_LOGGER.error("Could not extract events: %s", response, exc_info=True)
return False
def get_camera_info(self, camera_id):
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, exc_info=True)
return []
return {}
def get_network_info(self):
"""Retrieve network status."""
@@ -171,7 +191,9 @@ class BlinkSyncModule:
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)
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
@@ -243,7 +265,7 @@ class BlinkOwl(BlinkSyncModule):
"""Update sync-less cameras."""
return super().update_cameras(camera_type=BlinkCameraMini)
def get_camera_info(self, camera_id):
def get_camera_info(self, camera_id, **kwargs):
"""Retrieve camera information."""
try:
for owl in self.blink.homescreen["owls"]:
+6 -2
View File
@@ -4,8 +4,12 @@ coverage:
status:
project:
default:
target: 80
threshold: 0.02
target: 80%
threshold: 2%
patch:
default:
target: 60%
threshold: 5%
comment: true
require_ci_to_pass: yes
+2 -2
View File
@@ -6,8 +6,8 @@ pre-commit==2.5.1
pylint==2.5.3
pydocstyle==5.0.2
pytest==5.4.3
pytest-cov==2.9.0
pytest-cov==2.10.0
pytest-sugar==0.9.3
pytest-timeout==1.3.4
pytest-timeout==1.4.1
restructuredtext-lint==1.3.1
pygments==2.6.1
+59 -4
View File
@@ -83,8 +83,10 @@ class TestBlinkSetup(unittest.TestCase):
self.assertEqual(self.blink.sync["tEsT"], 1234)
@mock.patch("blinkpy.api.request_camera_usage")
def test_setup_cameras(self, mock_req):
@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": [
{
@@ -195,12 +197,11 @@ class TestBlinkSetup(unittest.TestCase):
self.assertEqual(combined["fizz"], "buzz")
self.assertEqual(combined["bar"], "foo")
@mock.patch("blinkpy.api.request_homescreen")
@mock.patch("blinkpy.blinkpy.BlinkOwl.start")
def test_initialize_blink_minis(self, mock_start, mock_home):
def test_initialize_blink_minis(self, mock_start):
"""Test blink mini initialization."""
mock_start.return_value = True
mock_home.return_value = {
self.blink.homescreen = {
"owls": [
{
"enabled": False,
@@ -233,6 +234,60 @@ class TestBlinkSetup(unittest.TestCase):
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."""
+3 -3
View File
@@ -80,11 +80,11 @@ class TestBlinkSyncModule(unittest.TestCase):
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"), [])
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), {})
mock_resp.return_value = {}
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), [])
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"), [])
self.assertEqual(self.blink.sync["test"].get_camera_info("1"), {})
def test_get_network_info(self, mock_resp):
"""Test network retrieval."""