DEVELOPERS BLOG

Enterprise Mobile Computing with BlackBerry 10 Apps and the Internet of Things Protocol MQTT: Part 2

FEATURE STORIES / 11.05.13 / mdwrim

automotive 2

In part one of this series, we explored how the Internet of Things (IoT) and Big Data will play a major role in future app development. John Murray and I brainstormed several ideas around how sensor technologies and data collected via mobile applications can have a major effect on the enterprise automotive industry. We also explored why MQTT, the open standards based protocol from IBM, would be the ideal client for building these applications.

So our next job was to implement an MQTT client as a proof of concept for BlackBerry 10 applications. Rather than implement a standalone application, we decided a shared library that could provide an API and be used across multiple applications would be the best approach. We’ll blog about our experience in implementing the MQTT library in a later post, but for now, here’s a glimpse of what the API looks like from the library’s two key header files:

class MqttClient {
private:
       MqttClientImpl *_mqttClientImpl;
public:
       MqttClient(const char *hostName = "localhost", const char *portNumber = "1883");
       virtual ~MqttClient();

       enum QosLevel {AtMostOnce, AtLeastOnce, ExactlyOnce, Undefined};

       void connect(const char *id, const char *willTopic, uint8_t willQos, uint8_t willRetain, const char *willMessage, MqttError &connectError);
       void connect(const uint8_t *id, ssize_t idLen, const uint8_t *willTopic, ssize_t willTopicLen, uint8_t willQos, uint8_t willRetain, const uint8_t *willMessage, ssize_t willMessageLen, MqttError &connectError);

       void connect(const char *id, MqttError &connectError);
       void connect(const uint8_t *id, ssize_t idLen, MqttError &connectError);

       void disconnect(MqttError &disconnectError);

       void publish(const char *topic, const char *payload, MqttError &publishError);
       void publish(const char *topic, const uint8_t *payload, ssize_t plength, MqttError &publishError);
       void publish(const char *topic, const uint8_t *payload, ssize_t plength, uint8_t retained, MqttError &publishError);
       void publish(const uint8_t *topic, ssize_t tlength, const uint8_t *payload, ssize_t plength, MqttError &publishError);
       void publish(const uint8_t *topic, ssize_t tlength, const uint8_t *payload, ssize_t plength, uint8_t retained, MqttError &publishError);

       void setCallbacks(mqttCallbacks_t callbacks);

       void subscribe(const char *topic, MqttError &subscribeError);
       void subscribe(const uint8_t *topic, ssize_t tlength, MqttError &subscribeError);

       void unSubscribe(const char *topic, MqttError &unSubscribeError);
       void unSubscribe(const uint8_t *topic, ssize_t tlength, MqttError &unSubscribeError);

       bool isConnected();

       void setHostname(const char *hostName);
       void setPortNumber(const char *portNumber);

       void setQos(const QosLevel qos);
       QosLevel getQos();
        void getApiVersion(char *version);
};
Figure 1: the MQTT public API methods
#ifndef MQTTCALLBACKS_H_
#define MQTTCALLBACKS_H_

#include <stdint.h>
#include <sys/types.h>

namespace mqtt_client {
typedef void (*mqttSubscription_cb) (const uint8_t *topic, ssize_t tlength, const uint8_t *payload, ssize_t length);
typedef void (*mqttDisconnected_cb) ();
typedef void (*mqttPublish_cb)      (const uint8_t *topic, ssize_t tlength, const uint8_t *payload, ssize_t plength, uint8_t retained);
typedef void (*mqttPubAck_cb)       (uint16_t messageId);
typedef void (*mqttPubRec_cb)       (uint16_t messageId);
typedef void (*mqttPubComp_cb)      (uint16_t messageId);
typedef void (*mqttSubAck_cb)       (uint16_t messageId);
typedef void (*mqttUnSubAck_cb)     (uint16_t messageId);

typedef struct {
       mqttSubscription_cb subscription;
       mqttDisconnected_cb disconnected;
       mqttPublish_cb      publish;
       mqttPubAck_cb       puback;
       mqttPubRec_cb       pubrec;
       mqttPubComp_cb      pubcomp;
       mqttSubAck_cb       suback;
       mqttUnSubAck_cb     unsuback;
} mqttCallbacks_t;
} /* namespace mqtt_client */

#endif /* MQTTCALLBACKS_H_ */

