Contents


Conserve water with the Internet of Things, Part 3

Customize your Cloudant sensor data for client queries, and build an HTML5 app to display the data in a graph

Comments

Important: IBM Internet of Things Foundation (IoT Foundation) is now named IBM Watson IoT Platform. The Bluemix service names have also changed. This article was written using the previous names. The content and images have not been updated. It is provided "as is." Given the rapid evolution of technology, some steps and illustrations may have changed as well.

This third of a three-part tutorial series takes you through construction and configuration of a water-conservation solution — a houseplant soil-moisture monitor — that runs on the Internet of Things. In Part 1, you set up the hardware and used the Internet of Things Foundation Starter on IBM Bluemix™ to build a Node-RED app that stores incoming sensor data in a Cloudant database and sends it from there to Twitter. In Part 2, you secured your Node-RED app and set up automated deployment to Bluemix.

In this final installment, you'll create an open data API to make the data available from the Cloudant data store. Then you'll use the Data-Driven Documents (D3.js) JavaScript library to build an HTML5 app that provides a visualization of the sensor data for desktop and mobile devices:

You'll make the data available for the client app to create a graph that shows the last x days' worth of readings for temperature, moisture, and pressure values for a particular sensor.

What you'll need to build your solution

  • A Bluemix account linked to your IBM ID.
  • Completion of the steps in Part 1 and Part 2 of this tutorial series.
  • HTML and JavaScript experience

Step 1. Prepare the Cloudant data store

In this step, you'll make the sensor readings in the Poseidon Cloudant database available in a format that can be consumed by a client. More specifically, you'll make the data available for the client app to create a graph that shows the last x days' worth of readings for temperature, moisture, and pressure values for a particular sensor.

Every sensor reading that's stored in the database now has the following format:

{"_id":"f15b90c35ac432034b7d08d628f204f9","_rev":"2-9d58792b0ad4e39116572ac811a2d509",
"temperature":21.74,"timestamp":"2014-09-11T20:49:03.950070",
"altitude":167703.6,"clientID":"ExamplePlantSensor",
"pressure":1021.52,"longitude":4.8,"moisture":699,"latitude":50.2}

