Project in progress
dasBridge

dasBridge © Apache-2.0

A Maker interface to the Alexa Smart Home, using Raspberry Pi, Gobot and Arduino's Firmata Protocol at home, and AWS/Serverless on Cloud.

  • 3,946 views
  • 0 comments
  • 12 respects

Components and supplies

Apps and online services

About this project

Intro

Publishing Alexa's Smart Home Skill for a Maker doesn't need to be hard. In order to prove it, we built dasBridge, a platform which aims to solve address the main pain points in building Alexa Smart Home Devices for the Maker. As such, it includes:

  • Boilerplate code for a generic Alexa Smart Home Bridge, supporting a couple of interesting devices (Temperature, Color Lamp, and Smart Relay)
  • Boilerplate configuration for AWS, using the Serverless Framework
  • Clients using either GoBot or custom Firmware to allow one to integrate their devices to Amazon's IoT Gateway

Samples Include:

  • Generic Temperature Sensor (using GoBot + Arduino with Firmata + BMP280)
  • Color Lamp (Bare Golang + Custom Arduino Firmware + NeoPixels)
  • Generic Smart Relay (ditto, except with Relays)

It was meant to be easily extensible, thus acting as the core fabric for your next Smart Home Skills

The Vision

dasBridge is meant to serve as a template for a pure, enterprise grade device gateway. By this, we mean that we've already built the wheel, do you don't have to reinvent it.

