The inspiration and motivation for this project was the fact that although you can typically control home IoT devices from a mobile app, or from a device such as Amazon Alexa, it is not always convenient. Having to get out your phone and log into the app just to switch the lights on or off is not ideal. It is much more convenient to use a device such as the AWS IoT button for such purpose! This goal of this project was therefore to get the AWS IoT button to control an IoT smart plug, in this case a TP-Link HS110, using the AWS IoT service into which the button seamlessly integrates.
What it does
This project demonstrates how to use the AWS IoT button to control an IoT smart plug, in this case a TP-Link HS110, using the AWS IoT service. It allows to switch the smart plug ON by pressing the IoT button once, and OFF by pressing it twice.
There may be a few ways of achieving this. However, in case of TP-Link smart home devices, TP-Link provides a RESTful web API which can be called directly to control your devices, and which is used in this project.
As part of the project setup the AWS IoT button is configured to connect to the AWS IoT service and the HS110 smart plug is registered in the TP-Link IoT cloud service. When pressed, the AWS IoT button it invokes an AWS lambda function, passing in arguments including the button serial number and type of press (short, double or long). The lambda function, provided as part of this project, interprets the data passed from the AWS IoT button and invokes the TP-Link API to change the relay state of the registered IoT smart plug.
Note that there is no demo that you can just run without setting everything up for yourself - this is because you need to use your own IoT button and own smart plug to control, and they need to be paired by providing your own credentials. You therefore need to follow detailed setup instructions in the README file in the linked GitHub repository to get it working.
How I built it and how it works
As a prerequisite, you need to set up an AWS account (https://console.aws.amazon.com/). You then need to configure your AWS IoT button to work with AWS - most of the AWS related setup is done automatically when you use the AWS IoT button wizard (https://aws.amazon.com/iotbutton/getting-started/), although you can do it manually if you wish to - it is however not in scope of this project to go through details of manual AWS IoT configuration.
As part of the AWS IoT button setup, an AWS Lambda function is created, which receives data from the AWS IoT button (when pressed) and by default sends a notification email to the user. The code of this function should be overwritten by one provided as part of this project (written in Python 2.7), or another Lambda function can be created and registered in the AWS IoT rules engine as an action to be triggered when the AWS IoT button posts a message to the AWS IoT message broker.
All key actions performed from when you press the AWS IoT button to when the IoT smart plug changes state are shown in the diagram below.
When the button is pressed it wakes up, connects to the WiFi network on which it is configured to work, establishes a secure connection with the AWS IoT service platform and sends a message to it with information (as JSON) such as the button's serial number, and the press type - short, double or long.
The message is then passed to the AWS IoT platform which checks whether the button can access certain AWS IoT resources and processes the message, checking if it matches any of the processing rules configured.
Following one of the configured rules, the AWS IoT platform then executes the Lambda function registered as an action to perform when a message from the AWS IoT button with a matching topic (iotbutton/<serial nr of the button>) is received.
The code for this AWS Lambda function is the centerpiece of the project. When run, having received data from the AWS IoT button (as JSON), the Lambda function invokes the TP-Link web API to control the HS110 smart plug. It uses your TP-Link cloud credentials, which you have to provide in the Lambda function, to log into the TP-Link web service, get a list of your registered devices, and ask the service to change the relay state of the smart plug.
The TP-Link cloud communicates with the smart plug back through the WiFi Access Point (6) and instructs it to change relay status accordingly.
The code is in Python and I used Visual Studio 2015 Community Edition to write and test it, however you just need any Python environment to edit it and experiment with it. Please refer to detailed instructions in the README file in the GitHub repository.
Challenges I ran into
One of the main challenges was that the TP-Link web API is not really documented, and it takes some research and experimenting to work it out. There is also a risk that if TP-Link decides to change the API in a non-backwards compatible way (however unlikely that might be), the solution will need to be modified accordingly.
Accomplishments that I'm proud of
I did it! It's great to use the button and see it work flawlessly end-to-end over multiple servers and APIs.
What I learned
I learned that the AWS IoT framework allows you to set up, use and control IoT devices easily, especially using the AWS IoT button setup wizard provided. Having even rudimentary knowledge of AWS, the IoT framework, and services such as Lambda allows to put together a software framework controlling your IoT devices in little time - security and communication is taken care of for you and you have to focus mainly on implementing the necessary logic in the control function.
I also learned that although IoT devices are often designed for long life and ubiquitous access, there is a price to pay for that which you need to understand designing an IoT based solution. One factor is the time required to set up communication between the devices, as it may require waking them up from "deep sleep" and establishing secure connections via sometimes multiple relays. It takes up to a few seconds between the AWS IoT button is pressed and the smart plug reacts. While it is acceptable in this case, there might be other applications where the connection setup time might have to be well considered in the design.
One last thing to reflect on is security. The more we depend on IoT, the more risk there is that an intruder being able to get access to control those devices could cause serious disruption or even damage. There may be several systems and servers involved in communication, as in this project, and a weakness in one of the links can break the whole chain. While AWS provides strong security by default, software architects and developers have to take care of other security aspects such as e.g. credentials stored explicitly in lambda functions.
The currently implemented Lambda function controls just a single device. In the next step it can however be extended to control several IoT devices, potentially controlling the entire smart home. This can be done by matching the serial number of the AWS IoT button used, which is passed in the IoT message sent by the button and as an argument into the lambda function, with the ID and name of the TP-Link IoT device to control. It can also be extended to control IoT devices from other manufacturers, or interact with services such as IFTTT.
Additionally, as mentioned in the section above, some security aspects of the solution may need improvement - in particular a better way of storing TP-Link access credentials can be considered than putting them as plaintext in the Lambda function.