Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ In [12]: mydoorbell.
mydoorbell.account_id mydoorbell.kind
mydoorbell.address mydoorbell.last_recording_id
mydoorbell.battery_life mydoorbell.latitude
mydoorbell.check_activity mydoorbell.live_streaming_json
mydoorbell.check_alerts mydoorbell.live_streaming_json
mydoorbell.debug mydoorbell.longitude
mydoorbell.existing_doorbell_type mydoorbell.name
mydoorbell.existing_doorbell_type_duration mydoorbell.recording_download
Expand Down
63 changes: 56 additions & 7 deletions ring_doorbell/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import requests
import pytz

from ring_doorbell.utils import _locator
from ring_doorbell.utils import _locator, _save_cache, _read_cache
from ring_doorbell.const import (
API_VERSION, API_URI, CHIMES_ENDPOINT, CHIME_VOL_MIN, CHIME_VOL_MAX,
DEVICES_ENDPOINT, DOORBELLS_ENDPOINT, DOORBELL_VOL_MIN, DOORBELL_VOL_MAX,
Expand All @@ -32,7 +32,7 @@ class Ring(object):
"""A Python Abstraction object to Ring Door Bell."""

def __init__(self, username, password, debug=False, persist_token=False,
push_token_notify_url=""):
push_token_notify_url="http://localhost/"):
"""Initialize the Ring object."""
self.features = None
self.is_connected = None
Expand Down Expand Up @@ -72,7 +72,7 @@ def _authenticate(self, attempts=RETRY_TOKEN):
self.params = {'api_version': API_VERSION,
'auth_token': self.token}

if self._persist_token:
if self._persist_token and self._push_token_notify_url:
url = API_URI + PERSIST_TOKEN_ENDPOINT
PERSIST_TOKEN_DATA['auth_token'] = self.token
PERSIST_TOKEN_DATA['device[push_notification_token]'] = \
Expand Down Expand Up @@ -140,7 +140,9 @@ def query(self,
if method == 'GET':
response = req.json()
break
_LOGGER.error("%s", MSG_GENERIC_FAIL)

if self.debug:
_LOGGER.debug("%s", MSG_GENERIC_FAIL)
return response

@property
Expand Down Expand Up @@ -199,13 +201,40 @@ def __init__(self):
self.family = None
self.name = None

# alerts notifications
self._alert_cache = None
self.alert = None
self.alert_expires_at = None

def __repr__(self):
"""Return __repr__."""
return "<{0}: {1}>".format(self.__class__.__name__, self.name)

def update(self):
"""Refresh attributes."""
self._get_attrs()
self._update_alert()

def _update_alert(self):
"""Verify if alert received is still valid."""
if self.alert and self.alert_expires_at:
if datetime.now() >= self.alert_expires_at:
self.alert = None
self.alert_expires_at = None
elif self._alert_cache:
aux = _read_cache(self._alert_cache)
if ((isinstance(aux, dict)) and
('now' in aux) and
('expires_in' in aux)):
aux_expires_at = datetime.fromtimestamp(
aux.get('now') + aux.get('expires_in'))

# verify if pickle object is still valid
if datetime.now() <= aux_expires_at:
self.alert = aux
self.alert_expires_at = aux_expires_at
else:
_save_cache(None, self._alert_cache)

def _get_attrs(self):
"""Return chime attributes."""
Expand Down Expand Up @@ -332,11 +361,31 @@ def battery_life(self):
value = 100
return value

@property
def check_activity(self):
def check_alerts(self, cache=None):
"""Return JSON when motion or ring is detected."""
# save alerts attributes to an external pickle file
# when multiple resources are checking for alerts
if cache:
self._alert_cache = cache

url = API_URI + DINGS_ENDPOINT
return self._ring.query(url)
self.update()

try:
resp = self._ring.query(url)[0]
except IndexError:
return None

if resp:
timestamp = resp.get('now') + resp.get('expires_in')
self.alert = resp
self.alert_expires_at = datetime.fromtimestamp(timestamp)

# save to a pickle data
if self._alert_cache:
_save_cache(self.alert, self._alert_cache)
return True
return None

@property
def existing_doorbell_type(self):
Expand Down
26 changes: 26 additions & 0 deletions ring_doorbell/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# coding: utf-8
# vim:sw=4:ts=4:et:
"""Python Ring Doorbell utils."""
import os
from ring_doorbell.const import NOT_FOUND

try:
import cPickle as pickle
except ImportError:
import pickle


def _locator(lst, key, value):
"""Return the position of a match item in list."""
Expand All @@ -11,3 +17,23 @@ def _locator(lst, key, value):
if d[key] == value)
except StopIteration:
return NOT_FOUND


def _save_cache(data, filename):
"""Dump data into a pickle file."""
try:
with open(filename, 'wb') as pickle_db:
pickle.dump(data, pickle_db)
return True
except:
raise


def _read_cache(filename):
"""Read data from a pickle file."""
try:
if os.path.isfile(filename):
return pickle.load(open(filename, 'rb'))
except:
raise
return None