How to use the Doorbell Event Source for Alexa Devices

Alexa Echo Device There is a notification capability available for amazon echo devices called Alexa.DoorbellEventSource which can be used to integrate door bells. A door bell device can push notifications to echo devices, so you will be notified by voice when someone rings at the door.

If you want to implement your own door bell events (or other push notifications), you need a SmartHome Skill with account linking enabled, lambda functions, a database to store credentials and tokens, alexa echo devices and of course a door bell that can send either a POST request to an API-Gateway or an MQTT message to IoT core.

I assume you already have a working SmartHome Skill. Make sure you have set up account linking, because this is required to use the Alexa Event Gateway, not just for doorbell events but also for other push notifications. Detailed instructions to configure account linking can be found here, read through steps 2 to 5, but skip the API-GW deployment parts.

Setup a doorbell device definition

To configure the doorbell device In your SmartHome lambda function you must add a new device with the DoorbellEventSource capability to the device discovery event response:

{
    endpointId: 'doorbell-01',
    manufacturerName: "WebGate",
    modelName: "Helios IP doorbell",
    friendlyName: "Front door",
    description: "Helios IP doorbell and intercom",
    displayCategories: [ "DOORBELL" ],
    cookie: {},
    capabilities: [
        {   "type": "AlexaInterface",
            "interface": "Alexa.DoorbellEventSource",
            "version": "3",
            "proactivelyReported": true
        }
    ]
}

After device discovery by alexa, open the doorbell device in the alexa app and enable announcements for the doorbell press event!

Account linking

Since we need account linking to get the credentials to push events to the Event Gateway, you must also add a handler in your SmartHome skill lambda function to handle authorization requests. This will be triggered when you enable the skill in the app and log in using LWA (Login with amazon). If your SmartHome skill is already enabled, just disable and re-enable again to force the login.

if (event.directive.header.namespace==="Alexa.Authorization") {
	if (event.directive.header.name==="AcceptGrant") {
		// event contains the users access code. Store to database or request tokens here
		var result = {
		"event": {
		    "header": {
		        "namespace": "Alexa.Authorization",
		        "name": "AcceptGrant.Response",
		        "payloadVersion": "3",
		        "messageId": MSG_ID
		    },
		    "payload": {}
		}
		};
		console.log("Accept.Grant RESPONSE", JSON.stringify(result));
	    context.succeed(result);
	}	
}

The AcceptGrant event sent to the SmartHome Skill will look like this:

{
    "directive": {
        "header": {
            "namespace": "Alexa.Authorization",
            "name": "AcceptGrant",
            "payloadVersion": "3",
            "messageId": "a62200f4-7450-0154-9cb5-01bc01c4ccaa"
        },
        "payload": {
            "grant": {
                "type": "OAuth2.AuthorizationCode",
                "code": "ANFfxxxxxxxxxxx"
            },
            "grantee": {
                "type": "BearerToken",
                "token": "Atza|Iw...."
            }
        }
    }
}

The AcceptGrant event contains a token which identifies the user and an authentication code which can be used to request bearer tokens to communicate on behalf of the user with the Alexa Event Gateway. Use payload.grantee.token to identify the user and create a user profile in your database.

Get bearer tokens

Next step is to request a bearer token by sending the payload.grant.code from the AcceptGrant event above to the auth API.

POST /auth/o2/token HTTP/1.1
Host: api.amazon.com
Port: 443
Content-Type: application/x-www-form-urlencoded
charset: UTF-8

Body: 

grant_type: authorization_code
code: {Grant code from the AcceptGrant event above}
client_id: {the messaging client id from your smarthome skill}
client_secret: {the client secret from your smarthome skill}

You can find the messaging client_id and client_secret in the alexa skill editor when you enable Alexa Skill Messaging as described here.

The response to this POST request should look like this:

 "access_token": "Atza|IwEBz.....",
    "refresh_token": "Atzr|IwEBz...",
    "token_type": "bearer",
    "expires_in": 3600

Save the received credentials to the user profile in your database (e.g. DynamoDB) and also the timestamp, so you know when the access token expires and needs to be refreshed using the refresh token. Those credentials are needed every time you communicate with the Alexa Event Gateway.

Send event to the event gateway

Finally we have a valid bearer token to send events on behalf of the end-user. We can now send a DoorBell event to the Alexa Event Gateway while the token is valid. When the token has expired, you should proactively refresh the token first, before sending the event to the gateway, or you will get a status 400 response.

POST request to the event gateway to trigger the doorbell interaction:

POST /v3/events HTTP/1.1
Host: api.amazonalexa.com
Port: 443
Content-Type: application/json
Authorization: Bearer {insert bearer token here}

{
    "context": { },
    "event": {
        "header": {
            "messageId": {MSG_ID},
            "namespace" : "Alexa.DoorbellEventSource",
            "name": "DoorbellPress",
            "payloadVersion": "3"
        },
        "endpoint": {
            "scope": {
                "type": "BearerToken",
                "token": {insert bearer token again but without 'Bearer' prefix}
            },
            "endpointId": "doorbell-01"
        },
        "payload" : {
            "cause": {
                "type": "PHYSICAL_INTERACTION"
            },
            "timestamp": "2018-10-18T11:44:18.485Z"
        }
    }
}

On success you will just receive a status code 202 without any request body and the event should be announced on your alexa echo devices! Make sure you have enabled announcements in the doorbell device settings in the alexa app!

If your bearer token has expired, you will receive a status 400 and you have to refresh the bearer token first by sending the refresh token (stored in the user profile database) to the authentication API:

POST /auth/o2/token HTTP/1.1
Host: api.amazon.com
Port: 443
Content-Type: application/x-www-form-urlencoded
charset: UTF-8

Body: 

grant_type: refresh_token
refresh_token: {refresh token}
client_id: {the messaging client id from your smarthome skill}
client_secret: {the client secret from your smarthome skill}

You have to store the renewed credentials again in your user profile database and then send the DoorBell event again to the event gateway using the renewed bearer token.

To actually trigger the procedure to deliver the DoorBell event as described above, you can put all this into a Lambda function and expose the lambda either via API-Gateway or set up a trigger in the IoT Hub console and listen for a specific topic to invoke the lambda function.