Contents


Build a cloud-ready temperature sensor with the Arduino Uno and the IBM Watson IoT Platform, Part 2

Write the sketch and connect to the IBM Watson IoT Platform

Comments

Content series:

This content is part # of # in the series: Build a cloud-ready temperature sensor with the Arduino Uno and the IBM Watson IoT Platform, Part 2

Stay tuned for additional content in this series.

This content is part of the series:Build a cloud-ready temperature sensor with the Arduino Uno and the IBM Watson IoT Platform, Part 2

Stay tuned for additional content in this series.

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.

In Part 1 of this four-part tutorial series, I discussed the design of a project for monitoring temperatures in my wiring closet, built by using the Arduino Uno and the Virtuabotix DHT11 temperature sensor. I showed the construction of the circuit for the project and walked you through the installation of the Arduino IDE and how to test out each of the individual components of the project with different Arduino sample sketches. You're now ready to see the design of the sketch that ties the IoT project into the cloud and the steps to enable monitoring of realtime temperature and humidity data remotely. However, first I need to discuss the protocol that you'll use to communicate with the IBM IoT Foundation: MQTT.

What is MQTT?

MQTT (formerly Message Queueing Telemetry Transport) is a lightweight, fast communications protocol designed for the Internet of Things. It has its origins at IBM (where it was originally developed by Andy Stanford-Clark), and it has since been submitted to Organization for the Advancement of Structured Information Standards (OASIS) for standardization, where the current version of the protocol standard is version 3.1. The MQTT V3.1 Protocol Specification specification states that its purpose is to be a "lightweight broker-based publish/subscribe messaging protocol designed to be open, simple, lightweight and easy to implement." In the time since its introduction, the "easy to implement" part has certainly proven to be true, as several different libraries implementing MQTT clients have been developed. You can find links to nearly all of them at the Eclipse Paho project page.

MQTT is perfect for use in embedded devices because it:

  • Is asynchronous, with multiple different levels of quality of service, which is important in cases where Internet connections are unreliable.
  • Sends short, tight messages that make it handy for low-bandwidth situations.
  • Doesn't require much software to implement a client, which makes it great for devices like the Arduino with limited memory.

MQTT is the protocol that the IBM IoT Foundation QuickStart is designed to take input on.

Downloading and installing the Arduino MQTT libraries

In this tutorial, you'll use the built-in features of the IBM Internet of Things Foundation Quickstart to graph the realtime data from the Arduino sensor.

It's just as easy to install the client libraries for MQTT for the Arduino as it is to find and install the libraries that you've already looked at in Part 1 for the specific hardware devices. The particular library to use for your project can be found at the Arduino Client for MQTT website, which describes the library, links to the documentation, and provides another link to GitHub where you can download it.

In my example, I used the V1.9.1 client from the GitHub link. Download the ZIP or TAR file and then extract the PubSubClient directory from the archive into the libraries subdirectory of your Arduino IDE directory. Then restart the Arduino IDE. The PubSubClient>mqtt_auth, PubSubClient>mqtt_basic, and PubSubClient>mqtt_publish_in_callback menu options should be available now, as shown in Figure 1.

Figure 1. PubSubClient menu
Screenshot of the PubSubClient menu options
Screenshot of the PubSubClient menu options

Locally testing MQTT

The process that you've been following so far in this tutorial series is to introduce a new component or technology into the solution and then test it independently to ensure that it's functioning correctly. Now that you've downloaded and installed the MQTT client software, you'll do the same thing for it. However, you still need an additional piece of software to test your client.

MQTT is a broker-based protocol: Clients connect to a broker that mediates the communication between them. In fact, it's a simple process. A set of clients register their interest on a topic with the broker. When another client publishes a message onto that topic, the broker forwards the message to the subscribing clients.

The broker you'll use for local testing is another open source contribution called Mosquitto. You can install it on the local PC that you are using to program the Arduino and then test that the Arduino can communicate with the broker.

Mosquitto

