Skip to content

Commit d78d7e1

Browse files
authored
Merge pull request #527 from fronzbot/dev
0.18.0
2 parents ff306b8 + 35c99ac commit d78d7e1

File tree

10 files changed

+329
-20
lines changed

10 files changed

+329
-20
lines changed

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: pip
4+
directory: "/"
5+
schedule:
6+
interval: daily
7+
open-pull-requests-limit: 10
8+
reviewers:
9+
- fronzbot

CHANGES.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ Changelog
44

55
A list of changes between each release
66

7+
0.18.0 (2021-12-11)
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
10+
**Bugfixes:**
11+
12+
- None
13+
14+
**New Features:**
15+
16+
- Support for Blink Doorbell (`@magicalyak <https://github.com/fronzbot/blinkpy/pull/526>`__)
17+
18+
**Other:**
19+
20+
- Bump pytest-cov to 3.0.0
21+
- Bump pre-commit to 2.15.0
22+
- Bump pytest to 6.2.5
23+
- Bump pylint to 2.10.2
24+
- Bump pygments to 2.10.0
25+
- Bump flake8-docstrings to 1.6.0
26+
- Bump pydocstyle to 6.0.0
27+
- Bump coverage to 5.5
28+
29+
730
0.17.1 (2021-02-18)
831
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
932

@@ -15,14 +38,17 @@ A list of changes between each release
1538
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1639

1740
**Bugfixes:**
41+
1842
- Fix video downloading bug (`#424 <https://github.com/fronzbot/blinkpy/pull/424>`__)
1943
- Fix repeated authorization email bug (`#432 <https://github.com/fronzbot/blinkpy/pull/432>`__ and `#428 <https://github.com/fronzbot/blinkpy/pull/428>`__)
2044

2145
**New Features:**
46+
2247
- Add logout method (`#429 <https://github.com/fronzbot/blinkpy/pull/429>`__)
2348
- Add camera record method (`#430 <https://github.com/fronzbot/blinkpy/pull/430>`__)
2449

2550
**Other:**
51+
2652
- Add debug script to main repo to help with general debug
2753
- Upgrade login endpoint from v4 to v5
2854
- Add python 3.9 support

blinkpy/blinkpy.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from slugify import slugify
2424

2525
from blinkpy import api
26-
from blinkpy.sync_module import BlinkSyncModule, BlinkOwl
26+
from blinkpy.sync_module import BlinkSyncModule, BlinkOwl, BlinkLotus
2727
from blinkpy.helpers import util
2828
from blinkpy.helpers.constants import (
2929
DEFAULT_MOTION_INTERVAL,
@@ -180,6 +180,36 @@ def setup_owls(self):
180180
self.network_ids.extend(network_list)
181181
return camera_list
182182

183+
def setup_lotus(self):
184+
"""Check for doorbells cameras."""
185+
network_list = []
186+
camera_list = []
187+
try:
188+
for lotus in self.homescreen["doorbells"]:
189+
name = lotus["name"]
190+
network_id = str(lotus["network_id"])
191+
if network_id in self.network_ids:
192+
camera_list.append(
193+
{
194+
network_id: {
195+
"name": name,
196+
"id": network_id,
197+
"type": "doorbell",
198+
}
199+
}
200+
)
201+
continue
202+
if lotus["onboarded"]:
203+
network_list.append(str(network_id))
204+
self.sync[name] = BlinkLotus(self, name, network_id, lotus)
205+
self.sync[name].start()
206+
except KeyError:
207+
# No sync-less devices found
208+
pass
209+
210+
self.network_ids.extend(network_list)
211+
return camera_list
212+
183213
def setup_camera_list(self):
184214
"""Create camera list for onboarded networks."""
185215
all_cameras = {}
@@ -194,9 +224,13 @@ def setup_camera_list(self):
194224
{"name": camera["name"], "id": camera["id"]}
195225
)
196226
mini_cameras = self.setup_owls()
227+
lotus_cameras = self.setup_lotus()
197228
for camera in mini_cameras:
198229
for network, camera_info in camera.items():
199230
all_cameras[network].append(camera_info)
231+
for camera in lotus_cameras:
232+
for network, camera_info in camera.items():
233+
all_cameras[network].append(camera_info)
200234
return all_cameras
201235
except (KeyError, TypeError):
202236
_LOGGER.error("Unable to retrieve cameras from response %s", response)

