diff --git a/README.md b/README.md index 0271abf..61cadea 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ 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() @@ -30,7 +30,7 @@ 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. diff --git a/example.py b/example.py index ad988e4..07ddb5a 100644 --- a/example.py +++ b/example.py @@ -1,4 +1,3 @@ -import pykuna import sys import time @@ -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)) diff --git a/pykuna/camera.py b/pykuna/camera.py index 6d6307d..d472956 100644 --- a/pykuna/camera.py +++ b/pykuna/camera.py @@ -1,5 +1,5 @@ ENDPOINT_CAMERA = 'cameras' -ENDPOINT_USER = 'users' +ENDPOINT_USERS = 'users' ENDPOINT_THUMBNAIL = 'thumbnail' @@ -241,7 +241,6 @@ 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 = { @@ -249,7 +248,6 @@ def set_property(self, 'brightness': brightness, 'bulb_on': bulb_on, 'led_mask': led_mask, - 'notifications_enabled': notifications_enabled, 'volume': volume }.items() if value is not None } @@ -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) + diff --git a/pykuna/kuna.py b/pykuna/kuna.py index 267b44c..25ad4f3 100644 --- a/pykuna/kuna.py +++ b/pykuna/kuna.py @@ -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' @@ -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.""" @@ -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""" @@ -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 diff --git a/setup.py b/setup.py index b1fb36e..eebfb74 100644 --- a/setup.py +++ b/setup.py @@ -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",