You can download Mosquitto from the Mosquitto website. It is available for Windows®, Mac, and most Linux® variants. Installing it is simple: For Linux, it simply amounts to installing a new package; for Windows, you can install the system as either a Windows service or a separate executable. If you're using Windows, be sure to clear the check box to install as a service. It's easier to run it from the command line because you can more easily view the debug information as it's logged.

After you install Mosquitto, start it from the command line (on any platform) by running the command:

mosquitto -v

The -v flag is for "verbose" logging, which means that you can see information about the connections being made and messages being received or sent. You'll see the result of that in a minute as you start sending messages to the local broker.

Downloading the sample sketch

The next step is to download the sample sketch that pulls together all of the pieces (see Download). You'll publish a message through MQTT to an MQTT broker (first to your local broker, and then to the broker that is part of the IoT Foundation QuickStart). For the IoT Foundation QuickStart to eventually parse and display the sensor data, you must publish it to a topic named iot-2/evt/status/fmt/json. Likewise, you must format the data in a specific way also. If you look at the IoT Foundation QuickStart documentation for the "Connect my device to QuickStart" recipe, you'll see that the data must be in the following JavaScript Object Notation (JSON) format:

{
    "d": {
         "name1": "stringvalue",
         "name2": intvalue,
         ...
    }
}

The sample sketch is a simple program. From the other Arduino samples that I pointed you to in Part 1, you can see that all Arduino programs have the same structure. They include a standard set of functions named setup() and loop(), along with some optional variable declarations and declarations of any utility functions that you use in either your setup() or loop() functions. First, you'll look at the beginning of the code to make a few changes to some of those variable declarations so that you can test the program locally.

Changes to the sample sketch

As with all other Arduino sketches, the very top of the program contains references to the libraries that you use in the sketch:

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <dht11.h>

As you can see, the sketch uses the Ethernet libraries to drive the Ethernet shield and the DHT11 libraries for access to the readings from the DHT11 — as in the examples you looked at in Part 1. However, you're also using the PubSubClient libraries for the first time. To take advantage of these, you need to make a couple of changes to the code to test it against the local server:

// Update this to either the MAC address found on the sticker on your Ethernet shield (newer shields)
// or a different random hexadecimal value (change at least the last four bytes)
byte mac[]    = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
char macstr[] = "deedbafefeed";
// Note this next value is only used if you intend to test against a local MQTT server
byte localserver[] = {192, 168, 1, 98 };
// Update this value to an appropriate open IP on your local network
byte ip[]     = {192, 168, 1, 20 };

As the first comment says, the first change you need to make is to update the mac and macstr variables to match the MAC address of your Ethernet shield. Newer Ethernet shields have this printed on a sticker on the card. If you are using an older card, just randomly change the last four hexadecimal characters to other valid hex values and you should be fine. Next, change the ip variable to be to an open IP address on your local network. The Ethernet libraries are capable of using DHCP, and you can look up how to do that if you're interested, but it's simpler to use fixed IP addresses wherever possible. Next, update the localserver variable to the IP address of the computer on which you are using the Mosquitto server. Finally, you'll update the sketch to connect to your local MQTT server instead of the IBM IoT Foundation QuickStart server.

Locate this section of the code:

// Uncomment this next line and comment out the line after it to test against a local MQTT server
//PubSubClient client(localserver, 1883, 0, ethClient);
PubSubClient client(servername, 1883, callback, ethClient);

