Simple communication via MQTT between node apps - node.js

Hi I'm really new to MQTT and I've read a lot of posts and blogs about it the last days, yet I seem not to fully understand the different parts needed, such as Broker, Clients.
I want two node apps to communicate with each other via a local mqtt service. As far as I understand, this mqtt service is called broker. I managed it to let 2 node apps communicate via a public broker like this:
app1 (sender)
const mqtt = require('mqtt');
// to be changed to own local server/service
const client = mqtt.connect('http://broker.hivemq.com');
client.on('connect', () => {
let id = 0;
setInterval(() => {
client.publish('myTopic', 'my message - ' + ++id);
}, 3000);
});
app2 (receiver)
const mqtt = require('mqtt');
// to be changed to own local server/service
const client = mqtt.connect('http://broker.hivemq.com');
client.on('connect', () => {
client.subscribe('myTopic');
});
client.on('message', (topic, message) => {
console.log('MSG: %s: %s', topic, message);
});
As this worked, I wanted to move on by replacing the public broker with a private one. After a while I found mqtt-server as a node package.
So I tried the following as a third node app, which is supposed to be the broker for app1 and app2:
server (MQTT broker)
fs = require('fs');
mqttServer = require('mqtt-server');
let subscriptions = [];
let servers = mqttServer(
// servers to start
{
mqtt: 'tcp://127.0.0.1:1883',
mqttws: 'ws://127.0.0.1:1884',
},
// options
{
emitEvents: true
},
// client handler
function (client) {
client.connack({
returnCode: 0
});
client.on('publish', (msg) => {
let topic = msg.topic;
let content = msg.payload.toString();
// this works, it outputs the topic and the message.
// problem is: app2 does not receive them.
// do we have to forward them somehow here?
console.log(topic, content);
});
client.on('subscribe', (sub) => {
let newSubscription = sub.subscriptions[0];
subscriptions.push(newSubscription);
console.log('New subscriber to topic:', newSubscription.topic);
});
});
servers.listen(function () {
console.log('MQTT servers now listening.');
});
Problem
After adjusting the connection-Uris (both to ws://127.0.0.1:1884) in app1 and app2 The server app receives all messages that are published and recognises that someone connected and listens to a specific topic.
But: While the server gets all those events/messages, app2 does not receive those messages anymore. Deducing that, something with this broker must be wrong, since using the public broker everything works just fine.
Any help is appreciated! Thanks in advance.

I can't get mqtt-server to work either, so try Mosca.
Mosca only needs a back end if you want to send QOS1/2 messages, it will work with out one.
var mosca = require('mosca');
var settings = {
port:1883
}
var server = new mosca.Server(settings);
server.on('ready', function(){
console.log("ready");
});
That will start a mqtt broker on port 1883
You need to make sure your clients are connecting with raw mqtt not websockets, so makes sure the urls start mqtt://

Related

Connect node JS server to remote laravel-echo-server channel

I have two servers, server 1 hosting laravel echo and server 2 hosting NodeJS. I want server 2 to be able to listen and transmit on a laravel-echo channel which is in server 1.
Anyone have an idea on how to proceed?
I tested with socket IO but I don't receive the events emitted from laravel echo server.
Here is the code I am using
const io = require('socket.io-client');
const socket = io('http://localhost:6001');
socket.on('*', (data) => {
console.log(data);
});
socket.emit('subscribe', {
channel: 'licence-update-7e32cd49-8714-42bf-804b-d823c5698ecc'
});
socket.on('connect', () => {
socket.emit('subscribe', {
// channel: 'private-channel',
channel: 'licence-update-7e32cd49-8714-42bf-804b-d823c5698ecc'
// auth: Cache.get('private-channel:socket-id')
});
});
socket.on('event-name', (data) => {
console.log(data);
});
the code executes but I do not receive a notification.
I want server 2 to be notified whenever there are actions on server 1 and vice versa.
Works using version socket.io.client version 2.4.0 of laravel-echo-client

Is there any way to receive event when new client connect and disconnect?

We are using node as a server and mqtt as a library.
we installed mosquitto as a brocker for web socket.
Now we have to track record when new client connect and disconnect but problem is that we unable to get any event.
so Is there any way to achieve this ?
const mqttServer = require('mqtt');
const clientId = appName + "_" + moment().valueOf();
const conOptions = {
clientId,
username: mqtt.user,
password: mqtt.pass,
keepalive: 10,
clean: false,
rejectUnauthorized: false
};
const conUrl = mqtt.uri;
const mqttClient = mqttServer.connect(conUrl, conOptions);
mqttClient.on("error", (err) => {
logger.error(`${chalk.red('✗')} MQTT Error : `, err);
});
mqttClient.on('offline', () => {
logger.error(`${chalk.red('✗')} MQTT Offline`);
});
mqttClient.on('reconnect', () => {
logger.error(`${chalk.red('✗')} MQTT Reconnect`);
});
mqttClient.on('connect', () => {
logger.info(`${chalk.green('✓')} MQTT Connected with ClientID ${chalk.yellow(clientId)}`);
});
mqttClient.on('message', (topic, message) => {
logger.error(`New message in MQTT : ${message.toString()} on ${topic}`);
});
Why not just have each client publish their own message when they connect/disconnect.
This allows you to control exactly what is in the message.
You can send the disconnect message before you tell the client to disconnect.
Also you can also make use of the Last Will & Testament to have the broker publish (after the KeepAlive has expired) a message on the client's behalf if it is disconnected due to a crash/network failure.
This technique will work with any browser.

Ionic 4 chat application and how to send message to particular user?

I created application in Ionic 4, and for backend I use Lumen. Application should have chat page and in that purpose I add Redis, Socket.io and nodejs. I successfully created public room, and chat between users in that room works. Problem is how to send private message for user, how to initialize users for their private room.
This is how I created public room:
constructor(private socket: Socket) {
this.getMessages().subscribe(message => {
this.messages.push(message);
});
}
getMessages() {
const observable = new Observable(observer => {
this.socket.on('message', (data) => {
observer.next(data);
});
});
return observable;
}
I send message from Lumen application and Redis:
public function sendMessage()
{
$redis = Redis::Connection();
$sendMessage = json_encode(['user' => 'John Doe', 'text' => 'Some message, text', 'channel' => 'message']);
$redis->publish('add-message', $sendMessage);
}
And my node server is:
let express = require('express');
let app = express();
let http = require('http').Server(app);
let redis = require('redis');
let client = redis.createClient("redis://127.0.0.1:6379");
let io = require('socket.io')(http);
app.use('/', express.static('www'));
http.listen(3000, '192.168.10.10', function(){
console.log('listening on *:3000');
});
client.on('message', function(chan, msg) {
let data = JSON.parse(msg);
io.sockets.emit(data.channel, msg);
});
client.subscribe('add-message');
Bottom line everyone who is subscribed on 'message' channel will get message. Problem is that I subscribe user on channel when came to chat page. I don't know how to subscribe user, and when, on channel where some another user send him message.Also how that sender user to create new room, I suppose to use id of users for room name (per instance user1_user2).
Does anyone know how I can solve this problem? I don't know even I described well.
Thanks in advance

Socket.io keeps multiple connected sockets alive for 1 client

I am using Socket.io to connect a React client to a Node.js server and the query option in socket.io to identify uniquely every new client. However, the server creates multiple sockets for every client and, when I need to send something from the server, I don't know which socket use, because I have more than one, and all of them are connected.
The client code:
import io from "socket.io-client";
...
const socket = io(process.env.REACT_APP_API_URL + '?userID=' + userID, { forceNew: true });
socket.on('connect', () => {
socket.on('new-order', data => {
const { add_notification } = this.props;
add_notification(data);
});
The server code:
....
server = http
.createServer(app)
.listen(8080, () => console.log(env + ' Server listening on port 8080'));
io = socketIo(server);
io.on('connection', socket => {
const userID = socket.handshake.query.userID;
socket.on('disconnect', () => {
socket.removeAllListeners();
});
});
And here the server-side that emits events to the client:
for (const socketID in io.sockets.connected) {
const socket = io.sockets.connected[socketID];
if (socket.handshake.query.userID === userID) {
// Here, I find more than one socket for the same condition, always connected.
socket.emit(event, data)
}
}
Here, it is possible to see all these socket for the same client:
I tried to send events for all socket from a given userID, however, multiple events are triggered to the client, showing duplicated data to the user. I also tried to send events to the last socket, but, sometimes it works, sometimes doesn't.
Someone have a clue how to uniquely identify a socket when there are several clients?

I am not able to connect to mqtt server from node.js

I am completely new to mqtt and node.js i want to get data from mqtt server at regular intervals and populate in my html5 page
Here is the sample code that am try to connect but not sure it is right way or not
var mqtt = require('mqtt');
// connect to the message server
var client = mqtt.connect('mqtt://test.mosquitto.org');
// publish 'Hello mqtt' to 'test'
client.publish('test', 'Hello mqtt');
// terminate the client
client.end()
Assuming you really are working purely with node.js you haven't given the client time to actually connect before trying to publish a message.
The node.js mqtt module README has a full example (which it appears you've copied and removed most of the important bits from). I have removed the subscription part from the demo code, but this is the bare minimum needed to publish a message.
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://test.mosquitto.org');
client.on('connect', function () {
client.publish('test', 'Hello mqtt');
client.end();
});
Following code upload data on hivemq MQTT Broker at regular interval.
var mqtt = require('mqtt');
// connect to the message server
var client = mqtt.connect('mqtt://broker.hivemq.com');
client.on('connect', function () {
setInterval(function () { client.publish('mytopic', 'Hello mqtt') }, 1000)
})
If you want to retrieve that data then use the following function
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
client.end()
})

Resources