(In fact, this still was originally built to be sent straight to Alexa Skills' Certification. However, time constraints held us back - we might reconsider doing it at a later point)

Premises and Design Goals involve:

  • Using Arduino as a gateway to the underlying hardware whenever possible, and leave the middleware to Raspberry. Considering the price for an Arduino Board + a Raspberry Pi (W or not) + card + USB Power, it looks like the 'IoT Tax' (read: the cost to connect a device) for the average maker could be safely around USD 20 per device, which is acceptable
  • Using TypeScript to ensure correctness on the server side with an Average Performance and Good Productivity, while Golang + Gobot + Firmata on the Device Side will work as a good prototyping environment, offering both performance, portability and performance - while with average productivity levels
  • Rely as much as possible on an AWS Serverless Stack in order to heavily reduce costs. On the worst case, rely on CloudWatch Period Events, and/or AWS Step Functions. At the same time, leverage as much as possible from the Device Shadow API, while ensuring enough isolation

Required Stuff

In order to build this, its required to the user the ability to:

  • Use git and github (e.g. clone a repo, commit)
  • Basic node.js skills (installing node and running npm), regardless of windows and Linux
  • Basic Arduino Skills (assemble a circuit, compile and upload a sketch)
  • Basic Raspberry Pi and Linux skills (install a package, open a shell session and run commands and download/unpack packages)
  • Be able to install the Go Language on the Raspberry Pi

Building and Deploying the Skill

Prerequisites:

  • Machine with both git and nodejs installed - desktop recommended, regardless of being Windows or Linux

On the examples below, we'll be using Linux commands, but it shouldn't be hard to translate those to Windows. If you've got problems, feel free to address in the comments below.

On the machine, clone the dasBridge skill code:

git clone https://github.com/dasbridge/dasbridge-skill.git

Then, go to the dasBridge directory and run npm install:

cd dasbridge
npm install

Go to the 'data' directory and run the 'serverless deploy' command:

cd data
../node_modules/.bin/serverless deploy

Go back to its parent directory and copy the data/stack.json file to src/config/stack.json, and then run the 'serverless deploy' command again:

cd ..
cp data/stack.json src/config/stack.json
serverless deploy

After completion, inspect the results of stack.json of the current directory. Copy the value of the 'SkillLambdaFunctionQualifiedArn' parameter - the first line shown below:

$ cat stack.json 
{
 "SkillLambdaFunctionQualifiedArn": "arn:aws:lambda:us-east-1:005368163414:function:db-dev-skill:28",
 "ModelLambdaFunctionQualifiedArn": "arn:aws:lambda:us-east-1:005368163414:function:db-dev-model:10",
 "ProvisionerLambdaFunctionQualifiedArn": "arn:aws:lambda:us-east-1:005368163414:function:db-dev-provisioner:28",
 "StatusLambdaFunctionQualifiedArn": "arn:aws:lambda:us-east-1:005368163414:function:db-dev-status:16",
 "ServiceEndpoint": "https://t2p7v4dasdas.execute-api.us-east-1.amazonaws.com/dev",
 "ServerlessDeploymentBucketName": "db-dev-serverlessdeploymentbucket-166syk9vv046z"
}

Now, hop on to the Amazon Developer Website, https://developer.amazon.com/, authenticate/register account. Lets start with a Security Profile:

Login with Amazon

Mapping users to things requires us to also map to Amazon Users. So we need to create a Login With Amazon (LWA) Configuration and a Security Profile. Open a new tab to https://developer.amazon.com/lwa/sp/overview.html and click on "Create a New Security Profile", then:

  • Security Profile Name: dasBridge
  • Security Profile Description: dasBridge lwa profile

Save. Copy the ClientId and Client Secret, but keep this tab open since we'll need to edit it further.

Alexa Skills Kit

From the Developer Console, select "Alexa" | "Alexa Skills Kit" | "Add a New Skill", and then fill the values below (unless otherwise specified, accept the defaults):

Page: "Skill Information"

  • Skill Type: Smart Home Skill API
  • Name: dasBridge
  • Click Save

Copy the value of the "Application Id" field, the 'amzn1.ask.skill.xxx' string.

Now, open the another tab and open the AWS Console, check the 'N. Virginia' region is selected, and open the Lambda page. Find the 'db-dev-skill' Lambda function and click it.

On the next screen, click on 'Alexa Smart Home' (under 'Add Triggers'), then under 'Configure triggers, paste the string for the 'Application Id' you got two paragraphs ago, and click on 'Add'. See the screen below.

Once you do it, don't forget to click on the Yellow 'Save' button which will appear once you clicked 'Add':

Now go back to the Amazon Developer Page for the Alexa Skills Kit. Under the 'Configuration' section, paste the value of the "SkillLambdaFunctionQualifiedArn" without the trailing ':NUMBER'. e.g., if you value is

arn:aws:lambda:us-east-1:005368163414:function:db-dev-skill:28

Select so you paste only this value (notice I removed the trailing colon-and-number):

arn:aws:lambda:us-east-1:005368163414:function:db-dev-skill

Copy this value and paste it under the 'Default' section, and then:

Configuration Section:

  • Provide geographical region endpoints? No
  • Scope / Add Scope: profile
  • Authorization Grant Type: Auth Code Grant

Now, paste the values from the Client Id and Client Secret from the tab for the LWA Security Profile.

Copy the values of the 'Redirect URL's' , switch to the LWA Profile Tab, and paste it into their 'Web Settings' | 'Allowed Return URLs'. Save and close this tab (wheew):

Back to the Skill Configuration, now you can save it. Here's a picture to help you validate it:

Skip the 'Publishing Information' and jump to the 'Private and Compliance Section'. Fill with those values:

  • Does this skill allow users to make purchases or spend real money? No
  • Does this Alexa skill collect users' personal information? Yes
  • Is this skill directed to or does it target children under the age or 13? No
  • Export Compliance? <check>
  • Does this skill contain advertising? No

Save. While its not ready to submit for certification (remember we skipped the 'Publishing Information' section), its ready for us to use

Enabling the Skill

Open the Alexa App on your phone, then 'Skills' | 'Your Skills' | 'Dev Skills', click on 'dasBridge' and then 'Enable'. The rest of this flow should be self-explanatory.

If you want to troubleshoot this step, besides AWS, here are two other things you can look up:

Smoketail

smoketail (https://npmjs.com/package/smoketail) is tail -f, but for lambdas. Lambdas write into a thing called AWS CloudWatch Logs. Use this command to troubleshoot the lambda skill:

$ ./node_modules/.bin/smoketail -f /aws/lambda/db-dev-skill 

DynamoDB

If you sucessfully managed to write into the table, the DynamoDB table should have an entry with your user id (application-scoped) and name / email under the db-dev-dbCustomerTable-* DynamoDB Table:

On a product built based on dasBridge, you could use CustomerService (src/customer.ts) to validate and/or send notifications for newer users to finish their setup, for instance.

If you've made this far, rejoice! You just made the hardest part of the whole process: Configuring the Lambdas, Skill and LWA Profiles all at once. From now on, everything gets easier to develop!

AWS IoT Configuration

AWS has the AWS IoT Service. Its more than a platform than a service. Among other things, it manages:

  • Device Provisioning, Metadata and Authentication Service (X509 Keys, CA's, Thing Registry)
  • Authorization Layer (IAM, Policies)
  • Taxonomy (Device Groups)
  • The Device Shadow API
  • Messaging Layer (MQTT / MQTT over WebSockets)
  • Jobs and Greengrass

As for the first four items above, they're modelled as such:

Some notes:

  • A Device Shadow is one attribute of a Thing. There's also a Thing Name - which is going to be critical for our policy below
  • A Certificate might belong to an AWS-managed Certificate Authority, of one you brought by creating your own root CA
  • If you're using the AWS-managed CA, AWS has its own root certificate (and some sub certificates) in order to allow you to use.

So, in order to provision a device (read: 'Thing'), we need at least a Thing Type and a Policy. Creating a new Thing becomes a matter of creating the certificate and the thing, and binding those together into their Types and Policies.

Right now, we'll focus on the basic configuration so the lambdas can have the right security to only manage their device shadows, as well as being able to connect using their own certificates.

From the directory you cloned the dasbridge-skill code, open the misc/policy.json on a text editor, and replace the string '235367163414' with your AWS Account Id, a 12-digit number which could be obtained with this command:

aws sts get-account-id

For example, from another AWS account, the 12-digit number is the 'Account' value:

{
   "Account": "062880515026", 
   "UserId": "062880515026", 
   "Arn": "arn:aws:iam::062880515026:root"
}

Now from the AWS Console, open the IoT service console and select 'Secure' | 'Policies', then create a new policy called 'db-default-policy' with its contents (switch to 'Advanced Mode' in order to paste the JSON). Remember to save.

Now from 'Manage' | 'Types', create a new Thing Type called 'db-default-device' with those 'user_id' as one of their (indexed) attribute.

Check twice before saving: In order to delete, you need to first deprecate and wait 5 minutes before deleting the thing type, so its wise to double check everything.

It should look like this:

Now, on DynamoDB, select the db-data-dev-dbThingsType-* table add a new record with these parameters:

  • thing_type: 'db-default-thing-type'
  • thing_policy (click on +, then String): 'db-default-policy'

This basically map that our API, when it requests to provision a new device with type 'db-default-device', it gets created with this thing_policy.

So far so good. We now had the basic infrastructure for the lambda ready to use for our clients. There's just one step left to start connecting and building things into Alexa Smart Home

Building the Example Clients and Requesting Configuration Files

DasBridge Users (like you, or your significant other which you can entrust to manage your home appliances) needs some access to manage it. As such, there are two lambdas which are paired with cli tools to generate device configuration files. Those device configuration files are json files with all the required information to setup an AWS API Gateway Configuration. For instance, here's one valid confirmation file:

{
 "rootCertificates": {
   "https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem": "-----BEGIN CERTIFICATE-----\nMIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\nyjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\nExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\nU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\nZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\nMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\nZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\nbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\nU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\naXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\nnmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\nt0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\nSdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\nBO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\nrCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\nNIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\nBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\nBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\naXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\nMzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\np6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\nWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\nhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n-----END CERTIFICATE-----"
 },
 "endpoint": "a3slywy094gyae.iot.us-east-1.amazonaws.com",
 "thingPolicy": "thingDefaultPolicy",
 "certificateArn": "arn:aws:iot:us-east-1:235368163414:cert/187898e723f64afaef9ecae462aef6ac2b2ba8b8a2c50c90b3693dc129a1d2e6",
 "certificateId": "187898e723f64afaef9ecae462aef6ac2b2ba8b8a2c50c90b3693dc129a1d2e6",
 "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgIUWMzDF26wZ6/8TOAI5hnDhNXKxl4wDQYJKoZIhvcNAQEL\nBQAwTTFLMEkGA1UECwxCQW1hem9uIFdlYiBTZXJ2aWNlcyBPPUFtYXpvbi5jb20g\nSW5jLiBMPVNlYXR0bGUgU1Q9V2FzaGluZ3RvbiBDPVVTMB4XDTE4MDEyMDIyMjkx\nNFoXDTQ5MTIzMTIzNTk1OVowHjEcMBoGA1UEAwwTQVdTIElvVCBDZXJ0aWZpY2F0\nZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSCJttpCIiGKIEfC9nz\nWtBvBforBJGZOU1y1Zq3tweSXsmlw2zEAv5o07OAm0ZgrD1gFXpb9dTtEWrPA/kv\n67o/ku3WPFqJtnoM1wixErUqMWtzfGcBlYRFy5HJVVpDaU8kc4WL6XzOMnuTtohj\nMQsJ5NIlzjSMOLQOkQxq/EekuNy7V2ttc/0hgiGynUg2TYT3oXLMtbuA2RtlOTFG\nmY1ygkNmDZ5W8c26/nVA487rty3oP11oI8t73Ephngu7d5cTuVkXSyudr1e9yBzS\ni1WMzAAerjrx/RAM2c5tY9AEtJS23o5GfMWnmggcVv+EoGxWEu/ipmkSTKbQV5Zr\n/0kCAwEAAaNgMF4wHwYDVR0jBBgwFoAUQXqasaL3a3YfdoNZLXNYBVYJWdAwHQYD\nVR0OBBYEFPofk/kQFyWrxx5mIoKpIY8hzndfMAwGA1UdEwEB/wQCMAAwDgYDVR0P\nAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQCcA2tKUMPTCrmme9lK37aAARCw\nBcdtwhc9/zXTkGAQrVEl6bwmqqKb+I8ykYw6t6NNuJs4y1CnfP4rJloOk0Ui9/Ra\nqzAwTWP19WUX9Lj1fRDs33KKc3JcmN4Mbb/IAKzmOHYOsS1BCzzcF+O3XggRLiao\nbie/6d7yywzKWCJoeunskMdY6O5uN8SLyJO0nk0myMpteMIPq4xdh+yNh2w7yKBs\nuPFhNLCYpRXCwlbnVSKrL0LEb8tErZ7FIh2RuYAdRZmdLHyVU0zaibOM8e95/mTS\n73OiXlN+xiZdOaBJ8s20BpKEpPkT7wsabW2kvfZRgIKwOC8D6VR736YCLZrH\n-----END CERTIFICATE-----\n",
 "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtIIm22kIiIYogR8L2fNa\n0G8F+isEkZk5TXLVmre3B5JeyaXDbMQC/mjTs4CbRmCsPWAVelv11O0Ras8D+S/r\nuj+S7dY8Wom2egzXCLEStSoxa3N8ZwGVhEXLkclVWkNpTyRzhYvpfM4ye5O2iGMx\nCwnk0iXONIw4tA6RDGr8R6S43LtXa21z/SGCIbKdSDZNhPehcsy1u4DZG2U5MUaZ\njXKCQ2YNnlbxzbr+dUDjzuu3Leg/XWgjy3vcSmGeC7t3lxO5WRdLK52vV73IHNKL\nVYzMAB6uOvH9EAzZzm1j0AS0lLbejkZ8xaeaCBxW/4SgbFYS7+KmaRJMptBXlmv/\nSQIDAQAB\n-----END PUBLIC KEY-----\n",
 "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAtIIm22kIiIYogR8L2fNa0G8F+isEkZk5TXLVmre3B5JeyaXD\nbMQC/mjTs4CbRmCsPWAVelv11O0Ras8D+S/ruj+S7dY8Wom2egzXCLEStSoxa3N8\nZwGVhEXLkclVWkNpTyRzhYvpfM4ye5O2iGMxCwnk0iXONIw4tA6RDGr8R6S43LtX\na21z/SGCIbKdSDZNhPehcsy1u4DZG2U5MUaZjXKCQ2YNnlbxzbr+dUDjzuu3Leg/\nXWgjy3vcSmGeC7t3lxO5WRdLK52vV73IHNKLVYzMAB6uOvH9EAzZzm1j0AS0lLbe\njkZ8xaeaCBxW/4SgbFYS7+KmaRJMptBXlmv/SQIDAQABAoIBAQCCO0CznjT04u4I\nMpEHX0cPCHrkgfLa5RRtp0MrTA62XMkcbQbwyv5p9NGAOXJNtWOvKEp2rDBRvfSJ\n/e+c8hD9n+5uv9ltbNwFdIwUDkU0Bcv//SMs4fywoPZ9KSf2Zpps6hyaplX/oHjV\npb3U6tOwZiP75iC+0sf6SGQn9GwtdxiYlMRwlBFVUcxlWdEYKz6Id2xVedQTzfEu\n1e4xxUp7QAMpUkkBGOY0gdTJbuW7Hl0HgvjFqMD0diIaq/BqYL9A0JrOfWyBojp/\n6fT+QlzDBqkD7bIHTynfgtubP0us80pdK66c/jMXTNLAeZahTocSwZjJWsK1p4XE\nsbDR6pRNAoGBAObzFJq+Seefi4my7g356JRYG1c1EpqVE0CBrvQcEwc7PKEdsAXK\nEOH2qF0jMqpmYvmid44qIU+7rldhf2VOIEHtX1maD5eTrqOVMjFo73oHVbLdmYVp\nHzCNkJV4uz/wFz93DWJx4mDyDYL5Ur1B0yYI1lljuXEU6GyEA8XL9t8zAoGBAMgW\ncOtv3Q+rOY/xbYCYdc5sElXxF+jdbD4bywtEH68Oi+MqPYZYqZQsCEbPTdypsZFy\nVwWauR0SN5HS2mBAd4FCKf6LXzNYyg+N9cMFsDY6c3oqQ5f3xqdgG02hYE4HRdZa\nQJBk7+Gl8F7gKJN2CQ5ml5v92di0ph+4HtdM8teTAoGBAJkpZmXFgu/YcEru3k9o\niGUxFVi9eswHx4/FMYj0wW3PTEMxlBYSzyV8VmYGPMijREp4A7/Fkvf06QdMQpel\nu2DdkpmywVpt96jG/lWkWQVdrekEa5b9g1DI4bUvL0eU62YMh1TdYBuZC3rr7IJV\nEDouLDF2IHqtOgMVfgcEYIHfAoGAerrBIrjn6L+HPFLDbxiVUjuZ95s9pjmDNomH\nvu5XXOJYTcvQF0L1KYzkusJXqR1xbJys4iQonbtZ2Jl0F4wTgXabGaZVi8JPlsDl\n2Wz4zBqIUIvyEBoMgQgDV1fAIbx2SufrKGaxeUB2s0tduC2zmmC1aBqKcFFGgLhI\nOpnZbv8CgYEAyekW3TcBmwhZUXFihbqZ565OeyhqyOUiixZmXRVVkb5Ox81wgjfv\nDE8raSQ2WGERG14IDvo1eb2tFvtNXuaXGs02ZvbA2T6B7CaGTBrUKjEubSB6VUao\nzSJD40T5KWBDmW0V6GZNz5E8QyVz2vFCEap3HEKdSjQF8x5nlWbPHCo=\n-----END RSA PRIVATE KEY-----\n",
 "thingArn": "arn:aws:iot:us-east-1:235368163414:thing/sample01",
 "thingId": "0e67d5ba-261b-48de-85b5-c0d72e403599",
 "thingName": "sample01"
}

So, in order to connect into AWS IoT Gateway via MQTT (and via TLS), you need:

  • A DNS Endpoint
  • A Certificate and its Private Key
  • A Root Certificate to validate the other endpoint
  • A Thing Name (in order to figure out which topic to publish/subscribe for the Device Shadows API)

Most of those data (Except private key) are also stored in DynamoDB, thus making it easier to troubleshoot it.

The file above contains all those data, plus some extra metadata thus making it easy for you to troubleshoot. However, in order to manage those device files (generate and remove), its interesting to add another indirection layer.

Enter API Keys.

Since dasBridge is deployed as a serverless application, you, as a power AWS User, can generate API Gateway Keys which, in turn, can allow you to easily create and remove devices under the AWS IoT using an HTTPS RESTful endpoint for it.

So we'll just run an utility to generate an API Key, configure it and return it to you, so we can move into the Raspberry Pi and properly use those files.

Provided you've got Linked the e-mail user@example.com (which is your AWS Account email), simply run from your project directory:

$ # Compile a local version of the tools
$ ./node_modules/.bin/tsc
$ node ./build/src/tools/generateApiKey.js user@example.com
email: user@example.com
customerKeysTable: db-data-dev-dbCustomerKeysTable-1JIDLW5TPMR2R
customerTable: db-data-dev-dbCustomerTable-1CXQ2BCFY8G59
ServiceEndpoint: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev
restApiId: t2p7v4dvcf
restApiStage: dev
item: {
 "last_updated": 1518563648,
 "user_id": "amzn1.account.BLAHBLAHBLAHBHASLDADSA",
 "email": "user@example.com",
 "short_id": "BLAHBLAHBLAHBHASLDADSA",
 "name": "Sample User"
}
apiKey:  {
 "id": "hCjiUbAnRG14deL1IbdB2rHe9QeFI7q4VexKLb",
 "value": "hCjiUbAnRG14deL1IbdB2rHe9QeFI7q4VexKLb",
 "enabled": true,
 "createdDate": "2018-02-14T00:23:42.000Z",
 "lastUpdatedDate": "2018-02-14T00:23:42.000Z",
 "stageKeys": [
   "t2p7v4dvcf/dev"
 ]
}

From now on, the key with id raKkBARg6eaPTiMdaIplS3ZssqOR3qRC9OBopzZt can now be used to issue requests to the dasBridge endpoint at https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev to manage your devices.

This endpoint is key-protected and returns a status, so this command will fail since there's not an API Key sent:

$ curl https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev
{"message": "Forbidden"}

While that when you supply the key with the X-Api-Key parameter on curl, and if its valid, it should return this:

$ curl -H'X-Api-Key: hCjiUbAnRG14deL1IbdB2rHe9QeFI7q4VexKLb' https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev
{
 "name": "Sample User",
 "email": "user@example.com"
}

Keep note of the Endpoint, and your API Key. We'll use that in a moment.

Compiling the CLI Tools on the Raspberry Pi

For this part, we'll be based on Raspbian and deb-based distros (it should work on Ubuntu, for instance). YMMV.

Configure the Raspberry Pi as usual, and then log on on it. First, install git (for go get):

apt-get -y install git

Now, open the go downloads page and click on downloads. Select the armv6l version and copy its URL, then run wget:

wget https://dl.google.com/go/go1.10.linux-armv6l.tar.gz

Create a share/ dir and unpack it there:

mkdir share
cd share
tar ~/go1.10.linux-armv6l.tar.gz
mkdir

Edit ~/.bashrc and append these lines. Replace the first two lines with the results from the previous section:

export DB_ENDPOINT=[ENDPOINT URL]
export DB_API_KEY=[API KEY]
export GOROOT=$HOME/share/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin 

Reload your environment:

source ~/.bashrc 

Test by fetching gb, which is a required dependency:

go get github.com/constabulary/gb/...
which gb

It should display the path to gb: /home/pi/go/bin/gb

Now we'll install some sample clients. Start by compiling the current project:

gb build

Now start using the CLI tools for dasBridge:

./bin/db-device-check 
INFO[0000] Using endpoint:https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/ 
Response: {
 "name": "Sample User",
 "email": "user@example.com"
} 

This will validate your API Keys. If everything is fine, register a new client:

./bin/db-device-register myShinyDevice db-default-thing-type
INFO[0000] Using endpoint: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/ (in fact: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/device) 
Response: {"rootCertificates":{"https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem":"-----BEGIN CERTIFICATE-----\nMIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\nyjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\nExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\nU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\nZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\nMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\nZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\nbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\nU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\naXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\nnmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\nt0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\nSdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\nBO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\nrCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\nNIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\nBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\nBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\naXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\nMzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\np6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\nWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\nhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n-----END CERTIFICATE-----"},"endpoint":"a3slywy094gyae.iot.us-east-1.amazonaws.com","thingPolicy":"db-default-policy","certificateArn":"arn:aws:iot:us-east-1:235368163414:cert/e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificateId":"e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificatePem":"-----BEGIN CERTIFICATE-----\nMIIDWjCCAkKgAwIBAgIVANAk5wk9DWkumIcIhef6ZCh6SxorMA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xODAyMTgxNTM0\nMTNaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\ndGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDX7o+q4LZO/9+OOBDF\ncsUQV/xJjVddmbO0hs5wM5VPaqmoLIYorHPc0sJhN9+LibcXvPbCE+fOMlkMCuI8\nfrRiDiC7+ik8ns+Nbqa5/zXyO2pYmGwqgPEYFeX3v66qmcl9YOHFrAbFAA9x4Ng3\n5k/TWvMIFS1G7KWH4iHPV3ecTX1YcngoQI8joZOoUz35e/7jUkH7+fXaGLsCIBTc\ndmg+fyP6VGH0tIqRxptar3UIUEjnYS/Wr6qmyRCr2r5PIOq2+7g2jJNfyISuXcAd\n6ejlwX2F2qVGZlmCVRYIAaRAYhrFPWUYFu67zZ+9R5VbGclm6CoBHLHha5pAIVPR\nJxdTAgMBAAGjYDBeMB8GA1UdIwQYMBaAFDynll3zULGOIZTKNhFgX4GdiAccMB0G\nA1UdDgQWBBQGt3ef///BerXAq7WlD5SyJfnktzAMBgNVHRMBAf8EAjAAMA4GA1Ud\nDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAeFkYGshcNuHNTXIVk6d8JdU0\n+5RA9acaGB9xFX5Q9er8rubyHwyBmGZxsJ6cUQF41fmqn8e6QIEWbg5t3+hIYD0u\nM0hXUOnNppLVYce7Rn+JCvxQDcVbBCXwvU6ROZ5HyIyfmNdM56kEtAHm1qWdIZ70\ngi7zhHhi0GziKo7FmY2mFvvSLw6Iw66qfNZEjrNatfiPreqnserwFCFt6Yh8sj3i\n9yEQB1ttnxmVm89VEayuJwvdJhIlar6DIoUm3nMjYVixV0ev5GMbg/ej8CB8wMjF\nexSJ3aHGMaMpVqRHIzFprpLpBoKAPtK9tpJHlVIsi4BqYHgR9BCUMLBuIG4DZQ==\n-----END CERTIFICATE-----\n","publicKey":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1+6PquC2Tv/fjjgQxXLF\nEFf8SY1XXZmztIbOcDOVT2qpqCyGKKxz3NLCYTffi4m3F7z2whPnzjJZDAriPH60\nYg4gu/opPJ7PjW6muf818jtqWJhsKoDxGBXl97+uqpnJfWDhxawGxQAPceDYN+ZP\n01rzCBUtRuylh+Ihz1d3nE19WHJ4KECPI6GTqFM9+Xv+41JB+/n12hi7AiAU3HZo\nPn8j+lRh9LSKkcabWq91CFBI52Ev1q+qpskQq9q+TyDqtvu4NoyTX8iErl3AHeno\n5cF9hdqlRmZZglUWCAGkQGIaxT1lGBbuu82fvUeVWxnJZugqARyx4WuaQCFT0ScX\nUwIDAQAB\n-----END PUBLIC KEY-----\n","privateKey":"-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA1+6PquC2Tv/fjjgQxXLFEFf8SY1XXZmztIbOcDOVT2qpqCyG\nKKxz3NLCYTffi4m3F7z2whPnzjJZDAriPH60Yg4gu/opPJ7PjW6muf818jtqWJhs\nKoDxGBXl97+uqpnJfWDhxawGxQAPceDYN+ZP01rzCBUtRuylh+Ihz1d3nE19WHJ4\nKECPI6GTqFM9+Xv+41JB+/n12hi7AiAU3HZoPn8j+lRh9LSKkcabWq91CFBI52Ev\n1q+qpskQq9q+TyDqtvu4NoyTX8iErl3AHeno5cF9hdqlRmZZglUWCAGkQGIaxT1l\nGBbuu82fvUeVWxnJZugqARyx4WuaQCFT0ScXUwIDAQABAoIBAQCFcWudyXNBDQXm\nCSXsL8ozGHzUI6ILOTKCbRDk7CvowV0JjkJ2nmSX4jO4CuR+gmQBKolAVTbbCehX\n9d3sTs1BD8QRBz82tFpF6EznAx4ejbNh/whRmA/mt5m/6tiRm6qWbin4lCA23Juu\n36ofmZhZYIpyw0uQ2ixN9mS4kzBbCbD8zsc+cP/4Ex+9O3nZd3p64MZjCvMRmH18\nhohrjVCHB9hG+cO2GIVKQMJh0Aj4r/V7p6kIfpZ0oUWCnSk2pZ8178neuzdtlJQt\nENyaDMVuOcU+Mr06B4mT/C/9C/rZdUD+VfL7ihEftWxuJBiuAoj+L94SdGXp03Zi\nouss4Mm5AoGBAPz7sPb9He5m8aC2YSubol1/rbX0cKQTuM8k9jbPylr5CuFcmiMt\n/XhcVes76zRlxkyKGgEB3uKkc32NNrHjH0xY5eIm8tRC7ZRq+IYQxFOawodHbPqw\nYBcn5BUYecsmuZ22Lu3gqqGgkEGSZ3JN/RTilCPTqi30rRYVkhB6QbIFAoGBANqB\nwm7zUh65MPiTIBy2045zI8vaHn2H05eQGY9ax7/NDxSqMSK+hZh1VLIAC3OiFZfK\nLCT2qODRJ1MDuPPd3u5I2oduzeyKtHV24nnkbpXzSWy1ho4bF5MN6qXyIPOu0QVq\nFUpI8a9911rlYyZhsjY1oOCi1bfswsM1qDZqJKt3AoGASNNjpBZFcYWs9SjLXDRX\nTzccGI8fhfwvbWIkhq7Wf83Fdg6kSJBKsUVTbn43PUQ3C32N8tBJC1Fv9aqbHiZV\nsjK9KpcvvC7wGZOZq25UNgUNDshe9OOlJcVUAUakePjS4jW52LyeIh0IqfetU9hj\njImVP6MFEGmpEfxvqdKn6skCgYAfjc1+KDUbqrKfst9YRi6Wy5nHvl/Y0NyFbpHC\nWeGumPYsjcc6tTilo4vviIIe2LE1kkR9sgEBNjLvkgILdWbUEkE8fYvPNNiKffiG\nka5GiTN5N12O9+qXmdLg0+5eQkh896zLZW1BYnLO9YEz8bfCjEwHJHyoatBVUFJS\nSVGyUQKBgC00Jo563DAqVrP7nv0VIvyTmr4m7TymX/8K8g+OY9uvJEGUpMndEoOn\nIRTFZeM5nTjg2sqkqt1PseFMkHzJEsVNNm6tZ/La3hpmn6f7b5fBjmItDoHYHxW0\nFMiug2+9P6RzDukbkeWQeEL0kQgd3UYuqgNZYmXV/h83zWJoHckw\n-----END RSA PRIVATE KEY-----\n","thingArn":"arn:aws:iot:us-east-1:235368163414:thing/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice","thingId":"83a64854-453d-4165-812b-20a97343f356","thingName":"AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice"} (200)
INFO[0002] Response Content: {"rootCertificates":{"https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem":"-----BEGIN CERTIFICATE-----\nMIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\nyjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\nExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\nU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\nZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\nMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\nZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\nbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\nU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\naXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\nnmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\nt0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\nSdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\nBO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\nrCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\nNIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\nBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\nBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\naXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\nMzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\np6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\nWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\nhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n-----END CERTIFICATE-----"},"endpoint":"a3slywy094gyae.iot.us-east-1.amazonaws.com","thingPolicy":"db-default-policy","certificateArn":"arn:aws:iot:us-east-1:235368163414:cert/e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificateId":"e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificatePem":"-----BEGIN CERTIFICATE-----\nMIIDWjCCAkKgAwIBAgIVANAk5wk9DWkumIcIhef6ZCh6SxorMA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xODAyMTgxNTM0\nMTNaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\ndGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDX7o+q4LZO/9+OOBDF\ncsUQV/xJjVddmbO0hs5wM5VPaqmoLIYorHPc0sJhN9+LibcXvPbCE+fOMlkMCuI8\nfrRiDiC7+ik8ns+Nbqa5/zXyO2pYmGwqgPEYFeX3v66qmcl9YOHFrAbFAA9x4Ng3\n5k/TWvMIFS1G7KWH4iHPV3ecTX1YcngoQI8joZOoUz35e/7jUkH7+fXaGLsCIBTc\ndmg+fyP6VGH0tIqRxptar3UIUEjnYS/Wr6qmyRCr2r5PIOq2+7g2jJNfyISuXcAd\n6ejlwX2F2qVGZlmCVRYIAaRAYhrFPWUYFu67zZ+9R5VbGclm6CoBHLHha5pAIVPR\nJxdTAgMBAAGjYDBeMB8GA1UdIwQYMBaAFDynll3zULGOIZTKNhFgX4GdiAccMB0G\nA1UdDgQWBBQGt3ef///BerXAq7WlD5SyJfnktzAMBgNVHRMBAf8EAjAAMA4GA1Ud\nDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAeFkYGshcNuHNTXIVk6d8JdU0\n+5RA9acaGB9xFX5Q9er8rubyHwyBmGZxsJ6cUQF41fmqn8e6QIEWbg5t3+hIYD0u\nM0hXUOnNppLVYce7Rn+JCvxQDcVbBCXwvU6ROZ5HyIyfmNdM56kEtAHm1qWdIZ70\ngi7zhHhi0GziKo7FmY2mFvvSLw6Iw66qfNZEjrNatfiPreqnserwFCFt6Yh8sj3i\n9yEQB1ttnxmVm89VEayuJwvdJhIlar6DIoUm3nMjYVixV0ev5GMbg/ej8CB8wMjF\nexSJ3aHGMaMpVqRHIzFprpLpBoKAPtK9tpJHlVIsi4BqYHgR9BCUMLBuIG4DZQ==\n-----END CERTIFICATE-----\n","publicKey":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1+6PquC2Tv/fjjgQxXLF\nEFf8SY1XXZmztIbOcDOVT2qpqCyGKKxz3NLCYTffi4m3F7z2whPnzjJZDAriPH60\nYg4gu/opPJ7PjW6muf818jtqWJhsKoDxGBXl97+uqpnJfWDhxawGxQAPceDYN+ZP\n01rzCBUtRuylh+Ihz1d3nE19WHJ4KECPI6GTqFM9+Xv+41JB+/n12hi7AiAU3HZo\nPn8j+lRh9LSKkcabWq91CFBI52Ev1q+qpskQq9q+TyDqtvu4NoyTX8iErl3AHeno\n5cF9hdqlRmZZglUWCAGkQGIaxT1lGBbuu82fvUeVWxnJZugqARyx4WuaQCFT0ScX\nUwIDAQAB\n-----END PUBLIC KEY-----\n","privateKey":"-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA1+6PquC2Tv/fjjgQxXLFEFf8SY1XXZmztIbOcDOVT2qpqCyG\nKKxz3NLCYTffi4m3F7z2whPnzjJZDAriPH60Yg4gu/opPJ7PjW6muf818jtqWJhs\nKoDxGBXl97+uqpnJfWDhxawGxQAPceDYN+ZP01rzCBUtRuylh+Ihz1d3nE19WHJ4\nKECPI6GTqFM9+Xv+41JB+/n12hi7AiAU3HZoPn8j+lRh9LSKkcabWq91CFBI52Ev\n1q+qpskQq9q+TyDqtvu4NoyTX8iErl3AHeno5cF9hdqlRmZZglUWCAGkQGIaxT1l\nGBbuu82fvUeVWxnJZugqARyx4WuaQCFT0ScXUwIDAQABAoIBAQCFcWudyXNBDQXm\nCSXsL8ozGHzUI6ILOTKCbRDk7CvowV0JjkJ2nmSX4jO4CuR+gmQBKolAVTbbCehX\n9d3sTs1BD8QRBz82tFpF6EznAx4ejbNh/whRmA/mt5m/6tiRm6qWbin4lCA23Juu\n36ofmZhZYIpyw0uQ2ixN9mS4kzBbCbD8zsc+cP/4Ex+9O3nZd3p64MZjCvMRmH18\nhohrjVCHB9hG+cO2GIVKQMJh0Aj4r/V7p6kIfpZ0oUWCnSk2pZ8178neuzdtlJQt\nENyaDMVuOcU+Mr06B4mT/C/9C/rZdUD+VfL7ihEftWxuJBiuAoj+L94SdGXp03Zi\nouss4Mm5AoGBAPz7sPb9He5m8aC2YSubol1/rbX0cKQTuM8k9jbPylr5CuFcmiMt\n/XhcVes76zRlxkyKGgEB3uKkc32NNrHjH0xY5eIm8tRC7ZRq+IYQxFOawodHbPqw\nYBcn5BUYecsmuZ22Lu3gqqGgkEGSZ3JN/RTilCPTqi30rRYVkhB6QbIFAoGBANqB\nwm7zUh65MPiTIBy2045zI8vaHn2H05eQGY9ax7/NDxSqMSK+hZh1VLIAC3OiFZfK\nLCT2qODRJ1MDuPPd3u5I2oduzeyKtHV24nnkbpXzSWy1ho4bF5MN6qXyIPOu0QVq\nFUpI8a9911rlYyZhsjY1oOCi1bfswsM1qDZqJKt3AoGASNNjpBZFcYWs9SjLXDRX\nTzccGI8fhfwvbWIkhq7Wf83Fdg6kSJBKsUVTbn43PUQ3C32N8tBJC1Fv9aqbHiZV\nsjK9KpcvvC7wGZOZq25UNgUNDshe9OOlJcVUAUakePjS4jW52LyeIh0IqfetU9hj\njImVP6MFEGmpEfxvqdKn6skCgYAfjc1+KDUbqrKfst9YRi6Wy5nHvl/Y0NyFbpHC\nWeGumPYsjcc6tTilo4vviIIe2LE1kkR9sgEBNjLvkgILdWbUEkE8fYvPNNiKffiG\nka5GiTN5N12O9+qXmdLg0+5eQkh896zLZW1BYnLO9YEz8bfCjEwHJHyoatBVUFJS\nSVGyUQKBgC00Jo563DAqVrP7nv0VIvyTmr4m7TymX/8K8g+OY9uvJEGUpMndEoOn\nIRTFZeM5nTjg2sqkqt1PseFMkHzJEsVNNm6tZ/La3hpmn6f7b5fBjmItDoHYHxW0\nFMiug2+9P6RzDukbkeWQeEL0kQgd3UYuqgNZYmXV/h83zWJoHckw\n-----END RSA PRIVATE KEY-----\n","thingArn":"arn:aws:iot:us-east-1:235368163414:thing/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice","thingId":"83a64854-453d-4165-812b-20a97343f356","thingName":"AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice"} 
INFO[0002] Saving config for '83a64854-453d-4165-812b-20a97343f356' into file 'AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice-83a64854-453d-4165-812b-20a97343f356.json' 

You can also list your existing devices:

$ ./bin/db-device-list 
INFO[0000] Using endpoint: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/ (in fact: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/device) 
Response: [{"certificateId":"e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificateArn":"arn:aws:iot:us-east-1:235368163414:cert/e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","thingId":"83a64854-453d-4165-812b-20a97343f356","thingArn":"arn:aws:iot:us-east-1:235368163414:thing/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice","thingName":"myShinyDevice"}] (200)
[{"certificateId":"e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","certificateArn":"arn:aws:iot:us-east-1:235368163414:cert/e768e1928dec019b3d748316572d17e2ae4531d21b6d126782976261799e1401","thingId":"83a64854-453d-4165-812b-20a97343f356","thingArn":"arn:aws:iot:us-east-1:235368163414:thing/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice","thingName":"myShinyDevice"}]

Ok, at this point, you already got a json file for connection. Take a break, soon we'll build a thermomether!

Building a Thermometer

Unfortunately, gobot only allows working with devices it has a device driver - implemented from the client (go) side. So that limits our option. In our case, we'll resort to a BMP280 Thermometer. Using Adafruit's BMP280 shield, and using an I2C connection, it should be like this:

For more details, check https://learn.adafruit.com/adafruit-bmp280-barometric-pressure-plus-temperature-sensor-breakout/overview

Once the circuit has been made, open the Arduino IDE on your desktop, and under File | Examples | Firmata, pick StandardFirmata. Select your Board and Port and upload. Now attach the Arduino to your Raspberry Pi, and identify its serial port with the dmesg command and checking under /dev/tty*

Using the json file we've generated in the previous section, fire up the thermometer reporter - the argument to the -s option should be your serial port (in this case, /dev/ttyUSB0):

./bin/db-bmp280-thermometer-service -s /dev/ttyUSB0 AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice-83a64854-453d-4165-812b-20a97343f356.json 
INFO[0000] Loaded config file: AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice-83a64854-453d-4165-812b-20a97343f356.json for AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice @ a3slywy094gyae.iot.us-east-1.amazonaws.com 
INFO[0003] Publishing state update to $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update (update: {"state":{"reported":{"Alexa.TemperatureSensor":{"3":{"temp":24.591446}}}}}) 
{
 "_topic": "$aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update/accepted",
 "metadata": {
   "reported": {
     "Alexa.TemperatureSensor": {
       "3": {
         "temp": {
           "timestamp": 1518970228
         }
       }
     }
   }
 },
 "state": {
   "reported": {
     "Alexa.TemperatureSensor": {
       "3": {
         "temp": 24.591446
       }
     }
   }
 },
 "timestamp": 1518970228,
 "version": 1
}
INFO[0004] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update/accepted 
INFO[0004] Connected                                    
INFO[0004] Sending status update: {"state":{"reported":{"connected":true}}} 
INFO[0004] Thing shadow updated successfully            
{
 "_topic": "$aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update/accepted",
 "metadata": {
   "reported": {
     "connected": {
       "timestamp": 1518970228
     }
   }
 },
 "state": {
   "reported": {
     "connected": true
   }
 },
 "timestamp": 1518970228,
 "version": 2
}

Keep it running. If things went ok and no errors, here's the steps you should take:

  • Say "-Alexa, discover my devices"
  • From the Alexa App, notice the new device will be there. Rename "myShinyDevice" to something easy for Alexa to understand such as 'Office'
  • Say "-Alexa, whats the temperature at the Office"
  • Enjoy!

Notice that at this point, adding new devices simply becomes easier!

But how does it work?

Thanks for asking. For most of the scenarios on dasBridge, everything is held by means of the Thing Shadows API. As such, we publish to our Device Shadow a payload as this:

INFO[0304] Publishing state update to $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update (update: {"state":{"reported":{"Alexa.TemperatureSensor":{"3":{"temp":35.15287}}}}}) 
{
 "_topic": "$aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myShinyDevice/shadow/update/accepted",
 "metadata": {
   "reported": {
     "Alexa.TemperatureSensor": {
       "3": {
         "temp": {
           "timestamp": 1518971390
         }
       }
     }
   }
 },
 "state": {
   "reported": {
     "Alexa.TemperatureSensor": {
       "3": {
         "temp": 35.15287
       }
     }
   }
 },
 "timestamp": 1518971390,
 "version": 14
}

Internally, the dasBridge Skill has a logic to parse the JSON Thing Descriptor and extract meaningful interfaces out of this:

discoverEndpoint(endpointId: string, thingMeta: ThingMetadata): AlexaDiscoveryEndpoint {
    //console.log('arguments:', JSON.stringify(arguments, null, 2))
    const friendlyNameToUSe = FULL_TO_SHORT.exec(endpointId)[1]
    let result: AlexaDiscoveryEndpoint = {
        endpointId: endpointId,
        friendlyName: friendlyNameToUSe, // TODO
        description: `${friendlyNameToUSe} Device`, // TODO
        manufacturerName: "the dasbridge project",
        capabilities: [],
        displayCategories: []
    }
    let hasTemperatureTimestamp = jmespath.search(thingMeta, 'metadata.reported."Alexa.TemperatureSensor"."3".temp.timestamp')
    if (hasTemperatureTimestamp && this.isLessThan30Minutes(hasTemperatureTimestamp)) {
        result.capabilities.push({
            type: "AlexaInterface",
            interface: "Alexa.TemperatureSensor",
            version: "3",
            properties: {
                supported: [
                    {name: "temperature"}
                ]
            },
            proactivelyReported: false,
            retrievable: true
        } as AlexaCapability)
        result.displayCategories.push('TEMPERATURE_SENSOR')
    }
    // metadata.reported."Alexa.TemperatureSensor"."3".temp.timestamp
    return result
}

This means: if there's an 'Alexa.TemperatureSensor' key, with a sub key of '3' and 'temp', and its Thing Shadow Metadata has been reported under 30 minutes, it will report as a "TEMPERATURE_SENSOR" interface.

Interacting with the Alexa Smart Home platform, when queried, becomes a matter of retrieving the Device Shadow and building its payload e.g.:

           let hasTemperatureTimestamp = jmespath.search(thingMeta, 'metadata.reported."Alexa.TemperatureSensor"."3".temp.timestamp')
           if (hasTemperatureTimestamp && this.isLessThan30Minutes(hasTemperatureTimestamp)) {
               const sampleTime = new Date(hasTemperatureTimestamp * 1000)
               const temperature = jmespath.search(thingMeta, 'state.reported."Alexa.TemperatureSensor"."3".temp')
               const timeOfSample = moment(sampleTime).utc().toISOString()
               answer.context.properties.push({
                   namespace: "Alexa.TemperatureSensor",
                   name: "temperature",
                   value: {
                       value: temperature.toFixed(1),
                       scale: "CELSIUS"
                   },
                   timeOfSample: timeOfSample,
                   uncertaintyInMilliseconds: 1000
               })
           }  

Building a NeoPixel Strip Lamp

Now lets try another example. Using an Arduino Uno and a Neopixel Strip, like this:

Now, open the Arduino IDE and install the Adafruit Neopixels Library. Once done, install the sketch on the client repo, under sketches/rgbmodem.ino, compile and upload. This sketch implements the AT interface, but only for managing the Leds.

You could compile and upload, and open the Serial Console. Try those commands to the Arduino:

  • Set to green: AT+RGB=FF0000
  • Turn it off: AT+OFF

Now reconnect it to the Raspberry Pi and generate a new device key for this lamp:

./bin/db-device-register myRGBLamp db-default-thing-type
INFO[0000] Using endpoint: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/ (in fact: https://t2p7v4dvcf.execute-api.us-east-1.amazonaws.com/dev/device) 
Response: {"rootCertificates":{"https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem":"-----BEG...
OA_myRGBLamp","thingId":"5cdd7fb7-1216-4ea0-90df-9b49790288f0","thingName":"AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp"} (200)
INFO[0000] Response Content: {"rootCertificates":{"https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authori...
 RSA PRIVATE KEY-----\n","thingArn":"arn:aws:iot:us-east-1:235368163414:thing/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp","thingId":"5cdd7fb7-1216-4ea0-90df-9b49790288f0","thingName":"AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp"} 
INFO[0000] Saving config for '5cdd7fb7-1216-4ea0-90df-9b49790288f0' into file 'AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp-5cdd7fb7-1216-4ea0-90df-9b49790288f0.json' 

And fire up its client:

./bin/db-rgb-service /dev/ttyUSB0 *myRGBLamp*
INFO[0000] Loaded config file: AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp-5cdd7fb7-1216-4ea0-90df-9b49790288f0.json for AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp @ a3slywy094gyae.iot.us-east-1.amazonaws.com 
INFO[0000] Publishing state update to $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/update (update: {"state":{"reported":{"Alexa.ColorController":{"3":{"color":{"brightness":0,"hue":0,"saturation":0}}},"Alexa.PowerController":{"3":{"powerState":"OFF"}}}}}) 
ERRO[0000] Oops: runtime error: invalid memory address or nil pointer dereference 
INFO[0000] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/update/accepted 
INFO[0000] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/get 
INFO[0000] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/get/rejected 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/delete 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/delete/accepted 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/delete/rejected 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/update 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/update/documents 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/update/rejected 
INFO[0001] Subscribed to topic: $aws/things/AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp/shadow/get/accepted 
INFO[0001] Connected                                    
INFO[0001] Sending status update: {"state":{"reported":{"connected":true}}} 
INFO[0001] Thing shadow updated successfully            

This device implements two interfaces: Alexa.PowerController and Alexa.ColorController. Here's the flow to do:

  • Say "-Alexa, discover my devices"
  • Open the Alexa App and rename myRGBLight into something meaningful, such as "Desk Lamp"
  • You an either operate from the Alexa App, or use Voice commands, such as "Alexa, turn [on|off] Desk Lamp" and/or "Alexa, set the Desk Lamp Color to [color]"

Perhaps you're more into videos, right? So here it is:

dasBridge Smart Lamp Demo

Packing Up

One neat trick is that you can actually ensure everything is loaded and configured comes from this URL. Basically, if you know your Arduino Configuration (USB Vendor / Product Id, as well as Serial Number), you can configure so everything can be started at boot time. So, for instance, I did look into the parameters for my Arduino on /dev/ttyACM2:

pi@rpi0:~ $ sudo udevadm info -a -n /dev/ttyACM2 | egrep -e '(serial|idVendor|idProduct)'               
   ATTRS{idProduct}=="0043"
   ATTRS{idVendor}=="2341"
   ATTRS{serial}=="7543831363335121C1F0"
   ATTRS{idProduct}=="9514"
   ATTRS{idVendor}=="0424"
   ATTRS{idProduct}=="0002"
   ATTRS{idVendor}=="1d6b"
   ATTRS{serial}=="3f980000.usb"

I also created a systemd service mapping my configuration. It came like this:

$ cat /etc/systemd/system/rgblamp.service
[Unit]
Description=RGB Lamp Service
After=network.target
[Service]
WorkingDirectory=/home/pi/db-client
ExecStart=/home/pi/db-client/bin/db-rgb-service /dev/rgblamp AG6JLK4J4SVY6O2NZZIM5DLKVKOA_myRGBLamp-5cdd7fb7-1216-4ea0-90df-9b49790288f0.json

So in the end, I've got this configuration file under /dev/udev/rules.d/99-misc.rules:

SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", ATTRS{serial}=="7543831363335121C1F0", SYMLINK+="rgblamp", ENV{SYSTEMD_WANTS}
="rgblamp.service"

That meant that, if everything has been properly set, nothing was needed to connect my modules!

Conclusion

dasBridge has a fun project to build. However, we've got lives and constraints on real life. If not, we'd be able to:

  • Bring the vision to smaller hardware, specifically MCU's such as the ESP32, as well as some ST and/or nRF5x series
  • Be able to come up with more samples, such as the smart camera
  • Condier moving out of the Alexa Smart Home paradigm

However, those might be implemented in the future. Meanwhile, we invite you to check https://github.com/dasbridge and join the gitter rooms there.

Thank you!

Code

dasBridge Server Repository
Server side of dasBridge
dasBridge Clients
Client-side of dasBridge

Schematics

BMP280 Example Schematics
Bmp280 aylekzvexj
Neopixel Lamp Schematics
Neopixel bb rtojmdmuwm

Comments

Similar projects you might like

Animated Smart Light with Alexa and Arduino

Project tutorial by Bruno Portaluri

  • 3,703 views
  • 9 comments
  • 23 respects

Intelligent Door Lock

Project in progress by Md. Khairul Alam

  • 16,033 views
  • 19 comments
  • 96 respects

Where's my stuff?? - Find your misplaced things with Alexa!

Project in progress by Crakers

  • 1,646 views
  • 0 comments
  • 6 respects

Herb Box Eco System

Project tutorial by Walter Heger

  • 37,149 views
  • 20 comments
  • 239 respects

WaterPi: Houseplant Remote Watering and Monitoring System

Project tutorial by Demirhan Aydin

  • 29,566 views
  • 14 comments
  • 128 respects

WalaBeer Tank

Project tutorial by Balázs Simon

  • 23,110 views
  • 4 comments
  • 159 respects
Add projectSign up / Login