From f3a9a0d4f97d661ec3a830e0768a4eda2aab1df4 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 28 Dec 2018 14:13:46 -0500 Subject: [PATCH 1/7] Added Python 3.7 to Travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index eef022a..3723ce0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ matrix: env: TOXENV=py35 - python: "3.6" env: TOXENV=py36 + - python: "3.7" + env: TOXENV=py37 - python: "3.4.2" env: TOXENV=lint install: pip install -U tox coveralls From ff8549f9dd87b7e9beb4393a29107d579b1eb7f1 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 28 Dec 2018 14:32:32 -0500 Subject: [PATCH 2/7] Treat SSL errors when fetching images --- pyarlo/utils.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyarlo/utils.py b/pyarlo/utils.py index 191b7c4..f4681d0 100644 --- a/pyarlo/utils.py +++ b/pyarlo/utils.py @@ -1,9 +1,12 @@ # coding: utf-8 """Implementation of Arlo utils.""" +import logging import time from datetime import datetime as dt import requests +_LOGGER = logging.getLogger(__name__) + def to_datetime(timestamp): """Return datetime object from timestamp.""" @@ -19,7 +22,12 @@ def pretty_timestamp(timestamp, date_format='%a-%m_%d_%y:%H:%M:%S'): def http_get(url, filename=None): """Download HTTP data.""" - ret = requests.get(url) + try: + ret = requests.get(url) + except requests.exceptions.SSLError as error: + _LOGGER.error(error) + return False + if ret.status_code != 200: return False From 584a373a360fc980e0f96e5d08211d613f4416bb Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 28 Dec 2018 14:37:29 -0500 Subject: [PATCH 3/7] Fixed Python 3.7 tests for Travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3723ce0..9c62525 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: env: TOXENV=py36 - python: "3.7" env: TOXENV=py37 + dist: xenial + sudo: true - python: "3.4.2" env: TOXENV=lint install: pip install -U tox coveralls From db70aeb81705309c56ad32bbab1094f6cd146524 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 28 Dec 2018 14:47:50 -0500 Subject: [PATCH 4/7] Bump Arlo version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5e4df53..8dea378 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ def readme(): setup( name='pyarlo', packages=['pyarlo'], - version='0.2.3', + version='0.2.4', description='Python Arlo is a library written in Python 2.7/3x ' + 'that exposes the Netgear Arlo cameras as Python objects.', long_description=readme(), From c1d7cf861300dddfad8ebb259ecd28f593f950d3 Mon Sep 17 00:00:00 2001 From: Brad Misterek Date: Thu, 30 May 2019 06:23:32 -0600 Subject: [PATCH 5/7] Make the type of motion accessible. This only works on some cameras, and requires an Arlo Smart subscription. Tested on Arlo Q (with and without subscription) and Arlo Pro (without subscription) --- pyarlo/media.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyarlo/media.py b/pyarlo/media.py index 8c8fad0..ac2acfa 100644 --- a/pyarlo/media.py +++ b/pyarlo/media.py @@ -187,6 +187,13 @@ def video_url(self): return self._attrs.get('presignedContentUrl') return None + @property + def motion_type(self): + """Returns the type of motion that triggered the camera. Requires subscription.""" + if self._attrs is not None: + return self._attrs.get("objCategory") + return None + def download_thumbnail(self, filename=None): """Download JPEG thumbnail. From 05a35fb1eaa09a339ae69e8043400f2a039c770a Mon Sep 17 00:00:00 2001 From: You Wang Date: Sun, 22 Mar 2020 14:11:42 -0700 Subject: [PATCH 6/7] New auth mechanism --- pyarlo/__init__.py | 14 +++++++++----- pyarlo/const.py | 28 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/pyarlo/__init__.py b/pyarlo/__init__.py index edc71ca..9b48712 100644 --- a/pyarlo/__init__.py +++ b/pyarlo/__init__.py @@ -2,12 +2,13 @@ """Base Python Class file for Netgear Arlo camera module.""" import logging import requests +import base64 from pyarlo.base_station import ArloBaseStation from pyarlo.camera import ArloCamera from pyarlo.media import ArloMediaLibrary from pyarlo.const import ( - BILLING_ENDPOINT, DEVICES_ENDPOINT, + API_URL, BILLING_ENDPOINT, DEVICES_ENDPOINT, FRIENDS_ENDPOINT, LOGIN_ENDPOINT, PROFILE_ENDPOINT, PRELOAD_DAYS, RESET_ENDPOINT) @@ -69,10 +70,11 @@ def _authenticate(self): method='POST', extra_params={ 'email': self.__username, - 'password': self.__password - }) + 'password': base64.b64encode(self.__password.encode()).decode()}, + extra_headers={ + 'Referer': API_URL}) - if isinstance(data, dict) and data.get('success'): + if isinstance(data, dict) and data.get('meta') and data['meta']['code'] == 200: data = data.get('data') self.authenticated = data.get('authenticated') self.country_code = data.get('countryCode') @@ -85,7 +87,9 @@ def _authenticate(self): def cleanup_headers(self): """Reset the headers and params.""" - headers = {'Content-Type': 'application/json'} + headers = { + 'Content-Type': 'application/json', + 'Auth-Version': '2'} headers['Authorization'] = self.__token self.__headers = headers self.__params = {} diff --git a/pyarlo/const.py b/pyarlo/const.py index 2bba1b9..5f5c535 100644 --- a/pyarlo/const.py +++ b/pyarlo/const.py @@ -1,23 +1,23 @@ """Constants used by Python Arlo.""" # API Endpoints -API_URL = "https://arlo.netgear.com/hmsweb" +API_URL = "https://my.arlo.com" -DEVICE_SUPPORT_ENDPOINT = API_URL + "/devicesupport/v2" -SUBSCRIBE_ENDPOINT = API_URL + "/client/subscribe" -UNSUBSCRIBE_ENDPOINT = API_URL + "/client/unsubscribe" -BILLING_ENDPOINT = API_URL + "/users/serviceLevel/v2" -DEVICES_ENDPOINT = API_URL + "/users/devices" -FRIENDS_ENDPOINT = API_URL + "/users/friends" -LIBRARY_ENDPOINT = API_URL + "/users/library" -LOGIN_ENDPOINT = API_URL + "/login/v2" -LOGOUT_ENDPOINT = API_URL + "/logout" -NOTIFY_ENDPOINT = API_URL + "/users/devices/notify/{0}" -PROFILE_ENDPOINT = API_URL + "/users/profile" +DEVICE_SUPPORT_ENDPOINT = API_URL + "/hmsweb/devicesupport/v2" +SUBSCRIBE_ENDPOINT = API_URL + "/hmsweb/client/subscribe" +UNSUBSCRIBE_ENDPOINT = API_URL + "/hmsweb/client/unsubscribe" +BILLING_ENDPOINT = API_URL + "/hmsweb/users/serviceLevel/v2" +DEVICES_ENDPOINT = API_URL + "/hmsweb/users/devices" +FRIENDS_ENDPOINT = API_URL + "/hmsweb/users/friends" +LIBRARY_ENDPOINT = API_URL + "/hmsweb/users/library" +LOGIN_ENDPOINT = "https://ocapi-app.arlo.com/api/auth" +LOGOUT_ENDPOINT = API_URL + "/hmsweb/logout" +NOTIFY_ENDPOINT = API_URL + "/hmsweb/users/devices/notify/{0}" +PROFILE_ENDPOINT = API_URL + "/hmsweb/users/profile" RESET_ENDPOINT = LIBRARY_ENDPOINT + "/reset" RESET_CAM_ENDPOINT = RESET_ENDPOINT + "/?uniqueId={0}" -STREAM_ENDPOINT = API_URL + "/users/devices/startStream" -SNAPSHOTS_ENDPOINT = API_URL + "/users/devices/fullFrameSnapshot" +STREAM_ENDPOINT = API_URL + "/hmsweb/users/devices/startStream" +SNAPSHOTS_ENDPOINT = API_URL + "/hmsweb/users/devices/fullFrameSnapshot" # number of days to preload video PRELOAD_DAYS = 30 From 710870bf4a17c18a7114c9f7bde2a101fa8db917 Mon Sep 17 00:00:00 2001 From: You Wang Date: Sun, 22 Mar 2020 15:11:58 -0700 Subject: [PATCH 7/7] Fix tests with new auth mechanism --- tests/fixtures/pyarlo_authentication.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/fixtures/pyarlo_authentication.json b/tests/fixtures/pyarlo_authentication.json index c8de888..562aed2 100644 --- a/tests/fixtures/pyarlo_authentication.json +++ b/tests/fixtures/pyarlo_authentication.json @@ -9,4 +9,5 @@ "token": "999999999999", "userId": "999-123456", "validEmail": true}, - "success": true} + "meta": {"code":200} +}