I'm trying to publish a message on a MQTT Broker on a raspberry trough paho.
I've built an "app" with visual studio 2015 (on windows 10) and I'm using the ripple simulator to test it but I always get this error:
AMQJS0011E Invalid state not connected.
I also tried to export the files and to open them as regular webpages with firefox on a linux system and I get the same kind of error so I don't think is something windows related.
The function that gets triggered with a button is playCanzone()
function playCanzone() {
console.log("play premuto");
mqttHost = '192.168.9.184';
topic = 'testTopic';
client = new Paho.MQTT.Client(mqttHost, 8080, "myclientid_" + parseInt(Math.random() * 100, 10));
onConnect();//publish('mEssaggio', 'testtopic/bar', 2);
}
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({ onSuccess: onConnect });
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe(topic);
message = new Paho.MQTT.Message("Hello");
message.destinationName = topic;
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
Your trying to send things before the connection is open.
This should behave better and ensure everything happens in order
var client; topic;
function playCanzone() {
console.log("play premuto");
var mqttHost = '192.168.9.184';
topic = 'testTopic';
client = new Paho.MQTT.Client(mqttHost, 8080, "myclientid_" + parseInt(Math.random() * 100, 10));
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({ onSuccess: onConnect });
}
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe(topic);
var message = new Paho.MQTT.Message("Hello");
message.destinationName = topic;
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
Related
I have a webserver with websockets set up on an ESP8266. The application runs fine on both client and server sides, sending and receiving data. However, if the server side disconnects (power cycle or upload new code), the client (Chrome) won't reconnect to the websocket. I can reload/refresh the web page, and it claims (according to the console log) to be connecting to the websocket, but it does not. The only solution I have found that works is to close the tab, and then restart a new session.
My code is heavily based on this tutorial from Random Nerd Tutorials
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
function initWebSocket() {
console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function onOpen(event) {
console.log('Connection opened');
}
function onClose(event) {
console.log('Connection closed');
setTimeout(initWebSocket, 2000);
}
Is there something that is missing from the code above to make it more reliable?
You probably need to use setInterval. Try this, you may have to tweek it a bit.
var gateway = `ws://${window.location.hostname}/ws`;
var websocket, sockTimer=null;
function initWebSocket() {
console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onerror = onError; // new
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function onOpen(event) {
clearInterval(sockTimer) // <= better
console.log('Connection opened');
}
function onError() { // <= New
sockTimer = setInterval(init, 1000 * 60);
};
function onClose(event) {
console.log('Connection closed');
//setTimeout(initWebSocket, 2000);
sockTimer = setInterval(initWebSocket, 1000 * 60); // <=new
}
I'm trying to write a simple wrapper class around the Paho MQTT JavaScript client. (The idea is to put some extra validation around MQTT messaging, to ensure messages are processed in the correct order.)
I'm not very comfortable with JavaScript classes, and I'm getting in a mess trying to work out what's wrong with this...
class Hermes {
constructor(uri, topic, callback) {
var clientId = "clientID_" + parseInt(Math.random() * 1000);
this.client = new Paho.MQTT.Client(uri, clientId);
this.topic = topic;
this.callback = callback;
this.client.onMessageArrived = this._onMessageArrived;
this.client.onConnectionLost = this._onConnectionLost;
this.client.connect({
onSuccess: this._onConnect,
onFailure: this._onFailure
});
}
_onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("_onConnect: " + this.client.clientId)
this.client.subscribe(this.topic);
}
// called when connection fails
_onFailure(responseObject) {
console.log("_onFailure: "+responseObject.errorMessage);
}
// called when a message arrives
_onMessageArrived(message) {
console.log("_onMessageArrived: "+message.payloadString)
// TODO: validate message and pass to callback
}
// called when client loses connection
_onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost: "+responseObject.errorMessage);
}
}
}
function handleMessage(message) {
// TODO: handle message
}
var hermes = new Hermes("ws://mqtt.example.com:9001/mqtt", "test", handleMessage);
Expected result:
_onConnect: clientID_xxx should be logged in the console when the client successfully connects.
Actual result:
onConnectionLost: AMQJS0005E Internal error. Error Message: undefined is not an object (evaluating 'this.client.clientId'), Stack trace: _onConnect#file:///Users/richardguy/Desktop/hermes.js:16:45
The MQTT broker is running on a VPS and I can publish/subscribe messages successfully using the Paho Javascript library outside of a class, like so...
uri = "ws://mqtt.example.com:9001/mqtt"
var clientId = "clientID_" + parseInt(Math.random() * 1000);
client = new Paho.MQTT.Client(uri, clientId);
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
client.connect({
onSuccess: onConnect,
onFailure: onFailure
});
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("_onConnect: " + client.clientId)
client.subscribe("test");
}
// called when connection fails
function onFailure(responseObject) {
console.log("_onFailure: "+responseObject.errorMessage);
}
// called when a message arrives
function onMessageArrived(message) {
console.log("_onMessageArrived: "+message.payloadString)
// TODO: validate message and pass to callback
}
// called when client loses connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost: "+responseObject.errorMessage);
}
}
Is this just a mistake in the class definition, or something to do with the Paho MQTT library??
Solution:
I needed to pass an object (in this case the instance of the Hermes class) to use as the context for the onSuccess callback rather than using this (which isn't what I thought it was, as usual...), using invocationContext in the connection options.
class Hermes {
constructor(uri, topic, callback) {
var clientId = "clientID_" + parseInt(Math.random() * 1000);
this.client = new Paho.MQTT.Client(uri, clientId);
this.topic = topic;
this.callback = callback;
this.client.onMessageArrived = this._onMessageArrived;
this.client.onConnectionLost = this._onConnectionLost;
this.client.connect({
onSuccess: this._onConnect,
onFailure: this._onFailure,
invocationContext: this
});
}
_onConnect(responseObject) {
// Once a connection has been made, make a subscription and send a message.
let self = responseObject.invocationContext;
self.client.subscribe(self.topic);
}
// called when connection fails
_onFailure(responseObject) {
console.log("_onFailure: "+responseObject.errorMessage);
}
// called when a message arrives
_onMessageArrived(message) {
console.log("_onMessageArrived: "+message.payloadString)
// TODO: validate message and pass to callback
}
// called when client loses connection
_onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost: "+responseObject.errorMessage);
}
}
}
function handleMessage(message) {
}
var hermes = new Hermes("ws://mqtt.example.com:8080/mqtt", "test", handleMessage);
Your problem is that this is not what you think it is.
The callbacks are all made from the clients network handler, so this is actually a reference to the handler.
You can pass an object to use as the context for the onSuccess and onFailure callbacks in the connection options using invocationContext, but not for the other callbacks.
I'm trying to make a random system of connections. I have a button that initiates a connection and also looks for new peer for a new automatic call. But it is intermittent, sometimes it works perfect, sometimes I do not know anymore.
Backend - server.js
/** successful connection */
wss.on('connection', function (client) {
console.log("A new WebSocket client was connected.");
/** incomming message */
client.on('message', function (message) {
/** broadcast message to all clients */
var obj = JSON.parse(message);
if("callState" in obj) {
// New client, add it to the id/client object
// client.set('call_state') = 1
console.log("Recebeu mensagem!!!");
}else if("sdp" in obj || "ice" in obj) {
wss.broadcast(message, client);
}else{
console.log("Recebeu: "+message);
}
});
});
// broadcasting the message to all WebSocket clients.
wss.broadcast = function (data, exclude) {
console.log("Broadcasting message to all " + this.clients.length + " WebSocket clients.");
for(var i in this.clients) {
client = this.clients[i];
// don't send the message to the sender...
if (client === exclude) continue;
if (client.readyState === client.OPEN) client.send(data);
else console.error('Error: the client state is ' + client.readyState);
}
};
Frontend - webrtc.js
/** button START */
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.addStream(localStream);
if ('ontrack' in peerConnection) {
// WebRTC Spec, Firefox
peerConnection.ontrack = ontrack
} else {
// Chrome, etc. This can be removed once all browsers support `ontrack`
peerConnection.onaddstream = gotRemoteStream
}
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
In the server log shows that every time I press the "Start" button it log 1 SDP message and 14 ICE messages
EDIT: Including error
When I call the "start" button for the first time, everything works. However, in the following calls sometimes only the audio feature remains and at other times without a new connection.
I was able to reproduce an error after clicking "Start" several times:
DOMException [InvalidStateError: "Cannot set remote answer in state
stable" code: 11 nsresult: 0x8053000b]
I have a local server running on: https://luisdemarchi.aplicativo.info:8091
I have opened the server.js and the address:http://localhost:8081 on my browser. But then a text "Upgrade Required" appeared at the top left conern of the website.
What is the problem of that? What else do I need to upgrade?
Here is the server.js:
var serialport = require('serialport');
var WebSocketServer = require('ws').Server;
var SERVER_PORT = 8081;
var wss = new WebSocketServer({
port: SERVER_PORT
});
var connections = new Array;
SerialPort = serialport.SerialPort,
portName = process.argv[2],
serialOptions = {
baudRate: 9600,
parser: serialport.parsers.readline('\n')
};
if (typeof portName === "undefined") {
console.log("You need to specify the serial port when you launch this script, like so:\n");
console.log(" node wsServer.js <portname>");
console.log("\n Fill in the name of your serial port in place of <portname> \n");
process.exit(1);
}
var myPort = new SerialPort(portName, serialOptions);
myPort.on('open', showPortOpen);
myPort.on('data', sendSerialData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
function showPortOpen() {
console.log('port open. Data rate: ' + myPort.options.baudRate);
}
function sendSerialData(data) {
if (connections.length > 0) {
broadcast(data);
}
}
function showPortClose() {
console.log('port closed.');
}
function showError(error) {
console.log('Serial port error: ' + error);
}
function sendToSerial(data) {
console.log("sending to serial: " + data);
myPort.write(data);
}
wss.on('connection', handleConnection);
function handleConnection(client) {
console.log("New Connection");
connections.push(client);
client.on('message', sendToSerial);
client.on('close', function () {
console.log("connection closed");
var position = connections.indexOf(client);
connections.splice(position, 1);
});
}
function broadcast(data) {
for (c in connections) {
connections[c].send(data);
}
}
OK, websockets...
The "upgrade required" status marks the start of a websocket handshake. Normally your client sends this first to the WS server. The server answers in a pretty similar manner (details here : https://www.rfc-editor.org/rfc/rfc6455 ), and then proceed to pipe the actual data.
Here, you're opening a connection from your client as regular http, sending a simple GET. What you see on the screen is the server dumbly proceeding with an already corrupted handshake.
That's not how you open a WS client side connection. You don't usually open WS pages from the browser. It ought to be opened from a JavaScript call, such as new WebSocket(uri). So what you want is a regular http server on another port, that serves a page containing the necessary Javascript to open the actual WS connection and do something useful with its data. You'll find a clean example here : http://www.websocket.org/echo.html
I'm using socket.io for realtime communication. When inetrnet is not available for few seconds, then it will connect to server when the connection is establish and then it will immediately trigger event which will log in my clinet. After establishing connection, (i think) my socket.io on server side fire disconnect event after ~one minute (in callback function I log off my client), and that is my problem.
This is my server side. (a have server.js and he run other.js files, in object 'files' a have that files).
server.js :
io = require('socket.io').listen(server);//server listening on 8080 port
io.configure(function () {
io.set('transports', ['websocket', 'xhr-polling']);
io.set('log level', 1);
io.disable('browser client');
});
var files = {
control: null,
terminal: null,
messages: null
};
for (var game in games) {
games[game] = require('./game_modules/' + game + '.js').listen(io, create_waiter(game));
}
require('http').createServer(function (req, res) {
var resultCode = 500;
var resultText = '';
var parts = require('url').parse(req.url, true);
var matches = parts.pathname.match('^/([a-z_-]+)/([a-z_-]+)/$');
if (matches) {
var game = matches[1];
var command = matches[2];
resultText = games[game][command](parts.query);
resultCode = 200;
res.writeHead(resultCode, {'Content-Type': 'text/plain'});
res.end(resultText);
}).listen(8081, "127.0.0.1");
control.js :
var control = module.exports = function() {
};
control.listen = function(io) {
this.server = io.of('/control');
this.onTerminate = onTerminate;
//********************************************************************************
this.server.on('connection', function(socket) {
socket.on('disconnect', function(data) {
console.log(data); //after my client reconnect, disconnect event is triggered, and
//console.log write 'close timeout'
After client reconnect, I do not want trigger disconnect event, or if disconnect event was triggered I want check in callback function: is my client connected and prevent "log off" for my client.
Thanks :)