Skip to content

Commit

Permalink
v0.4.0 (#3)
Browse files Browse the repository at this point in the history
* Change cameras from list to dict

Streamline updates to upper implementation.

* Add better logging for API request errors

* Initial support for getting camera recordings

* Update example.py
  • Loading branch information
marthoc authored Mar 7, 2019
1 parent 675e714 commit ac95639
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 21 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ Where:
- `USERNAME` is the email address you use for the Kuna app; and,
- `PASSWORD` is your password for the Kuna app.

After authenticating, populate (or refresh) a list of all cameras in the Kuna account by calling the `update()` method on the API object:
After authenticating, populate (or refresh) a dict of all cameras in the Kuna account (key = camera serial number, value = camera object) by calling the `update()` method on the API object:

```python
kuna.update()
```

## Methods

The following methods are available on a camera device object in the KunaAPI.cameras list:
The following methods are available on a camera device object in the KunaAPI.cameras dict:

- `update()` - refresh only that camera's properties from the API.
- `get_thumbnail()` - returns a camera snapshot as a jpeg image.
Expand Down
9 changes: 5 additions & 4 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import pykuna
import sys
import time

Expand All @@ -10,15 +9,17 @@ def main():
exit(1)

# create an API object, passing username and password
kuna = pykuna.KunaAPI(sys.argv[1], sys.argv[2])
from pykuna import KunaAPI
kuna = KunaAPI(sys.argv[1], sys.argv[2])

# authenticate() to get/refresh the access token
kuna.authenticate()

# update() to populate .cameras with a list of cameras in the account
# update() to populate kuna.cameras with a dict of cameras in the account;
# key is camera serial number, value is camera object
kuna.update()

for camera in kuna.cameras:
for camera in kuna.cameras.values():
# print the name and serial number of the camera
print('Camera: {} (Serial No. {})'.format(camera.name, camera.serial_number))

Expand Down
28 changes: 25 additions & 3 deletions pykuna/camera.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ENDPOINT_CAMERA = 'cameras'
ENDPOINT_USER = 'users'
ENDPOINT_USERS = 'users'
ENDPOINT_THUMBNAIL = 'thumbnail'


Expand Down Expand Up @@ -241,15 +241,13 @@ def set_property(self,
brightness: int = None,
bulb_on: bool = None,
led_mask: bool = None,
notifications_enabled: bool = None,
volume: int = None):
""""Set a property of the device."""
json = {
key: value for key, value in {
'brightness': brightness,
'bulb_on': bulb_on,
'led_mask': led_mask,
'notifications_enabled': notifications_enabled,
'volume': volume
}.items() if value is not None
}
Expand All @@ -268,3 +266,27 @@ def light_on(self):
def light_off(self):
"""Turn the light bulb off."""
self.set_property(bulb_on=False)

def set_notifications(self, notifications_enabled: bool):
"""Set notifications for the Camera."""
path = '{}/{}/{}/{}/'.format(
ENDPOINT_CAMERA,
self.serial_number,
ENDPOINT_USERS,
self.owner['email']
)

print(path)

json = {
'notifications_enabled': notifications_enabled
}

self._request('post', path, json=json)

def enable_notifications(self):
self.set_notifications(True)

def disable_notifications(self):
self.set_notifications(False)

40 changes: 29 additions & 11 deletions pykuna/kuna.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
API_URL = 'https://server.kunasystems.com/api/v1'
AUTH_ENDPOINT = 'account/auth'
CAMERAS_ENDPOINT = 'user/cameras'
RECORDINGS_ENDPOINT = 'recordings'

USER_AGENT = 'Kuna/2.4.4 (iPhone; iOS 12.1; Scale/3.00)'
USER_AGENT_THUMBNAIL = 'Kuna/156 CFNetwork/975.0.3 Darwin/18.2.0'

Expand All @@ -20,7 +22,8 @@ def __init__(self, username, password):
self._username = username
self._password = password
self._token = None
self.cameras = []
self.cameras = {}
self.recordings = {}

def authenticate(self):
"""Login and get an auth token."""
Expand All @@ -31,23 +34,35 @@ def authenticate(self):

result = self._request('post', AUTH_ENDPOINT, json=json)

if result is None:
raise AuthenticationError('No token returned, check username and password')

if 'token' in result:
try:
self._token = result['token']
return
except TypeError:
raise AuthenticationError('No Kuna API token response returned, check username and password.')
except KeyError as err:
_LOGGER.error('Error retrieving Kuna auth token: {}'.format(err))
raise err

def update(self):
"""Refresh the list of all cameras in the Kuna account."""
"""Refresh the dict of all cameras in the Kuna account."""
result = self._request('get', CAMERAS_ENDPOINT)
cameras = []

for item in result['results']:
cam = KunaCamera(item, self._request)
cameras.append(cam)
self.cameras[item['serial_number']] = KunaCamera(item, self._request)

def refresh_recordings(self):
"""Refresh the dict of all recordings in the Kuna account."""
if not self.cameras:
_LOGGER.warning('Cannot fetch recordings, no cameras in the Kuna account.')
return

for camera in self.cameras.values():
params = {
'serial_numbers[]': camera.serial_number
}
result = self._request('get', RECORDINGS_ENDPOINT, params=params)

self.cameras = cameras
for recording in result['results']:
self.recordings[recording['label']] = recording['mp4']

def _request(self, method, path, json=None, params=None, thumbnail=False):
"""Make an API request"""
Expand Down Expand Up @@ -84,5 +99,8 @@ def _request(self, method, path, json=None, params=None, thumbnail=False):
except HTTPError as err:
if err.response.status_code == 401:
raise UnauthorizedError('Kuna Auth Token invalid or stale?')
else:
_LOGGER.error('Kuna API request error: {}'.format(err))
except Timeout:
_LOGGER.error('Request to Kuna API timed out.')
raise
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setuptools.setup(
name="pykuna",
version="0.3.0",
version="0.4.0",
author="Mark Coombes",
author_email="mark@markcoombes.ca",
description="Python3 library for interacting with the Kuna camera mobile API",
Expand Down

0 comments on commit ac95639

Please sign in to comment.