blinkpy/camera.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,42 @@ def get_liveview(self):
273273
server_split[0] = "rtsps:"
274274
link = "".join(server_split)
275275
return link
276+
277+
278+
class BlinkDoorbell(BlinkCamera):
279+
"""Define a class for a Blink Doorbell camera."""
280+
281+
def __init__(self, sync):
282+
"""Initialize a Blink Doorbell."""
283+
super().__init__(sync)
284+
self.camera_type = "doorbell"
285+
286+
@property
287+
def arm(self):
288+
"""Return camera arm status."""
289+
return self.sync.arm
290+
291+
@arm.setter
292+
def arm(self, value):
293+
"""Set camera arm status."""
294+
_LOGGER.warning(
295+
"Individual camera motion detection enable/disable for Blink Doorbell is unsupported at this time."
296+
)
297+
298+
def snap_picture(self):
299+
"""Snap picture for a blink doorbell camera."""
300+
url = f"{self.sync.urls.base_url}/api/v1/accounts/{self.sync.blink.account_id}/networks/{self.network_id}/lotus/{self.camera_id}/thumbnail"
301+
return api.http_post(self.sync.blink, url)
302+
303+
def get_sensor_info(self):
304+
"""Get sensor info for blink doorbell camera."""
305+
306+
def get_liveview(self):
307+
"""Get liveview link."""
308+
url = f"{self.sync.urls.base_url}/api/v1/accounts/{self.sync.blink.account_id}/networks/{self.network_id}/lotus/{self.camera_id}/liveview"
309+
response = api.http_post(self.sync.blink, url)
310+
server = response["server"]
311+
server_split = server.split(":")
312+
server_split[0] = "rtsps:"
313+
link = "".join(server_split)
314+
return link

blinkpy/helpers/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import os
44

55
MAJOR_VERSION = 0
6-
MINOR_VERSION = 17
7-
PATCH_VERSION = 1
6+
MINOR_VERSION = 18
7+
PATCH_VERSION = 0
88

99
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
1010

blinkpy/sync_module.py

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from requests.structures import CaseInsensitiveDict
66
from blinkpy import api
7-
from blinkpy.camera import BlinkCamera, BlinkCameraMini
7+
from blinkpy.camera import BlinkCamera, BlinkCameraMini, BlinkDoorbell
88
from blinkpy.helpers.util import time_to_seconds
99
from blinkpy.helpers.constants import ONLINE
1010

@@ -126,11 +126,14 @@ def update_cameras(self, camera_type=BlinkCamera):
126126
name = camera_config["name"]
127127
self.motion[name] = False
128128
owl_info = self.get_owl_info(name)
129+
lotus_info = self.get_lotus_info(name)
129130
if blink_camera_type == "mini":
130131
camera_type = BlinkCameraMini
132+
if blink_camera_type == "lotus":
133+
camera_type = BlinkDoorbell
131134
self.cameras[name] = camera_type(self)
132135
camera_info = self.get_camera_info(
133-
camera_config["id"], owl_info=owl_info
136+
camera_config["id"], owl_info=owl_info, lotus_info=lotus_info
134137
)
135138
self.cameras[name].update(camera_info, force_cache=True, force=True)
136139

@@ -149,6 +152,16 @@ def get_owl_info(self, name):
149152
pass
150153
return None
151154