Uncomment the line that contains the constructor starting client(localserver and comment out the line below it starting client(servername. Then save the sketch.

Now that you've made the necessary changes, you'll take a quick look at the rest of this simple program. In between the two snippets you've already seen comes a set of variable declarations:

char servername[]="quickstart.messaging.internetofthings.ibmcloud.com";
String clientName = String("d:quickstart:arduino:") + macstr;
String topicName = String("iot-2/evt/status/fmt/json");
dht11 DHT11;
float tempF = 0.0;
float tempC = 0.0;
float humidity = 0.0;
EthernetClient ethClient;

As you can see, there are variables for the temperature in Fahrenheit and Celsius and for the humidity. There's also a variable that will contain the instance of the Ethernet client that will be used by the PubSub client.

Next comes the definition of the setup() function:

void setup()

{
  // Start the Ethernet client, open up serial port for debugging, and attach the DHT11 sensor
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  DHT11.attach(3);
}

This function is quite simple; it starts up the Ethernet client with the provided MAC address and static IP address that the client will run at. It then starts up the serial port (for communication to the Serial Monitor for debugging purposes) and finally opens up communication with DHT11 on pin 3.

The next function to examine is loop(), which is called continuously as long as the Arduino is in operation:

void loop()
{
  char clientStr[34];
  clientName.toCharArray(clientStr,34);
  char topicStr[26];
  topicName.toCharArray(topicStr,26);
  getData();
  if (!client.connected()) {
    Serial.print("Trying to connect to: ");
    Serial.println(clientStr);
    client.connect(clientStr);
  }
  if (client.connected() ) {
    String json = buildJson();
    char jsonStr[200];
    json.toCharArray(jsonStr,200);
    boolean pubresult = client.publish(topicStr,jsonStr);
    Serial.print("attempt to send ");
    Serial.println(jsonStr);
    Serial.print("to ");
    Serial.println(topicStr);
    if (pubresult)
      Serial.println("successfully sent");
    else
      Serial.println("unsuccessfully sent");
  }
  delay(5000);
}

As you can see, most of this function is dedicated to producing debugging output. However, there are a few central elements to notice. Near the top of the function is a call to the getData() function (which you'll examine next) that obtains the sensor data from the DHT11. The loop() function then checks to see if the PubSubClient client is connected. If it's not connected, the loop() function tries to connect to the MQTT broker. If it is connected, then the loop() function formats a JSON string using buildJson() and then publishes that to the MQTT broker by using the publish() method of the PubSubClient. Finally, loop() waits for 5,000 ms at the bottom of the function before the Arduino runtime circles back around and calls the function again.

Next, look at the getData() function:

void getData() {
  int chk = DHT11.read();
  switch (chk)
  {
  case 0:
    Serial.println("Read OK");
    humidity = (float)DHT11.humidity;
    tempF = DHT11.fahrenheit();
    tempC = DHT11.temperature;
    break;
  case -1:
    Serial.println("Checksum error");
    break;
  case -2:
    Serial.println("Time out error");
    break;
  default:
    Serial.println("Unknown error");
    break;
  }
}

This function simply checks the status of the data from the DHT11 library, then reads off the sensor data values if it is ready; otherwise, it prints out an informational message on the console.

Finally, look at the function that formats the JSON output:

String buildJson() {
  String data = "{";
  data+="\n";
  data+= "\"d\": {";
  data+="\n";
  data+="\"myName\": \"Arduino DHT11\",";
  data+="\n";
  data+="\"temperature (F)\": ";
  data+=(int)tempF;
  data+= ",";
  data+="\n";
  data+="\"temperature (C)\": ";
  data+=(int)tempC;
  data+= ",";
  data+="\n";
  data+="\"humidity\": ";
  data+=(int)humidity;
  data+="\n";
  data+="}";
  data+="\n";
  data+="}";
  return data;
}

One of the weaknesses of Processing as implemented in the Arduino is its lack of good facilities for string processing. You might have noticed some of the odd conversions that had to be made between instances of the String class and the string type to call functions expecting one or the other. Likewise, formatting even a simple JSON string like this one can be challenging because of the lack of a good string formatting library — even though such functions exist for formatting output to the console.

Testing against a local Mosquitto broker

Okay, you're almost there with the first part. Now, upload the modified sketch to the Arduino following the procedures for uploading discussed in Part 1. As soon as you see the status "Done uploading." in the status line of the Arduino IDE, open the Serial Monitor by pressing Ctrl-Shift-M.

Validating your output

Now, assuming that everything has gone well, you should see the following type of output in the terminal window where you started Mosquitto:

1405807697: mosquitto version 1.2.3 (build date 22/12/2013 13:36:32.54) starting
1405807697: Using default config.
1405807697: Opening ipv6 listen socket on port 1883.
1405807697: Opening ipv4 listen socket on port 1883.
1405807718: New connection from 192.168.1.20 on port 1883.
1405807718: New client connected from 192.168.1.20 as d:quickstart:arduino:deedb
afefeed (c2, k15).
1405807718: Sending CONNACK to d:quickstart:arduino:deedbafefeed (0)
1405807718: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,
 m0, 'iot-2/evt/status/fmt/json', ... (100 bytes))
1405807723: Socket error on client d:quickstart:arduino:deedbafefeed, disconnect
ing.
1405807723: New connection from 192.168.1.20 on port 1883.
1405807723: New client connected from 192.168.1.20 as d:quickstart:arduino:deedb
afefeed (c2, k15).
1405807723: Sending CONNACK to d:quickstart:arduino:deedbafefeed (0)
1405807723: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,
 m0, 'iot-2/evt/status/fmt/json', ... (100 bytes))
1405807729: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,
 m0, 'iot-2/evt/status/fmt/json', ... (100 bytes))
