Using IoT-Ignite MQTT Client
MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high latency or unreliable networks. IoT-Ignite platform provides MQTT Client library for connecting things to cloud easily. This library is implemented with JAVA 8. MQTT Client library enables developers to create custom sensors and custom agents for your own IoT Application. In this article, you will learn how to use IoT-Ignite MQTT Client in your own projects easily. MQTT Client Library is explained in IoT-Ignite MQTT Client Library document.
In this sample project, we use an MQTT client running on a Linux computer. This client sends random values to IoT-Ignite Platform.
In order to create MQTT Client, you need:
- IoT-Ignite Devzone account
- Familiarity with Java programming language
- IoT-Ignite MQTT Client Library – Hosted in Github
Creating MQTT Client Credentials
In order to connect MQTT Client to IoT Ignite Platform, you need a client Id, username, and password. This is one time operation for each client. Registration can be completed from a simple web page using REST API provided by IoT-Ignite Platform. These credentials can be created with the API below.
https://api.ardich.com/api/v3/device-admin/register-device
Post credentials in form of JSON below:
{
"deviceId": "{DEVICE_ID}",
"password": "{PASSWORD}",
"username": "{USERNAME}"
}
Parameters
- DEVICE_ID: Unique device id for MQTT Client.
- USERNAME: Unique username for mqtt client.
- PASSWORD: User password.
Usage
Device MQTT Credentials can be registered from Unix-like Operating Systems with the command below.
$ curl -X POST -d 'deviceId={DEVICE_ID}&username=USERNAME&password=PASSWORD&' \
-H “Authorization: Bearer {ACCESS-TOKEN}” \
> https://api.ardich.com/api/v3/device-admin/register-device
ACCESS_TOKEN parameter should be filled according to IoT-Ignite Oauth2 Service Authorization.
Implementing MQTT Client
MQTT Client library can be compiled with Maven easily. In this Project, we use Maven for dependency management and compiling.
Generating Maven POM File for Example Project
Let’s start with creating Maven Project. Add MQTT library dependencies to pom.xml.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>MQTTExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MQTTExample</name>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.example.MQTTExample.App</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.ardic.mqtt</groupId>
<artifactId>mqtt-client-wrapper</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repo.iotingite</id>
<url>https://repo.iot-ignite.com/content/groups/public/</url>
</repository>
</repositories>
</project>
Create Random Number Generator Service
Create Singleton class for generating random values.
import java.util.Random;
import java.util.Date;
import com.ardic.mqtt.client.service.MessagePublisherService;
import com.google.gson.Gson;
public class RandomValueCollector {
public static RandomValueCollector service = new RandomValueCollector();
private RandomValueCollector() {
collectRandomValue();
}
public static RandomValueCollector getInstance() {
return service;
}
private void collectRandomValue() {
MessagePublisherService publisher = MessagePublisherService.getInstance();
while (true) {
Random randomGenerator = new Random();
int value = randomGenerator.nextInt(1000);
sendSensorValue(publisher, value);
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void sendSensorValue(MessagePublisherService publisher, int value) {
}
}
To send generated values to IoT Ignite Platform, we use sendSensorValue function.
Sensor Data Model
We can generate sensor data message with google-gson library. This library can convert Java Objects to JSON format easily. For this operation, we should create 3 classes.
SensorDataValue.java
public class SensorDataValue<T> {
private long date;
private T[] values;
public SensorDataValue(long time, T[] values) {
this.date = time;
this.values = values;
}
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public T[] getValue() {
return values;
}
public void setValue(T[] values) {
this.values = values;
}
}
SensorDataPackage.java
public class SensorDataPackage {
private SensorDataValue[] sensorData;
public SensorDataValue[] getSensorData() {
return sensorData;
}
public void setSensorData(SensorDataValue[] sensorData) {
this.sensorData = sensorData;
}
}
and finally SensorMessage.java
public class SensorMessage {
private SensorDataPackage data;
public SensorDataPackage getData() {
return data;
}
public void setData(SensorDataPackage data) {
this.data = data;
}
}
Let’s use these 3 model to generate a message for publishing. Below code is the implementation of sendSensorValue function in RandomValueCollector.java.
private void sendSensorValue(MessagePublisherService publisher, int value) {
Integer[] valueArray = { value };
SensorDataValue[] dataValue = new SensorDataValue[1];
dataValue[0] = new SensorDataValue(new Date().getTime(), valueArray);
SensorDataPackage dataPackage = new SensorDataPackage();
dataPackage.setSensorData(dataValue);
SensorMessage message = new SensorMessage();
message.setData(dataPackage);
publisher.publishMessage("DeviceProfile/Built-in Sensors/RandomData", new Gson().toJson(message));
}
In this code, we published message to “DeviceProfile/Built-in Sensors/RandomData” topic. With this notation, we named our node as “Built-in Sensors” and we named our sensor as “RandomData“.
Sensor Inventory Model
We should provide RandomData sensor in Sensor Inventory message before sending sensor values to the IoT-Ignite Platform.
Sensor.Java
public class Sensor {
private String id;
private String dataType;
private String vendor;
private boolean actuator;
private String type;
public Sensor(String id, String dataType, String vendor, boolean actuator, String type) {
this.id = id;
this.dataType = dataType;
this.vendor = vendor;
this.actuator = actuator;
this.type = type;
}
public String getId() {
return id;
}
public String getDataType() {
return dataType;
}
public String getVendor() {
return vendor;
}
public boolean isActuator() {
return actuator;
}
public String getType() {
return type;
}
}
Node.Java
import java.util.List;
public class Node {
private String nodeId;
private List things;
public Node(String nodeId, List things) {
this.nodeId = nodeId;
this.things = things;
}
public String getNodeId() {
return nodeId;
}
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
public List getThings() {
return things;
}
public void setThings(List things) {
this.things = things;
}
}
ListSensorData.Java
import java.util.List;
public class ListSensorData {
private List data;
public List
getData() {
return data;
}
public void setData(List data) {
this.data = data;
}
}
Providing Connection Statuses of Nodes and Sensors
IoT-Ignite dashboard can show connection status of the sensors and nodes. To provide connection status, you should send “Device Node Presence” message to IoT-Ignite cloud. In this message, we should list all nodes and sensors in the same json with connection state. We will use Thing.java for creating list items in this message.
public class InventoryItem {
private String nodeId;
private String sensorId;
private String description;
private int connected;
public InventoryItem(String nodeId, String sensorId, String description, int connected) {
this.nodeId = nodeId;
this.sensorId = sensorId;
this.description = description;
this.connected = connected;
}
public String getNodeId() {
return nodeId;
}
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
public String getSensorId() {
return sensorId;
}
public void setSensorId(String sensorId) {
this.sensorId = sensorId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getConnected() {
return connected;
}
public void setConnected(int connected) {
this.connected = connected;
}
}
InventoryItem parameters are defined below:
- nodeId: Node Unique Id
- sensorId: Sensor Unique Id
- description: Description of node or sensor. (Optional)
- connected: Connection status of node or sensor. 1: online, 0:offline
Creating Main Class
Finally, you should create the main class for MqttClient. This main class will initialize MQTT session, then send sensorInventory information and finally start RandomValueGenerator to send sensor value to the IoT-Ignite Platform.
App.java
import java.util.ArrayList;
import java.util.List;
import com.ardic.mqtt.client.service.MessagePublisherService;
import com.ardic.mqtt.client.service.SessionService;
import com.google.gson.Gson;
public class App {
static boolean connectionClose = false;
public static void main(String[] args) {
SessionService session = SessionService.getInstance();
if (session.connect()) {
sendSensorInventory();
initiateAgents();
while (!connectionClose) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
session.disconnect();
System.exit(0);
} else {
System.exit(1);
}
}
private static void sendSensorInventory() {
// Initialize Thing list for DeviceNodePresence message
ListSensorData thingList = new ListSensorData();
thingList.setData(new ArrayList());
// Initialize sensor list
List sensorList = new ArrayList();
Sensor randomSensor = new Sensor("RandomSensor", "INTEGER", "ARDIC", false, "Random Sensor");
sensorList.add(randomSensor);
List nodeList = new ArrayList();
Node builtinNode = new Node("Built-in Sensors", sensorList);
nodeList.add(builtinNode);
// Add "Built-In Sensors" node and "RandomSensor" as online to thingList
thingList.getData().add(new InventoryItem(builtinNode.getNodeId(), null, "", 1));
thingList.getData()
.add(new InventoryItem(builtinNode.getNodeId(), randomSensor.getId(), randomSensor.getType(), 1));
ListSensorData inventory = new ListSensorData();
inventory.setData(nodeList);
// Publish DeviceNodeInventory
MessagePublisherService.getInstance().publishMessage("DeviceProfile/Status/DeviceNodeInventory",
new Gson().toJson(inventory));
// Publish DeviceNodePresence
MessagePublisherService.getInstance().publishMessage("DeviceProfile/Status/DeviceNodePresence",
new Gson().toJson(thingList));
}
private static void initiateAgents() {
RandomValueCollector.getInstance();
}
}
Running MQTT Client
After building operation, maven will create “MQTTExample-1.0.0-with-dependencies.jar” file in “target” directory. MQTT credentials should be provided for running this jar file.
Generate mqtt.properties file with the format below:
MQTT_USERNAME = {mqtt-username}
MQTT_PASSWORD = {mqtt-password}
MQTT_CLIENT_ID = {mqtt-client-id}
After creating configuration file, run jar file with the command below:
$ java -jar MQTTExample-1.0.0-jar-with-dependencies.jar -Dmqtt.properties="./mqtt.configurations"