Compare commits

...
19 Commits
Author SHA1 Message Date
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
9 changed files with 149 additions and 39 deletions
+2 -2
View File
@@ -107,7 +107,7 @@ def request_system_arm(blink, network):
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}/arm"
url = f"{blink.urls.base_url}/api/v1/accounts/{blink.account_id}/networks/{network}/state/arm"
return http_post(blink, url)
@@ -119,7 +119,7 @@ def request_system_disarm(blink, network):
:param blink: Blink instance.
:param network: Sync module network id.
"""
url = f"{blink.urls.base_url}/network/{network}/disarm"
url = f"{blink.urls.base_url}/api/v1/accounts/{blink.account_id}/networks/{network}/state/disarm"
return http_post(blink, url)
+21 -3
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):
@@ -128,7 +133,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
@@ -142,13 +146,22 @@ class Blink:
def setup_owls(self):
"""Check for mini cameras."""
if self.no_owls:
_LOGGER.debug("Skipping owl extraction.")
return []
response = api.request_homescreen(self)
self.homescreen = response
network_list = []
camera_list = []
try:
for owl in response["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 +171,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 +186,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)
+13 -2
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):
@@ -61,7 +62,10 @@ class BlinkCamera:
@property
def temperature_c(self):
"""Return temperature in celcius."""
return round((self.temperature - 32) / 9.0 * 5.0, 1)
try:
return round((self.temperature - 32) / 9.0 * 5.0, 1)
except TypeError:
return None
@property
def image_from_cache(self):
@@ -226,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."""
@@ -234,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-rc3"
PATCH_VERSION = "0-rc5"
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
+28 -26
View File
@@ -77,8 +77,10 @@ class BlinkSyncModule:
@arm.setter
def arm(self, value):
"""Arm or disarm system."""
_LOGGER.warning("Arm/Disarm API for %s not currently implemented.", self.name)
"""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."""
@@ -122,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)
@@ -142,8 +161,11 @@ 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]
@@ -241,7 +263,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"]:
@@ -272,23 +294,3 @@ class BlinkOwl(BlinkSyncModule):
@network_info.setter
def network_info(self, value):
"""Set network_info property."""
@property
def arm(self):
"""Return arm status."""
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_motion_detection_enable(
self.blink, self.network_id, self.sync_id
)
return api.request_motion_detection_disable(
self.blink, self.network_id, self.sync_id
)
+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
+1 -1
View File
@@ -2,7 +2,7 @@ black==19.10b0
coverage==5.1
flake8==3.8.3
flake8-docstrings==1.5.0
pre-commit==2.5.0
pre-commit==2.5.1
pylint==2.5.3
pydocstyle==5.0.2
pytest==5.4.3
+58 -1
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": [
{
@@ -233,6 +235,61 @@ class TestBlinkSetup(unittest.TestCase):
self.assertEqual(self.blink.sync["foo"].name, "foo")
self.assertEqual(self.blink.sync["bar"].name, "bar")
@mock.patch("blinkpy.api.request_homescreen")
def test_blink_mini_cameras_returned(self, mock_home):
"""Test that blink mini cameras are found if attached to sync module."""
self.blink.network_ids = ["1234"]
mock_home.return_value = {
"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 = []
result = self.blink.setup_owls()
self.assertEqual(self.blink.network_ids, [])
self.assertEqual(result, [])
@mock.patch("blinkpy.api.request_homescreen")
@mock.patch("blinkpy.api.request_camera_usage")
def test_blink_mini_attached_to_sync(self, mock_usage, mock_home):
"""Test that blink mini cameras are properly attached to sync module."""
self.blink.network_ids = ["1234"]
mock_home.return_value = {
"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."""
+19 -1
View File
@@ -11,7 +11,7 @@ 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
from blinkpy.camera import BlinkCamera, BlinkCameraMini
CAMERA_CFG = {
@@ -161,3 +161,21 @@ class TestBlinkCameraSetup(unittest.TestCase):
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)