Figure 2: the MQTT call back methods

Having created our API library, the next step was to use it in an application. Initially, we just implemented a test client that allowed us to exercise the main parts of the API. The application is called “TestMqtt,” and it’s available in GitHub. Here are a few screen shots:

TestMqtt on a Q10 device

Figure 3: TestMqtt on a Q10 device

Next, we looked back at our brainstorm notes with the idea that we could develop a “concept demonstration application” based on our automotive ideas. We decided a quick win would be an application that, amongst other things, processed heart rate measurement data emitted by a Bluetooth Smart heart rate monitor embedded in the driver’s seat, and transmitted it over MQTT to the cloud. If you’ve read any of our previous posts, you may know that John and I already released a Bluetooth Smart heart rate application.

Thinking beyond heart rate data, we decided our “concept demonstration application” should illustrate a variety of other ideas from our brainstorm. We also imagined the application running in an in-car mobile computing device powered by the BlackBerry 10 OS. Data collected from sensors in and around the car and driver would be transmitted over MQTT to the enterprise systems and conversely, the enterprise systems would communicate data such as:

  • Geographically relevant data (such as pollen counts)
  • Notifications produced through analysis of:
    • The vehicle’s transmitted data alone
    • Aggregation and analysis of data from all vehicles
    • Information derived by augmenting vehicle and driver data with data from other systems, such as driver health records containing allergy information. We could make notifications as relevant as possible to the individual driver and the location of the vehicle.

We then realized that all these ideas would take a little more time than we had available, so we hard coded ideas for the concept application’s UI in all cases except for the heart rate measurement, which is displayed in the top left hand corner of the screen and published over MQTT to an MQTT broker.

Figure 4 shows our automotive IoT concept architecture:

IoT concept architecture

Figure 4 – IoT concept architecture

Neither John nor I would claim to be the world’s greatest UI designers, and we acknowledge that an in-car console such as the one envisaged would need a really well designed UI. However, this is what we came up with and we hope that if nothing else it serves to illustrate the idea:

AutomotiveMqttConcept application UI

Figure 5 – the AutomotiveMqttConcept application UI

The UI is divided into three columns with driver information first, then information about driving and driving style, and finally, information about the vehicle including current speed and Bluetooth collected tire pressures, which we could color-code to indicate warning conditions.

If you watch our video presentation on this subject, you’ll see the heart rate data being updated live from a Bluetooth Smart heart monitor:

Integrating the concept application with our MQTT API library was really easy. Here’s the key code that achieved this:

// connect to test.mosquitto.org
void HeartMonitor::monitorHeartRate()
{
......

    if (!_mqttClient->isConnected()) {
        MqttError connectError("");
        _mqttClient->setHostname("test.mosquitto.org");
        _mqttClient->connect(QString("MyId-").append(QString::number(qrand() % 30000)).toLatin1().data(), connectError);

        if (connectError.getCode() == MqttError::PASS_CODE) {
            qDebug() << "YYYY MQTT Connected OK";
        } else {
            qDebug() << "YYYY MQTT Connection error: " << connectError.getDescription().data();
        }

    } else {
        qDebug() << "YYYY MQTT Already Connected";
    }
}
void HeartMonitor::logHeartRate(const QVariant &rate)
{
    QMetaObject::invokeMethod(_root, "logHeartRate", Q_ARG(QVariant, rate));

    if (_mqttClient->isConnected()) {
        MqttError publishError("");
        _mqttClient->publish("test/hrm/rate", rate.toByteArray().data(), publishError);
        if (publishError.getCode() == MqttError::PASS_CODE) {
            qDebug() << "YYYY MQTT Published OK";
        } else {
            qDebug() << "YYYY MQTT Publish error: " << publishError.getDescription().data();
        }
    }
}

We hope our article has provided food for thought. Phones are no longer just phones, smart or otherwise, and the era of mobile computing is upon us. Sensors are everywhere, and short-range communications technologies like Bluetooth Smart are making it easy to collect data from sensors. MQTT is well positioned to be the “protocol of choice” for the Internet of Things, and BlackBerry 10 is ready and waiting to form the heart of innovative new systems that blend the personal and mobile computing device with the enterprise, where can derive value Big Data.

Sense. Understand. Adapt

Now go and do that homework!

References

Footnotes

Martin Woolley and John Murray are members of the OASIS MQTT Technical Committee.

About mdwrim