Skip to content

Commit

Permalink
Merge pull request #65 from fronzbot/battery-percent
Browse files Browse the repository at this point in the history
Added new request url for camera config
  • Loading branch information
fronzbot authored May 21, 2018
2 parents 66a6701 + 91a877d commit 65dd547
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 17 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ A list of changes between each release

0.8.0.dev (Development version)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added support for battery voltage level
- Added motion detection per camera
- Added fully accessible camera configuration dict

0.7.0 (2018-02-08)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
49 changes: 43 additions & 6 deletions blinkpy/blinkpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,17 @@ def __init__(self, config, blink):
config['thumbnail'])
self.clip = "{}{}".format(self.urls.base_url, config['video'])
self.temperature = config['temp']
self.battery = config['battery']
self._battery_string = config['battery']
self.notifications = config['notifications']
self.motion = {}
self.motion = dict()
self.header = None
self.image_link = None
self.arm_link = None
self.region_id = config['region_id']
self.battery_voltage = -180
self.motion_detected = None
self.wifi_strength = None
self.camera_config = dict()

@property
def attributes(self):
Expand All @@ -128,6 +132,8 @@ def attributes(self):
'thumbnail': self.thumbnail,
'video': self.clip,
'notifications': self.notifications,
'motion_detected': self.motion_detected,
'wifi_strength': self.wifi_strength,
'network_id': self.blink.network_id
}
return attributes
Expand All @@ -142,13 +148,18 @@ def armed(self):
"""Return camera arm status."""
return True if self._status == 'armed' else False

@property
def battery(self):
"""Return battery level as percentage."""
return round(self.battery_voltage / 180 * 100)

@property
def battery_string(self):
"""Return string indicating battery status."""
status = "Unknown"
if self.battery > 1 and self.battery <= 3:
if self._battery_string > 1 and self._battery_string <= 3:
status = "OK"
elif self.battery >= 0:
elif self._battery_string >= 0:
status = "Low"
return status

Expand All @@ -175,10 +186,26 @@ def update(self, values):
self.urls.base_url, values['thumbnail'])
self.clip = "{}{}".format(
self.urls.base_url, values['video'])
self.temperature = values['temp']
self.battery = values['battery']
self._battery_string = values['battery']
self.notifications = values['notifications']

try:
cfg = self.blink.camera_config_request(self.id)
self.camera_config = cfg
except requests.exceptions.RequestException as err:
_LOGGER.warning("Could not get config for %s with id %s",
self.name, self.id)
_LOGGER.warning("Exception raised: %s", err)

try:
self.battery_voltage = cfg['camera'][0]['battery_voltage']
self.motion_detected = cfg['camera'][0]['motion_alert']
self.wifi_strength = cfg['camera'][0]['wifi_strength']
self.temperature = cfg['camera'][0]['temperature']
except KeyError:
_LOGGER.warning("Problem extracting config for camera %s",
self.name)

def image_refresh(self):
"""Refresh current thumbnail."""
url = self.urls.home_url
Expand Down Expand Up @@ -327,6 +354,7 @@ def get_videos(self, start_page=0, end_page=1):
videos.append(this_page)

for page in videos:
_LOGGER.debug("Retrieved video page %s", page)
for entry in page:
camera_name = entry['camera_name']
clip_addr = entry['address']
Expand Down Expand Up @@ -365,6 +393,7 @@ def get_cameras(self):
device = BlinkCamera(element, self)
self.cameras[device.name] = device
self._idlookup[device.id] = device.name
self.refresh()

def set_links(self):
"""Set access links and required headers for each camera in system."""
Expand Down Expand Up @@ -497,3 +526,11 @@ def _status_request(self):
self.network_id)
headers = self._auth_header
return _request(self, url=url, headers=headers, reqtype='get')

def camera_config_request(self, camera_id):
"""Retrieve more info about Blink config."""
url = "{}/network/{}/camera/{}/config".format(self.urls.base_url,
self.network_id,
str(camera_id))
headers = self._auth_header
return _request(self, url=url, headers=headers, reqtype='get')
41 changes: 31 additions & 10 deletions tests/test_blink_cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
USERNAME = 'foobar'
PASSWORD = 'deadbeef'

CAMERA_CFG = {
'camera': [
{
'battery_voltage': 90,
'motion_alert': True,
'wifi_strength': -30,
'temperature': 68
}
]
}


class TestBlinkCameraSetup(unittest.TestCase):
"""Test the Blink class in blinkpy."""
Expand All @@ -35,18 +46,21 @@ def setUp(self):
'notifications': 2,
'region_id': 'test'
}

