Digital Experience and the Internet of Things

Recently I created a Digital Experience + Internet of Things concept.  It started when I found a really neat Internet of Things Foundation demo.  Give it a try, and you’ll see your smartphone moving in real-time using only your browser.

IoT Demo AppThis demo is part of IBM’s Internet of Things Foundation  – a service available on Bluemix, which is a platform that provides services like this along with “runtimes” to build applications.  A runtime might be a traditional Java server like WebSphere Liberty or more modern runtimes like Node.js.  Personally I enjoy writing applications in Node.js, but I’d rather build this application in IBM Digital Experience.  A few reasons why:

  • Security.  It seems like every Node.js sample application I see has some comment like /* your authentication code here */.  That stuff is hard … there’s a reason someone didn’t actually write it.
  • Context.  Say we build an IoT application and, we can see data like speed, temperature, movement, etc in real-time.  Alone that’s interesting, but if there’s a problem, a maintenance manual would be helpful.  Or maybe a list of online technicians with relevant skills to assist.  Combining context with content is powerful, but in the “app-only” model more scope means more code.
  • Integration.  An IoT platform is there to obtain and store information from the “things”.  To get that information, you need to use APIs – that’s an integration need.  And then there’s the parsing of data and web presentation and all the stuff – again – that needs to be as simple as possible.

Here’s the concept that I built.  It comes in two forms: an overview page with a list of devices deployed and a detail page that shows specifics about the device.

Let’s dissect the overview page.

IoT Overview PageThe chart and the table are web content.  And both make use of the Digital Data Connector (DDC).  In short, DDC fetches the data from the IoT platform.  It will also parse the incoming data – JSON in this case.  What happens next is the really cool part.  The web developer doesn’t touch the data.  They use placeholders in their HTML to refer to the data – no parsing, no “where did this come from”.  They just know that if they use the “id” placeholder the real value from the data will be shown.  Visually it looks like this: on the left is the web developer writing HTML in Digital Experience and on the right is the raw data a developer using an API would see.  The arrows show how DDC bridges the two.

IoT DDCWhat are some other fun facts?

  • The chart on the left, it’s using DDC and web content too.  But instead of emitting the HTML markup seen in the screenshot, it also emits Javascript code.  And that code works with a Javascript library called Chart.js.
  • The data is being delivered directly to Digital Experience and not to the browser.  This feature is known as the Outbound HTTP Proxy (formerly AJAX Proxy).  It’s an important point because A) to the user, it’s all coming from Digital Experience and B) not all services will allow browser to service (CORS) communication.
  • The Proxy I mentioned also supports authentication to external services.  I was able to exploit the Bluemix demo easily because the user credentials were visible in the web app.  Conversely, Digital Experience allows me to pass the user’s credentials or a shared credential (Credential Vault) to the IoT platform from the server rather than the web app.  Just one more thing that made this easier.

Next, let’s look at the detail page (click it to animate).

IoT Live ViewThe web content you see on the left is contextual.  This is the example I gave earlier – based on what I’m seeing, what else might be helpful to display?

The graph you see with my phone moving up and down is data that is being sent from the IoT platform.  I re-used the Chart.js library from the other page to graph the data points in real-time.  And these data points are being sent via an MQTT Javascript client that is communicating with the IoT platform.

To build the MQTT client, I used IBM’s Script Portlet.  The Script Portlet allows me to write a simple web application using nothing more than a browser.  (It’s like 80 lines of code!)

IoT Script PortletBut rather than use the web editor you see here, I developed the application locally.  This allowed me to use my favorite IDE.  When the app was ready, I simply pushed a button and published it in Digital Experience thanks to the local developer tools.

Now for the technical details.

To use DDC, I would suggest simply reading Stuart’s post on developerWorks.  Here are the properties needed for the WP List Rendering Profile Service.

