From 2788ab58eac89bb24d8cf1a560bde43c746cc8fc Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 04:03:31 +0000 Subject: [PATCH 1/6] First cut at blink mini support --- blinkpy/blinkpy.py | 19 +++++- blinkpy/camera.py | 26 +++++++-- blinkpy/sync_module.py | 127 +++++++++++++++++++++++++++++++++++------ tests/test_blinkpy.py | 33 +++++++++++ 4 files changed, 181 insertions(+), 24 deletions(-) diff --git a/blinkpy/blinkpy.py b/blinkpy/blinkpy.py index 9f98f14..0aeaee2 100644 --- a/blinkpy/blinkpy.py +++ b/blinkpy/blinkpy.py @@ -23,7 +23,7 @@ from dateutil.parser import parse from slugify import slugify from blinkpy import api -from blinkpy.sync_module import BlinkSyncModule +from blinkpy.sync_module import BlinkSyncModule, BlinkOwl from blinkpy.helpers import util from blinkpy.helpers.constants import ( DEFAULT_MOTION_INTERVAL, @@ -68,6 +68,7 @@ class Blink: self.version = __version__ self.available = False self.key_required = False + self.homescreen = {} @util.Throttle(seconds=MIN_THROTTLE_TIME) def refresh(self, force=False): @@ -129,6 +130,8 @@ class Blink: self.setup_sync_module(name, network_id, sync_cameras) self.cameras = self.merge_cameras() + self.setup_owls() + self.available = True self.key_required = False return True @@ -138,6 +141,20 @@ class Blink: self.sync[name] = BlinkSyncModule(self, name, network_id, cameras) self.sync[name].start() + def setup_owls(self): + """Check for mini cameras.""" + response = api.request_homescreen(self) + self.homescreen = response + try: + for owl in response["owls"]: + name = owl["name"] + network_id = owl["network_id"] + if owl["onboarded"]: + self.sync[name] = BlinkOwl(self, name, network_id, owl) + except KeyError: + # No sync-less devices found + pass + def setup_camera_list(self): """Create camera list for onboarded networks.""" all_cameras = {} diff --git a/blinkpy/camera.py b/blinkpy/camera.py index 0443dd5..f999396 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -133,9 +133,10 @@ class BlinkCamera: self.temperature_calibrated = self.temperature _LOGGER.warning("Could not retrieve calibrated temperature.") - # Check if thumbnail exists in config, if not try to - # get it from the homescreen info in the sync module - # otherwise set it to None and log an error + self.update_images(config, force_cache=force_cache) + + def update_images(self, config, force_cache=False): + """Update images for camera.""" new_thumbnail = None thumb_addr = None if config["thumbnail"]: @@ -202,7 +203,8 @@ class BlinkCamera: ) def video_to_file(self, path): - """Write video to file. + """ + Write video to file. :param path: Path to write file """ @@ -213,3 +215,19 @@ class BlinkCamera: return with open(path, "wb") as vidfile: copyfileobj(response.raw, vidfile) + + +class BlinkCameraMini(BlinkCamera): + """Define a class for a Blink Mini camera.""" + + def update(self, config, force_cache=False, **kwargs): + """Update a blink mini camera.""" + self.name = config["name"] + self.camera_id = str(config["id"]) + self.network_id = str(config["network_id"]) + self.serial = config["serial"] + if not self.serial: + self.serial = f"{self.network_id}-{self.camera_id}" + self.motion_enabled = config["enabled"] + + self.update_images(config, force_cache=force_cache) diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index f109212..6f9d6b4 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -4,7 +4,7 @@ import logging from requests.structures import CaseInsensitiveDict from blinkpy import api -from blinkpy.camera import BlinkCamera +from blinkpy.camera import BlinkCamera, BlinkCameraMini from blinkpy.helpers.util import time_to_seconds from blinkpy.helpers.constants import ONLINE @@ -85,16 +85,8 @@ class BlinkSyncModule: def start(self): """Initialize the system.""" - 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, - exc_info=True, - ) + response = self.sync_initialize() + if not response: return False try: @@ -108,24 +100,39 @@ class BlinkSyncModule: 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 name = camera_config["name"] - self.cameras[name] = BlinkCamera(self) + self.cameras[name] = camera_type(self) self.motion[name] = False camera_info = self.get_camera_info(camera_config["id"]) self.cameras[name].update(camera_info, force_cache=True, force=True) except KeyError: - _LOGGER.error( - "Could not create cameras instances for %s", self.name, exc_info=True - ) + _LOGGER.error("Could not create camera instances for %s", self.name) return False - - if not is_ok: - return False - self.available = True return True def get_events(self, **kwargs): @@ -205,3 +212,85 @@ class BlinkSyncModule: 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.""" + self._response = response + cameras = [{network_id: {"name": name, "id": response["id"]}}] + super().__init__(blink, name, network_id, cameras) + self.sync_id = response["id"] + self.serial = response["serial"] + 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.""" + super().update_cameras(camera_type=camera_type) + + def get_camera_info(self, camera_id): + """Retrieve camera information.""" + try: + for owl in self.blink.homescreen["owls"]: + if owl["name"] == self.name: + return owl + except 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._response["enabled"], + "sync_module_error": False, + "account_id": self.blink.account_id, + } + } + + @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 + ) diff --git a/tests/test_blinkpy.py b/tests/test_blinkpy.py index 9f551e9..847d470 100644 --- a/tests/test_blinkpy.py +++ b/tests/test_blinkpy.py @@ -9,6 +9,7 @@ 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__ @@ -192,6 +193,38 @@ class TestBlinkSetup(unittest.TestCase): self.assertEqual(combined["fizz"], "buzz") self.assertEqual(combined["bar"], "foo") + @mock.patch("blinkpy.api.request_homescreen") + def test_initialize_blink_minis(self, mock_home): + """Test blink mini initialization.""" + mock_home.return_value = { + "owls": [ + { + "enabled": False, + "id": 1, + "name": "foo", + "network_id": 2, + "onboarded": True, + "status": "online", + "thumbnail": "/foo/bar", + "serial": "", + }, + { + "enabled": True, + "id": 3, + "name": "bar", + "network_id": 4, + "onboarded": True, + "status": "online", + "thumbnail": "/foo/bar", + "serial": "", + }, + ] + } + self.blink.sync = {} + self.blink.setup_owls() + self.assertEqual(self.blink.sync["foo"].__class__, BlinkOwl) + self.assertEqual(self.blink.sync["bar"].__class__, BlinkOwl) + class MockSync: """Mock sync module class.""" From be1a5bf92fa2e073f19dc3f77fc325d8259ec94c Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 04:10:47 +0000 Subject: [PATCH 2/6] Update liveview for mini --- blinkpy/camera.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/blinkpy/camera.py b/blinkpy/camera.py index f999396..ea6f425 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -231,3 +231,13 @@ class BlinkCameraMini(BlinkCamera): self.motion_enabled = config["enabled"] self.update_images(config, force_cache=force_cache) + + 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 From 6479423c6c8cc42427b6ac8e5600e8b76765771f Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 04:33:11 +0000 Subject: [PATCH 3/6] Fix test --- tests/test_blinkpy.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_blinkpy.py b/tests/test_blinkpy.py index 847d470..c726655 100644 --- a/tests/test_blinkpy.py +++ b/tests/test_blinkpy.py @@ -161,10 +161,12 @@ class TestBlinkSetup(unittest.TestCase): @mock.patch("blinkpy.blinkpy.Blink.setup_camera_list") @mock.patch("blinkpy.api.request_networks") - def test_setup_post_verify(self, mock_networks, mock_camera): + @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"}} } From 7dd32a0dadec6658e4ace6875578f673ec5ece0c Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 13:30:29 +0000 Subject: [PATCH 4/6] Make sure cameras are properly merged, initilize minis properly --- blinkpy/blinkpy.py | 8 ++++++-- blinkpy/camera.py | 12 +++++------- blinkpy/sync_module.py | 7 ++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/blinkpy/blinkpy.py b/blinkpy/blinkpy.py index 0aeaee2..6b904f5 100644 --- a/blinkpy/blinkpy.py +++ b/blinkpy/blinkpy.py @@ -33,7 +33,6 @@ from blinkpy.helpers.constants import ( from blinkpy.helpers.constants import __version__ from blinkpy.auth import Auth, TokenRefreshFailed, LoginError - _LOGGER = logging.getLogger(__name__) @@ -128,9 +127,9 @@ class Blink: 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.setup_owls() + self.cameras = self.merge_cameras() self.available = True self.key_required = False @@ -145,16 +144,21 @@ class Blink: """Check for mini cameras.""" response = api.request_homescreen(self) self.homescreen = response + network_list = [] try: for owl in response["owls"]: name = owl["name"] network_id = owl["network_id"] 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) + def setup_camera_list(self): """Create camera list for onboarded networks.""" all_cameras = {} diff --git a/blinkpy/camera.py b/blinkpy/camera.py index ea6f425..627abe7 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -222,13 +222,11 @@ class BlinkCameraMini(BlinkCamera): def update(self, config, force_cache=False, **kwargs): """Update a blink mini camera.""" - self.name = config["name"] - self.camera_id = str(config["id"]) - self.network_id = str(config["network_id"]) - self.serial = config["serial"] - if not self.serial: - self.serial = f"{self.network_id}-{self.camera_id}" - self.motion_enabled = config["enabled"] + self.name = config.get("name", "unknown") + self.camera_id = str(config.get("id", "")) + self.network_id = str(config.get("network_id", "")) + self.serial = config.get("serial", f"{self.network_id}-{self.camera_id}") + self.motion_enabled = config.get("enabled", False) self.update_images(config, force_cache=force_cache) diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index 6f9d6b4..b33748c 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -219,11 +219,11 @@ class BlinkOwl(BlinkSyncModule): def __init__(self, blink, name, network_id, response): """Initialize a sync-less object.""" - self._response = response cameras = [{network_id: {"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}" @@ -242,13 +242,14 @@ class BlinkOwl(BlinkSyncModule): def update_cameras(self, camera_type=BlinkCameraMini): """Update sync-less cameras.""" - super().update_cameras(camera_type=camera_type) + super().update_cameras(camera_type=BlinkCameraMini) def get_camera_info(self, camera_id): """Retrieve camera information.""" try: for owl in self.blink.homescreen["owls"]: if owl["name"] == self.name: + self.status = owl["enabled"] return owl except KeyError: pass @@ -265,7 +266,7 @@ class BlinkOwl(BlinkSyncModule): "network": { "id": self.network_id, "name": self.name, - "armed": self._response["enabled"], + "armed": self.status, "sync_module_error": False, "account_id": self.blink.account_id, } From 4f00aac7a2b0b1662bd1fa74b1fc2c6d96df72e6 Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 15:25:57 +0000 Subject: [PATCH 5/6] Fixed missing camera init from owl, cleaned up camera a bit --- blinkpy/camera.py | 47 +++++++++++++++++++-------------------- blinkpy/sync_module.py | 4 ++-- tests/test_blinkpy.py | 12 +++++++--- tests/test_sync_module.py | 21 +++++++++++++++-- 4 files changed, 53 insertions(+), 31 deletions(-) diff --git a/blinkpy/camera.py b/blinkpy/camera.py index 627abe7..4f75c11 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -112,18 +112,24 @@ class BlinkCamera: def update(self, config, force_cache=False, **kwargs): """Update camera info.""" - # force = kwargs.pop('force', False) - self.name = config["name"] - self.camera_id = str(config["id"]) - self.network_id = str(config["network_id"]) - self.serial = config["serial"] - self.motion_enabled = config["enabled"] - self.battery_voltage = config["battery_voltage"] - self.battery_state = config["battery_state"] - self.temperature = config["temperature"] - self.wifi_strength = config["wifi_strength"] + self.extract_config_info(config) + self.get_sensor_info() + self.update_images(config, force_cache=force_cache) - # Retrieve calibrated temperature from special endpoint + 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 ) @@ -133,13 +139,11 @@ class BlinkCamera: self.temperature_calibrated = self.temperature _LOGGER.warning("Could not retrieve calibrated temperature.") - self.update_images(config, force_cache=force_cache) - def update_images(self, config, force_cache=False): """Update images for camera.""" new_thumbnail = None thumb_addr = None - if config["thumbnail"]: + if config.get("thumbnail", False): thumb_addr = config["thumbnail"] else: _LOGGER.warning( @@ -155,10 +159,12 @@ class BlinkCamera: self.motion_detected = False clip_addr = None - if self.name in self.sync.last_record: + 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 @@ -220,15 +226,8 @@ class BlinkCamera: class BlinkCameraMini(BlinkCamera): """Define a class for a Blink Mini camera.""" - def update(self, config, force_cache=False, **kwargs): - """Update a blink mini camera.""" - self.name = config.get("name", "unknown") - self.camera_id = str(config.get("id", "")) - self.network_id = str(config.get("network_id", "")) - self.serial = config.get("serial", f"{self.network_id}-{self.camera_id}") - self.motion_enabled = config.get("enabled", False) - - self.update_images(config, force_cache=force_cache) + def get_sensor_info(self): + """Get sensor info for blink mini camera.""" def get_liveview(self): """Get liveview link.""" diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index b33748c..d2a0906 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -219,7 +219,7 @@ class BlinkOwl(BlinkSyncModule): def __init__(self, blink, name, network_id, response): """Initialize a sync-less object.""" - cameras = [{network_id: {"name": name, "id": response["id"]}}] + cameras = [{"name": name, "id": response["id"]}] super().__init__(blink, name, network_id, cameras) self.sync_id = response["id"] self.serial = response["serial"] @@ -242,7 +242,7 @@ class BlinkOwl(BlinkSyncModule): def update_cameras(self, camera_type=BlinkCameraMini): """Update sync-less cameras.""" - super().update_cameras(camera_type=BlinkCameraMini) + return super().update_cameras(camera_type=BlinkCameraMini) def get_camera_info(self, camera_id): """Retrieve camera information.""" diff --git a/tests/test_blinkpy.py b/tests/test_blinkpy.py index c726655..bd93720 100644 --- a/tests/test_blinkpy.py +++ b/tests/test_blinkpy.py @@ -196,8 +196,10 @@ class TestBlinkSetup(unittest.TestCase): self.assertEqual(combined["bar"], "foo") @mock.patch("blinkpy.api.request_homescreen") - def test_initialize_blink_minis(self, mock_home): + @mock.patch("blinkpy.blinkpy.BlinkOwl.start") + def test_initialize_blink_minis(self, mock_start, mock_home): """Test blink mini initialization.""" + mock_start.return_value = True mock_home.return_value = { "owls": [ { @@ -208,7 +210,7 @@ class TestBlinkSetup(unittest.TestCase): "onboarded": True, "status": "online", "thumbnail": "/foo/bar", - "serial": "", + "serial": "1234", }, { "enabled": True, @@ -218,7 +220,7 @@ class TestBlinkSetup(unittest.TestCase): "onboarded": True, "status": "online", "thumbnail": "/foo/bar", - "serial": "", + "serial": "abcd", }, ] } @@ -226,6 +228,10 @@ class TestBlinkSetup(unittest.TestCase): 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") class MockSync: diff --git a/tests/test_sync_module.py b/tests/test_sync_module.py index baf2bb1..211cdb4 100644 --- a/tests/test_sync_module.py +++ b/tests/test_sync_module.py @@ -4,8 +4,8 @@ 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.sync_module import BlinkSyncModule, BlinkOwl +from blinkpy.camera import BlinkCamera, BlinkCameraMini @mock.patch("blinkpy.auth.Auth.query") @@ -275,3 +275,20 @@ class TestBlinkSyncModule(unittest.TestCase): """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) From b8da6e219753ad8c82fab8477b6f42f5eff0ac2f Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 9 Jun 2020 16:53:33 +0000 Subject: [PATCH 6/6] Add unsupported notifications, updated Mini thumbnail endpoint --- blinkpy/camera.py | 15 +++++++++++++++ blinkpy/sync_module.py | 5 +---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/blinkpy/camera.py b/blinkpy/camera.py index 4f75c11..4372e1d 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -226,6 +226,21 @@ class BlinkCamera: class BlinkCameraMini(BlinkCamera): """Define a class for a Blink Mini camera.""" + @property + def arm(self): + """Return camera arm status.""" + return self.sync.arm + + @arm.setter + def arm(self, value): + """Set camera arm status.""" + self.sync.arm = value + + 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.""" diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index d2a0906..77c1719 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -78,10 +78,7 @@ class BlinkSyncModule: @arm.setter def arm(self, value): """Arm or disarm system.""" - if value: - return api.request_system_arm(self.blink, self.network_id) - - return api.request_system_disarm(self.blink, self.network_id) + _LOGGER.warning("Arm/Disarm API for %s not currently implemented.", self.name) def start(self): """Initialize the system."""