1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 12:59:34 +00:00
Files
core/homeassistant/components/google_assistant/http.py
Andrew Hayworth 2bf2214d51 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.
2018-11-06 10:39:10 +01:00

84 lines
2.7 KiB
Python

"""
Support for Google Actions Smart Home Control.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/google_assistant/
"""
import logging
from aiohttp.web import Request, Response
# Typing imports
from homeassistant.components.http import HomeAssistantView
from homeassistant.core import callback
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
from .const import (
GOOGLE_ASSISTANT_API_ENDPOINT,
CONF_EXPOSE_BY_DEFAULT,
CONF_EXPOSED_DOMAINS,
CONF_ENTITY_CONFIG,
CONF_EXPOSE,
)
from .smart_home import async_handle_message
from .helpers import Config
_LOGGER = logging.getLogger(__name__)
@callback
def async_register_http(hass, cfg):
"""Register HTTP views for Google Assistant."""
expose_by_default = cfg.get(CONF_EXPOSE_BY_DEFAULT)
exposed_domains = cfg.get(CONF_EXPOSED_DOMAINS)
entity_config = cfg.get(CONF_ENTITY_CONFIG) or {}
def is_exposed(entity) -> bool:
"""Determine if an entity should be exposed to Google Assistant."""
if entity.attributes.get('view') is not None:
# Ignore entities that are views
return False
if entity.entity_id in CLOUD_NEVER_EXPOSED_ENTITIES:
return False
explicit_expose = \
entity_config.get(entity.entity_id, {}).get(CONF_EXPOSE)
domain_exposed_by_default = \
expose_by_default and entity.domain in exposed_domains
# Expose an entity if the entity's domain is exposed by default and
# the configuration doesn't explicitly exclude it from being
# exposed, or if the entity is explicitly exposed
is_default_exposed = \
domain_exposed_by_default and explicit_expose is not False
return is_default_exposed or explicit_expose
hass.http.register_view(
GoogleAssistantView(is_exposed, entity_config))
class GoogleAssistantView(HomeAssistantView):
"""Handle Google Assistant requests."""
url = GOOGLE_ASSISTANT_API_ENDPOINT
name = 'api:google_assistant'
requires_auth = True
def __init__(self, is_exposed, entity_config):
"""Initialize the Google Assistant request handler."""
self.is_exposed = is_exposed
self.entity_config = entity_config
async def post(self, request: Request) -> Response:
"""Handle Google Assistant requests."""
message = await request.json() # type: dict
config = Config(self.is_exposed,
request['hass_user'].id,
self.entity_config)
result = await async_handle_message(
request.app['hass'], config, message)
return self.json(result)