Extending your home IoT network using AWS
Venkat Swaminathan
Ideator, Innovator, Hacker: Connected solutions, AI, IoT, Home Automation, Prototyping
In this post I explain how to access a home automation system securely from the Big Bad World outside using AWS and some open source tools. Some additional knowledge might be required: I will be happy to discuss that in the comments so everyone can participate.
Objective
I have a bunch of devices at home (e.g. lights, water pumps in fish tank) that are controlled using WiFi in the house. These are connected using the home WiFi. We make an assumption that this is secure; even though it's possible and feasible to hack the home WiFi by professionals.
The objective is to be able to make a REST/HTTP call to the device in my house from anywhere in the world in a secure way. "Anywhere in the world" is expected to be my mobile phone when I am traveling, my work location, etc.
Hardware setup
The Sonoff-4ch WiFi switch allows you to switch devices such as lamps, water filters, around the house. These can be controlled using MQTT by sending messages ("Set Switch 1 ON") to specific topics that they listen on. They also publish status of their switches ("Switch 1 is ON") to MQTT topics.
I have an MQTT server running on a Pi Zero that's dedicated this purpose. I can now control these switches from any laptop or phone that's now connected to my home MQTT server. Our problem now is to communicate with this MQTT server. One way is to open up a port in the home wifi router and use VPN and related technologies to set up a secure channel. Seemed like a bit of work to me. And I have to then manage the router and the ports and it all sounds like too much work for me.
AWS to the rescue
Given that I am an ex-AWS employee, and that the only professional certification I have ever bothered to take is that of an AWS Solution Architect, and that AWS has free tiers for most of the services, makes AWS an automatic candidate for all my personal hobby work :-)
Here is an overview of how the various components connect to each other.
AWS IoT
The first service we shall use is AWS IoT. You can configure this service to essentially run an MQTT server in the AWS Cloud. It has a free tier, has security, can scale if needed and is perfect for my use. Once I set up the MQTT server there, I can now configure my home MQTT server that's on the Pi Zero in bridge mode. Bridging two MQTT servers with TLS provides a key-based secure channel between the two. Here's a configuration file on my home server that connects securely to the AWS IoT server.
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
#
# Create a bridge to AWS IoT server
#
connection iotGw
address <your-AWS-IoT-server>.amazonaws.com:8883
bridge_protocol_version mqttv311
bridge_insecure false
cleansession true
clientid bridgeawsiot
start_type automatic
notifications false
log_type all
topic # in 0
bridge_cafile /home/vswamina/certs/root.ca.pem
bridge_certfile /home/vswamina/certs/<yourkey>.cert.pem
bridge_keyfile /home/vswamina/certs/<yourkey>.private.key
We now have our MQTT service securely brought out to the outside world. However you still cannot expose this service publicly because if you you will have no way to control who can access it and what policies you want on it. You may also want a level of abstraction between your device topics on MQTT and the real world control messages that you send.
AWS Lambda
The next service we shall is AWS Lambda. This is a serverless computing model where you can run code on the AWS cloud and you are charged for only the time that the code runs. The Lambda function will call the AWS IoT MQTT server defined earlier and this function will be triggered by a call from AWS API Gateway that we will see in the next section.
We shall write a small code segment in Python to do some basic translation to start with. The actual call to the AWS MQTT server is kept inside the Lambda function.
# Import SDK packages
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import json
def lambda_handler(event, context):
'''Demonstrates a simple HTTP endpoint using API Gateway. You have full
access to the request and response payload, including headers and
status code.
'''
# For certificate based connection
myMQTTClient = AWSIoTMQTTClient("UniqueName")
# allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = False;
# For Websocket connection
# myMQTTClient = AWSIoTMQTTClient("myClientID", useWebsocket=True)
# Configurations
# For TLS mutual authentication
myMQTTClient.configureEndpoint("<your-AWS-IoT-server.amazonaws.com", 8883)
# For Websocket
# myMQTTClient.configureEndpoint("YOUR.ENDPOINT", 443)
myMQTTClient.configureCredentials("root.ca.pem", "private.key", "certificate.pem")
# For Websocket, we only need to configure the root CA
# myMQTTClient.configureCredentials("YOUR/ROOT/CA/PATH")
myMQTTClient.configureOfflinePublishQueueing(5) # Zero offline Publish queueing
myMQTTClient.configureDrainingFrequency(2) # Draining: 2 Hz
myMQTTClient.configureConnectDisconnectTimeout(2) # 10 sec
myMQTTClient.configureMQTTOperationTimeout(5) # 5 sec
myMQTTClient.connect(5)
if event['body'] is not None:
print(event)
body = json.loads(event['body'])
device = body['device']
number = body['number']
action = body['action']
out = {}
out['statusCode'] = "200"
out['body'] = "OK"
topic = "cmnd/"+device+"/power"+str(number)
payload = action
myMQTTClient.publish(topic, payload, 0)
myMQTTClient.disconnect()
return out
We now have the ability to call a method in the cloud and pass it some high level data, e.g. "Turn light 1 on". This method knows which switch controls "Light 1" and where the MQTT server is located. We now have a higher level of abstraction.
AWS API Gateway
The last step to opening up the whole interface is to use AWS API Gateway to manage the service. We shall create an API and then point that API to the Lambda code that we created earlier. The API Gateway provides token based security and additional features such as throttling. This ensures that (a) I can't have someone, either by accident or deliberately, turning on my lights 10,000 times a second, and (b) without a key or token, the API is not accessible by anyone.
What we now have is the ability for someone with the authorized access to be able to control devices in my house. This interface is secure, scalable and you pay only for what you use. Welcome to the new world of serverless computing for IoT devices.
Giving back... at Karibtech Foundation
7 年Nice, but why Python? :)