self.blink.urls = blinkpy.BlinkURLHandler('test')
self.blink.network_id = '0000'

def tearDown(self):
"""Clean up after test."""
self.blink = None

@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
return_value=CAMERA_CFG)
@mock.patch('blinkpy.blinkpy.requests.post',
side_effect=mresp.mocked_requests_post)
@mock.patch('blinkpy.blinkpy.requests.get',
side_effect=mresp.mocked_requests_get)
def test_camera_properties(self, mock_get, mock_post):
def test_camera_properties(self, mock_get, mock_post, mock_cfg):
"""Tests all property set/recall."""
self.blink.urls = blinkpy.BlinkURLHandler('test')

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

for name in self.blink.cameras:
camera = self.blink.cameras[name]

camera.update(self.camera_config)
self.assertEqual(camera.id, '1111')
self.assertEqual(camera.name, 'foobar')
self.assertEqual(camera.armed, False)
Expand All @@ -68,19 +82,21 @@ def test_camera_properties(self, mock_get, mock_post):
camera.clip,
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
)
self.assertEqual(camera.temperature, 70)
self.assertEqual(camera.battery, 3)
self.assertEqual(camera.temperature, 68)
self.assertEqual(camera.battery, 50)
self.assertEqual(camera.battery_string, "OK")
self.assertEqual(camera.notifications, 2)
self.assertEqual(camera.region_id, 'test')
self.assertEqual(camera.motion_detected, True)
self.assertEqual(camera.wifi_strength, -30)

camera_config = self.camera_config
camera_config['active'] = 'armed'
camera_config['thumbnail'] = '/test2/image'
camera_config['video'] = '/test2/clip.mp4'
camera_config['temp'] = 60
camera_config['battery'] = 0
camera_config['notifications'] = 4

for name in self.blink.cameras:
camera = self.blink.cameras[name]
camera.update(camera_config)
Expand All @@ -93,8 +109,8 @@ def test_camera_properties(self, mock_get, mock_post):
camera.clip,
"https://rest.test.{}/test2/clip.mp4".format(BLINK_URL)
)
self.assertEqual(camera.temperature, 60)
self.assertEqual(camera.battery, 0)
self.assertEqual(camera.temperature, 68)
self.assertEqual(camera.battery, 50)
self.assertEqual(camera.battery_string, "Low")
self.assertEqual(camera.notifications, 4)
camera_config['battery'] = -10
Expand All @@ -107,7 +123,9 @@ def test_camera_case(self):
self.blink.cameras['foobar'] = camera_object
self.assertEqual(camera_object, self.blink.cameras['fOoBaR'])

def test_camera_attributes(self):
@mock.patch('blinkpy.blinkpy.Blink.camera_config_request',
return_value=CAMERA_CFG)
def test_camera_attributes(self, mock_cfg):
"""Tests camera attributes."""
self.blink.urls = blinkpy.BlinkURLHandler('test')

Expand All @@ -117,6 +135,7 @@ def test_camera_attributes(self):

for name in self.blink.cameras:
camera = self.blink.cameras[name]
camera.update(self.camera_config)
camera_attr = camera.attributes
self.assertEqual(camera_attr['device_id'], '1111')
self.assertEqual(camera_attr['name'], 'foobar')
Expand All @@ -129,7 +148,9 @@ def test_camera_attributes(self):
camera_attr['video'],
"https://rest.test.{}/test/clip/clip.mp4".format(BLINK_URL)
)
self.assertEqual(camera_attr['temperature'], 70)
self.assertEqual(camera_attr['battery'], 3)
self.assertEqual(camera_attr['temperature'], 68)
self.assertEqual(camera_attr['battery'], 50)
self.assertEqual(camera_attr['notifications'], 2)
self.assertEqual(camera_attr['network_id'], '0000')
self.assertEqual(camera_attr['motion_detected'], True)
self.assertEqual(camera_attr['wifi_strength'], -30)
10 changes: 9 additions & 1 deletion tests/test_blink_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,17 @@ def test_get_videos(self, req):
'/test/thumb')

@mock.patch('blinkpy.blinkpy._request')
def test_get_cameras(self, req):
@mock.patch('blinkpy.blinkpy.Blink._video_request')
def test_get_cameras(self, vid_req, req):
"""Test camera extraction."""
req.return_value = {'devices': [self.config]}
vid_req.return_value = [
{
'camera_name': 'foobar',
'address': '/new.mp4',
'thumbnail': '/new'
}
]
self.blink.get_cameras()
self.assertTrue('foobar' in self.blink.cameras)

Expand Down

0 comments on commit 65dd547

Please sign in to comment.