Read door open/close events from the activity log. (#31732)
As polling for lock status is every 15 minutes, we read lock and unlock events from the activity log. An upstream update of py-august was needed to expose the door open and close events. Door open and close events are now seen within a few seconds instead of delayed 15+ minutes.
This commit is contained in:
parent
787edf9417
commit
54eb740ff6
4 changed files with 77 additions and 6 deletions
|
@ -205,6 +205,7 @@ class AugustData:
|
|||
self._house_ids.add(device.house_id)
|
||||
|
||||
self._doorbell_detail_by_id = {}
|
||||
self._door_last_state_update_time_utc_by_id = {}
|
||||
self._lock_last_status_update_time_utc_by_id = {}
|
||||
self._lock_status_by_id = {}
|
||||
self._lock_detail_by_id = {}
|
||||
|
@ -290,6 +291,16 @@ class AugustData:
|
|||
_LOGGER.debug("Completed retrieving doorbell details")
|
||||
self._doorbell_detail_by_id = detail_by_id
|
||||
|
||||
def update_door_state(self, lock_id, door_state, update_start_time_utc):
|
||||
"""Set the door status and last status update time.
|
||||
|
||||
This is called when newer activity is detected on the activity feed
|
||||
in order to keep the internal data in sync
|
||||
"""
|
||||
self._door_state_by_id[lock_id] = door_state
|
||||
self._door_last_state_update_time_utc_by_id[lock_id] = update_start_time_utc
|
||||
return True
|
||||
|
||||
def update_lock_status(self, lock_id, lock_status, update_start_time_utc):
|
||||
"""Set the lock status and last status update time.
|
||||
|
||||
|
@ -330,7 +341,8 @@ class AugustData:
|
|||
def _update_locks_status(self):
|
||||
status_by_id = {}
|
||||
state_by_id = {}
|
||||
last_status_update_by_id = {}
|
||||
lock_last_status_update_by_id = {}
|
||||
door_last_state_update_by_id = {}
|
||||
|
||||
_LOGGER.debug("Start retrieving lock and door status")
|
||||
for lock in self._locks:
|
||||
|
@ -346,9 +358,10 @@ class AugustData:
|
|||
# Since there is a a race condition between calling the
|
||||
# lock and activity apis, we set the last update time
|
||||
# BEFORE making the api call since we will compare this
|
||||
# to activity later we want activity to win over stale lock
|
||||
# to activity later we want activity to win over stale lock/door
|
||||
# state.
|
||||
last_status_update_by_id[lock.device_id] = update_start_time_utc
|
||||
lock_last_status_update_by_id[lock.device_id] = update_start_time_utc
|
||||
door_last_state_update_by_id[lock.device_id] = update_start_time_utc
|
||||
except RequestException as ex:
|
||||
_LOGGER.error(
|
||||
"Request error trying to retrieve lock and door status for %s. %s",
|
||||
|
@ -365,7 +378,8 @@ class AugustData:
|
|||
_LOGGER.debug("Completed retrieving lock and door status")
|
||||
self._lock_status_by_id = status_by_id
|
||||
self._door_state_by_id = state_by_id
|
||||
self._lock_last_status_update_time_utc_by_id = last_status_update_by_id
|
||||
self._door_last_state_update_time_utc_by_id = door_last_state_update_by_id
|
||||
self._lock_last_status_update_time_utc_by_id = lock_last_status_update_by_id
|
||||
|
||||
def get_last_lock_status_update_time_utc(self, lock_id):
|
||||
"""Return the last time that a lock status update was seen from the august API."""
|
||||
|
@ -377,6 +391,16 @@ class AugustData:
|
|||
|
||||
return self._lock_last_status_update_time_utc_by_id[lock_id]
|
||||
|
||||
def get_last_door_state_update_time_utc(self, lock_id):
|
||||
"""Return the last time that a door status update was seen from the august API."""
|
||||
# Since the activity api is called more frequently than
|
||||
# the lock api it is possible that the door has not
|
||||
# been updated yet
|
||||
if lock_id not in self._door_last_state_update_time_utc_by_id:
|
||||
return dt.utc_from_timestamp(0)
|
||||
|
||||
return self._door_last_state_update_time_utc_by_id[lock_id]
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_LOCK_DETAIL_UPDATES)
|
||||
def _update_locks_detail(self):
|
||||
detail_by_id = {}
|
||||
|
|
|
@ -6,6 +6,7 @@ from august.activity import ActivityType
|
|||
from august.lock import LockDoorStatus
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.util import dt
|
||||
|
||||
from . import DATA_AUGUST
|
||||
|
||||
|
@ -137,6 +138,52 @@ class AugustDoorBinarySensor(BinarySensorDevice):
|
|||
|
||||
self._state = self._state == LockDoorStatus.OPEN
|
||||
|
||||
activity = self._data.get_latest_device_activity(
|
||||
self._door.device_id, ActivityType.DOOR_OPERATION
|
||||
)
|
||||
|
||||
if activity is not None:
|
||||
self._sync_door_activity(activity)
|
||||
|
||||
def _update_door_state(self, door_state, update_start_time):
|
||||
new_state = door_state == LockDoorStatus.OPEN
|
||||
if self._state != new_state:
|
||||
self._state = new_state
|
||||
self._data.update_door_state(
|
||||
self._door.device_id, door_state, update_start_time
|
||||
)
|
||||
|
||||
def _sync_door_activity(self, activity):
|
||||
"""Check the activity for the latest door open/close activity (events).
|
||||
|
||||
We use this to determine the door state in between calls to the lock
|
||||
api as we update it more frequently
|
||||
"""
|
||||
last_door_state_update_time_utc = self._data.get_last_door_state_update_time_utc(
|
||||
self._door.device_id
|
||||
)
|
||||
activity_end_time_utc = dt.as_utc(activity.activity_end_time)
|
||||
|
||||
if activity_end_time_utc > last_door_state_update_time_utc:
|
||||
_LOGGER.debug(
|
||||
"The activity log has new events for %s: [action=%s] [activity_end_time_utc=%s] > [last_door_state_update_time_utc=%s]",
|
||||
self.name,
|
||||
activity.action,
|
||||
activity_end_time_utc,
|
||||
last_door_state_update_time_utc,
|
||||
)
|
||||
activity_start_time_utc = dt.as_utc(activity.activity_start_time)
|
||||
if activity.action == "doorclosed":
|
||||
self._update_door_state(LockDoorStatus.CLOSED, activity_start_time_utc)
|
||||
elif activity.action == "dooropen":
|
||||
self._update_door_state(LockDoorStatus.OPEN, activity_start_time_utc)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"Unhandled door activity action %s for %s",
|
||||
activity.action,
|
||||
self.name,
|
||||
)
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Get the unique of the door open binary sensor."""
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "august",
|
||||
"name": "August",
|
||||
"documentation": "https://www.home-assistant.io/integrations/august",
|
||||
"requirements": ["py-august==0.8.1"],
|
||||
"requirements": ["py-august==0.11.0"],
|
||||
"dependencies": ["configurator"],
|
||||
"codeowners": []
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ pushover_complete==1.1.1
|
|||
pwmled==1.4.1
|
||||
|
||||
# homeassistant.components.august
|
||||
py-august==0.8.1
|
||||
py-august==0.11.0
|
||||
|
||||
# homeassistant.components.canary
|
||||
py-canary==0.5.0
|
||||
|
|
Loading…
Add table
Reference in a new issue