Skip to content

Commit 0d83a7f

Browse files
authored
Merge pull request #68 from fronzbot/v0.8.0
V0.8.0
2 parents ff47dc4 + 80f4ca7 commit 0d83a7f

File tree

5 files changed

+100
-19
lines changed

5 files changed

+100
-19
lines changed

CHANGES.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ Changelog
33

44
A list of changes between each release
55

6+
0.8.0 (2018-05-21)
7+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
- Added support for battery voltage level (fixes `#64 <https://github.com/fronzbot/blinkpy/issues/64>`_)
9+
- Added motion detection per camera
10+
- Added fully accessible camera configuration dict
11+
- Added celcius property to camera (fixes `#60 <https://github.com/fronzbot/blinkpy/issues/60>`_)
12+
613
0.7.1 (2018-05-09)
714
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
815
- Fixed pip 10 import issue during setup (`@fronzbot <https://github.com/fronzbot/blinkpy/pull/61>`_)

blinkpy/blinkpy.py

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,17 @@ def __init__(self, config, blink):
107107
config['thumbnail'])
108108
self.clip = "{}{}".format(self.urls.base_url, config['video'])
109109
self.temperature = config['temp']
110-
self.battery = config['battery']
110+
self._battery_string = config['battery']
111111
self.notifications = config['notifications']
112-
self.motion = {}
112+
self.motion = dict()
113113
self.header = None
114114
self.image_link = None
115115
self.arm_link = None
116116
self.region_id = config['region_id']
117+
self.battery_voltage = -180
118+
self.motion_detected = None
119+
self.wifi_strength = None
120+
self.camera_config = dict()
117121

118122
@property
119123
def attributes(self):
@@ -124,10 +128,13 @@ def attributes(self):
124128
'status': self._status,
125129
'armed': self.armed,
126130
'temperature': self.temperature,
131+
'temperature_c': self.temperature_c,
127132
'battery': self.battery,
128133
'thumbnail': self.thumbnail,
129134
'video': self.clip,
130135
'notifications': self.notifications,
136+
'motion_detected': self.motion_detected,
137+
'wifi_strength': self.wifi_strength,
131138
'network_id': self.blink.network_id
132139
}
133140
return attributes
@@ -142,16 +149,26 @@ def armed(self):
142149
"""Return camera arm status."""
143150
return True if self._status == 'armed' else False
144151

152+
@property
153+
def battery(self):
154+
"""Return battery level as percentage."""
155+
return round(self.battery_voltage / 180 * 100)
156+
145157
@property
146158
def battery_string(self):
147159
"""Return string indicating battery status."""
148160
status = "Unknown"
149-
if self.battery > 1 and self.battery <= 3:
161+
if self._battery_string > 1 and self._battery_string <= 3:
150162
status = "OK"
151-
elif self.battery >= 0:
163+
elif self._battery_string >= 0:
152164
status = "Low"
153165
return status
154166

167+
@property
168+
def temperature_c(self):
169+
"""Return temperature in celcius."""
170+
return round((self.temperature - 32) / 9.0 * 5.0, 1)
171+
155172
def snap_picture(self):
156173
"""Take a picture with camera to create a new thumbnail."""
157174
_request(self.blink, url=self.image_link,
@@ -175,10 +192,26 @@ def update(self, values):
175192
self.urls.base_url, values['thumbnail'])
176193
self.clip = "{}{}".format(
177194
self.urls.base_url, values['video'])
178-
self.temperature = values['temp']
179-
self.battery = values['battery']
195+
self._battery_string = values['battery']
180196
self.notifications = values['notifications']
181197

