Skip to content
This repository has been archived by the owner on Jul 30, 2021. It is now read-only.

Commit

Permalink
Merge pull request #75 from tchellomello/arlo_fixes
Browse files Browse the repository at this point in the history
Enhanced how Arlo queries API to reduce polls
  • Loading branch information
tchellomello authored Jun 5, 2018
2 parents ff8aca2 + 0134833 commit 5bdc358
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 13 deletions.
22 changes: 21 additions & 1 deletion pyarlo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,28 @@ def is_connected(self):
"""Connection status of client with Arlo system."""
return bool(self.authenticated)

def update(self):
def update(self, update_cameras=False, update_base_station=False):
"""Refresh object."""
self._authenticate()

# update attributes in all cameras to avoid duped queries
if update_cameras:
url = DEVICES_ENDPOINT
data = self.query(url).get('data')
for camera in self.cameras:
for dev_info in data:
if dev_info.get('deviceName') == camera.name:
_LOGGER.debug("Refreshing %s attributes", camera.name)
camera.attrs = dev_info

# preload cached videos
# the user is still able to force a new query by
# calling the Arlo.video()
camera.make_video_cache()

# force update base_station
if update_base_station:
for base in self.base_stations:
base.update()

# vim:sw=4:ts=4:et:
73 changes: 63 additions & 10 deletions pyarlo/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from pyarlo.const import (
RESET_CAM_ENDPOINT, STREAM_ENDPOINT, STREAMING_BODY,
SNAPSHOTS_ENDPOINT, SNAPSHOTS_BODY)
SNAPSHOTS_ENDPOINT, SNAPSHOTS_BODY, PRELOAD_DAYS)
from pyarlo.media import ArloMediaLibrary
from pyarlo.utils import http_get

Expand All @@ -13,21 +13,45 @@
class ArloCamera(object):
"""Arlo Camera module implementation."""

def __init__(self, name, attrs, arlo_session):
def __init__(self, name, attrs, arlo_session,
min_days_vdo_cache=PRELOAD_DAYS):
"""Initialize Arlo camera object.
:param name: Camera name
:param attrs: Camera attributes
:param arlo_session: PyArlo shared session
:param min_days_vdo_cache: min. days to preload in video cache
"""
self.name = name
self._attrs = attrs
self._session = arlo_session
self._cached_videos = None
self._min_days_vdo_cache = min_days_vdo_cache

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

@property
def attrs(self):
"""Return device attributes."""
return self._attrs

@attrs.setter
def attrs(self, value):
"""Override device attributes."""
self._attrs = value

@property
def min_days_vdo_cache(self):
"""Return minimal days to lookup when building the video cache."""
return self._min_days_vdo_cache

@min_days_vdo_cache.setter
def min_days_vdo_cache(self, value):
"""Set minimal days to lookup when building the video cache."""
self._min_days_vdo_cache = value

# pylint: disable=invalid-name
@property
def device_id(self):
Expand Down Expand Up @@ -92,34 +116,63 @@ def user_role(self):

@property
def last_image(self):
"""Return last image capture by camera."""
"""Return last image captured by camera."""
return http_get(self._attrs.get('presignedLastImageUrl'))

@property
def last_image_from_cache(self):
"""
Return last thumbnail present in self._cached_images.
This is useful in Home Assistant when the ArloHub has not
updated all information, but the camera.arlo already pulled
the last image. Using this method, everything is kept synced.
"""
if self.last_video:
return http_get(self.last_video.thumbnail_url)
return None

@property
def last_video(self):
"""Return the last <ArloVideo> object from camera."""
library = ArloMediaLibrary(self._session, preload=False)
try:
return library.load(only_cameras=[self], limit=1)[0]
except IndexError:
return None
if self._cached_videos is None:
self.make_video_cache()

if self._cached_videos:
return self._cached_videos[0]
return None

def videos(self, days=180):
def make_video_cache(self, days=None):
"""Save videos on _cache_videos to avoid dups."""
if days is None:
days = self._min_days_vdo_cache
self._cached_videos = self.videos(days)

def videos(self, days=None):
"""
Return all <ArloVideo> objects from camera given days range
:param days: number of days to retrieve
"""
if days is None:
days = self._min_days_vdo_cache
library = ArloMediaLibrary(self._session, preload=False)
try:
return library.load(only_cameras=[self], days=days)
except (AttributeError, IndexError):
# make sure we are returning an empty list istead of None
# returning an empty list, cache will be forced only when calling
# the update method. Changing this can impact badly
# in the Home Assistant performance
return []

@property
def captured_today(self):
"""Return list of <ArloVideo> object captured today."""
return self.videos(days=0)
if self._cached_videos is None:
self.make_video_cache()

return [vdo for vdo in self._cached_videos if vdo.created_today]

def play_last_video(self):
"""Play last <ArloVideo> recorded from camera."""
Expand Down
14 changes: 13 additions & 1 deletion pyarlo/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from datetime import datetime
from datetime import timedelta
from pyarlo.const import LIBRARY_ENDPOINT, PRELOAD_DAYS
from pyarlo.utils import http_get, http_stream, pretty_timestamp
from pyarlo.utils import http_get, http_stream, to_datetime, pretty_timestamp

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -128,6 +128,18 @@ def created_at_pretty(self, date_format=None):
return pretty_timestamp(self.created_at, date_format=date_format)
return pretty_timestamp(self.created_at)

@property
def created_today(self):
"""Return True if created today."""
if self.datetime.date() == datetime.today().date():
return True
return False

@property
def datetime(self):
"""Return datetime when video was created."""
return to_datetime(self.created_at)

@property
def content_type(self):
"""Return content_type."""
Expand Down
7 changes: 7 additions & 0 deletions pyarlo/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# coding: utf-8
"""Implementation of Arlo utils."""
import time
from datetime import datetime as dt
import requests


def to_datetime(timestamp):
"""Return datetime object from timestamp."""
return dt.fromtimestamp(time.mktime(
time.localtime(int(str(timestamp)[:10]))))


def pretty_timestamp(timestamp, date_format='%a-%m_%d_%y:%H:%M:%S'):
"""Huminize timestamp."""
return time.strftime(date_format,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_camera_properties(self, mock):
self.assertEqual(camera.hw_version, "H7")
self.assertEqual(camera.timezone, "America/New_York")
self.assertEqual(camera.user_role, "ADMIN")
self.assertTrue(len(camera.captured_today), 1)
self.assertEqual(len(camera.captured_today), 0)
self.assertIsNotNone(camera.properties)
self.assertEqual(camera.base_station, basestation)

Expand Down

0 comments on commit 5bdc358

Please sign in to comment.