155+
def get_lotus_info(self, name):
156+
"""Extract lotus information."""
157+
try:
158+
for doorbell in self.blink.homescreen["doorbells"]:
159+
if doorbell["name"] == name:
160+
return doorbell
161+
except (TypeError, KeyError):
162+
pass
163+
return None
164+
152165
def get_events(self, **kwargs):
153166
"""Retrieve events from server."""
154167
force = kwargs.pop("force", False)
@@ -164,6 +177,9 @@ def get_camera_info(self, camera_id, **kwargs):
164177
owl = kwargs.get("owl_info", None)
165178
if owl is not None:
166179
return owl
180+
lotus = kwargs.get("lotus_info", None)
181+
if lotus is not None:
182+
return lotus
167183
response = api.request_camera_info(self.blink, self.network_id, camera_id)
168184
try:
169185
return response["camera"][0]
@@ -190,7 +206,9 @@ def refresh(self, force_cache=False):
190206
for camera_name in self.cameras.keys():
191207
camera_id = self.cameras[camera_name].camera_id
192208
camera_info = self.get_camera_info(
193-
camera_id, owl_info=self.get_owl_info(camera_name)
209+
camera_id,
210+
owl_info=self.get_owl_info(camera_name),
211+
lotus_info=self.get_lotus_info(camera_name),
194212
)
195213
self.cameras[camera_name].update(camera_info, force_cache=force_cache)
196214
self.available = True
@@ -294,3 +312,66 @@ def network_info(self):
294312
@network_info.setter
295313
def network_info(self, value):
296314
"""Set network_info property."""
315+
316+
317+
class BlinkLotus(BlinkSyncModule):
318+
"""Representation of a sync-less device."""
319+
320+
def __init__(self, blink, name, network_id, response):
321+
"""Initialize a sync-less object."""
322+
cameras = [{"name": name, "id": response["id"]}]
323+
super().__init__(blink, name, network_id, cameras)
324+
self.sync_id = response["id"]
325+
self.serial = response["serial"]
326+
self.status = response["enabled"]
327+
if not self.serial:
328+
self.serial = f"{network_id}-{self.sync_id}"
329+
330+
def sync_initialize(self):
331+
"""Initialize a sync-less module."""
332+
self.summary = {
333+
"id": self.sync_id,
334+
"name": self.name,
335+
"serial": self.serial,
336+
"status": self.status,
337+
"onboarded": True,
338+
"account_id": self.blink.account_id,
339+
"network_id": self.network_id,
340+
}
341+
return self.summary
342+
343+
def update_cameras(self, camera_type=BlinkDoorbell):
344+
"""Update sync-less cameras."""
345+
return super().update_cameras(camera_type=BlinkDoorbell)
346+
347+
def get_camera_info(self, camera_id, **kwargs):
348+
"""Retrieve camera information."""
349+
try:
350+
for doorbell in self.blink.homescreen["doorbells"]:
351+
if doorbell["name"] == self.name:
352+
self.status = doorbell["enabled"]
353+
return doorbell
354+
except (TypeError, KeyError):
355+
pass
356+
return None
357+
358+
def get_network_info(self):
359+
"""Get network info for sync-less module."""
360+
return True
361+
362+
@property
363+
def network_info(self):
364+
"""Format lotus response to resemble sync module."""
365+
return {
366+
"network": {
367+
"id": self.network_id,
368+
"name": self.name,
369+
"armed": self.status,
370+
"sync_module_error": False,
371+
"account_id": self.blink.account_id,
372+
}
373+
}
374+
375+
@network_info.setter
376+
def network_info(self, value):
377+
"""Set network_info property."""

requirements_test.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
black==19.10b0
2-
coverage==5.4
3-
flake8==3.8.4
4-
flake8-docstrings==1.5.0
5-
pre-commit==2.10.1
6-
pylint==2.6.2
7-
pydocstyle==5.1.1
8-
pytest==6.2.2
9-
pytest-cov==2.11.1
2+
coverage==5.5
3+
flake8==3.9.1
4+
flake8-docstrings==1.6.0
5+
pre-commit==2.15.0
6+
pylint==2.10.2
7+
pydocstyle==6.0.0
8+
pytest==6.2.5
9+
pytest-cov==3.0.0
1010
pytest-sugar==0.9.4
1111
pytest-timeout==1.4.2
1212
restructuredtext-lint==1.3.2
13-
pygments==2.8.0
13+
pygments==2.10.0
1414
testtools>=2.4.0

0 commit comments

Comments
 (0)