IoT DDC PropertiesBe careful not to forget importing the SSL certificate for Bluemix and setting the AJAX proxy digital_data_connector_policy URL. Both are documented in the article.  To test the AJAX Proxy (Outbound HTTP Proxy) access the following URL.  You should get data back.

http://<your portal>/wps/proxy/https/play.internetofthings.ibmcloud.com/api/v0002/bulk/devices?_limit=10&hpaa.slotid=iot

The hpaa.slotid=iot is what adds the shared credentials from the Credential Vault to the request.

The MQTT Client application is the following.

  <div style="display:none" data-script-portlet-original-tag="head">
     <script type="text/javascript" src="[Plugin:ScriptPortletElementURL element="js/require.js"]"></script>
<script type="text/javascript">
    requirejs.config({
        baseUrl : "/"
    });
    
    require(["ibmiotf"] , function(Client){
      console.log("loaded IOTF library");
        var data = {
            labels: [],
            datasets: [
        {
            label: "Acceleration (Y)",
            fill: false,
            lineTension: 0.1,
            backgroundColor: "rgba(75,192,192,0.4)",
            borderColor: "rgba(75,192,192,1)",
            borderCapStyle: 'butt',
            borderDash: [],
            borderDashOffset: 0.0,
            borderJoinStyle: 'miter',
            pointBorderColor: "rgba(75,192,192,1)",
            pointBackgroundColor: "#fff",
            pointBorderWidth: 1,
            pointHoverRadius: 5,
            pointHoverBackgroundColor: "rgba(75,192,192,1)",
            pointHoverBorderColor: "rgba(220,220,220,1)",
            pointHoverBorderWidth: 2,
            pointRadius: 1,
            pointHitRadius: 10,
            responsive: false,
            data: [],
        }
            ]
            };

        var ctx = document.getElementById("myChart");
        var myLineChart = new Chart(ctx, {
        type: 'line',
        data: data
        });
            
        var appClientConfig = {
            "org" : "play",
        "id" : "vans-iphone",
        "auth-key" : "<probably should get your own>",
        "auth-token" : "<ditto>"
        }
        
        var appClient = new Client.IotfApplication(appClientConfig);
      
          console.log("loaded IOTF client " + appClient);
      
        appClient.connect();
        
        appClient.on("connect", function () {
            console.log("connected");
            appClient.subscribeToDeviceEvents("iot-phone","vans-iphone","+","json");
        });
        
        appClient.on("deviceEvent", function (deviceType, deviceId, eventType, format, payload) {
            console.log("Device Event from :: "+deviceType+" : "+deviceId+" of event "+eventType+" with payload : "+payload);
            var json = JSON.parse(payload);
            // this is a hack to ensure when the device is offline that the chart does not
            // push new data entries
            if(json.d.ay != data.datasets[0].data[data.datasets[0].data.length-1]) {
                myLineChart.data.labels.push("");
                myLineChart.data.datasets[0].data.push(json.d.ay);
                myLineChart.update();
            }
        });
  });
    </script>
</div>
<div data-script-portlet-original-tag="body">      
    <canvas id="myChart" width="300" height="150"></canvas>
  </div>

Notice this snippet.

requirejs.config({
        baseUrl : "/"
    });

I’m setting the base path for where requirejs will look for the ibmiotf module.  This means the ibmiotf.js file must be at http://<webserver>/ibmiotf.js for example.  In my setup, I placed it on the IBM HTTP server (htdocs folder).  I did this because I had difficulty with getting requirejs to play nicely with the Script Portlet.  The ibmiotf.js module can be found in the dist folder of /iot-nodejs on GitHub (iotf-client-bundle.min.js) .

Chart.js was added as a theme module and profile.  This allowed me to simply change the profile of the overview and detail pages to including the charting functionality.  Be careful that OS files don’t sneak their way to the server (._Chart.js seen in the screenshot).  This usually results in the theme code failing because there’s a foreign file it does not understand.

IoT Chart Theme Modue iot_profileHappy Coding!