I've been interested in the Amazon Dash button as a generic IoT device since they were introduced. The original branded buttons are a great deal at $5, but using them for other than their intended purpose is a chore. With Amazon's introduction of the generic IoT Button, it is now quite simple to create custom behavior associated with the button. These notes describe how I used one to I create an 'emergency' button for my 103 year old father.
My father is in good shape and still lives alone in his own home, however, I wanted to provide him with a foolproof method of contacting someone for help. There are a lot of options out there, but I couldn't find any that matched my criteria for such a device/service. My criteria:
- Did not require require him to speak / converse
- Did not require anything more than a single button press
- Configurable message content
- Message delivery by any of: SMS, telephone call, email
- Configurable message recipients
This note focuses on Amazon IoT technology, so I'm not going to go into the rationale behind the requirements or the alternatives I considered.
One can use the IoT Button (IOTB) without writing any code. In fact some of Amazon's quickstart documentation will walk you through that. However, manually provisioning an end-to-end system is tedious and can be error prone. It's certainly worth doing it manually the first time, just to see what's happening, but automated provisioning is a necessity on an ongoing basis.
As I intended to put this in production (i.e., use it for my father), I chose to write software to handle the provisioning.
I placed the code in a git repository on GitHub named riprock. It was previously on Bitbucket, but I decided to give GitHub a try. GitHub's markdown is different than that of Bitbucket, so the Readme isn't rendering satisfactorily. You can find a PDF version of the documentation here.
riprock uses Amazon's Boto3 Python library to communicate with AWS for provisioning and testing. I have used Boto for many years with AWS in conjunction with Fabric and Cuisine with great results, although I have migrated to Ansible. Ansible doesn't currently have all the support needed for Lambda, so I used Boto3 directly in riprock.
A warning about the code... it is brittle and single-purpose. It was written mainly as an exploratory effort to understand IOTB and Lambda provisioning - it is not general purpose code for provisioning IOTBs. Having said that, if you are just getting started with IOTB and Lambda, or if you need a very simple messaging system similar to this, it might be a good place to get started with your research.
riprock's documentation is fairly extensive and the code is well-commented. This note doesn't cover the technical aspects of riprock; if you are interested in those, you'll need to head over there. For your convenience, you can find a PDF of riprock's documentation here.
riprock includes all the code necessary to fully provision an AWS to send SMS and email and to make voice calls when an IOTB is pressed. These are the basics of what it does:
Provisioning the IOTB in AWS
- Creates the AWS IoT policy to allow the IOTB to publish messages
- Creates an AWS Thing Type for the IOTB
- Creates an AWS Thing using the IOTB's serial number
- Creates a RSA keypair for the IOTB and issues a X.509 certificate
- Associates the X.509 certificate with the IoT policy created earlier
- Associates the AWS Thing with the X.509 certificate
Testing AWS IOTB Provisioning
riprock has a simple MQTT client that will subscribe to and print all IOTB messages that are published to your AWS account. It also has a simple IOTB simulator that allows one to simulate an IOTB button-press using software. This lets one do basic testing of the AWS provisioning without even having a button on-hand.
Provisioning the IOTB Itself
Before the IOTB can be used, the private key and the X.509 certificate created above must be provisioned into the IOTB. riprock doesn't do that, but the documentation does.
Provisioning AWS Lambda
The previous steps allow the IOTB to post messages to AWS, but says nothing about what happens when the IOTB is pressed. riprock contains a Lambda handler in Python that controls what happens when the button is pressed.
The behavior of the handler is controlled by a YAML file. In the file, one specifies the content of the message to be delivered and to whom it should be delivered. riprock is designed so that the messaging behavior can be changed without modifying the actual Lambda Handler code stored on AWS.
riprock does the following:
- Uploads the YAML messaging behavior specification to S3.
- Creates an AWS IAM Role and associates it with standard IAM Policies that allows the handler to read S3 buckets and write CloudWatch logs.
- Creates a Lambda Handler 'deployment package' by using lambda-uploader.
- Creating a virtualenv.
- Installing the necessary packages in the virtualenv.
- Packaging the handler implementation and virtualenv in a zip file which is the deployment package.
- Uploads the deployment package to Lambda.
- Provides Lambda with the runtime environment necessary to control messaging behavior.
- Associates the Lambda Handler with the IAM Role created earlier.
For convenience, the handler code is designed so that it can be tested on a local development machine before it is uploaded to AWS.
There are a lot of moving parts that must be carefully setup but, overall, the process is fairly simple. Working through all of this and writing example code certainly helped me understand it all.
One comment about messaging... AWS SNS allows one to send SMS messages, and AWS SES allows one to send email, however AWS does not have a service that allows one to place voice calls. The inability to place voice calls was a very large issue for me. Because of that, I ended up writing my Lambda Handler to use Twilio for both SMS and voice messaging.
I should also note that I encountered significant problems with sending SMS via AWS SNS. I had problems with messages either being delivered late (sometimes as much a 15-30 minutes late) or, worse, not being delivered at all. A fair amount of Googling leads me to believe that this is a common problem for many. I'm sure it could have been resolved, but it seemed unnecessary for the immediate need as I had to use Twilio for voice anyway. Twilio is fantastic and messages are delivered almost instantaneously.