MQTT Java Client
MQTT is a light-weight protocol initially developed by IBM for transferring telemetry data. It' based on the publisher-subscriber paradigm: a device can publish data into the system and many receivers can subscribe to get data changes notifications.
Data is published under a unique path named "topic". Subscribers can subscribe to a single topic or to a certain set of topics that match the provided pattern. If the latter is the case, pattern may contain wildcards "." and "#")
Talking specifically about AirVantage, data is published under the topic "messages/json". The data being published is a JSON object whose structure is defined by the application model (see this link for more details)
AirMobile application
For the AirMobile sensor, I defined the following application. The rationale behind this is to have simple streams of sensor data that can be manipulated as a stand-alone entity or mashed-up with other streams. All the streams have a common base structure that includes the following fields
- Latitude
- Longitude
- Sensor value
This should make it easier to accommodate data from other sensors. For example if AirMobile is going to be enhanced by adding a new VOC sensor, the only action required is to append a new stream to the application document. Here is the current AirMobile application
<?xml version="1.0" encoding="ISO-8859-1"?> <app:application xmlns:app="http://www.sierrawireless.com/airvantage/application/1.0" type="com.ag.airmobile" name="AirMobile" revision="0.0.5"> <capabilities> <communication> <protocol comm-id="SERIAL" type="MQTT" /> </communication> <data> <encoding type="MQTT"> <asset default-label="AirMobile Sensor (T)" id="airmobile_temperature"> <variable default-label="Latitude" path="latitude" type="double"/> <variable default-label="Longitude" path="longitude" type="double"/> <variable default-label="Value" path="value" type="double"/> </asset> <asset default-label="AirMobile Sensor (RH)" id="airmobile.humidity"> <variable default-label="Latitude" path="latitude" type="double"/> <variable default-label="Longitude" path="longitude" type="double"/> <variable default-label="Value" path="value" type="double"/> </asset> <asset default-label="AirMobile Sensor (CO)" id="airmobile.co"> <variable default-label="Latitude" path="latitude" type="double"/> <variable default-label="Longitude" path="longitude" type="double"/> <variable default-label="Value" path="value" type="double"/> </asset> <asset default-label="AirMobile Sensor (NO2)" id="airmobile.no2"> <variable default-label="Latitude" path="latitude" type="double"/> <variable default-label="Longitude" path="longitude" type="double"/> <variable default-label="Value" path="value" type="double"/> </asset> <asset default-label="AirMobile Sensor (Dust)" id="airmobile.dust"> <variable default-label="Latitude" path="latitude" type="double"/> <variable default-label="Longitude" path="longitude" type="double"/> <variable default-label="Value" path="value" type="double"/> </asset> </encoding> </data>
Payload creation
According to the AirMobile application, the payload is expected to be as follow
{ "airmobile_temperature.latitude": 45.123, "airmobile_temperature.longitude": 9.111, " airmobile_temperature.value": 25.1 }
The Java code to generate this object is quite straightforward
private String convertToJson(String prefix, SensorData data) { long timestamp = System.currentTimeMillis(); Map<String, List<DataValue>> values = new HashMap<String, List<DataValue>>(); if (data.getValue() != null) values.put(String.format("airmobile_%s.value", prefix), Collections.singletonList(new DataValue(timestamp, data.getValue()))); if (data.getLatitude() != null) { values.put(String.format("airmobile_%s.latitude", prefix), Collections.singletonList(new DataValue(timestamp, data.getLatitude()))); } if (data.getLongitude() != null) { values.put(String.format("airmobile_%s.longitude", prefix), Collections.singletonList(new DataValue(timestamp, data.getLongitude()))); } return gson.toJson(Collections.singletonList(values)); }
The parameter prefix identifies the reading being published. Possible values are
- temperature
- humidity
- no
- co2
- dust
The Java MQTT client can be implemented by leveraging the Paho MQTT library. The steps to implement the client are
1. Create a MqttClient object
this.client = new MqttClient("tcp://" + serverHost + ":1883", MqttClient.generateClientId(), new MemoryPersistence()); client.setCallback(callback); this.opt = new MqttConnectOptions(); opt.setUserName(clientId.toUpperCase()); opt.setPassword(password.toCharArray()); opt.setKeepAliveInterval(30);
serverHost is the AirVantage server URL (na.airvantage.net or eu.airvantage.net dependending if you want to use datacenter in North America or in Europe)
clientId and password are the credentials you provided when you created the system on the AIrVantage portal (more details in this tutorial)
2. Connect
this.client.connect(opt);
3. Push data
String message = this.convertToJson(data); MqttMessage msg = new MqttMessage(message.getBytes("UTF-8")); msg.setQos(0); this.client.publish(opt.getUserName() + "/messages/json", msg);
Testing the MQTT client
To test the MQTT client, I created a minimal Android app. You can see the app in action in the video attached to this post