mqtt client disconnected when subscribe with thingsboard topic - node.js

I am trying to make a connection with thingsboard by subscribing to a topic so that I can receive an updated state changes. But after subscription the client seems to be disconnected. Below is my code
const mqttEndpoint = 'MyLocalIpAddress:1883'
const MQTT_TOPIC = 'v1/devices/me/attributes'
const mqttClient = mqtt.connect(`mqtt://${mqttEndpoint}`, {
username: '123456789asdf',
rejectUnauthorized: false,
})
mqttClient.on('connect', function () {
mqttClient.subscribe(MQTT_TOPIC, function (err) {
if (!err) {
console.log('subscribed')
}
})
})
mqttClient.on('message', (topic, message) => {
// message is Buffer
console.log('topic', topic);
console.log('message', message.toString());
//this.server.emit('msgToClient', message.toString());
mqttClient.end()
})
mqttClient.on('close', () => {
console.log('mqtt: connection closed');
})
I think the javascript mqtt code seems to be ok. But I am not figuring it out how can receive an update state from the thingsboard via mqtt.
The events in the console while running the above code:
Processing connect msg for client: mqttjs_f7181153!
Processing connect msg for client with user name: 123456789asdf!
Client connected!
subscribed
Client disconnected!
Also I had tried it with mosquitto but seems to be the connection is successful but not receiving anything if there is an update in state
mosquitto_sub -d -h "localhost" -t "v1/devices/me/attributes" -u "123456789asdf"

Related

socket.io and node cluster: dispatch events to sockets