198+
try:
199+
cfg = self.blink.camera_config_request(self.id)
200+
self.camera_config = cfg
201+
except requests.exceptions.RequestException as err:
202+
_LOGGER.warning("Could not get config for %s with id %s",
203+
self.name, self.id)
204+
_LOGGER.warning("Exception raised: %s", err)
205+
206+
try:
207+
self.battery_voltage = cfg['camera'][0]['battery_voltage']
208+
self.motion_detected = cfg['camera'][0]['motion_alert']
209+
self.wifi_strength = cfg['camera'][0]['wifi_strength']
210+
self.temperature = cfg['camera'][0]['temperature']
211+
except KeyError:
212+
_LOGGER.warning("Problem extracting config for camera %s",
213+
self.name)
214+
182215
def image_refresh(self):
183216
"""Refresh current thumbnail."""
184217
url = self.urls.home_url
@@ -327,6 +360,7 @@ def get_videos(self, start_page=0, end_page=1):
327360
videos.append(this_page)
328361

329362
for page in videos:
363+
_LOGGER.debug("Retrieved video page %s", page)
330364
for entry in page:
331365
camera_name = entry['camera_name']
332366
clip_addr = entry['address']
@@ -365,6 +399,7 @@ def get_cameras(self):
365399
device = BlinkCamera(element, self)
366400
self.cameras[device.name] = device
367401
self._idlookup[device.id] = device.name
402+
self.refresh()
368403

369404
def set_links(self):
370405
"""Set access links and required headers for each camera in system."""
@@ -497,3 +532,11 @@ def _status_request(self):
497532
self.network_id)
498533
headers = self._auth_header
499534
return _request(self, url=url, headers=headers, reqtype='get')
535+
536+
def camera_config_request(self, camera_id):
537+
"""Retrieve more info about Blink config."""
538+
url = "{}/network/{}/camera/{}/config".format(self.urls.base_url,
539+
self.network_id,
540+
str(camera_id))
541+
headers = self._auth_header
542+
return _request(self, url=url, headers=headers, reqtype='get')

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 = 7
7-
PATCH_VERSION = 1
6+
MINOR_VERSION = 8
7+
PATCH_VERSION = 0
88

99
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
1010

tests/test_blink_cameras.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@
1515
USERNAME = 'foobar'
1616
PASSWORD = 'deadbeef'
1717

18+
CAMERA_CFG = {
19+
'camera': [
20+
{
21+
'battery_voltage': 90,
22+
'motion_alert': True,
23+
'wifi_strength': -30,
24+
'temperature': 68
25+
}
26+
]
27+
}
28+
1829

1930
class TestBlinkCameraSetup(unittest.TestCase):
2031
"""Test the Blink class in blinkpy."""
@@ -35,18 +46,21 @@ def setUp(self):
3546
'notifications': 2,
3647
'region_id': 'test'
3748
}
49+
3850
self.blink.urls = blinkpy.BlinkURLHandler('test')
3951
self.blink.network_id = '0000'
4052

4153
def tearDown(self):
4254
"""Clean up after test."""
4355
self.blink = None
4456

57+
@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
58+
return_value=CAMERA_CFG)
4559
@mock.patch('blinkpy.blinkpy.requests.post',
4660
side_effect=mresp.mocked_requests_post)
4761
@mock.patch('blinkpy.blinkpy.requests.get',
4862
side_effect=mresp.mocked_requests_get)
49-
def test_camera_properties(self, mock_get, mock_post):
63+
def test_camera_properties(self, mock_get, mock_post, mock_cfg):
5064
"""Tests all property set/recall."""
5165
self.blink.urls = blinkpy.BlinkURLHandler('test')
5266

@@ -56,7 +70,7 @@ def test_camera_properties(self, mock_get, mock_post):
5670

