Note this is probably a lot, but below is what I did no joy. Hiding a couple things:
Login to Developer Console: https://developer.amazon.com/alexa/console/ask?
Click Create Skill
Name: HomeAssistant
Select Smart home
Verify Provision your own is selected
Click Create Skill
Verify v3 selected on page
Copy your Skill ID: ###########################################
Open a new tab and login to AWS Console https://console.aws.amazon.com/
Click Services > IAM > Roles > Create role
Select AWS Service
Select Lambda
Click Next: Permissions
Search for AWSLambdaBasicExecutionRole and select it.
Click Next: Tags
Click Next: Review
Enter Role Name of AWSLambdaBasicExecutionRole-SmartHome and click Create role
Click Service > Lambda
Verified N. Virginia selected
Click Create Function
Set Author from scratch
Function Name: HomeAssistant
Runtime: Python 3.7
Expand Choose execution role
Select Use an existing role
Select AWSLambdaBasicExecutionRole-SmartHome
Click Create function
Expand Designer
Click Add Trigger
Select Alexa Smart Home
Application ID paste in your Skill ID from before
Click Add
Click on HomeAssistant
Clear the contents of lambda_function.py and paste in
"""
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 grantee for Linking directive
scope = directive.get('payload', {}).get('grantee')
if scope is None:
# token is in payload for Discovery directive
scope = directive.get('payload', {}).get('scope')
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'))
Under Environment variables add:
BASE_URL: https://<public_url>:8123
DEBUG: True
Click Save
Copy ARN at top: ###############################################
Make sure you have the following in your configuration.yaml and reboot:
alexa:
smart_home:
In AWS Console click Test
Event Name: Discovery
Clear the body and put in:
{
"directive": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover",
"payloadVersion": "3",
"messageId": "1bd5d003-31b9-476f-ad03-71d471922820"
},
"payload": {
"scope": {
"type": "BearerToken"
}
}
}
}
Click Create
Go to Home Assistant and create a Long-Lived Access Token
##########################################################################################################################
Go back to AWS console and add LONG_LIVED_ACCESS_TOKEN Environment Variables
Click Save
Test should pass
Go back to the developer console tab still open and paste in the ARN value for Default endpoint and click Save
Click Setup Account Linking
Authorization URI: https://<public_url>:8123/auth/authorize
Access Token URI: https://<public_url>:8123/auth/token
Your Client ID: https://pitangui.amazon.com/
Client Secret: HiThere
Authorization Scheme: Credentials in request body
Scope click + and put in smart_home
Click Save
Open the mobile app go to Skills & Games > Your Skills Dev
Click on HomeAssistant
Click ENABLE TO USE
We were unable to link HomeAssistant at this time
Think this is related but in the log:
2019-11-17 12:09:44 ERROR (MainThread) [homeassistant.components.http.data_validator] Data does not match schema: required key not provided @ data[‘redirect_uri’]
2019-11-17 12:35:01 WARNING (MainThread) [homeassistant.components.http.ban] Login attempt or request with invalid authentication from 3.230.166.109
EDIT: See a lot of people with this problem. Some say it’s a HA issue with oauth 2.0 authentication and how HA handles it but no clue.