Overview

Skill Level: Any Skill Level

Entry level to intermediate level

Ingredients

A bluemix account, a Raspberry Pi 2 or 3, a PIR motion sensor

Step-by-step

  1. Github repository for this recipe

    If you’re a savvy Bluemix developer, and you just want to take a look at how to talk to IoT in node.js, just pull my code from this github repository.

     git clone https://github.com/nicolefinnie/iot-nodejs-tutorial  

    And this is the source code of implementing multiple sensors (accelerometers, motion sensors, humidity/temperature sensors and raindrop sensors) on 4 Raspberry Pis hooked up with the IBM IoT platform.

     git clone https://github.com/nicolefinnie/iot-disaster

    Video of our demo

    Otherwise, read on!

    /************************************** WARNING **********************************************
    * python scripts are every sensitive about indentation, the scripts below may not render
    * properly but the scripts in the git repository should be correct.
    ****************************************************************************************************/

  2. Get your Raspberry Pi sensor working!

    The most interesting part of IoT is to wire up your Raspberry Pi. A motion sensor is very good for beginners to learn how Raspberry Pi works with sensors. That’s why I picked this one from the pile of my sensors. My PIR motion sensor can detect within a range of up to 7 metres, the pins from right to left represent Power, High-Low ouput, GND (ground). This is the spec of my PIR motion sensor, you might want to verify yours is similar :

    https://www.mpja.com/download/31227sc.pdf

    In this recipe, I hooked up the blue wire to a 5V port, the yellow to a GND, and the green to GPIO port 4. You can refer to the GPIO mapping here:

    https://www.raspberrypi.org/documentation/usage/gpio/

    Install a helper library wiring Pi that makes controlling GPIO ports very easy

    sudo apt-get update
    sudo apt-get upgrade

    git clone git://git.drogon.net/wiringPi
    cd wiringPi
    ./build

    Install python package manager and IBM IoT library on your raspberry Pi

    sudo apt-get install python-pip
    sudo pip install ibmiotf

    Before connecting your Raspberry Pi with IoT, make sure the hardware is working. You can test your motion sensor running the following scripts.

    motionSensor.py

    #!/usr/bin/python
    # Define setup() that initializes GPIO, and sample() that samples data
    import RPi.GPIO as GPIO

    gpioPort = 0

    def setup(inputPort):
    global gpioPort
    gpioPort = inputPort
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(gpioPort, GPIO.IN, GPIO.PUD_DOWN)

    def sample():
    global gpioPort
    data = {}
    currentState = GPIO.input(gpioPort)
    data['motionDetected'] = currentState
    return data

    testMotionSensor.py

    #!/usr/bin/python
    # It samples the data from the motion sensor every half second

    import motionSensor
    import json
    import time

    gpioPort = 4
    motionSensor.setup(gpioPort)

    while True:
    time.sleep(0.5)
    try:
    motionData = motionSensor.sample()
    jsonData = json.dumps(motionData)
    print "Current motion sensor data:", jsonData
    except Exception as e:
    print "Uh oh, exception!", e

    Run the test script issuing the following command, and don’t forget to wave at your motion sensor. The script will print the current status detected by the motion sensor every 0.5 second.

    pi@hhbear:~/iot-tutorial $ sudo python testMotionSensor.py 
    Current motion sensor data: {"motionDetected": 0}
    Current motion sensor data: {"motionDetected": 0}
    Current motion sensor data: {"motionDetected": 1}
    Current motion sensor data: {"motionDetected": 1}

  3. Register your Raspberry Pi on the IoT platform ( Raspberry Pi

    So, people might wonder how the IoT platform can talk to a Raspberry Pi. Since there are tons of excellent recipes availble on developerWorks, I’ll refer you to the following tutorial, which will walk you through registering your Raspberry Pi on IoT.

    https://developer.ibm.com/recipes/tutorials/raspberry-pi-4/

    Afterwards, let’s check out if you have followed the tutorial properly:

    You should’ve downloaded and executed the IoT library iot_1.0-1_armhf.deb

    curl -LO https://github.com/ibm-messaging/iot-raspberrypi/releases/download/1.0.2/iot_1.0-1_armhf.deb

    You should’ve generated a unique device ID from the unique Mac address via the IoT library run on Raspberry Pi

     b827eb80403e (for example, this is my device ID)  

    An auth-token should’ve been generated when you added your device to the IoT platform.

     auth-token= abcdefg_12345 (the auth-token for your device)

    You created an unbound IoT platform service, and this is how your IoT platform dashboard looks like. Device type raspberrypi is defined by myself. I’ve registered 4 Raspberry Pis in my organization.

    You registered your device on Bluemix. And you can see my device ID b827eb80403e at the very bottom.

    You created a device.cfg on your Raspberry Pi

      /etc/iotsample-raspberrypi/device.cfg

    This is an example of my /etc/iotsample-raspberrypi/device.cfg, you should have filled it in with your own configuration data by now if you followed the recommended tutorial properly. It allows your IoT platform to connect to your Raspberry Pi by exchanging the auth-token.

    org = 273pdc                         # The organization of your IoT platform service
    type = raspberrypi # Your Device Type defined when you add your device to IoT
    id = b827eb80403e # Your Device ID
    auth-method = token
    auth-token = abcdefg_12345 # generated by your IoT platform service when you add a device to it

  4. Generate an API key on the IoT platform ( Raspberry Pi => IoT )

    In the previous step, you’ve seen how IoT hunts your Raspberry Pi down among all other devices on Earth. However, your Raspberry Pi has to talk to the IoT platform somehow. To authenticate your Raspberry Pi, you need to generate an API key on the IoT platform, which gives you an authentication key and an authentication token. When you read here, you might wonder why there are so many keys and tokens – Earth is a dangerous place, you can’t just trust any Raspberry Pi you know.

    On your IoT dashboard, click the button Generate API key

    Ta da! An API key and an authentication token are generated, you just need to add a comment to name the API key. Please take a screenshot of this window, because you won’t get a chance to see it ever again. You will need to store this API key and authentication on your Raspberry Pi in the next step. (Of course I have deleted this API key from my IoT platform, otherwise you could’ve sent your sensor data to my IoT platform 🙂 )

  5. Create a Node.js Bluemix app and bind the IoT service

    Create a node.js web application on Bluemix and bind the app to the unbound IOT platform service you created in the very first step. Ta da! Now you should have an up-and-running Node.js app.

    I’ll skip the steps of how to add a git repository and edit code. If you don’t know how or enounter any problems, see here
    https://hub.jazz.net/tutorials/jazzeditor/

    I’d recommend you install an eclipse plug-in for Bluemix and import this app as a git project to your eclipse workspace. For more details about how to set up your eclipse workspace with this git repository, see here https://hub.jazz.net/docs/gitclient/#eclipse_using_egit

  6. Build a Node.js web application using ibmiotf library

    ibmiotf is a node.js library implemented by IBM that sends MQTT commands under the hood. It facilitates subscribing to multiple devices and publishing events to those devices, so this app is implemented using ibmiotf. For more details, see http://iotf.readthedocs.io/en/latest/applications/libraries/nodejs.html

    app.js is created by Bluemix as the startup script. You can see the definition in package.json, where I also import the library ibmiotf, so Bluemix will install this library for me during deployment.

    package.json

    {
    "name": "NodejsStarterApp",
    "version": "0.0.1",
    "private": true,
    "scripts": {
    "start": "node app.js"
    },
    "dependencies": {
    "express": "4.13.x",
    "cfenv": "1.0.x",
    "ibmiotf":"~0.2.11"
    },
    "repository": {},
    "engines": {
    "node": "4.2.x"
    }
    }

    Connecting to IoT is very simple. First, you need to retrieve the credentials of the IoT service, such as iotCredentialsIdentifier, org, apiKey, apiToken. The credentials stored in Bluemix is very similar to Environment Variables VCAP_SERVICES

    The internal configuration in Bluemix is a bit different (see below). I added two different ways to parse the credentials in app.js, which can be found in the aforementioned github repository. One is parsing VCAP_SERVICES for testing your Node.js app and the IoT service on your local host. The other is parsing the internal configuration for running the Node.js app on Bluemix. However, I’ll only introduce the way to parse the internal configuration in Bluemix.

    Internal configuration in Bluemix ( note the json structure is a bit different than your VCAP_SERVICES in the screenshot above)

    {
    "iot-raspberrypi":
    {
    "name": "iot-raspberrypi",
    "label": "iotf-service",
    "plan": "iotf-service-free",
    "credentials": {
    "iotCredentialsIdentifier": "xxxxxxx",
    "mqtt_host": "273pdc.messaging.internetofthings.ibmcloud.com",
    "mqtt_u_port": 1883,
    "mqtt_s_port": 8883,
    "base_uri": "https://273pdc.internetofthings.ibmcloud.com:443/api/v0001",
    "http_host": "273pdc.internetofthings.ibmcloud.com",
    "org": "273pdc",
    "apiKey": "xxxxxxxxxxxxxxxxx",
    "apiToken": "xxxxxxxxxxxxxxxx"
    }
    }
    }

    app.js – retrieve the credentials of the IoT service defined above

      
    //@attention iot-raspberrypi is the IoT platform service name in this example, you should replace it with yours
    var iotPlatformServiceName = 'iot-raspberrypi';

    // IBM IoT service
    var Client = require('ibmiotf').IotfApplication;

    // this iot service credentials
    var iotCredentials;

    //Loop through configuration internally defined in Bluemix and retrieve the credential from the IoT service
    var baseConfig = appEnv.getServices(iotPlatformServiceName);
    iotCredentials = baseConfig[iotPlatformServiceName];

    var iotAppConfig = {
    "org" : iotCredentials.credentials.org,
    "id" : iotCredentials.credentials.iotCredentialsIdentifier,
    "auth-method" : "apikey",
    "auth-key" : iotCredentials.credentials.apiKey,
    "auth-token" : iotCredentials.credentials.apiToken
    }

    app.js – connect to IoT and subscribe to device events published by client.py on Raspberry Pi

    var appClient = new Client(iotAppConfig);

    appClient.connect();
    console.log("Successfully connected to our IoT service!");

    // subscribe to input events
    appClient.on("connect", function () {
    console.log("subscribe to input events");
    appClient.subscribeToDeviceEvents("raspberrypi");
    });

    var motionSensorData = {"motionPayload":{}};

    // deviceType "raspberrypi" and eventType "motionSensor" are published by client.py on RaspberryPi
    appClient.on("deviceEvent", function(deviceType, deviceId, eventType, format, payload){
    if (eventType === 'motionSensor'){
    motionSensorData.motionPayload = JSON.parse(payload);
    }
    }

  7. Hook up your Raspberry Pi with the IoT Platform

    Now you have all authentication keys and tokens you need, let’s hook up your Raspberry Pi with the IoT platform both ways. Create a device configuration on /home/pi/device.cfg (or wherever) for your RaspberryPi to connect to IoT. This device.cfg is for Raspberry Pi to talk to the IoT platform.

    [application]org=273pdc                                       # your org - same as /etc/iotsample-raspberrypi/device.cfg
    id=b827eb80403e # your device ID - same as /etc/iotsample-raspberrypi/device.cfg
    auth-method=apikey
    auth-key=a-273pdc-idj1eozloh # your API key generated in the step Generate API Key
    auth-token=zEu*MfYu@XGZSdxjjA # your Authentication token generated in the step Generate API Key
    type=raspberrypi # your device type - same as /etc/iotsample-raspberrypi/device.cfg

    At this point, your Raspberry Pi is more than ready to talk to your IoT service. This python script client.py samples the data by calling sample() defined in motionSensor.py. And it connects your Raspberry Pi to IoT and publishes motionSensor events in the JSON form.

    client.py

    #!/usr/bin/python
    # This is only executed on the device client e.g. Raspberry Pi
    import time
    import os, json
    import ibmiotf.application
    import uuid
    import motionSensor

    client = None

    motionSensorGPIOPort = 4


    try:
    options = ibmiotf.application.ParseConfigFile("/home/pi/device.cfg")
    options["deviceId"] = options["id"] options["id"] = "aaa" + options["id"] client = ibmiotf.application.Client(options)
    print "try to connect to IoT"
    client.connect()
    print "connect to IoT successfully"

    motionStatus = False
    motionSensor.setup(motionSensorGPIOPort)


    while True:
    motionData = motionSensor.sample()
    jsonMotionData = json.dumps(motionData)
    client.publishEvent("raspberrypi", options["deviceId"], "motionSensor", "json", jsonMotionData)

    if motionData['motionDetected'] != motionStatus:
    motionStatus = motionData['motionDetected'] print "Change in motion detector status, motionDetected is now:", motionStatus

    time.sleep(0.2)

    except ibmiotf.ConnectionException as e:
    print e

    Check out the dashboard of your IoT platform, you should see lots of motionSensor events constanly coming in.

  8. Implement RESTful APIs to return sensor data to Client (view)

    After subscribing to device events, we need to register RESTful APIs, this is a simple GET example to allow our client(view) to send a GET request to our app. In this GET API, we return the motion sensor data we subscribed to in the previous step.

    app.js

     app.get('/sensordata', raspberryPiServer.returnCurrentSensorData(motionSensorData));

    And this API is implemented in express JS. It does nothing more than just returning the motion sensor data.

    raspberryPiServer.js

     /*eslint-env node */

    /**
    * Server side - express JS - where you should define REST APIs of the server side.
    */
    // client asks server for the sensor data, and server sends back the sensor data
    exports.returnCurrentSensorData = function(sensorData){
    return function(req, res){
    res.send(sensorData);
    };
    };

  9. Client (view) requests sensor data

    The client side code is written in angular.JS, which is pretty popular for web front-end implementation. In this code snippet, you can probably guess it runs an interval task constantly. In this interval task, the client requests the sensor data by calling the GET API implemented in the previous step. When motion is detected, it toggles a switch in the view.

    home.client.html

    <section> 
    <div ng-controller="HomeController" >
    <div class="switch">
    <label>
    No Motion
    <input id="switch" type="checkbox">
    <span class="lever"></span>
    Motion Detected
    </label>
    </div>
    </div>
    </section>

    client.controller.js

    /** Client side - angularJS - where controllers are defined.
    * HTML talks to these controllers.
    */

    var homeControllers = angular.module('HomeControllers', []);

    homeControllers.controller('HomeController', ['$scope', '$rootScope', '$http', '$interval',
    function ($scope, $rootScope, $http, $interval) {

    // Set of all tasks that should be performed periodically
    var runIntervalTasks = function() {
    $http({
    method: 'GET',
    url: '/sensordata'
    }).then(function successCallback(response) {

    if (response.data.motionPayload !== undefined) {
    // switch on when motion is detected
    if(Object.keys(response.data.motionPayload).length > 0){
    var payload = JSON.parse(response.data.motionPayload);
    $('#switch').prop('checked', payload.motionDetected);
    }
    }
    }, function errorCallback(response) {
    console.log("failed to listen to sensor data");
    });
    };
    }
    ]);

  10. A real life test

    So, let’s test the app in real life. Log in to your Raspberry Pi, and start the script client.py

    sudo python client.py 

    Good, no motion is detected for now.

    All of a sudden, an intruder is detected! With this intruder detection app, I’m sure you feel more safe now.

    This is just a basic example. You can extend this app to multiple Raspberry Pis and different sensors and build a more sophisticated GUI.

3 comments on"Build an IoT Bluemix app in Node.js with sensors on Raspberry Pi"

  1. Gurisoft.com January 22, 2017

    Hi. Great article. I wonder if we can have multiple motion sensors (one for each compartment of a house for example) and also what other types of sensors are out there? Smoke sensor, light sensor, humidity and temperature (indoor and outdoors) sensors? Cheers!

  2. Danny Williams March 09, 2017

    Just working through this recipe at the moment. I believe you’re missing a close-bracket “)” at the end of the code snippet “app.js – connect to IoT and subscribe to device events published by client.py on Raspberry Pi”

Join The Discussion