How to control an IoT device using AWS in a Node.js application.
Tags: aws, iot, awsiotdevicesdk, node
Published: 2020-05-04 10:40:34

---
title: How to control an IoT device using AWS in a Node.js application.
published: true
description: In this article, I showed how to get started building solutions for IoT devices powered by AWS IoT SDK for Node.js.
tags: #AWS #IoT #aws-iot-device-sdk #node
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/a9yyxwbv1uvn3x0w578n.png
---

I recently have been participating in a hackathon in which we're required to build a smart meter solution for the growing population of prepaid meter users in Nigeria. This project is intended to solve some of the everyday problems of users of these prepaid meter devices, for example, a user should be able to turn the meter on and off from the software we're building.  This, in fact, was exactly my second task as a backend engineer on the project.

I initially picked this story without having a detailed look at the specs so I felt it was going to be an easy endpoint which I could implement by using a device `status` enum on the DB, set it to `ON` by default and then create a `PATCH` endpoint that takes a meter ID and updates the status to `OFF` or `ON` depending... Boy was I wrong.

> Read your spec guys...

Before I continue rambling tho,

# What is an IoT device
It is an acronym which means the Internet of things...


> The internet of things, or IoT, is a system of interrelated computing devices, mechanical and digital machines, objects, animals, or people that are provided with unique identifiers (UIDs) and the ability to transfer data over a network without requiring human-to-human or human-to-computer interaction.

Don't pay much attention to the boring long definition tho, were more focused on the `Things` part.

> A thing, in the context of the Internet of things (IoT), is a representation of a specific device or logical entity. It can be a physical device or sensor (for example, a light bulb or a switch on a wall). It can also be a logical entity like an instance of an application or physical entity that does not connect to AWS IoT but is related to other devices that do (for example, a car that has engine sensors or a control panel).

# The solution

The real solution was to connect my device(the meter) to a cloud-based service like AWS or GCP I went with AWS.

What we really want to do here is connect a physical IoT device to a cloud service like AWS and with some code magic build some form of `ON` and `OFF` switch into the application. Since most of us, won't have access to such hardware to use for full experimenting, The alternative is to create a thing on AWS. This `thing` mirrors a real device and if you ever want to go all the way you can get the hardware anytime and sync it to the `thing` we would be creating on AWS soon.

## Setting up a device(thing) on AWS

- Visit [aws.amazon.com](aws.amazon.com) on the top right, click the `my account` drop-down and select `AWS management console`
- Follow the next few steps to sign in to your account
- After successful login on the top left click on `services` and search for our service of interest `IoT core` once found select and you'll be navigated to this page 👇🏽

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0he8rsy0lbui10jo1t71.png)

From the side nav to your left, click `secure => policies => create`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nzky0cufzp226ec8a5gi.png)

On the Action input field, start typing `*` and select the suggested option. Make sure to fill the form as shown on the screenshot. Scroll to the bottom and click `create`.

Still from  the side nav to your left click `manage => create a single thing`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/abtatx3ijvm7qgoa9k3e.png)

Enter a name for your thing scroll down and click `create type`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/76i7piopj8dq4hpdmapk.png)

After creating a type, you should see a page like 👇🏽, scroll to the bottom and click next

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tu9b0bc40188qpqi59hd.png)

This last action will navigate you to a new page and you'll see a button to `create certificate` click on it and you'll be navigated to this page 👇🏽

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v73kbqxkj7oa5enfu2ny.png)

Make sure to download all 4 keys, using the download buttons. The last download button should be opened in a new tab. we will need them later on. Click `Activate`, scroll down and click `Attach a policy`, this action would redirect you to this page 👇🏽

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1tudb5tn5wxgvznq4qxy.png)

Select the policy we created earlier `myIoTPolicy` and click `Register Thing`

If you can see the screen below 👇🏽 then congratulations you just created a `thing` ready to be controlled by code!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sdmxefrxf956tgd16lk5.png)


# Code

Next, we need to implement a switch that can control the device we just created. To do this we need a few things

- An existing Node.js project(setup one or clone [this] (https://github.com/vic3king/bulljs-email-setup.git) to make your life easier as I would be using it throughout this article.
- AWS-IoT-SDK for node [see docs](https://www.npmjs.com/package/aws-iot-device-sdk#device)

On your console install the SDK by running

```bash
npm i aws-iot-device-sdk
```

Navigate to `server => config`, create a file called `awsConfig.js` and paste the following code

```javascript

import awsIot from 'aws-iot-device-sdk';

const thingShadows = awsIot.thingShadow({
  keyPath: '../../Downloads/63efc683ec-private.pem.key',
  certPath: '../../Downloads/63efc683ec-certificate.pem.crt',
  caPath: '../../Downloads/AmazonRootCA1.pem',
  host: 'a1xfh88u91agm5-ats.iot.us-east-2.amazonaws.com',
  clientId: 'Meter-001',
  region: 'us-east-2',
});

thingShadows.on('status', (thingName, stat, clientToken, stateObject) => {
  console.log(JSON.stringify(stateObject.state));
});

export default { thingShadows };

```

From the code, we simply import `aws-iot-device-sdk`, create a `thingShadow`, and initialize it with the config keys(be sure to switch up the path to point to your own keys), and then we export that instance.

In case you're wondering how to get your `CA_PATH` remember the tab we opened on another window? well if you don't you can visit this [link]( https://www.amazontrust.com/repository/AmazonRootCA1.pem) download the contents and save to a file called `AmazonRootCA1.pem`. The remaining information can be found on your AWS dashboard.

Next, we want to create a controller function. Navigate to the Controllers folder and create a file called `meter.js`, paste the following code

```javascript
import awsService from '../config/awsSwitch';

/**
 * @class MeterController
 */
export default class MeterController {
  /**
   * @method on
   * @description Connects to a device
   * @param {*} req
   * @param {*} res
   * @returns {object} meter
   */
  static async on(req, res) {
    let clientTokenUpdate;

    awsService.thingShadows.register('USER_METER', {}, async () => {
      const userMeterState = {
        state: {
          desired: {
            status: 'ON',
          },
        },
      };
      clientTokenUpdate = awsService.thingShadows.update(
        'USER_METER',
        userMeterState
      );

      if (clientTokenUpdate === null) {
        return res.status(400).send({
          status: false,
          error: 'update shadow failed, operation still in progress',
        });
      }

      return res.status(200).json({
        status: true,
        message: 'Meter successfully connected',
      });
    });
  }

  /**
   * @method off
   * @description Disconnects a running instance of a device
   * @param {*} req
   * @param {*} res
   * @returns {object} meter
   */
  static async off(req, res) {
    awsService.thingShadows.end();

    return res.status(200).json({
      status: true,
      message: 'Meter successfully disconnected',
    });
  }
}
```

 We have two controller functions here `ON` and `OFF` one registers a `thingShadow` and passes in the state `ON` and for  `OFF` we forcefully close the connection.

> A few things to note
-  A thing shadow is an instance of a physical device like we created on AWS. 
- We forcefully close the connection when we call the off endpoint because AWS IoT(to my knowledge) has no form of clean disconnect. what this means, in essence, is that after calling the off endpoint if we need to establish a connection again, we have to restart our server. I have an open issue questioning this design, click [here](https://github.com/aws/aws-iot-device-sdk-js/issues/322)

- Also for simplicity, I won't be including a DB interaction after connecting to a thing, but in a real-world implementation(like what I'm building), you would want to save each `things` details to a DB and link it to a particular user. Your schema for doing that could look something like this 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ez5ocl9d36j75yqr16ey.png)

Finally, we have to create our routes for `On` and `Off` and test our implementation

Navigate to `server => routes` and add a new file `meter.routes.js`, paste the following code

```javascript
import express from 'express';
import controllers from '../controllers';

const meterRoute = express.Router();

const {
  meterController: { on, off },
} = controllers;

meterRoute.patch('/meter/on', on);

meterRoute.patch('/meter/off', off);

export default meterRoute;

```

In the `index.js` file in the same directory replace the existing code with

```javascript 
import express from 'express';

// auth Routes
import authRoute from './auth.routes';

// meter Routes
import meterRoute from './meter.routes';

// express router
const router = express.Router();

router.use('/auth', authRoute);

router.use(meterRoute);

export default router;
```

#Testing our implementation

Start the server by running `npm run start:dev`

> If you hit an error along these lines `Error: premature close`... You may have missed something in your policy setup(Happened to me the first time) Follow this [link](https://docs.aws.amazon.com/iot/latest/developerguide/create-iot-policy.html) to fix it. Or drop a comment 🙂

Finally, using your preferred API testing tool(Insomnia for me). hit the following endpoints

- PATCH `http://localhost:3333/v1/meter/on`
- PATCH `http://localhost:3333/v1/meter/off`

To verify the connection and disconnection of the device 

From your AWS console side nav click on the `activity` button, you should see some changes 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n1w77ivb65gmmmwvi6yz.png)

> This updates real-time as well. so you can keep this tab open hit the endpoints and watch the changes happen.

#Its a wrap 🎉

That's it guys, let me know what you think, how can we improve on this? Your feedback is important!. I will hopefully see this project through and write more articles on cool things we can do with AWS IoT SDK.

Stay safe and wash your hands!