Connect Raspberry Pi with AWS IoT

I have been having fun with Raspberry Pi in the past few months, my Pi2 is used to control a RC car and a missile launcher, while my Pi3 is serving as my morning dashboard. Now it is time to continue to journey and connect my Pi3 with AWS IoT.

Step 1: Install Node.js and npm on Pi3:

curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install npm

Step 2: Follow the AWS IoT instructions to create public/private keys, and download the AWS IoT Device SDK.

Step 3: Time to write some code! You can read some examples from the SDK. It sounds confusing but it is important to understand what is “Thing” and “Thing Shadow”. Thing Shadow is basically device metadata in the format of JSON that represents the current state of device. We will need to use this to update AWS IoT. Here is the code I wrote:

const AWS_IOT = require("aws-iot-device-sdk");

const CLIENT_ID = "Pi3";
const THING_NAME = "Pi3";
const CA_CERT = "/home/pi/aws_iot/certs/root-CA.crt";
const CLIENT_CERT = "/home/pi/aws_iot/certs/certificate.pem.crt";
const PRIVATE_KEY = "/home/pi/aws_iot/certs/private.pem.key";

var thingShadows = AWS_IOT.thingShadow({
  keyPath: PRIVATE_KEY,
  certPath: CLIENT_CERT,
  caPath: CA_CERT,
  clientId: CLIENT_ID,
  region: "us-east-1"
});

thingShadows.on("connect", function() {

thingShadows.register(THING_NAME);
console.log("Registered " + THING_NAME);

thingShadows.on("status", function(thingName, stat, clientToken, stateObject) {
  console.log("received status " + stat + " on " + thingName +
    ": " + JSON.stringify(stateObject));
});

thingShadows.on("update", function(thingName, stateObject) {
  console.log("received update " + " on " + thingName +
    ": " + JSON.stringify(stateObject));
});

thingShadows.on("delta", function(thingName, stateObject) {
  console.log("received delta " + " on " + thingName +
    ": " + JSON.stringify(stateObject));
});

thingShadows.on("timeout", function(thingName, clientToken) {
  console.log("received timeout on " + thingName +
    " for token: " + clientToken);
});

});

function getDeviceIPAddress() {
  var os = require('os');

  var interfaces = os.networkInterfaces();
  for (var k in interfaces) {
    for (var k2 in interfaces[k]) {
      var address = interfaces[k][k2];
      if (address.family === 'IPv4' && !address.internal) {
        return address.address;
      }
    }
  }

  return null;
}

var stdin = process.openStdin();
stdin.addListener("data", function(d) {
  var input = d.toString().trim();
  if (input === "quit") {
    console.log("bye-bye!");
    process.exit();
  }

  var stateData = {
    "state": {
    "reported": {
      "status": input,
      "ip": getDeviceIPAddress()
    }
  }
}

thingShadows.update(THING_NAME, stateData);
  console.log("Updated " + THING_NAME + " with data: " +
    JSON.stringify(stateData));
});

By running the program, whatever I type would be seen as the “status” and sent to AWS IoT. The status update is accepted.

pi@raspberrypi3:~/aws_iot $ node pi_example.js 
Registered Pi3
online
Updated Pi3 with data: {"state":{"reported":{"status":"online","ip":"192.168.1.124"}},"clientToken":"Pi3-0"}
received status accepted on Pi3: {"state":{"reported":{"status":"online","ip":"192.168.1.124"}},"metadata":{"reported":{"status":{"timestamp":1465692164},"ip":{"timestamp":1465692164}}},"timestamp":1465692164}

Using the AWS IoT console, clicking Pi3, it will show:

Shadow status: In sync

Step 4: Create a rule when Pi is online, write some data to S3. To keep it simple, I created the following query string:

SELECT * FROM ‘$aws/things/Pi3/shadow/update’

Then set a S3 action that writes a file named “pi_status” in bucket “iot_data”. Now if I run the program again, the file “pi_status” will be created in S3.

That’s it! Now we have Pi3 successfully connected with AWS IoT!

Although AWS IoT is a new service, I wish AWS could have done a better job on documentations, I found several things wrong from the developer guide, confusing and missing contents, and the console error messages are not friendly either.

Next steps:

  • Modify the rule to be able to query JSON object, so that we can publish a message to SNS when Pi is online.
  • Write a Lambda function to acquire Pi’s status.
  • Connect Pi with another device or application via AWS IoT.
Advertisements