Add support for locks in google assistant component (#18233)
* Add support for locks in google assistant component This is supported by the smarthome API, but there is no documentation for it. This work is based on an article I found with screenshots of documentation that was erroneously uploaded: https://www.androidpolice.com/2018/01/17/google-assistant-home-can-now-natively-control-smart-locks-august-vivint-first-supported/ Google Assistant now supports unlocking certain locks - Nest and August come to mind - via this API, and this commit allows Home Assistant to do so as well. Notably, I've added a config option `allow_unlock` that controls whether we actually honor requests to unlock a lock via the google assistant. It defaults to false. Additionally, we add the functionNotSupported error, which makes a little more sense when we're unable to execute the desired state transition. https://developers.google.com/actions/reference/smarthome/errors-exceptions#exception_list * Fix linter warnings * Ensure that certain groups are never exposed to cloud entities For example, the group.all_locks entity - we should probably never expose this to third party cloud integrations. It's risky. This is not configurable, but can be extended by adding to the cloud.const.NEVER_EXPOSED_ENTITIES array. It's implemented in a modestly hacky fashion, because we determine whether or not a entity should be excluded/included in several ways. Notably, we define this array in the top level const.py, to avoid circular import problems between the cloud/alexa components.
This commit is contained in:
parent
ddee5f8b86
commit
2bf2214d51
14 changed files with 283 additions and 43 deletions
|
@ -10,6 +10,7 @@ from homeassistant.components import (
|
|||
input_boolean,
|
||||
media_player,
|
||||
light,
|
||||
lock,
|
||||
scene,
|
||||
script,
|
||||
switch,
|
||||
|
@ -19,6 +20,7 @@ from homeassistant.const import (
|
|||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_LOCKED,
|
||||
STATE_OFF,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
|
@ -40,6 +42,7 @@ TRAIT_COLOR_SPECTRUM = PREFIX_TRAITS + 'ColorSpectrum'
|
|||
TRAIT_COLOR_TEMP = PREFIX_TRAITS + 'ColorTemperature'
|
||||
TRAIT_SCENE = PREFIX_TRAITS + 'Scene'
|
||||
TRAIT_TEMPERATURE_SETTING = PREFIX_TRAITS + 'TemperatureSetting'
|
||||
TRAIT_LOCKUNLOCK = PREFIX_TRAITS + 'LockUnlock'
|
||||
|
||||
PREFIX_COMMANDS = 'action.devices.commands.'
|
||||
COMMAND_ONOFF = PREFIX_COMMANDS + 'OnOff'
|
||||
|
@ -54,6 +57,7 @@ COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT = (
|
|||
COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE = (
|
||||
PREFIX_COMMANDS + 'ThermostatTemperatureSetRange')
|
||||
COMMAND_THERMOSTAT_SET_MODE = PREFIX_COMMANDS + 'ThermostatSetMode'
|
||||
COMMAND_LOCKUNLOCK = PREFIX_COMMANDS + 'LockUnlock'
|
||||
|
||||
|
||||
TRAITS = []
|
||||
|
@ -77,10 +81,11 @@ class _Trait:
|
|||
|
||||
commands = []
|
||||
|
||||
def __init__(self, hass, state):
|
||||
def __init__(self, hass, state, config):
|
||||
"""Initialize a trait for a state."""
|
||||
self.hass = hass
|
||||
self.state = state
|
||||
self.config = config
|
||||
|
||||
def sync_attributes(self):
|
||||
"""Return attributes for a sync request."""
|
||||
|
@ -628,3 +633,45 @@ class TemperatureSettingTrait(_Trait):
|
|||
climate.ATTR_OPERATION_MODE:
|
||||
self.google_to_hass[params['thermostatMode']],
|
||||
}, blocking=True)
|
||||
|
||||
|
||||
@register_trait
|
||||
class LockUnlockTrait(_Trait):
|
||||
"""Trait to lock or unlock a lock.
|
||||
|
||||
https://developers.google.com/actions/smarthome/traits/lockunlock
|
||||
"""
|
||||
|
||||
name = TRAIT_LOCKUNLOCK
|
||||
commands = [
|
||||
COMMAND_LOCKUNLOCK
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
"""Test if state is supported."""
|
||||
return domain == lock.DOMAIN
|
||||
|
||||
def sync_attributes(self):
|
||||
"""Return LockUnlock attributes for a sync request."""
|
||||
return {}
|
||||
|
||||
def query_attributes(self):
|
||||
"""Return LockUnlock query attributes."""
|
||||
return {'isLocked': self.state.state == STATE_LOCKED}
|
||||
|
||||
def can_execute(self, command, params):
|
||||
"""Test if command can be executed."""
|
||||
allowed_unlock = not params['lock'] and self.config.allow_unlock
|
||||
return params['lock'] or allowed_unlock
|
||||
|
||||
async def execute(self, command, params):
|
||||
"""Execute an LockUnlock command."""
|
||||
if params['lock']:
|
||||
service = lock.SERVICE_LOCK
|
||||
else:
|
||||
service = lock.SERVICE_UNLOCK
|
||||
|
||||
await self.hass.services.async_call(lock.DOMAIN, service, {
|
||||
ATTR_ENTITY_ID: self.state.entity_id
|
||||
}, blocking=True)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue