Significantly reduce code in august integration (#32030)
* Significantly reduce code in august integration * Activity updates can now be processed by py-august this allows us to eliminate the activity sync code for the door sensors and locks * Lock and door state can now be consumed from the lock detail api which allows us to remove the status call apis and reduce the number of API calls to august * Refactor the testing method for locks (part #1) * Update homeassistant/components/august/binary_sensor.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * Switch to asynctest instead of unittest for mock.patch Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
a12c4da0ca
commit
d4075fb262
17 changed files with 579 additions and 429 deletions
|
@ -2,11 +2,11 @@
|
|||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
|
||||
from august.activity import ACTIVITY_ACTION_STATES, ActivityType
|
||||
from august.activity import ActivityType
|
||||
from august.lock import LockDoorStatus
|
||||
from august.util import update_lock_detail_from_activity
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.util import dt
|
||||
|
||||
from . import DATA_AUGUST
|
||||
|
||||
|
@ -15,11 +15,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
|
||||
|
||||
async def _async_retrieve_door_state(data, lock):
|
||||
"""Get the latest state of the DoorSense sensor."""
|
||||
return await data.async_get_door_state(lock.device_id)
|
||||
|
||||
|
||||
async def _async_retrieve_online_state(data, doorbell):
|
||||
"""Get the latest state of the sensor."""
|
||||
detail = await data.async_get_doorbell_detail(doorbell.device_id)
|
||||
|
@ -61,8 +56,6 @@ SENSOR_DEVICE_CLASS = 1
|
|||
SENSOR_STATE_PROVIDER = 2
|
||||
|
||||
# sensor_type: [name, device_class, async_state_provider]
|
||||
SENSOR_TYPES_DOOR = {"door_open": ["Open", "door", _async_retrieve_door_state]}
|
||||
|
||||
SENSOR_TYPES_DOORBELL = {
|
||||
"doorbell_ding": ["Ding", "occupancy", _async_retrieve_ding_state],
|
||||
"doorbell_motion": ["Motion", "motion", _async_retrieve_motion_state],
|
||||
|
@ -76,21 +69,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||
devices = []
|
||||
|
||||
for door in data.locks:
|
||||
for sensor_type in SENSOR_TYPES_DOOR:
|
||||
if not data.lock_has_doorsense(door.device_id):
|
||||
_LOGGER.debug(
|
||||
"Not adding sensor class %s for lock %s ",
|
||||
SENSOR_TYPES_DOOR[sensor_type][SENSOR_DEVICE_CLASS],
|
||||
door.device_name,
|
||||
)
|
||||
continue
|
||||
|
||||
if not data.lock_has_doorsense(door.device_id):
|
||||
_LOGGER.debug(
|
||||
"Adding sensor class %s for %s",
|
||||
SENSOR_TYPES_DOOR[sensor_type][SENSOR_DEVICE_CLASS],
|
||||
door.device_name,
|
||||
"Not adding sensor class door for lock %s ", door.device_name,
|
||||
)
|
||||
devices.append(AugustDoorBinarySensor(data, sensor_type, door))
|
||||
continue
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding sensor class door for %s", door.device_name,
|
||||
)
|
||||
devices.append(AugustDoorBinarySensor(data, "door_open", door))
|
||||
|
||||
for doorbell in data.doorbells:
|
||||
for sensor_type in SENSOR_TYPES_DOORBELL:
|
||||
|
@ -127,81 +115,35 @@ class AugustDoorBinarySensor(BinarySensorDevice):
|
|||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
return SENSOR_TYPES_DOOR[self._sensor_type][SENSOR_DEVICE_CLASS]
|
||||
"""Return the class of this device."""
|
||||
return "door"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the binary sensor."""
|
||||
return "{} {}".format(
|
||||
self._door.device_name, SENSOR_TYPES_DOOR[self._sensor_type][SENSOR_NAME]
|
||||
)
|
||||
return "{} Open".format(self._door.device_name)
|
||||
|
||||
async def async_update(self):
|
||||
"""Get the latest state of the sensor and update activity."""
|
||||
async_state_provider = SENSOR_TYPES_DOOR[self._sensor_type][
|
||||
SENSOR_STATE_PROVIDER
|
||||
]
|
||||
lock_door_state = await async_state_provider(self._data, self._door)
|
||||
self._available = (
|
||||
lock_door_state is not None and lock_door_state != LockDoorStatus.UNKNOWN
|
||||
)
|
||||
self._state = lock_door_state == LockDoorStatus.OPEN
|
||||
|
||||
door_activity = await self._data.async_get_latest_device_activity(
|
||||
self._door.device_id, ActivityType.DOOR_OPERATION
|
||||
)
|
||||
detail = await self._data.async_get_lock_detail(self._door.device_id)
|
||||
|
||||
if door_activity is not None:
|
||||
self._sync_door_activity(door_activity)
|
||||
update_lock_detail_from_activity(detail, door_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
|
||||
)
|
||||
lock_door_state = None
|
||||
if detail is not None:
|
||||
lock_door_state = detail.door_state
|
||||
|
||||
def _sync_door_activity(self, door_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(door_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,
|
||||
door_activity.action,
|
||||
activity_end_time_utc,
|
||||
last_door_state_update_time_utc,
|
||||
)
|
||||
activity_start_time_utc = dt.as_utc(door_activity.activity_start_time)
|
||||
if door_activity.action in ACTIVITY_ACTION_STATES:
|
||||
self._update_door_state(
|
||||
ACTIVITY_ACTION_STATES[door_activity.action],
|
||||
activity_start_time_utc,
|
||||
)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"Unhandled door activity action %s for %s",
|
||||
door_activity.action,
|
||||
self.name,
|
||||
)
|
||||
self._available = lock_door_state != LockDoorStatus.UNKNOWN
|
||||
self._state = lock_door_state == LockDoorStatus.OPEN
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Get the unique of the door open binary sensor."""
|
||||
return "{:s}_{:s}".format(
|
||||
self._door.device_id,
|
||||
SENSOR_TYPES_DOOR[self._sensor_type][SENSOR_NAME].lower(),
|
||||
)
|
||||
return f"{self._door.device_id}_open"
|
||||
|
||||
|
||||
class AugustDoorbellBinarySensor(BinarySensorDevice):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue