-
-
Save awarecan/630510a9742f5f8901b5ab284c25e912 to your computer and use it in GitHub Desktop.
| """ | |
| Copyright 2019 Jason Hu <awaregit at gmail.com> | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| """ | |
| import os | |
| import json | |
| import logging | |
| import urllib3 | |
| _debug = bool(os.environ.get('DEBUG')) | |
| _logger = logging.getLogger('HomeAssistant-SmartHome') | |
| _logger.setLevel(logging.DEBUG if _debug else logging.INFO) | |
| def lambda_handler(event, context): | |
| """Handle incoming Alexa directive.""" | |
| _logger.debug('Event: %s', event) | |
| base_url = os.environ.get('BASE_URL') | |
| assert base_url is not None, 'Please set BASE_URL environment variable' | |
| directive = event.get('directive') | |
| assert directive is not None, 'Malformatted request - missing directive' | |
| assert directive.get('header', {}).get('payloadVersion') == '3', \ | |
| 'Only support payloadVersion == 3' | |
| scope = directive.get('endpoint', {}).get('scope') | |
| if scope is None: | |
| # token is in payload.scope for Discovery directive | |
| scope = directive.get('payload', {}).get('scope') | |
| if scope is None: | |
| # token is in payload.grantee for AcceptGrant directive | |
| scope = directive.get('payload', {}).get('grantee') | |
| assert scope is not None, 'Malformatted request - missing endpoint.scope' | |
| assert scope.get('type') == 'BearerToken', 'Only support BearerToken' | |
| token = scope.get('token') | |
| if token is None and _debug: | |
| token = os.environ.get('LONG_LIVED_ACCESS_TOKEN') # only for debug purpose | |
| verify_ssl = not bool(os.environ.get('NOT_VERIFY_SSL')) | |
| http = urllib3.PoolManager( | |
| cert_reqs='CERT_REQUIRED' if verify_ssl else 'CERT_NONE', | |
| timeout=urllib3.Timeout(connect=2.0, read=10.0) | |
| ) | |
| response = http.request( | |
| 'POST', | |
| '{}/api/alexa/smart_home'.format(base_url), | |
| headers={ | |
| 'Authorization': 'Bearer {}'.format(token), | |
| 'Content-Type': 'application/json', | |
| }, | |
| body=json.dumps(event).encode('utf-8'), | |
| ) | |
| if response.status >= 400: | |
| return { | |
| 'event': { | |
| 'payload': { | |
| 'type': 'INVALID_AUTHORIZATION_CREDENTIAL' | |
| if response.status in (401, 403) else 'INTERNAL_ERROR', | |
| 'message': response.data.decode("utf-8"), | |
| } | |
| } | |
| } | |
| return json.loads(response.data.decode('utf-8')) |
Hi @awarecan. Thanks for the lambda_function. However, me and some more persons (see https://community.home-assistant.io/t/alexa-proactive-mode-unable-to-link-alexa/123530 cannot link the Alexa skill to homeassistant when the “Send Alexa Events” toggle in the Skill’s Permissions is set. Without that, linking works fine, even with the client_id and client_secret in the HA config. Do you have any idea what would be the cause of this? Thanks!
Found something: see here.
In addition, if you enable the Send Alexa Events permission for the skill, your Lambda function must handle the AcceptGrant directive. If your skill does not handle this directive, account linking fails when the user attempts to enable your skill. See Authenticate a Customer to Alexa with Permissions
@awarecan: Can you update the lambda function to handle this directive? Thanks!
Updated per community suggestion - have not tested by myself yet.
Hi,
Tried this several times with different combinations of credentials.
My Log from HA.
Log Details (ERROR)
Logger: aiohttp.server
Source: components/alexa/capabilities.py:1478
First occurred: 13:52:58 (2 occurrences)
Last logged: 13:53:17
Error handling request
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
resp = await task
File "/usr/local/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
resp = await handler(request)
File "/usr/local/lib/python3.7/site-packages/aiohttp/web_middlewares.py", line 119, in impl
return await handler(request)
File "/usr/src/homeassistant/homeassistant/components/http/real_ip.py", line 39, in real_ip_middleware
return await handler(request)
File "/usr/src/homeassistant/homeassistant/components/http/ban.py", line 73, in ban_middleware
return await handler(request)
File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 127, in auth_middleware
return await handler(request)
File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 125, in handle
result = await result
File "/usr/src/homeassistant/homeassistant/components/alexa/smart_home_http.py", line 120, in post
hass, self.smart_home_config, message, context=core.Context(user_id=user.id)
File "/usr/src/homeassistant/homeassistant/components/alexa/smart_home.py", line 39, in async_handle_message
response = await funct_ref(hass, config, directive, context)
File "/usr/src/homeassistant/homeassistant/components/alexa/handlers.py", line 84, in async_api_discovery
for alexa_entity in async_get_entities(hass, config)
File "/usr/src/homeassistant/homeassistant/components/alexa/handlers.py", line 85, in <listcomp>
if config.should_expose(alexa_entity.entity_id)
File "/usr/src/homeassistant/homeassistant/components/alexa/entities.py", line 285, in serialize_discovery
for i in self.interfaces()
File "/usr/src/homeassistant/homeassistant/components/alexa/entities.py", line 286, in <listcomp>
if locale in i.supported_locales
File "/usr/src/homeassistant/homeassistant/components/alexa/capabilities.py", line 205, in serialize_discovery
capability_resources = self.capability_resources()
File "/usr/src/homeassistant/homeassistant/components/alexa/capabilities.py", line 1478, in capability_resources
min_value = float(self.entity.attributes[input_number.ATTR_MIN])
KeyError: 'min'
And my output from Lambda
{
"event": {
"payload": {
"type": "INTERNAL_ERROR",
"message": "500 Internal Server Error\n\nServer got itself in trouble"
}
}
}
Hi,
I used this code to test the alexa skill but i received the below error. I am not a developer so im not able to fix this issue myself. Could you kindly check and advise what needs to be changed to fix this error?
{
"errorMessage": "HTTPSConnectionPool(host='XXX.XXX.XXX', port=8123): Max retries exceeded with url: /api/alexa/smart_home (Caused by SSLError(SSLError(1, '[SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:1056)')))",
"errorType": "MaxRetryError",
"stackTrace": [
" File "/var/task/lambda_function.py", line 62, in lambda_handler\n body=json.dumps(event).encode('utf-8'),\n",
" File "/var/runtime/urllib3/request.py", line 72, in request\n **urlopen_kw)\n",
" File "/var/runtime/urllib3/request.py", line 150, in request_encode_body\n return self.urlopen(method, url, **extra_kw)\n",
" File "/var/runtime/urllib3/poolmanager.py", line 323, in urlopen\n response = conn.urlopen(method, u.request_uri, **kw)\n",
" File "/var/runtime/urllib3/connectionpool.py", line 667, in urlopen\n **response_kw)\n",
" File "/var/runtime/urllib3/connectionpool.py", line 667, in urlopen\n **response_kw)\n",
" File "/var/runtime/urllib3/connectionpool.py", line 667, in urlopen\n **response_kw)\n",
" File "/var/runtime/urllib3/connectionpool.py", line 638, in urlopen\n _stacktrace=sys.exc_info()[2])\n",
" File "/var/runtime/urllib3/util/retry.py", line 398, in increment\n raise MaxRetryError(_pool, url, error or ResponseError(cause))\n"
]
}