Thingsboard: MQTT-Subscription to internal broker failed (Java/Paho) - java

I have some trouble in subscribing at the topic v1/devices/me/telemetry. I have no problems in subscribing on v1/devices/me/attributes using the paho Java-MQTT-Client. At the attributes-topic I can get new attributes when I post them in the UI. So my Java-Program seems to runs fine (see bottom).
I get the following at the console:
Subscriber running
checking
Mqtt Connecting to broker: tcp://192.168.1.25:1883
Mqtt Connected
MqttException (128)
MqttException (128)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:438)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:406)
at Test.MqttSubscriber.subscribe(MqttSubscriber.java:57)
at Test.MqttSubscriber.main(MqttSubscriber.java:30)
I guess that Error Code 128 means that the subscription was pulled back.
What am I doing wrong? Publishing content to thingsboard at that topic is no problem. Do I have to activate the broker for publishing/subscribing somehow? Does the internal broker of TB need a special command (JSON maybe) to grant a subscribtion? Or do I have to realise it with the IoT gateway (I understand it the way that TB can push data to an external broker - but here a simple subscription is needed)? Which alternative do I have to get device-telemetry from Thingsboard using MQTT?
I hope someone can help :) Thank you!
The Code is (MqttSubscriber.java):
package Test;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class MqttSubscriber implements MqttCallback {
private static final String brokerUrl ="tcp://192.168.1.25:1883"; //Broker
private static final String clientId = "test"; //Client-ID
private static final String topic = "v1/devices/me/telemetry"; //Topic
private static final String user = "AT2"; // Accesstoken/User from Device in TB!
private static final String pw = "test";
private static final char[] password = pw.toCharArray();
public static void main(String[] args) {
System.out.println("Subscriber running");
new MqttSubscriber().subscribe(topic);
}
public void subscribe(String topic) {
MemoryPersistence persistence = new MemoryPersistence();
try
{
MqttClient sampleClient = new MqttClient(brokerUrl, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setUserName(user);
connOpts.setPassword(password);
System.out.println("checking");
System.out.println("Mqtt Connecting to broker: " + brokerUrl);
sampleClient.connect(connOpts);
if (sampleClient.isConnected()==true) System.out.println("Mqtt Connected");
else System.out.println("could not connect");
sampleClient.setCallback(this);
sampleClient.subscribe(topic);
System.out.println("Subscribed");
System.out.println("Listening");
} catch (MqttException me) {
System.out.println(me);
me.printStackTrace();
}
}
//Called when the client lost the connection to the broker
public void connectionLost(Throwable arg0) {
}
//Called when a outgoing publish is complete
public void deliveryComplete(IMqttDeliveryToken arg0) {
}
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("| Topic:" + topic);
System.out.println("| Message: " +message.toString());
System.out.println("-------------------------------------------------");
}
}

As far as I can see the problem is an unsatisfied QoS level.
A subscription without a QoS parameter defaults to QoS == 1. If this QoS is not supported for the requested topic the client throws this exception.
Excerpt from Paho client whereby your call to subscribe(topic) cascades to this subscribe method:
public void subscribe(String[] topicFilters, int[] qos, IMqttMessageListener[] messageListeners) throws MqttException {
IMqttToken tok = aClient.subscribe(topicFilters, qos, null, null, messageListeners);
tok.waitForCompletion(getTimeToWait());
int[] grantedQos = tok.getGrantedQos();
for (int i = 0; i < grantedQos.length; ++i) {
qos[i] = grantedQos[i];
}
if (grantedQos.length == 1 && qos[0] == 0x80) {
throw new MqttException(MqttException.REASON_CODE_SUBSCRIBE_FAILED);
}
}
So you have to check the QoS level of the requested topic and subscribe with that QoS level. Because QoS 1 is rejected I presume the topic is published with QoS 0.

Related

How to identify the MQTT topic that received the message?