1405807734: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,
 m0, 'iot-2/evt/status/fmt/json', ... (100 bytes))

The key to knowing that you're getting things right is that you'll see the last few lines about Received PUBLISH from.... That means that the Arduino sketch is successfully connecting to the Mosquitto broker. Now, look over in your Serial Monitor; it should contain messages like the following:

Read OK
Trying to connect to d:quickstart:arduino:deedbafefeed
attempt to send {
"d": {
"myName": "Arduino DHT11",
"temperature (F)": 71,
"temperature (C)": 22,
"humidity": 43
}
}
to iot-2/evt/status/fmt/json
successfully sent

Connecting the Arduino to the IoT Foundation Quickstart

Okay, now that things are working locally, you're ready to try this out against the IoT Foundation QuickStart. In your browser, visit the IBM Internet of Things Foundation website, shown in Figure 2.

Figure 2. IBM IoT Foundation home page

Click the button that says Try it out with our Quickstart. You'll see the page shown in Figure 3.

Figure 3. IBM IoT Foundation Quickstart welcome page

In this tutorial, you'll use the built-in features of the IoT Foundation Quickstart to graph the realtime data from the Arduino sensor.

The IoT Foundation has several existing recipes for other devices. If you have a more sophisticated device such as an Intel Galileo or a Raspberry Pi, you'll want to try those recipes out. For now, simply type in the MAC address of your Arduino. But before you click Go, there's one more change to make in the sketch.

Changing the sketch

Remember back a few instructions ago when you changed the sketch to point to the local MQTT server rather than the MQTT server on the IoT Foundation? Now you're ready to change it back. Comment and uncomment the lines you changed back to the original code:

// Uncomment this next line and comment out the line after it to test against a local MQTT server
//PubSubClient client(localserver, 1883, 0, ethClient);
PubSubClient client(servername, 1883, callback, ethClient);

After you've made this change, save the sketch and upload it to the Arduino. If you want to restart the Serial Monitor, you can, but the real proof will be what you see when you look on the IoT Foundation. Go back to your browser, click the Go button on the Mac address page, and wait a few minutes.

Graphing the data

If things have worked out, you should see a page that displays a graph of your temperature readings, like the one shown in Figure 4.

Figure 4. Graphed data

You've done it! You now have a device that you built that is part of the global IoT. For my particular, simple case, this is all I needed: a graph that I could watch for a few hours to check the temperature inside my wiring closet. The bad news was that even at noon on a hot day, the temperature never budged higher than 73°F, so I'm back to the drawing board on figuring out my problem. But your journey learning how to take advantage of the IoT is just beginning.


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, Open source, Internet of Things
ArticleID=982620
ArticleTitle=Build a cloud-ready temperature sensor with the Arduino Uno and the IBM Watson IoT Platform, Part 2: Write the sketch and connect to the IBM Watson IoT Platform
publish-date=09162014