1
mirror of https://github.com/home-assistant/core synced 2024-09-15 17:29:45 +02:00

Add doorsense sensor for August 3rd Gen Smart Lock Pro (#17299)

* Add doorsense sensor for August 3rd Gen Smart Lock Pro

Add a binary sensor to August for the August 3rd Gen Smart Lock Pro doorsense sensor.

This is a re-do from PR 17116 https://github.com/home-assistant/home-assistant/pull/17116 that I closed due to rebase issue on my end.

* Changed to use snjoetw provided code

Going through the py-august I found that snjoetw had provided updated versions for the august component (august.py and binary_sensor/august.py) to include DoorSense sensor.
Changed what I did to to what snjoetw provided instead as he split it into 2 classes; much cleaner I think.

I modified his coding with:
   Fixes that were done to the August component and not part of the coding snjoetw provided.
   Added the debug logging improvement I had done in the code.

Note, fix I committed earlier for lock atribute (lock/august.py) is thus still the same.

* Reverted change from add_device to add_entities

Missed an item when merging snjoetw's code with current. Fixed.

* Updated call from add_devices to add_entities as well

Updated the call from add_devices to add_entities.

* Fixed permissions on files

Fixed permissions on components/august.py and binary_snesor/august.py

* Changed if/else to if/continue

Changed logic so that if the door sensor state is unknown during initalization the debug log is written and then continue the loop instead of using if/else logic.

* Added available property for Door Sensor

Added the available property for the Door Sensor and setting it to False if a status unknown is received.

* Updated setting self._available

Changed line for setting self._available to what Martin provided. Much  more efficient to read. :-)
This commit is contained in:
ehendrix23 2018-10-19 01:37:02 -06:00 committed by Paulus Schoutsen
parent 8bf58e1df5
commit f504e5ef61
3 changed files with 130 additions and 9 deletions

View File

