Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Alexa Smart Home Skill Adapter for Home Assistant
"""
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'))
@matt2005

This comment has been minimized.

Copy link
Owner Author

@matt2005 matt2005 commented Jul 2, 2019

Updated to allow linking when alexa proactive messaging Forum Issue

@Mirabis

This comment has been minimized.

Copy link

@Mirabis Mirabis commented Dec 22, 2020

Thankyou for the awesome code and Youtube tutorial. My HomeAssistant was only available through client certificates but the following link explained how to add that into the code :)

https://urllib3.readthedocs.io/en/latest/advanced-usage.html

@slbailey

This comment has been minimized.

Copy link

@slbailey slbailey commented Mar 17, 2021

Is there a way to tell "WHO" triggered the event in HA? I want to have an input_boolean but behave differently if person_id 1 says "turn on" vs. person_id 2 saying "turn on"

@LOCOSP

This comment has been minimized.

Copy link

@LOCOSP LOCOSP commented Apr 14, 2021

Hi there is thee any way to troubleshoot lambda?

I'm getting

Response
{
  "event": {
    "payload": {
      "type": "INTERNAL_ERROR",
      "message": "404: Not Found"
    }
  }
}
@svaguilarv

This comment has been minimized.

Copy link

@svaguilarv svaguilarv commented Apr 17, 2021

Hi there is thee any way to troubleshoot lambda?

I'm getting

Response
{
  "event": {
    "payload": {
      "type": "INTERNAL_ERROR",
      "message": "404: Not Found"
    }
  }
}

Hey, could you figure it out? I'm having the same problem.

@uturnr

This comment has been minimized.

Copy link

@uturnr uturnr commented Apr 18, 2021

For me the 404s went away after I made sure I had at least the following in configuration.yaml:

alexa:
  smart_home:

And then I restarted home assistant. If you navigate directly to this URL in your browser: https://<YOUR-HA-URL:YOUR-PORT>/api/alexa/smart_home you should see 405: Method Not Allowed rather than 404: Not Found

edit: That being said I have not been able to successfully discover devices with Alexa/HA (although testing the Lambda code is successful)

@zoltan4929

This comment has been minimized.

Copy link

@zoltan4929 zoltan4929 commented May 20, 2021

In my case, the two programs cannot be paired. When logging in to HomeAssistant, print: invalid client id or redirect uri

@sampathkumarspace

This comment has been minimized.

Copy link

@sampathkumarspace sampathkumarspace commented May 27, 2021

Everything is working , even i linked my dev skills account still my devices is not listing in "Alexa Discovery Devices" but i am getting response in code test

Test Event Name
Discovery

Response
{
"event": {
"header": {
"payloadVersion": "3",
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"messageId": "673f6b16-44f1-4e56-aa09-e6b1fb192213"
},
"payload": {
"endpoints": [
{
"additionalAttributes": {
"customIdentifier": "-switch.relay",
"model": "switch",
"softwareVersion": "2021.5.5",
"manufacturer": "Home Assistant"
},
"manufacturerName": "Home Assistant",
"description": "switch.relay via Home Assistant",
"capabilities": [
{
"interface": "Alexa.PowerController",
"version": "3",
"type": "AlexaInterface",
"properties": {
"retrievable": true,
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true
}
},
{
"interface": "Alexa.EndpointHealth",
"version": "3",
"type": "AlexaInterface",
"properties": {
"retrievable": true,
"supported": [
{
"name": "connectivity"
}
],
"proactivelyReported": true
}
},
{
"interface": "Alexa",
"version": "3",
"type": "AlexaInterface"
}
],
"cookie": {},
"endpointId": "switch#relay",
"friendlyName": "Relay",
"displayCategories": [
"SWITCH"
]
},
{
"additionalAttributes": {
"customIdentifier": "-switch.relay_2",
"model": "switch",
"softwareVersion": "2021.5.5",
"manufacturer": "Home Assistant"
},
"manufacturerName": "Home Assistant",
"description": "switch.relay_2 via Home Assistant",
"capabilities": [
{
"interface": "Alexa.PowerController",
"version": "3",
"type": "AlexaInterface",
"properties": {
"retrievable": true,
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true
}
},
{
"interface": "Alexa.EndpointHealth",
"version": "3",
"type": "AlexaInterface",
"properties": {
"retrievable": true,
"supported": [
{
"name": "connectivity"
}
],
"proactivelyReported": true
}
},
{
"interface": "Alexa",
"version": "3",
"type": "AlexaInterface"
}
],
"cookie": {},
"endpointId": "switch#relay_2",
"friendlyName": "Relay",
"displayCategories": [
"SWITCH"
]
}
]
}
}
}

@blueal

This comment has been minimized.

Copy link

@blueal blueal commented May 29, 2021

For me the 404s went away after I made sure I had at least the following in configuration.yaml:

alexa:
  smart_home:

And then I restarted home assistant. If you navigate directly to this URL in your browser: https://<YOUR-HA-URL:YOUR-PORT>/api/alexa/smart_home you should see 405: Method Not Allowed rather than 404: Not Found

edit: That being said I have not been able to successfully discover devices with Alexa/HA (although testing the Lambda code is successful)

Thanks so much for the help! It turns out I didn't update the config file properly, and I had a trailing "/" in the BASE_URL.

However, the Alexa app is failing to discover any new devices despite them being discovered in the lambda function.

Edit: Figured it out. The AWS Regions for the Lambda function are VERY sensitive. The US West Oregon region may support English, but it's only Canadian English. All English (US) users need to use us-east-1 (N. Virginia).

@JorgeAnzola

This comment has been minimized.

Copy link

@JorgeAnzola JorgeAnzola commented Jul 16, 2021

For me the problem was also a trailing slash at the end

@orrious

This comment has been minimized.

Copy link

@orrious orrious commented Jul 21, 2021

Is there a way to debug Account Linking? When I "Enable to Use" from Alexa App -> Skills it redirects to my Home Assistant authentication portal. I successfully authenticate to Home Assistant and then receive "Unable to link "MySkill Name" with Alexa. Test Discovery messages work. I have been using the haaska lambda code for over 2 years and trying to migrate to this integration. Btw, I'm not just replacing the lambda code in the haaska skill. I have created a new skill for this with its own lambda instance and configured it exactly as instructions provided in https://www.home-assistant.io/integrations/alexa.smart_home

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment