125 lines
4.3 KiB
Python
125 lines
4.3 KiB
Python
"""Consume the august activity stream."""
|
|
import logging
|
|
|
|
from aiohttp import ClientError
|
|
|
|
from homeassistant.util.dt import utcnow
|
|
|
|
from .const import ACTIVITY_UPDATE_INTERVAL
|
|
from .subscriber import AugustSubscriberMixin
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
ACTIVITY_STREAM_FETCH_LIMIT = 10
|
|
ACTIVITY_CATCH_UP_FETCH_LIMIT = 1000
|
|
|
|
|
|
class ActivityStream(AugustSubscriberMixin):
|
|
"""August activity stream handler."""
|
|
|
|
def __init__(self, hass, api, august_gateway, house_ids):
|
|
"""Init August activity stream object."""
|
|
super().__init__(hass, ACTIVITY_UPDATE_INTERVAL)
|
|
self._hass = hass
|
|
self._august_gateway = august_gateway
|
|
self._api = api
|
|
self._house_ids = house_ids
|
|
self._latest_activities_by_id_type = {}
|
|
self._last_update_time = None
|
|
self._abort_async_track_time_interval = None
|
|
|
|
async def async_setup(self):
|
|
"""Token refresh check and catch up the activity stream."""
|
|
await self._async_refresh(utcnow)
|
|
|
|
def get_latest_device_activity(self, device_id, activity_types):
|
|
"""Return latest activity that is one of the acitivty_types."""
|
|
if device_id not in self._latest_activities_by_id_type:
|
|
return None
|
|
|
|
latest_device_activities = self._latest_activities_by_id_type[device_id]
|
|
latest_activity = None
|
|
|
|
for activity_type in activity_types:
|
|
if activity_type in latest_device_activities:
|
|
if (
|
|
latest_activity is not None
|
|
and latest_device_activities[activity_type].activity_start_time
|
|
<= latest_activity.activity_start_time
|
|
):
|
|
continue
|
|
latest_activity = latest_device_activities[activity_type]
|
|
|
|
return latest_activity
|
|
|
|
async def _async_refresh(self, time):
|
|
"""Update the activity stream from August."""
|
|
|
|
# This is the only place we refresh the api token
|
|
await self._august_gateway.async_refresh_access_token_if_needed()
|
|
await self._async_update_device_activities(time)
|
|
|
|
async def _async_update_device_activities(self, time):
|
|
_LOGGER.debug("Start retrieving device activities")
|
|
|
|
limit = (
|
|
ACTIVITY_STREAM_FETCH_LIMIT
|
|
if self._last_update_time
|
|
else ACTIVITY_CATCH_UP_FETCH_LIMIT
|
|
)
|
|
|
|
for house_id in self._house_ids:
|
|
_LOGGER.debug("Updating device activity for house id %s", house_id)
|
|
try:
|
|
activities = await self._api.async_get_house_activities(
|
|
self._august_gateway.access_token, house_id, limit=limit
|
|
)
|
|
except ClientError as ex:
|
|
_LOGGER.error(
|
|
"Request error trying to retrieve activity for house id %s: %s",
|
|
house_id,
|
|
ex,
|
|
)
|
|
# Make sure we process the next house if one of them fails
|
|
continue
|
|
|
|
_LOGGER.debug(
|
|
"Completed retrieving device activities for house id %s", house_id
|
|
)
|
|
|
|
updated_device_ids = self._process_newer_device_activities(activities)
|
|
|
|
if updated_device_ids:
|
|
for device_id in updated_device_ids:
|
|
_LOGGER.debug(
|
|
"async_signal_device_id_update (from activity stream): %s",
|
|
device_id,
|
|
)
|
|
self.async_signal_device_id_update(device_id)
|
|
|
|
self._last_update_time = time
|
|
|
|
def _process_newer_device_activities(self, activities):
|
|
updated_device_ids = set()
|
|
for activity in activities:
|
|
self._latest_activities_by_id_type.setdefault(activity.device_id, {})
|
|
|
|
lastest_activity = self._latest_activities_by_id_type[
|
|
activity.device_id
|
|
].get(activity.activity_type)
|
|
|
|
# Ignore activities that are older than the latest one
|
|
if (
|
|
lastest_activity
|
|
and lastest_activity.activity_start_time >= activity.activity_start_time
|
|
):
|
|
continue
|
|
|
|
self._latest_activities_by_id_type[activity.device_id][
|
|
activity.activity_type
|
|
] = activity
|
|
|
|
updated_device_ids.add(activity.device_id)
|
|
|
|
return updated_device_ids
|