Alexa proactive mode - unable to link alexa

I’m using cloud and I get this error but I only seem to get it when I tell alexa to set a colour light to white. When I do that, the light goes white but then alexa says “I don’t know what went wrong” and reports this in the logs. All other colours trigger a success chime from alexa, but still logs invalid access token in the logs. If I do it in the app, most colours work fine, the white ones say “server was unresponsive”. Very odd

I opened an issue to hopefully catch attention from any dev:
https://github.com/home-assistant/home-assistant/issues/24867

2 Likes

The same for me. Also if I use your lambda, as soon as I activate “Send Alexa Events” in the Skill I am unable to link.

I just restarted from scratch with hass.io (0.95.4) and I’m unable to link after following the guide at https://www.home-assistant.io/components/alexa.smart_home

Had no issues with previous builds and haaska but wanted to link through HA and oauth.

Are you from US with an Amazon US account? Just asking to try to know why some people can link and some not.

Hi!
For all having problems linking: For me, this lambda seems to be working ok (from here). Environment variables HOST and BEARER_TOKEN (long lived acces token) must be set. Handler is called lambda_function.event_handler
Can anyone confirm? Than maybe we can improve it to use the HA authentication instead of the long lived token.

@matt2005

Please try to add following between line 40 and 41 to the lambda function from @awarecan:

    if scope is None:
        # token is in grantee for Linking directive 
        scope = directive.get('payload', {}).get('grantee')

seem to work for me and I don’t need the long lived access token.

Yes, US with US Amazon account.

Doesn’t seem to work for me.

it is now linking using the modified script
github gist

below is my configuration.

AWS region Ireland

#secrets.yaml
alexa_event_endpoint: "https://api.eu.amazonalexa.com/v3/events"
alexa:
  smart_home:
    endpoint: !secret alexa_event_endpoint
    client_id: !secret alexa_client_id
    client_secret: !secret alexa_client_secret

Can you confirm that you have “Send Alexa Events” enabled?
I used your code and I have the same endpoint but it doesn’t link :frowning:

Yes I have send events enabled.
I linked using the Alexa UK

I do still have the long lived access token setup in the lambda variables

ok, long token explains why you are able to link. the point is to use homeassistant authentication.

Previously it wouldn’t link even with it. When linking it redirects to homeassistant login page and then I login and it successfully linked.

Odd, but it doesn’t link for me even if I add long token and amended lambda function.

Not working for me with this version.
I also tried to delete everything and do it again.

Funny how cloud subscription got fixed in hours but this is not being looked by anyone.
This manual integration is completely broken.

1 Like

Have you tried linking without send events to Alexa and the config in homeassistant? I know I had it linking and then unlinked.
Are you using https on 443?
What version of homeassistant? What type of install?

Mine is 0 95.4 running in hassio in docker on a debian x64 host.

Glad it´s working! Did you also try without token in the environment? It should work (as long as you have homeassistant as oauth provider)

HA 0.95.4
Docker
My Home-Assistant runs on port 4443 instead of 443 because my provider blocks 80/443 access.

Ok guys,

Here is how I managed to get it working (some parts are from the original HAASKA):

Set Up Login With Amazon

  1. Sign in to the Amazon Developer Console.
  2. Click the link for “Login With Amazon” in the top navigation bar.
  3. Click the gold button that reads “Create a New Security Profile”.
  • Enter any security profile name you’d like, e.g. “haaska”
  • Write a short description, e.g. “haaska for my Home Assistant”
  • Add any url you’d like for the privacy notice, e.g. “https://myhass.example.com
  1. Click “Save” to continue.
  2. On your new Security Profile, click the gear button, and choose “Web Settings”.
  3. Make note of the Client ID, and Client Secret. Keep this window open for reference.

Linking Alexa Skills Kit to Login With Amazon

  1. Click the “Setup Account Linking” button at the bottom of the page.
  2. Enter the following:
Field Setting
Authorization URI https://www.amazon.com/ap/oa
Access Token URI https://api.amazon.com/auth/o2/token
Client ID The Client ID from your Login With Amazon window
Client Secret The Client Secret from your Login With Amazon window
Client Authentication Scheme HTTP Basic (Recommended)
Scope Click + Add Scope and enter: profile
Domain List Not used
Default Access Token Expiration Time Not used
  1. You will see a list of Redirect URIs. Please copy these down.
  2. Click Save at the top right.
  3. Go back to the Amazon Developer Console/Login with Amazon window. Click Edit at the bottom right.
  4. In “Allowed Return URLs” section, click “Add another” until you have three lines.
  5. On each line, add one of the Redirect URIs from the “Alexa Developer Console” window. Click Save.

And using this custom lambda I made:

#!/usr/bin/env python3.7
# coding: utf-8

# Copyright (c) 2019 Alexandre Leites
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import os
import json
import logging
import ssl
from http.client import HTTPSConnection, RemoteDisconnected

_debug  = bool(os.environ.get('DEBUG'))
_logger = logging.getLogger('HomeAssistant-SmartHome')
_logger.setLevel(logging.DEBUG if _debug else logging.INFO)

def handle_event(event, num_attempt = 1):
    try:
        _logger.debug('Event: %s', event)
        host       = os.environ.get('HOMEASSISTANT_HOST')
        port       = os.environ.get('HOMEASSISTANT_PORT', default='443')
        token      = os.environ.get('HOMEASSISTANT_TOKEN')
        awsRegion  = os.environ.get("AWS_DEFAULT_REGION")
        sslVerify  = os.environ.get("SSL_VERIFY", default = True)
        
        sslContext = ssl.create_default_context()
        sslContext.verify_mode    = ssl.CERT_REQUIRED if sslVerify else ssl.CERT_NONE
        sslContext.check_hostname = True if sslVerify else False
        
        _logger.debug('Host: %s', host)
        _logger.debug('Port: %s', port)
        _logger.debug('Token: %s', token)
        _logger.debug('AWS Region: %s', awsRegion)
        _logger.debug('SSL Verify: %s', sslVerify)
        
        directive = event.get('directive')
        assert directive is not None, 'Malformatted request - missing directive'
        assert directive.get('header', {}).get('payloadVersion') == '3', 'Only support payloadVersion == 3'

        connection = HTTPSConnection(host, port, context = sslContext)
        headers = {
            'Authorization': 'Bearer {}'.format(token),
            'Content-Type': 'application/json',
            'User-Agent': 'HALambda in {}'.format(awsRegion)
        }
        
        connection.request('POST', '/api/alexa/smart_home', body = json.dumps(event).encode('utf8'), headers = headers)
        response = connection.getresponse()
        if response.status != 200:
            _logger.error(f'HomeAssistant error {response.status} {response.reason}')
            return None
        
        return json.loads(response.read())
    except Exception:
        _logger.info("HomeAssistant closed the connection.")
        connection.close()
        if num_attempt >= 3:
            return None
        
        _logger.debug(f"Attempt {num_attempt} failed. Retrying...")
        return handle_event(event, num_attempt + 1)

def event_handler(event, context):
    try:
        return handle_event(event)
    except Exception:
        _logger.exception('Internal error calling HomeAssistant')
        return None

Environment variables:
DEBUG: True or False (I use True to test)
HOMEASSISTANT_HOST: Your HTTPS External HA address (without the port)
HOMEASSISTANT_PORT: Port number (443 by default)
HOMEASSISTANT_TOKEN: Your LONG LIVED TOKEN
SSL_VERIFY: True or False (I use False)

2 Likes