Currently we have an app that controls multiple devices through MQTT. Each device subscribes to a unique topic which is named after their device ID. For example, device A has device ID 123 so it will subscribe to topic 123. Then if the app wants to publish control message to device A, then it will publish a topic named 123, which is the device ID of device A.
By doing this, if we have 1000 devices then we will have 1000 topics. This is a really bad design. So we are thinking that maybe we can publish a topic to a specific client by setting the client ID that will receive the topic since each client that connects to the broker will have to set a client ID. However, we did not find any method that allows publishing to a specific client. And it seems that MQTT doesn't handle such thing. It only publishes to clients subscribing to the same topic.
So, is there any other way that we can do to to achieve one topic, but still able to publish message to specific clients?
Thanks!
There is no way to publish a message to a single subscriber at the MQTT protocol level.
One of the key tenets of a publish/subscribe system is to totally decouple the publisher from the subscribers, there is no way for a publisher to know if there are any subscribers to a given topic let alone target one specifically.
Using a topic for each device is not a problem as there is virtually no overhead in the broker for each topic. You can also use ACLs to ensure that each client can only subscribe their own topic (while still being able to publish to others if needed)
You could use a single topic that all clients subscribe to and encode the target device in the payload and have the device decide if the message is for it's self. One downside to this is that you can't apply ACLs to this model. Another downside is increased network traffic, since uninteresting messages will be sent to many subscribers.
We have managed this within the Mosca MQTT Broker, that is not on protocoll level, but it works fine, by a procedure that the clients send in the course of the subscription a message, containing an options, which controls the forwarding of logging (channel "logger") messages
{"login":{"UserName":"John_Doe","option":["receive_logs"]}}
Retrieve login information and
let LoggedInUsers = {};
server.on('published', function(packet, client) {
let contentstr = packet.payload.toString();
//parse Package Content
let packagecontent = JSON.parse(contentstr);
if (packagecontent.hasOwnProperty('login'))
if (!LoggedInUsers.hasOwnProperty(client.id))
LoggedInUsers[client.id] = packagecontent.login;
}
Provide an individual "authorizeForward", checking if the user is supposed to receive the relevent contents
let authorizeForward = function(client, packet, callback) {
if (packet.topic === "logger" && LoggedInUsers.hasOwnProperty(client.id))
if (LoggedInUsers[client.id].option.indexOf('receive_logs') === -1)
return;
callback(null, true);
};
The next step will be to request the data from a server and read the rights from there...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With