From b7e4bb535066a994d7ebd1a6fe538be97fb302b4 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Mon, 16 Oct 2017 04:31:58 -0400 Subject: [PATCH] Allows history to enforce to return minimum number of events for a given type. --- ring_doorbell/doorbot.py | 86 +++++++++++++++++++++++++++++----------- tests/test_ring.py | 4 ++ 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/ring_doorbell/doorbot.py b/ring_doorbell/doorbot.py index 9231029d..56755774 100644 --- a/ring_doorbell/doorbot.py +++ b/ring_doorbell/doorbot.py @@ -154,32 +154,70 @@ def existing_doorbell_type_duration(self, value): return True return None - def history(self, limit=30, timezone=None, kind=None): - """Return history with datetime objects.""" - # allow modify the items to return - params = {'limit': str(limit)} - - url = API_URI + URL_DOORBELL_HISTORY.format(self.account_id) - response = self._ring.query(url, extra_params=params) - - # convert for specific timezone - utc = pytz.utc - if timezone: - mytz = pytz.timezone(timezone) - - for entry in response: - dt_at = datetime.strptime(entry['created_at'], - '%Y-%m-%dT%H:%M:%S.000Z') - utc_dt = datetime(dt_at.year, dt_at.month, dt_at.day, dt_at.hour, - dt_at.minute, dt_at.second, tzinfo=utc) + def history(self, limit=30, timezone=None, kind=None, + enforce_limit=False, retry=8): + """ + Return history with datetime objects. + + :param limit: specify number of objects to be returned + :param timezone: determine which timezone to convert data objects + :param kind: filter by kind (ding, motion, on_demand) + :param enforce_limit: when True, this will enforce the limit and kind + :param retry: determine the max number of attempts to archive the limit + """ + queries = 0 + original_limit = limit + + # set cap for max queries + if retry > 10: + retry = 10 + + while True: + params = {'limit': str(limit)} + + url = API_URI + URL_DOORBELL_HISTORY.format(self.account_id) + response = self._ring.query(url, extra_params=params) + + # cherrypick only the selected kind events + if kind: + response = list(filter( + lambda array: array['kind'] == kind, response)) + + # convert for specific timezone + utc = pytz.utc if timezone: - tz_dt = utc_dt.astimezone(mytz) - entry['created_at'] = tz_dt - else: - entry['created_at'] = utc_dt + mytz = pytz.timezone(timezone) + + for entry in response: + dt_at = datetime.strptime(entry['created_at'], + '%Y-%m-%dT%H:%M:%S.000Z') + utc_dt = datetime(dt_at.year, dt_at.month, dt_at.day, + dt_at.hour, dt_at.minute, dt_at.second, + tzinfo=utc) + if timezone: + tz_dt = utc_dt.astimezone(mytz) + entry['created_at'] = tz_dt + else: + entry['created_at'] = utc_dt + + if enforce_limit: + # return because already matched the number + # of events by kind + if len(response) >= original_limit: + return response[:original_limit] - if kind: - return list(filter(lambda array: array['kind'] == kind, response)) + # ensure the loop will exit after max queries + queries += 1 + if queries == retry: + _LOGGER.warning("Could not find total of %s of kind %s", + original_limit, kind) + break + + # ensure the kind objects returned to match limit + limit = limit * 2 + + else: + break return response diff --git a/tests/test_ring.py b/tests/test_ring.py index 11f8d407..3203e832 100644 --- a/tests/test_ring.py +++ b/tests/test_ring.py @@ -78,6 +78,10 @@ def test_doorbell_attributes(self, mock): self.assertIsInstance(dev.history(limit=1, kind='motion'), list) self.assertEqual(0, len(dev.history(limit=1, kind='ding'))) + self.assertEqual(0, len(dev.history(limit=1, + kind='ding', + enforce_limit=True, + retry=50))) self.assertEqual('Mechanical', dev.existing_doorbell_type) self.assertTrue(data._persist_token)