By default, all readings are sorted by their ID (_id). The first thing to do is to create a new view in Cloudant that sorts the data by using a combined key of sensor name and timestamp. Then you'll be able to do a range lookup for a specific sensor and time range.

  1. Look up the host name, user name, and password of your Cloudant instance:
    1. Log in to Bluemix.
    2. In the dashboard, click the icon of the app that you created in Part 1 of this tutorial series.
    3. Select SDK for Node.js (on the left side).
    4. You can see the environment variables for the services in your Bluemix instance. (They might take a moment to load.) These variables contain the Cloudant host name, user ID, and password that you need in this tutorial:
      {
         "name": "MyPoseidon3:cloudantNoSQLDB",
         "label": "cloudantNoSQLDB",
         "plan": "Shared",
         "credentials": {
            "username": "f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix",
            "password": "11111111111111111111111111111b456b35bd2e609740ae54f83602",
            "host": "f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix.cloudant.com",
            "port": 443,
            "url": "https://f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix:
            801e32c10276a103abb374284d34a9bdfad91b456b35bd2e609740ae54f83602@f8fe0075-9b65-
            49c5-bffd-b67c1fe16260-bluemix.cloudant.com"
         }
      }

      Save this code in a file that you can access easily for copy/paste purposes.
  2. Create a history view in Cloudant:
    1. In your Bluemix instance dashboard, select your Cloudant service.
    2. Click Launch to load the admin user interface for your Cloudant instance.
    3. Click poseidonsensors.
    4. Click the + next to All Design Docs and select New View: Screenshot of a graph that plots monitor results
      Screenshot of a graph that plots monitor results
  3. Fill out the New View form:
    • For Save to Design Document, select New document.
    • In the _/design field, enter sensors.
    • For Index name, enter history.
    • Select None in the optional Reduce field.
    • In the Map function field, enter:
      function(doc) { 
         if(doc.clientID && doc.timestamp) {
            sensor_values = [0, 0, 0];
            if (doc.temperature) {
                  sensor_values[0] = doc.temperature;
            }
            if (doc.moisture) {
                  sensor_values[1] = doc.moisture;
            }
            if (doc.pressure) {
                  sensor_values[2] = doc.pressure;
            }      
            emit([doc.clientID, doc.timestamp], sensor_values);
        }
      }
  4. Click Save & Build index: Screenshot of the Save & Build Index dialog box
    Screenshot of the Save & Build Index dialog box
  5. Test your new view by browsing to:

    https://host/poseidonsensors/_design/sensors/_view/history

    For example: https://f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix.cloudant.com/poseidonsensors/_design/sensors/_view/history).

    You must provide the username and password from substep 1d. (In Step 2, you'll make this data available as open data without username and password.)

    This request returns all documents:

    Screenshot of the list of returned documents
    Screenshot of the list of returned documents
  6. You can limit the list by providing a start and end time through the startkey and endkey parameters. The URL structure becomes:

    https://host/poseidonsensors/_design/sensors/_view/history?startkey=[sensor_id, datetime]&endkey=[sensor_id,datetime]

    For example: https://f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix.cloudant.com/poseidonsensors/_design/sensors/_view/history?startkey=["BramPlantSensor", "2014-10-10T00:00:00.000000"]&endkey=["BramPlantSensor", "2014-11-10T00:00:00.000000"]
  7. Log out of Cloudant, and log back in to refresh the Cloudant admin UI. Now you can see your new history view in the Views list: Screenshot of the Views list
    Screenshot of the Views list
  8. The history view returns all the data you need to create a graph, but you can make it more compact by transforming it into comma-separated value (CSV) format (by using CouchDB list functions):
    1. Click All Design Docs in the Cloudant admin interface.
    2. Click Edit (pencil icon in right upper corner of the document)to edit the design document that you created in this step.
    3. Add the following code to the design document, immediately following the closing bracket of the views code section (don't forget the comma right after the closing bracket). See the GitHub repository for the full example code.
      , 
      "lists": {
          "csv": "function(head, req){ start({ 'headers': { 'Content-Type': 'text/csv' } }); send('timestamp,temperature,moisture,pressure\\u000A'); while(row = getRow()){ send(row.key[1] + ',' + row.value[0] + ',' + row.value[1] + ',' + row.value[2] + '\\u000A'); } }",
          "json": "function (head, req) { provides('json', function() {  var results = []; while (row = getRow()) {  results.push({ name: row.key });}send(JSON.stringify(results));});}"
        }
  9. Test the new lists view in your browser with the URL structure:
    https://host/poseidonsensors/_design/sensors/_list/csv/history?startkey=[sensor_id, datetime]&endkey=[sensor_id,datetime]

    For example: https://f8fe0075-9b65-49c5-bffd-b67c1fe16260-bluemix.cloudant.com/poseidonsensors/_design/sensors/_list/csv/history?startkey=["BramPlantSensor", "2014-10-10T00:00:00.000000"]&endkey=["BramPlantSensor", "2014-11-10T00:00:00.000000"]

    The URL returns a CSV file with sensor readings: Screenshot of the CSV file contents
    Screenshot of the CSV file contents
  10. Create a Cloudant view to expose a JSON list of sensors.
    1. In the Cloudant DB, click the + next to _design/sensors and select New View.
    2. For Index name, enter summary.
    3. In the Map function field, enter:
      function(doc) { 
      if(doc.clientID) {
        emit(doc.clientID, null);
      }
      }
    4. Set the Reduce function to _count and save.
    5. Verify the view works. For example: https://febecb81-4238-4826-a773-5284a4677024-bluemix.cloudant.com/poseidonsensors/_design/sensors/_view/summary?group=true
    6. In the Cloudant web client, go to All design docs and edit the _design/sensors document.
    7. In the lists section, add the json list after the "csv" list definition (don't forget to add a comma at the end of the previous line) and save:
      ,
      "json": "function (head, req) { provides('json', function() {  var results = []; while (row = getRow()) {  results.push({ name: row.key });}send(JSON.stringify(results));});}"
    8. Verify that the list works. For example: https://febecb81-4238-4826-a773-5284a4677024-bluemix.cloudant.com/poseidonsensors/_design/sensors/_list/json/summary?group=true
    9. Verify that the days parameter works by just adding it to the URL. For example: http://poseidontutorial-tftx.mybluemix.net/sensors/F5TX/history?days=1

That's it for this step. You have finished preparing your data store.

Step 2. Create the API

Now you'll design two APIs that enable the visualization app to retrieve its data. The first API retrieves a list of available sensors, and the second retrieves the data from a specific sensor. This table provides the specifications for these APIs:

URLParametersDescription
/sensors No parameters Returns a JSON list of all sensors. For example:
[
{"name":"BramPlantSensor"},
{"name":"KaiPlantSensor"},
{"name":"KaisGrove"},
{"name":"TheGruPi"},
{"name":"TheGruSensor"}
]
/sensors/{sensor}/history Returns a CSV list containing sensor readings for the specified {sensor}. The result is limited to the last 14 days by default, but it can be overwritten.
The history API returns a CSV list containing a history of sensor readings with the timestamp, temperature, moisture, and pressure levels.
For example:
timestamp,temperature,moisture,pressure
2014-10-26T22:14:42.733658,21.14,304,1022.69
2014-10-26T23:44:47.624428,20.74,372,1022.16
2014-10-27T00:44:50.906463,20.63,380,1021.98
2014-10-27T01:14:52.528547,20.5,335,1022.1
2014-10-27T02:14:55.786745,20.39,343,1022.29
2014-10-27T04:45:03.834080,20.1,271,1022.58
2014-10-27T05:45:07.169473,20.87,323,1022.74
sensor Name (unique ID) of the sensor
days Optional. Number of days of sensor readings to return

Use Node-RED to implement the APIs:

  1. Open the PoseidonProject DevOps Services repository and copy the contents of the /Tutorial3/Node-red/API_cloudant_proxy_flow.json file to the clipboard.
  2. Browse to your Bluemix application's public page and click Go to your Node-RED flow editor.
  3. Click the + to create a new worksheet, double-click the tab, and rename the worksheet to REST API.
  4. Select Import > Clipboard from the menu, paste the code, click Ok, and place the proxy flow somewhere on your worksheet.
  5. Click each of the "HTTP in" nodes (Sensor History and Sensor List) to see its configuration in the info tab.
  6. Edit each of the two Convert To Cloudant URL function nodes (double-click the node) and change the cloudantHost variable to match your Cloudant instance.
  7. Update the Cloudant GET node to use basic authentication:
    • Leave the URL field empty (the URL is provided by the previous node).
    • Select the Use basic authentication? check box.
    • For Username, enter the user name of your Cloudant instance.
    • For Password, enter the password of your Cloudant instance.
  8. Explore the properties of the Add CORS Header function node and the HTTP Response node.
  9. Click Deploy to make this proxy flow active.
  10. Test the list-sensors API by browsing to http://poseidon_host/sensors (for example, http://poseidon.mybluemix.net/sensors). You'll receive a JSON list of sensors.
  11. Test the retrieve-history API by browsing to http://poseidon_host/sensors/sensor_id/history (for example, http://poseidon.mybluemix.net/sensors/BramPlantSensor/history). You'll receive a CSV list of sensor values.

Your open data API is now ready for use without authentication.

Step 3. Create the HTML5 app with D3.js

  1. Export the HTML5 code to your local PC:
    1. Browse to the PoseidonProject DevOps Services repository.
    2. Click EDIT CODE. (Log in if necessary.)
    3. Browse to Tutorial3/node-app/public, right-click the public folder in the project tree, and select Export > Zip.
  2. Import the code into your running Bluemix environment:
    1. Browse to the DevOps Services repository for your running Bluemix instance. If you forgot the name, go to your Bluemix dashboard and click EDIT CODE: Screenshot of the app instance in the Bluemix dashboard
      Screenshot of the app instance in the Bluemix dashboard
    2. Browse to //public. Right-click public and select Import File or Zip archive. (By default the import action does not overwrite files, so you'll receive an error message. You only want to add a file, so you can ignore the message.)
  3. Commit the files to Git to trigger the autodeployment process:
    1. In the code editor for your DevOps Services project, click the Git icon (second from the top on the left).
    2. Select all changes.
    3. Enter a commit message (such as new html5 app) and click COMMIT.
    4. Click SYNC to push and sync the commits. This action triggers autodeploy.
    5. Check deployment status by clicking BUILD & DEPLOY on your project's overview page.
  4. Test the app by browsing to http://poseidon_host/sensors.html (for example, http://poseidon.mybluemix.net/sensors.html). You'll see a list of sensors that have already sent sensor readings: Screenshot of the list of sensors
  5. Click one of the sensors to view the graph created with D3.js.

Conclusion to this series

In this final tutorial, you learned how to create customized views on Cloudant and how to create an API proxy using Node-RED. You built an app that consumes the API and presents a graph of the sensor data.

We hope that you have enjoyed this series of Poseidon tutorials. We challenge you to improve the code and contribute your changes back. For example, you could send notifications when your plant needs watering.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Cloud computing, Web development, Open source, Internet of Things
ArticleID=992925
ArticleTitle=Conserve water with the Internet of Things, Part 3
publish-date=07182017