February 10th, 2019
It was days before I was about to become a Dad. I had been graciously given 6 weeks of paternity leave from my work when the baby came, and I wanted to do a cool project with that time. When it was 3am and I was up with our son, I wanted to have something that I can work towards.
The first few weeks of my son's life, the Pediatrician was interested in his diaper count. We could give estimates, or track it on paper, or even use an iOS app to track it. But those felt a tad cumbersome. So! With some excitement and a little late-night AWS architecting, I present to you my solution to easily track anything.
The app that I wanted to create had 2 parts. The first part was the ability to input data easily. To do this, I bought an AWS IOT button (You can buy it on Amazon). The IOT button can receive 3 different inputs: a single click, double click, and a long click. I mapped a single click to a #1 diaper, a double click to a #2 diaper, and a long click to a diaper with both. The IOT button is small, so I attached it to the diaper bag so that whenever we change a diaper, we can quickly press the button while we are doing everything else.
To view the data, I created a website that queries a DynamoDB table, then shows it with a simple React app. I hosted it on a subdomain, and Voilà, my diaper track app was live.
Side note: I decided to word the application with my son's production instead of diaper count. I mean, after all, this is his largest export of goods 😄.
Open up the AWS console and head over to the IOS Core management console and go to 'Manage' -> 'Register a thing'. You will need to download a certificate for your thing, or IOT button. Download the certificate and go ahead and hit the 'activate' button.
The certificate is to authenticate, but you also need to authorize your device, which you next need to do with an IOT policy. To do this, go to 'Secure' -> 'Policies'. You will need to give it a name, as well as two statements with the following action and resource ARNs:
First Statement:
Action: iot:connect Resource ARN: * Effect: Allow
Second Statement:
Action: iot:publish Resource ARN: The topic that our IOT device is going to publish to. This ARN follows this format: arn:aws:iot:<your-region>:<your-aws-account#>:topic/iotbutton/<your-button-serial-number> __Effect: __ Allow
You can find the actual serial number on the device itself. It should be a 16-digit number.
With the policy and certificate created, go to 'Secure' -> 'Certificate' and attach the policy you created to the certificate. This can be done by right clicking on the certificate on the certificates page.
Press and hold the button on your IOT button until it starts blinking blue. This will create a Wireless Access Point that you can connect to on your computer. Navigate to the following address with an internet browser to access the configuration page of your button: http:192.168.0.1/index.html.
Go through the form and set up the Wi-Fi configuration (so the button can access your AWS resources remotely through your home network) and the IOT configuration, using the configuration from your IOT button. If you aren't sure about what any of those fields are, you can view them by going to 'Manage' -> 'Things', click on your device in the console, then go to 'Interact'.
When you have configured your button, head to the 'Test' section of the AWS IOT Core page. You can use the MQTT client to subscribe to your topic. Make sure that underneath the Subscription topic, you use iotbutton/+.
The + is used as a wildcard when subscribing to a topic.
Now, when you click your button, you should see a JSON response for each click. If you aren't seeing it, then go back through these steps and see if you can troubleshoot where the issue is coming from. Double check that your IOT button has connected to your home network and that you successfully configured the certificate and policy above as well.
Before we can save the data that is coming from the IOT button, we need a place to save it. For this, we are going to use DynamoDB. DynamoDB is a great DB for our needs as it is schemaless and easy to use. The schemaless part is especially great when you are tinkering around on a new project and don't want to spend time figuring out your data structure quite yet. DynamoDB is typically my go to database as well as it integrates nicely with other AWS services.
So, head over to the DynamoDB section and create a new table. I suggest using the following values in creating the table:
Table Name: Whatever you would like! Partition Key: id (string) Sort Key: timestamp (string) Table Settings: Just keep the defaults here and go ahead and create the table!
With the table created, we are going to now move on to saving the data into the table.
Whenever the IOT button is pressed, we need to save the response in a database, so that we can query it later on from the website. IOT core is great because it allows us to do connect this all together right inside of IOT core. So, we will start by going to IOT core then on the left side bar, let's go to 'Act' and create a new rule.
When configuring the rule, let's use the following values to make sure that everything is configured correctly.
SELECT * FROM 'iotbutton/XXXXXXXXXXXXXXXX'
I used the following settings when adding my action. In case you are confused about the screenshot that I attached, the '${serialNumber}' is the serial number that is coming from the IOT button click and the '${timestamp()}' is a function that is returning the current timestamp. Make sure that you choose the table that you created in the previous section as well.
With the rule created, we are ready to roll! Go ahead and test it out and if everything works correctly, then the click of your button will now save a new entry into your DynamoDB table.
To query our Dynamo Table, we are going to create a lambda function that will be triggered by API Gateway. First, navigate to Lambda and create a function with a name, and make sure that Node is chosen for the language. I'll be using Node 8.10 for my code which was only just released! How exciting!
Paste in the following code:
let AWS = require("aws-sdk");
let dynamoDb = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
let params = {
TableName: process.env.TABLE_NAME
};
return await new Promise((resolve, reject) => {
dynamoDb.scan(params, (error, data) => {
if (error) {
resolve({
statusCode: 400,
error: `Error: ${error.stack}`
});
} else {
resolve({
statusCode: 200,
body: data.Items
});
}
});
});
};
In the code block, I’m also using an environment variable, so don't forget to also create a TABLE_NAME
environment variable and use your DynamoDB table name for the value.
Lastly, go ahead and test and make sure it is functional. You will need to make sure that you create an execution role for the lambda function to work as well!
API Gateway is an incredibly easy way to create some quick HTTP API Endpoints, so we are going to dive into API Gateway to create them! We don't need to worry about posting or inserting any data, as our application is read-only.
Want to brush up on REST? This Stack Overflow post has some pretty good refreshers! What exactly is restful programming?
Go to the API Gateway console and let’s click ‘Get Started’ or ‘Create New API’. We will be creating the GET endpoint here. Select ‘New API’ and name it something that is relevant to our query.
Now let’s create a new resource on the root level. We don't need to worry about adding in any specific parameters in the resource path because we want our /production endpoint to return everything in our DB!
Now that we have the resource created, we can add our method. Create a method from the actions dropdown, then select ‘GET’ and press the check mark. On the GET Setup, choose your lambda function that you created in the previous section making sure that you have the correct region selected as well. You can test the API here, to make sure that everything is working as well.
It is also important that you enable CORS on our endpoint. Now, in an ideal world you would add the appropriate headers in your lambda so that only your website is able to call your API. Feel free to do that over just enabling CORS.
Finally, let's deploy the API! When you are deploying the API, let's create a 'prod' stage and deploy to that stage. Note your Invoke URL, because we are going to need it in the next section!
I already have a starter project that you can use as a baseline for your own project! You can find all of the code here: https://github.com/drakeloud/IOT-Production-Tracker
Once you clone the project, make sure to do an npm install
and then search in the project for a 'TODO'. You will need to add your invoke URL from the previous section.
I find that the easiest way to actually host a website, especially in AWS, is to use S3. This is incredibly easy, especially when you are using a framework like Angular. To host, you first need to build your Angular project with 'ng build'. Once it is built, in the 'Dist' directory, find all of the files where the index.html is, and put them all onto a new S3 bucket. Setup the S3 bucket for a static website and give it the permissions to be accessed via the web. Then finally, grab the endpoint for your S3 bucket (E.g. http://{bucket-name}.s3-website-{region}.amazonaws.com) and checkout your new site!
Assuming that you were testing as you were going through the instructions, you should now be able to click your IOT button and see the event on your website!
Congratulations on creating your IoT Tracker 👏👏👏!
Playing around with AWS and IOT doesn't need to be something that you only do at school or at work. There are endless possibilities with what can be done, you just need to think creatively, have a desire to be innovative, and find a problem that you can solve with technology!
Want to be notified about new posts?
Then sign up to get posts directly to your email. You can opt-out at any time.