The client is subscribed to a x / # topic. There is the possibility of receiving message in the topics x / start and x / stop, and depending on the topic, it performs an action. I wonder how I can identify if it's coming up in the start or stop topic.
In the current code, I send an "action" key in the JSON: "start" or "stop". I want to delete this key and use the format that said above, identifying the topic.
Any further information they deem necessary, please request that I edit the post!
JDK 8
The code:
private MqttCallback callback = new MqttCallback() {
public void connectionLost(Throwable throwable) {
try {
connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
String messageReceived = new String(mqttMessage.getPayload());
actionPerformed(messageReceived);
}
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
};
private void actionPerformed(String message) throws IOException {
ClientDTO clientDTO = new ObjectMapper().readValue(message, ClientDTO.class);
if (clientDTO.getAction().equalsIgnoreCase("start")) {
startView(clientDTO);
} else if (clientDTO.getAction().equalsIgnoreCase("stop")) {
stopView();
}
}
public void connect() throws MqttException {
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName("a_nice_username");
options.setPassword("a_cool_password".toCharArray());
options.setAutomaticReconnect(true);
MqttClient client = new MqttClient("someaddress", MqttClient.generateClientId());
client.setCallback(callback);
try {
client.connect(options);
client.subscribe(topic);
TaskbarIcon.alteraIconeOnline();
} catch (Exception e) {
TaskbarIcon.alteraIconeOffline();
}
}
public void tipoConexao(int tipoConex) throws IOException {
switch (tipoConex) {
case 0:
topic += "/operador/" + getIdReceived() + "/#";
System.out.println(topic);
break;
//etc
}
The s in this method is the topic: public void messageArrived(String s, MqttMessage mqttMessage)
As is very well documented here:
messageArrived
void messageArrived(java.lang.String topic, MqttMessage message) throws java.lang.Exception
This method is called when a message arrives from the server.
This method is invoked synchronously by the MQTT client. An acknowledgment is not sent back to the server until this method
returns cleanly.
If an implementation of this method throws an Exception, then the client will be shut down. When the client is next re-connected, any
QoS 1 or 2 messages will be redelivered by the server.
Any additional messages which arrive while an implementation of this method is running, will build up in memory, and will then back up
on the network.
If an application needs to persist data, then it should ensure the data is persisted prior to returning from this method, as after
returning from this method, the message is considered to have been
delivered, and will not be reproducible.
It is possible to send a new message within an implementation of this callback (for example, a response to this message), but the
implementation must not disconnect the client, as it will be
impossible to send an acknowledgment for the message being processed,
and a deadlock will occur.
Parameters:
topic - name of the topic on the message was published to
message - the actual message.
Throws:
java.lang.Exception - if a terminal error has occurred, and the client should be shut down.

Offline messages are not consumed in Moquette with Paho Client

I have an issue with respect to consuming offline MQTT messages in Moquette server through eclipse Paho client.
Following are the steps which I have followed.
Created and spinned up the Moquette MQTT broker.
Created a simple MQTT consumer application using eclipse Paho client.
Set consumer to consume data on topic : "devices/reported/#" with QOS : 1 and CleanSession : False
Created a simple MQTT data publisher to publish data to MQTT broker using Eclipse Paho.
Used MQTT data publisher to publish messages to : "devices/reported/client_1" topic with QOS : 1
Above steps were successful without any issue.
Then I stopped my consumer application and sent MQTT data to broker with the same topic. using my publisher application - Server was able to receive these messages but in this moment there was no any consumer to consume this message since I have stopped my consumer.
Then I started my consumer application again. It was connected to the broker successfully but, it did not receive any message which I sent to broker while the consumer shutdown.
Do I need to do any specific configuration to my Moquette server to persist data (with clean session : false) ?
Or am I missing something ?
Please find my sample code below,
Moquette Server initialization
package com.gbids.mqtt.moquette.main;
import com.gbids.mqtt.moquette.server.PublishInterceptor;
import io.moquette.interception.InterceptHandler;
import io.moquette.server.Server;
import io.moquette.server.config.IConfig;
import io.moquette.server.config.MemoryConfig;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
public class ServerLauncher {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
final IConfig configs = new MemoryConfig(props);
final Server mqttBroker = new Server();
final List<? extends InterceptHandler> userHandlers = Arrays.asList(new PublishInterceptor());
mqttBroker.startServer(configs, userHandlers);
System.out.println("moquette mqtt broker started, press ctrl-c to shutdown..");
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("stopping moquette mqtt broker..");
mqttBroker.stopServer();
System.out.println("moquette mqtt broker stopped");
}
});
}
}
MQTT Consumer
package com.gbids.mqtt.moquette.main;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class ConsumerLauncher implements MqttCallback {
private static final String topicPrefix = "devices/reported";
private static final String broker = "tcp://0.0.0.0:1883";
private static final String clientIdPrefix = "consumer";
public static void main(String[] args) throws MqttException {
final String clientId = "consumer_1";
MqttClient sampleClient = new MqttClient(broker, clientId, new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(false);
sampleClient.connect(connOpts);
sampleClient.subscribe(topicPrefix + "/#", 1);
sampleClient.setCallback(new ConsumerLauncher());
}
public void connectionLost(Throwable throwable) {
System.out.println("Consumer connection lost : " + throwable.getMessage());
}
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
System.out.println("Message arrived from topic : " + s + " | Message : " + new String(mqttMessage.getPayload()) + " | Message ID : " +mqttMessage.getId());
}
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("Delivery completed from : " + clientIdPrefix + "_1");
}
}
MQTT Publisher
package com.gbids.mqtt.moquette.main;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class ClientLauncher {
private static final String content = "{\"randomData\": 25}";
private static final String willContent = "Client disconnected unexpectedly";
private static final String broker = "tcp://0.0.0.0:1883";
private static final String clientIdPrefix = "client";
public static void main(String[] args) throws Exception{
sendDataWithQOSOne();
System.exit(0);
}
private static void sendDataWithQOSOne(){
try {
final String clientId = "client_1";
MqttClient sampleClient = new MqttClient(broker, clientId, new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(false); // for publisher - this is not needed I think
sampleClient.connect(connOpts);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(1);
final String topic = "devices/reported/" + clientId;
sampleClient.publish(topic, message);
System.out.println("Message published from : " + clientId + " with payload of : " + content);
sampleClient.disconnect();
} catch (MqttException me) {
me.printStackTrace();
}
}
}
In your case you need to set the retained flag to true when creating the MqttMessage in your ClientLauncher (publisher). The default value is false as in the documentation.
...
message.setRetained(true)
...
Setting this flag enables messages to be retained on the broker and be sent to newly connected clients. Please be aware, that the broker only keeps the last message for a topic. There is no way to keep more than one message for a specific topic.

Sending message does not work in XMPP with Smack library

Problem Description
I'm writing chat application using XMPP and Smack Android library. I'm sending messages using code below and everything is working fine.
final ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addChatListener(this);
....
#Override
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(this);
}
#Override
public void processMessage(Chat chat, Message message) {
// Do something here.
}
Chat chat = ChatManager.getInstanceFor(connection).createChat(jid);
chat.sendMessage("message");
Question
Unfortunately the API above is deprecated org.jivesoftware.smack.chat.Chat and instead I should use org.jivesoftware.smack.chat2.Chat, so I am changing implementation as follows
final ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addOutgoingListener(this);
chatManager.addIncomingListener(this);
....
Chat chat = ChatManager.getInstanceFor(connection).chatWith(jid);
chat.send("message");
In this case I can still get Incoming messages, but when I am trying to send message with chat.send("message"); server does not get anything and addOutgoingListener callback is not called.
Any ideas why?
There is an example with an older version of smack:
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
public class Test {
public static void main(String args[]) throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration("127.0.0.1", 5222);
XMPPConnection connection = new XMPPConnection(config);
connection.connect();
connection.login("userx", "123456");
ChatManager cm = connection.getChatManager();
Chat chat = cm.createChat("tongqian#tsw-PC", null);
/*
* add listener
*/
cm.addChatListener(new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean create) {
chat.addMessageListener(new MessageListener() {
#Override
public void processMessage(Chat chat, Message msg) {
System.out.println(chat.getParticipant() + ":" + msg.getBody());
}
});
}
});
chat.sendMessage("hello");
while(true);
//connection.disconnect();
}
}
Answer
Digging a bit deeper I found the answer, the code below will help to send a message
Sending Message Code
final Chat chat = ChatManager.getInstanceFor(connection).chatWith(jid);
Message newMessage = new Message(jid, Message.Type.chat);
newMessage.setBody(message);
chat.send(newMessage);
Conclusion
So instead of sending a string message, you need to create a Message object and I think what is more important is to specify Message.Type.chat in the constructor and also jid and then call chat.send(...)
You can refer to this code snippet:
public void sendMessage(String to, Message newMessage) {
if(chatManager!=null) {
Chat newChat = chatManager.createChat(to);
try {
if (connection.isConnected() && connection.isAuthenticated()) {
newChat.sendMessage(newMessage);
}
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
else
{
Log.d(TAG,”chatmanager is null”);
}
}
And the link is https://ramzandroidarchive.wordpress.com/2016/03/13/send-messages-over-xmpp-using-smack-4-1/ .

ConfirmListener.handleNack is not invoked when exchange is missing

In my application I need to determine whether a message is successfully published into AMQP exchange or some error happens. It seems like Publisher Confirms were invented to address this issue so I started experimenting with them.
For my Java application I used com.rabbitmq:amqp-client:jar:3.5.4 and I chose a very simple scenario when the exchange (where I try to publish) is missing. I expected that ConfirmListener.handleNack is going to be invoked in such case.
Here's my Java code:
package wheleph.rabbitmq_tutorial.confirmed_publishes;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConfirmedPublisher {
private static final Logger logger = LoggerFactory.getLogger(ConfirmedPublisher.class);
private final static String EXCHANGE_NAME = "confirmed.publishes";
public static void main(String[] args) throws IOException, InterruptedException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.confirmSelect();
channel.addConfirmListener(new ConfirmListener() {
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
logger.debug(String.format("Received ack for %d (multiple %b)", deliveryTag, multiple));
}
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
logger.debug(String.format("Received nack for %d (multiple %b)", deliveryTag, multiple));
}
});
for (int i = 0; i < 100; i++) {
String message = "Hello world" + channel.getNextPublishSeqNo();
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
logger.info(" [x] Sent '" + message + "'");
Thread.sleep(2000);
}
channel.close();
connection.close();
}
}
However it's not the case. Log shows that no callback is executed:
17:49:34,988 [main] ConfirmedPublisher - [x] Sent 'Hello world1'
Exception in thread "main" com.rabbitmq.client.AlreadyClosedException: channel is already closed due to channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'confirmed.publishes' in vhost '/', class-id=60, method-id=40)
at com.rabbitmq.client.impl.AMQChannel.ensureIsOpen(AMQChannel.java:195)
at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:309)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:657)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:640)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:631)
at wheleph.rabbitmq_tutorial.confirmed_publishes.ConfirmedPublisher.main(ConfirmedPublisher.java:38)
What's interesting is that pubilsher confirms work as expected when I try to use library for NodeJS amqp-coffee (0.1.24).
Here's my NodeJS code:
var AMQP = require('amqp-coffee');
var connection = new AMQP({host: 'localhost'});
connection.setMaxListeners(0);
console.log('Connection started')
connection.publish('node.confirm.publish', '', 'some message', {deliveryMode: 2, confirm: true}, function(err) {
if (err && err.error && err.error.replyCode === 404) {
console.log('Got 404 error')
} else if (err) {
console.log('Got some error')
} else {
console.log('Message successfully published')
}
})
Here's the output that indicates that the callback is invoked with proper argument:
Connection started
Got 404 error
Am I using com.rabbitmq:amqp-client incorrectly or there's some inconsistency in that library?
It turned out that my assumption was not correct and ConfirmListener.handleNack should not be invoked in this case.
Here's a relevant portion of AMQP messages for the scenario described in the question observed for amqp-coffee library:
ch#1 -> {#method<channel.open>(out-of-band=), null, ""}
ch#1 <- {#method<channel.open-ok>(channel-id=), null, ""}
ch#1 -> {#method<confirm.select>(nowait=false), null, ""}
ch#1 <- {#method<confirm.select-ok>(), null, ""}
ch#1 -> {#method<basic.publish>(ticket=0, exchange=node.confirm.publish, routing-key=, mandatory=false, immediate=false), #contentHeader<basic>(content-type=string/utf8, content-encoding=null, headers=null, delivery-mode=2, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null), "some message"}
ch#1 <- {#method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'node.confirm.publish' in vhost '/', class-id=60, method-id=40), null, ""}
ch#2 -> {#method<channel.open>(out-of-band=), null, ""}
ch#2 <- {#method<channel.open-ok>(channel-id=), null, ""}
ch#2 -> {#method<confirm.select>(nowait=false), null, ""}
ch#2 <- {#method<confirm.select-ok>(), null, ""}
You can see that:
After unsuccessful publish the channel is closed by broker using channel.close that includes the reason.
basic.nack is not sent.
The library automatically opens another channel for subsequent operations.
This behaviour can be implemented in Java using ShutdownListener:
package wheleph.rabbitmq_tutorial.confirmed_publishes;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ShutdownListener;
import com.rabbitmq.client.ShutdownSignalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConfirmedPublisher {
private static final Logger logger = LoggerFactory.getLogger(ConfirmedPublisher.class);
private final static String EXCHANGE_NAME = "confirmed.publishes";
// Beware that proper synchronization of channel is needed because current approach may lead to race conditions
private volatile static Channel channel;
public static void main(String[] args) throws IOException, InterruptedException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
final Connection connection = connectionFactory.newConnection();
for (int i = 0; i < 100; i++) {
if (channel == null) {
createChannel(connection);
}
String message = "Hello world" + i;
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
logger.info(" [x] Sent '" + message + "'");
Thread.sleep(2000);
}
channel.close();
connection.close();
}
private static void createChannel(final Connection connection) throws IOException {
channel = connection.createChannel();
channel.confirmSelect(); // This in fact is not necessary
channel.addShutdownListener(new ShutdownListener() {
public void shutdownCompleted(ShutdownSignalException cause) {
// Beware that proper synchronization is needed here
logger.debug("Handling channel shutdown...", cause);
if (cause.isInitiatedByApplication()) {
logger.debug("Shutdown is initiated by application. Ignoring it.");
} else {
logger.error("Shutdown is NOT initiated by application. Resetting the channel.");
/* We cannot re-initialize channel here directly because ShutdownListener callbacks run in the connection's thread,
so the call to createChannel causes a deadlock since it blocks waiting for a response (whilst the connection's thread
is stuck executing the listener). */
channel = null;
}
}
});
}
}
There're few caveats:
Publisher confirms are not necessary in this case because we don't use ConfirmListener or any other functionality specific to that approach. However publisher confirms would be useful if we wanted to track which messages were successfully send and which not.
If we launch ConfirmedPublisher and after some time create the missing exchange, all following messages will be successfully published. However all the previous failed messages are lost.
Additional synchronization is needed.