@ -4,7 +4,6 @@ Support for August devices.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/august/
"""
import logging
from datetime import timedelta
@ -124,6 +123,7 @@ def setup_august(hass, config, api, authenticator):
return True
if state == AuthenticationState.BAD_PASSWORD:
_LOGGER.error("Invalid password provided")
return False
if state == AuthenticationState.REQUIRES_VALIDATION:
request_configuration(hass, config, api, authenticator)
@ -165,6 +165,7 @@ class AugustData:
self._doorbell_detail_by_id = {}
self._lock_status_by_id = {}
self._lock_detail_by_id = {}
self._door_state_by_id = {}
self._activities_by_id = {}
@property
@ -184,6 +185,7 @@ class AugustData:
def get_device_activities(self, device_id, *activity_types):
"""Return a list of activities."""
_LOGGER.debug("Getting device activities")
self._update_device_activities()
activities = self._activities_by_id.get(device_id, [])
@ -199,6 +201,7 @@ class AugustData:
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def _update_device_activities(self, limit=ACTIVITY_FETCH_LIMIT):
"""Update data object with latest from August API."""
_LOGGER.debug("Updating device activities")
for house_id in self.house_ids:
activities = self._api.get_house_activities(self._access_token,
house_id,
@ -218,14 +221,21 @@ class AugustData:
def _update_doorbells(self):
detail_by_id = {}
_LOGGER.debug("Start retrieving doorbell details")
for doorbell in self._doorbells:
_LOGGER.debug("Updating status for %s",
doorbell.device_name)
detail_by_id[doorbell.device_id] = self._api.get_doorbell_detail(
self._access_token, doorbell.device_id)
_LOGGER.debug("Completed retrieving doorbell details")
self._doorbell_detail_by_id = detail_by_id
def get_lock_status(self, lock_id):
"""Return lock status."""
"""Return status if the door is locked or unlocked.
This is status for the lock itself.
"""
self._update_locks()
return self._lock_status_by_id.get(lock_id)
@ -234,17 +244,43 @@ class AugustData:
self._update_locks()
return self._lock_detail_by_id.get(lock_id)
def get_door_state(self, lock_id):
"""Return status if the door is open or closed.
This is the status from the door sensor.
"""
self._update_doors()
return self._door_state_by_id.get(lock_id)
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def _update_doors(self):
state_by_id = {}
_LOGGER.debug("Start retrieving door status")
for lock in self._locks:
_LOGGER.debug("Updating status for %s",
lock.device_name)
state_by_id[lock.device_id] = self._api.get_lock_door_status(
self._access_token, lock.device_id)
_LOGGER.debug("Completed retrieving door status")
self._door_state_by_id = state_by_id
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def _update_locks(self):
status_by_id = {}
detail_by_id = {}
_LOGGER.debug("Start retrieving locks status")
for lock in self._locks:
_LOGGER.debug("Updating status for %s",
lock.device_name)
status_by_id[lock.device_id] = self._api.get_lock_status(
self._access_token, lock.device_id)
detail_by_id[lock.device_id] = self._api.get_lock_detail(
self._access_token, lock.device_id)
_LOGGER.debug("Completed retrieving locks status")
self._lock_status_by_id = status_by_id
self._lock_detail_by_id = detail_by_id

View File

@ -4,16 +4,26 @@ Support for August binary sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.august/
"""
import logging
from datetime import timedelta, datetime
from homeassistant.components.august import DATA_AUGUST
from homeassistant.components.binary_sensor import (BinarySensorDevice)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['august']
SCAN_INTERVAL = timedelta(seconds=5)
def _retrieve_door_state(data, lock):
"""Get the latest state of the DoorSense sensor."""
from august.lock import LockDoorStatus
doorstate = data.get_door_state(lock.device_id)
return doorstate == LockDoorStatus.OPEN
def _retrieve_online_state(data, doorbell):
"""Get the latest state of the sensor."""
detail = data.get_doorbell_detail(doorbell.device_id)
@ -46,7 +56,11 @@ def _activity_time_based_state(data, doorbell, activity_types):
# Sensor types: Name, device_class, state_provider
SENSOR_TYPES = {
SENSOR_TYPES_DOOR = {
'door_open': ['Open', 'door', _retrieve_door_state],
}
SENSOR_TYPES_DOORBELL = {
'doorbell_ding': ['Ding', 'occupancy', _retrieve_ding_state],
'doorbell_motion': ['Motion', 'motion', _retrieve_motion_state],
'doorbell_online': ['Online', 'connectivity', _retrieve_online_state],
@ -58,14 +72,78 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
data = hass.data[DATA_AUGUST]
devices = []
from august.lock import LockDoorStatus
for door in data.locks:
for sensor_type in SENSOR_TYPES_DOOR:
state_provider = SENSOR_TYPES_DOOR[sensor_type][2]
if state_provider(data, door) is LockDoorStatus.UNKNOWN:
_LOGGER.debug(
"Not adding sensor class %s for lock %s ",
SENSOR_TYPES_DOOR[sensor_type][1], door.device_name
)
continue
_LOGGER.debug(
"Adding sensor class %s for %s",
SENSOR_TYPES_DOOR[sensor_type][1], door.device_name
)
devices.append(AugustDoorBinarySensor(data, sensor_type, door))
for doorbell in data.doorbells:
for sensor_type in SENSOR_TYPES:
devices.append(AugustBinarySensor(data, sensor_type, doorbell))
for sensor_type in SENSOR_TYPES_DOORBELL:
_LOGGER.debug("Adding doorbell sensor class %s for %s",
SENSOR_TYPES_DOORBELL[sensor_type][1],
doorbell.device_name)
devices.append(
AugustDoorbellBinarySensor(data, sensor_type,
doorbell)
)
add_entities(devices, True)
class AugustBinarySensor(BinarySensorDevice):
class AugustDoorBinarySensor(BinarySensorDevice):
"""Representation of an August Door binary sensor."""
def __init__(self, data, sensor_type, door):
"""Initialize the sensor."""
self._data = data
self._sensor_type = sensor_type
self._door = door
self._state = None
self._available = False
@property
def available(self):
"""Return the availability of this sensor."""
return self._available
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES."""
return SENSOR_TYPES_DOOR[self._sensor_type][1]
@property
def name(self):
"""Return the name of the binary sensor."""
return "{} {}".format(self._door.device_name,
SENSOR_TYPES_DOOR[self._sensor_type][0])
def update(self):
"""Get the latest state of the sensor."""
state_provider = SENSOR_TYPES_DOOR[self._sensor_type][2]
self._state = state_provider(self._data, self._door)
from august.lock import LockDoorStatus
self._available = self._state != LockDoorStatus.UNKNOWN
class AugustDoorbellBinarySensor(BinarySensorDevice):
"""Representation of an August binary sensor."""
def __init__(self, data, sensor_type, doorbell):
@ -83,15 +161,15 @@ class AugustBinarySensor(BinarySensorDevice):
@property
def device_class(self):
"""Return the class of this device, from component DEVICE_CLASSES."""
return SENSOR_TYPES[self._sensor_type][1]
return SENSOR_TYPES_DOORBELL[self._sensor_type][1]
@property
def name(self):
"""Return the name of the binary sensor."""
return "{} {}".format(self._doorbell.device_name,
SENSOR_TYPES[self._sensor_type][0])
SENSOR_TYPES_DOORBELL[self._sensor_type][0])
def update(self):
"""Get the latest state of the sensor."""
state_provider = SENSOR_TYPES[self._sensor_type][2]
state_provider = SENSOR_TYPES_DOORBELL[self._sensor_type][2]
self._state = state_provider(self._data, self._doorbell)

View File

@ -4,12 +4,15 @@ Support for August lock.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/lock.august/
"""
import logging
from datetime import timedelta
from homeassistant.components.august import DATA_AUGUST
from homeassistant.components.lock import LockDevice
from homeassistant.const import ATTR_BATTERY_LEVEL
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['august']
SCAN_INTERVAL = timedelta(seconds=5)
@ -21,6 +24,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
devices = []
for lock in data.locks:
_LOGGER.debug("Adding lock for %s", lock.device_name)
devices.append(AugustLock(data, lock))
add_entities(devices, True)
@ -77,6 +81,9 @@ class AugustLock(LockDevice):
@property
def device_state_attributes(self):
"""Return the device specific state attributes."""
if self._lock_detail is None:
return None
return {
ATTR_BATTERY_LEVEL: self._lock_detail.battery_level,
}