5771
for name in self.blink.cameras:
5872
camera = self.blink.cameras[name]
59-
73+
camera.update(self.camera_config)
6074
self.assertEqual(camera.id, '1111')
6175
self.assertEqual(camera.name, 'foobar')
6276
self.assertEqual(camera.armed, False)
@@ -68,19 +82,22 @@ def test_camera_properties(self, mock_get, mock_post):
6882
camera.clip,
6983
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
7084
)
71-
self.assertEqual(camera.temperature, 70)
72-
self.assertEqual(camera.battery, 3)
85+
self.assertEqual(camera.temperature, 68)
86+
self.assertEqual(camera.temperature_c, 20.0)
87+
self.assertEqual(camera.battery, 50)
7388
self.assertEqual(camera.battery_string, "OK")
7489
self.assertEqual(camera.notifications, 2)
7590
self.assertEqual(camera.region_id, 'test')
91+
self.assertEqual(camera.motion_detected, True)
92+
self.assertEqual(camera.wifi_strength, -30)
93+
7694
camera_config = self.camera_config
7795
camera_config['active'] = 'armed'
7896
camera_config['thumbnail'] = '/test2/image'
7997
camera_config['video'] = '/test2/clip.mp4'
8098
camera_config['temp'] = 60
8199
camera_config['battery'] = 0
82100
camera_config['notifications'] = 4
83-
84101
for name in self.blink.cameras:
85102
camera = self.blink.cameras[name]
86103
camera.update(camera_config)
@@ -93,8 +110,8 @@ def test_camera_properties(self, mock_get, mock_post):
93110
camera.clip,
94111
"https://rest.test.{}/test2/clip.mp4".format(BLINK_URL)
95112
)
96-
self.assertEqual(camera.temperature, 60)
97-
self.assertEqual(camera.battery, 0)
113+
self.assertEqual(camera.temperature, 68)
114+
self.assertEqual(camera.battery, 50)
98115
self.assertEqual(camera.battery_string, "Low")
99116
self.assertEqual(camera.notifications, 4)
100117
camera_config['battery'] = -10
@@ -107,7 +124,9 @@ def test_camera_case(self):
107124
self.blink.cameras['foobar'] = camera_object
108125
self.assertEqual(camera_object, self.blink.cameras['fOoBaR'])
109126

110-
def test_camera_attributes(self):
127+
@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
128+
return_value=CAMERA_CFG)
129+
def test_camera_attributes(self, mock_cfg):
111130
"""Tests camera attributes."""
112131
self.blink.urls = blinkpy.BlinkURLHandler('test')
113132

@@ -117,6 +136,7 @@ def test_camera_attributes(self):
117136

118137
for name in self.blink.cameras:
119138
camera = self.blink.cameras[name]
139+
camera.update(self.camera_config)
120140
camera_attr = camera.attributes
121141
self.assertEqual(camera_attr['device_id'], '1111')
122142
self.assertEqual(camera_attr['name'], 'foobar')
@@ -129,7 +149,10 @@ def test_camera_attributes(self):
129149
camera_attr['video'],
130150
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
131151
)
132-
self.assertEqual(camera_attr['temperature'], 70)
133-
self.assertEqual(camera_attr['battery'], 3)
152+
self.assertEqual(camera_attr['temperature'], 68)
153+
self.assertEqual(camera_attr['temperature_c'], 20.0)
154+
self.assertEqual(camera_attr['battery'], 50)
134155
self.assertEqual(camera_attr['notifications'], 2)
135156
self.assertEqual(camera_attr['network_id'], '0000')
157+
self.assertEqual(camera_attr['motion_detected'], True)
158+
self.assertEqual(camera_attr['wifi_strength'], -30)

tests/test_blink_functions.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,17 @@ def test_get_videos(self, req):
6161
'/test/thumb')
6262

6363
@mock.patch('blinkpy.blinkpy._request')
64-
def test_get_cameras(self, req):
64+
@mock.patch('blinkpy.blinkpy.Blink._video_request')
65+
def test_get_cameras(self, vid_req, req):
6566
"""Test camera extraction."""
6667
req.return_value = {'devices': [self.config]}
68+
vid_req.return_value = [
69+
{
70+
'camera_name': 'foobar',
71+
'address': '/new.mp4',
72+
'thumbnail': '/new'
73+
}
74+
]
6775
self.blink.get_cameras()
6876
self.assertTrue('foobar' in self.blink.cameras)
6977

0 commit comments

Comments
 (0)