MQTT subscribe client doesn't receive messages after connection

I am trying to learn MQTT and have been playing around with it. I've written a client for publishing and a client for subscribing (see below).
If I run the subscribe client and then run the publish client (while subscribe is running), then everything works fine. My subscribe client receives the messages published to the topic correctly.
However, if I run the publish client first (ie. I publish a message to a topic) and then I run the subscribe client, I receive no messages.
In other words, if I connect with the sub client first and then publish messages with the pub client while sub client is connected, everything works fine. However, if I publish a message first, and then connect with my sub client, I receive no messages. My understanding is that I should receive the messages that are present on the topic once I connect with a client and subscribe to the topic.
I found what seems a similar issue: Cannot receive already published messages to subscribed topic on mqtt paho, although that case seems a little different. I've tried changing different QoS setting or cleanSession flag, but that didn't resolve the issue.
Any help would be appreciated!
Publish Client:
public class MQTT_Client_Pub implements MqttCallback{
MqttClient client;
public static void main(String[] args) {
new MQTT_Client_Pub().mqttPub();
}
public void mqttPub(){
try {
this.setConnection();
// Connect
client.connect();
// Create new message
MqttMessage message = new MqttMessage();
message.setPayload("A single test message from b112358".getBytes());
message.setQos(0);
// Publish message to a topic
System.out.println("Publishing a message.");
client.publish("pahodemo/test/b112358", message);
// Disconnect
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
public void setConnection(){
// Client
try{
client = new MqttClient("tcp://iot.eclipse.org:1883", "mqtt_test_b112358_pub");
} catch (MqttException e) {
e.printStackTrace();
}
// Connection Options
MqttConnectOptions options = new MqttConnectOptions();
// Set the will
options.setWill("pahodemo/clienterrors", "CRASHED - CONNECTION NOT CLOSED CLEANLY".getBytes(),2,true);
// Set Callback
client.setCallback(this);
}
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("Message delivered to the broker.");
}
public void messageArrived(String topic, MqttMessage message) throws Exception {}
public void connectionLost(Throwable cause) {}
}
Subscribe Client:
public class MQTT_Client_Sub implements MqttCallback{
MqttClient client;
public static void main(String[] args) {
new MQTT_Client_Sub().mqttSub();
}
public void mqttSub(){
try {
// Set connection
this.setConnection();
// Connect
client.connect();
// Subscribe
client.subscribe("pahodemo/test/b112358", 0);
// Disconnect
// client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
public void setConnection(){
try {
// Client
client = new MqttClient("tcp://iot.eclipse.org:1883", "mqtt_test_b112358_sub");
} catch (MqttException e) {
e.printStackTrace();
}
// Connection Options
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
// Set the will
options.setWill("pahodemo/clienterrors", "CRASHED - CONNECTION NOT CLOSED CLEANLY".getBytes(),2,true);
client.setCallback(this);
}
public void deliveryComplete(IMqttDeliveryToken token) {}
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("Message Arrived: " + message.getPayload() + " on tipic: " + topic.getBytes());
}
public void connectionLost(Throwable cause) {}
}
Messages published before the subscriber connects and subscribes will only be delivered under the following 2 situations
When the messages was published as retained. This means the last message on that topic will be delivered to a new subscriber at the point of subscription. This will only deliver the last message.
If the client had been previously connected and subscribed, then been disconnected. A message is then published and the client connects again with cleansession = false. (and when the subscription is at QOS1/2)
This may help: http://www.thingsprime.com/?p=2897

Categories