How to send message from a mosca broker to a mqtt.js client

superjos Source

we setup a MQTT client powered by MQTT.js (either on a desktop PC or on the actual board, is the same) and a MQTT broker powered by mosca, this one running on the desktop PC.

We are able to successfully send a message with a specific topic from client to broker, but now we're stuck on the opposite: send a message from broker to client.

We're following the code samples provided on both project docs, but with no luck. Client is able to correctly register to topic, but does not react in any way when message is sent. Broker is able to correctly send the message and also to listen to its own message, as it's listening for all messages anyway.

Excerpt from MQTT broker:

broker.on('published', function(packet, client) {
  console.log('MQTT broker received message');  // it passes by here
  console.log(' - packet:', packet);
  console.log(' - packet payload:', packet.payload.toString());
});

// ...

var packet = {
  topic: 'our_custom_topic',
  payload: ourCustomPayload,
  qos: 1,
  retain: false,  
};

console.log('MQTT broker sending message to client ...');

broker.publish(packet, function() {
  console.log('Message sent');  // it passes by here
});

Excerpt from MQTT client:

client.on('connect', function () {
  console.log('MQTT client connected');

  client.subscribe('our_custom_topic', { qos: 1 }, function onSubscribe(err, granted) {
    if (err) {
      console.log('subscribe errors:', err);  // no error shown
    }

    if (granted) {
      console.log('subscribe granted:', granted);  // it passes by here
    }
  });
});

// ...

client.on('message', function (topic, message, packet) {
  console.log('MQTT client received message');  // it DOESN'T pass by here
  console.log(' - topic', topic);
  console.log(' - message', JSON.stringify(message));
  console.log(' - packet', JSON.stringify(packet));
});

Update

The problem seems to show up when persistence is based on mongoDb. Instead messages are correctly sent to subscribers when persistence is memory-based. Here are our pub-sub settings when relying persistence on mongoDb. Actually, it's a development instance running on mongolab.com:

var mongoDbSettings = {
  // remote MongoLab mongodb instance
  url: 'mongodb://mqtt-db-user:<OUR-USER-CODE>@<THEIR-INSTANCE-SUBDOMAIN>.mongolab.com:39291/sample-mqtt-datastore',
  pubsubCollection: 'myCollections',
};

var mongoDbBrokerSettings = {
  port: 1883,  // mosca (mqtt) port

  // using ascoltatore over MongoDB
  backend: {
    type: 'mongo',
    url: mongoDbSettings.url,
    pubsubCollection: mongoDbSettings.pubsubCollection,
    mongo: {},
  },
  persistence: {
    factory: mosca.persistence.Mongo,
    url: mongoDbSettings.url,
  }
};

var broker = new mosca.Server(mongoDbBrokerSettings, function onCreated(err, broker) {
  // assume no errors

  console.log('MQTT broker is up and running');
});

does anyone spot anything wrong with that?

javascriptmqttiot

Answers

answered 3 years ago Teixi #1

An MQTT Broker handles messages between clients, does not sent them (except for Last Will Testament special messages).

You have to implement the following:

  • Client A subscribes to a topic: test/one
  • Client B publishes a message to the same topic: test/one
  • Automatically all subscribed clients to this topic (like Client A) will get the message.

But yes in Mosca you can instantiate a client object that acts as an MQTT Client and can publish.

You should debug that this messages are effectively published with an external client like mosquitto_sub or MQTT.fx subscribed to the our_custom_topic.

The persistence should not affect the publishing of messages, but you can install mosquitto and test if using it as backend works https://github.com/mcollina/mosca/wiki/Mosca-advanced-usage

answered 3 years ago aug2uag #2

You can publish directly from the broker, as it's a part of the Mosca public API:

/**
 * Publishes a packet on the MQTT broker.
 *
 * @api public
 * @param {Object} packet The MQTT packet, it should include the
 *                        topic, payload, qos, and retain keys.
 * @param {Object} client The client object (internal)
 * @param {Function} callback The callback
 */
Server.prototype.publish = function publish(packet, client, callback)...

As long as your client is subscribed, you can send via broker.publish({topic:"/foo/bar", payload:'foo'}, client) on the client (i.e. from callback) of the model instance you want to send.

comments powered by Disqus