I have a nodejs cluster server that is using mongo changestream listener, to emit data to clients over socket.io. I'm using Redis to store a userId and the socketId of all the connected users in a hash.
{ userId: 'aaa', socketId: 'bbb' }
The redis clients for storing this data is initialized in the master process.
The mongo changestream is created in the master process.
When the changestream sees a new document, it will send the document to a child process as a message. When the child process receives the message, it can retrieve the userId from the document. With the userId, the socketId for the client connection can be retrieved from redis.
The issue I am having is in trying to emit a message using the socketId after it is retrieved from redis.
I am creating a sockethandler object that contains the socketId. When I use this socketId to emit a socket message, like so:
io.sockets.to(userSocketId)
.emit("confirmOrder", "Your order is being processed!")
I receive an error:
(node:31804) UnhandledPromiseRejectionWarning: Error: The client is closed
at new ClientClosedError (/Users/a999999999/code/*/node_modules/#node-redis/client/dist/lib/errors.js:24:9)
The error is from redis, and originated on the socket emit line written above. ^^
Here is more code from the worker process:
const pubClient = createClient({ host: "127.0.0.1", port: 6379 }),
subClient = pubClient.duplicate();
io.adapter(createAdapter(pubClient, subClient));
setupWorker(io);
io.on("connection", (socket) => {
const socketId = socket.id;
socket.emit("connection", "SERVER: you are connected");
socket.on("userConnect", (user) => {
let { userId } = user;
userConnectClient
.HSET(userId, { userId, socketId })
.catch((err) => console.log("ERROR: ", err));
});
});
process.on("message", async ({ type, data }) => {
switch (type) {
case "dispatch:order":
let { order } = JSON.parse(data);
const socketsHandler = await createSocketsHandler(order);
const userSocketId = socketsHandler.user.socketId;
io.sockets
.to(userSocketId)
.emit("confirmOrder", "Your order is being processed!");
break;
}
});
async function createSocketsHandler(order) {
let { userId } = order;
let user = await userConnectClient
.HGETALL(userId)
.catch((err) => console.log(err));
return {
user: user,
};
}
I am temporarily stumped at this point. Currently experimenting with the io object, and trying to find better tools to monitor redis. Any help/questions is appreciated! Thank you!
I've since realized why the redis client was not working properly. I'm making use of publisher and subscriber clients with redis. The problem was, I was creating the redis clients in the worker process of the server. So, whenever the server is making a command to redis, it is not able to do it properly because there is a pair of clients for each worker process, which is not the proper implementation, I believe.
This was solved by creating the redisClient outside of my cluster server code. ;P My server can now properly subscribe to redis client in master and worker process!

how to keep alive the TCP client connection after end in node js

i need your help... i am new to TCP..
I had implemented TCP server and client... tcp server write data when connection is established and wait for kernal buffer getting empty then i emit end event from TCPserver and same as client received data from server in end event...
TCP server.js
const TCPserver = net.createServer().listen(4040);
var recvData='';
TCPserver.on('connection',(TCPclient)=>{
TCPclient.setKeepAlive(true);
console.log(`TCP Client Connected ${TCPclient.localAddress}:${TCPclient.localPort}`);
var strData=JSON.stringify({"msg":"testRequest from Cortana"})
var is_buffer_null=TCPclient.write(strData);
if(is_buffer_null){
TCPclient.end();
}
TCPclient.on('data',(data)=>{
recvData+=data;
})
TCPclient.on('end',()=>{
console.log("Packet is received : "+recvData);
recvData='';
})
TCPclient.on('drain',()=>{
TCPclient.end();
})
TCPclient.on('error',(err)=>{
console.log(err);
})
TCPclient.on('close',(hardError)=>{
console.log("Client disconnected");
if(hardError){ console.log("TCP error"); }
})
})
TCPclient.js
var TCPcortana = net.connect({ port: 4040, host:'127.0.0.1',allowHalfOpen:true},()=>{
console.log(`server connected to ${TCPcortana.localAddress}:${TCPcortana.localPort} `);
});
TCPcortana.setKeepAlive(true);
TCPcortana.on('data',(data)=>{
recvData+=data;
})
TCPcortana.on('end',()=>{
console.log("Packet is received : "+recvData);
processReq(recvData);
recvData='';
})
TCPcortana.on('drain',()=>{
TCPcortana.end();
})
TCPcortana.on('error',(err)=>{
console.log(err);
setTimeout(()=>{
TCPcortana.connect({ port: 4040, host:'127.0.0.1',allowHalfOpen:true});
},10000)
})
TCPcortana.on('close',(hardError)=>{
console.log("connection disconnected");
if(hardError){ console.log("TCP error"); }
})
function processReq(data) {
console.log("Packet being processed");
var stringData=JSON.stringify(data);
var is_buffer_empty=TCPcortana.write(stringData);
if(is_buffer_empty){
TCPcortana.end();
}
}
the Tcp client send responses then the client connection close, i am expecting the client was not closed and keep alive the connection between and server and client... please help me...
If you are trying to frequently send messages to the client without closing the connection, you need to use server send events.
Server Sent Events continue to keep the connection alive and the server can send "events" containing some data.
See this answer for more details.

How can i retrieve broker connect, disconnect, publish and subscribe event functions in EMQ X broker in Node js?

I am using an mqtt client with EMQ X broker (that is running as a service in my local linux machine) and tested the pub sub mechanism but I want to use broker event function (connect, disconnect, publish and subscribe) for adding a custom logic into broker events.
Kindly guide me how can i achieve this in emq X broker ?
Build your own logic using EMQ X REST API
https://github.com/wivwiv/egg-iot-with-mqtt
It is recommended to use the MQTT.js:
https://www.npmjs.com/package/mqtt#connect
const mqtt = require('mqtt')
// const url = 'mqtt://localhost:1883'
const url = 'mqtt://tools.emqx.io:1883'
const clinet = mqtt.connect(url, {
clientId: 'emqx_client_id',
username: '',
password: '',
})
client.on('connect', () => {
client.subscribe('presence', (err) => {
if (!err) {
setInterval(() => {
client.publish('presence', 'Hello EMQ X')
}, 1000)
}
})
})
client.on('message', (topic, message) => {
// message is Buffer
console.log('received from', topic, message.toString())
})

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.

How can I deal with message processing failures in Node.js using MQTT?

I'm using a service written in Node.js to receive messages via MQTT (https://www.npmjs.com/package/mqtt) which then writes to a database (SQL Server using mssql).
This will work very nicely when everything is functioning normally, I create the mqtt listener and subscribe to new message events.
However, if the connection to the DB fails (this may happen periodically due to a network outage etc.), writing the message to the database will fail and the message will be dropped on the floor.
I would like to tell the MQTT broker - "I couldn't process the message, keep it in the buffer until I can."
var mqtt = require('mqtt')
var client = mqtt.connect('mymqttbroker')
client.on('connect', function () {
client.subscribe('messagequeue')
})
client.on('message', function (topic, message) {
writeMessageToDB(message).then((result) => {console.log('success'};).catch((err) => {/* What can I do here ?*/});
})
Maybe set a timeout on a resend function? Probably should be improved to only try n times before dropping the message, but it's definitely a way to do it. This isn't tested, obviously, but it should hopefully give you some ideas...
var resend = function(message){
writeMessageToDB(message).then((result) => {
console.log('Resend success!')
})
.catch((err) => {
setTimeout(function(message){
resend(message);
}, 60000);
});
}
client.on('message', function (topic, message) {
writeMessageToDB(message).then((result) => {
console.log('success')
})
.catch((err) => {
resend(message);
});
});

Resources