Realtime data with MQTT, Node.js, MQTTClient.js and Socket.IO


In the past I’ve tried several solutions besides Ajax; Lightstreamer, Comet-like solutions and other similar products, but they all were either too big, required too much work for a single webpage or the price was too high. But now, the time has come to get rid of Ajax and polling web pages.

Once a year or so, I browse the web to look for an Ajax alternative. And this time I read this comment on a post about MQTT over Websockets. Node.js rang a bell, Websockets too and I decided to give it a try; with Flanagans Javascript bible next to me that shouldn’t be a problem.

So the ingredients for this exercise are:

  • MQTT, a machine-to-machine (M2M)/”Internet of Things” connectivity protocol, especially useful there where small code footprint is important;
  • Node.js, a platform for easily building fast, scalable network applications. Lightweight, event-driven and non-blocking I/O; ideal for real-time applications;
  • MQTTClient.js, an MQTT client for Node.js;
  • Socket.IO, which enables you to build realtime apps for virtually every browser and mobile device, using different transport mechanisms.

Hehe, it’s beginning to sound like a commercial but it ain’t – now you know what I’m talking about during the rest of this post.

I’ve already got a Smart meter and an Opentherm Gateway publishing their data to an MQTT broker, so that part was already working; I started with installing Node.js. There are several installers available and I picked the one that matches my PC: the x64 Windows installer, started it. Nnnf, done. Well, the rest was just as easy… now the code.

First thing I did was making a Javascript that would run on Node.js that would combine the Socket.IO functionality and an MQTT client to push MQTT topics to a browser; I named it the ‘pusher‘ script:

var sys = require('sys');
var net = require('net');
var mqtt = require('mqtt');

var io  = require('socket.io').listen(5000);
var client = new mqtt.MQTTClient(1883, '127.0.0.1', 'pusher');

io.sockets.on('connection', function (socket) {
  socket.on('subscribe', function (data) {
    console.log('Subscribing to '+data.topic);
    client.subscribe(data.topic);
  });
});

client.addListener('mqttData', function(topic, payload){
  sys.puts(topic+'='+payload);
  io.sockets.emit('mqtt',{'topic':String(topic),
    'payload':String(payload)});
});

That should do it.. I guess. We’ll see soon enough…

Next, a small web page:

<h1>Real Time</h1>
<script type="text/javascript" src="socket.io.min.js"></script>
<script type="text/javascript" src="jquery-1.4.2.js"></script>
<script type="text/javascript">
  var socket = io.connect('http://localhost:5000');
    socket.on('connect', function () {
      socket.on('mqtt', function (msg) {
        var elmarr=msg.topic.split("/");
        var elm=elmarr[3];
        console.log(msg.topic+' '+msg.payload);
        $('#'.concat(elm)).html(msg.payload);
     });
     socket.emit('subscribe',{topic:'/sensor/OTGW/returntemp'});
    });
</script>
<table class="tablegv" style="width: 500px;">
<tbody>
<tr class="tablegvHeader">
<td colspan="2"><center>Status</center></td>
</tr>
<tr>
<td>Return temp</td>
<td id="returntemp"></td>
</tr>
</tbody>
</table>

Here’s the result, the boiler return temperature shows up in the screen:

Pushing it!

Wow, it’s working… both the page and the console log below the page shows the incoming temperatures!

Needless to say this can easily expanded with room temperature, flow temperature, flame status, etcetera etcetera…. all updated instantly – as realtime as you can get! 🙂

But I wanted more…

Suppose you have a web page like this displaying the Smart meter information and another one displaying the Opentherm information. Both pages will result in subscriptions to all kinds of topics, either related to the Smart meter or the Opentherm. And I saw that both pages received all the information! That’s not good – I need to a way to make sure the smart meter page only receives updates it subscribed to.

After reading some more about Socket.IO I found out there’s a feature called ‘rooms’. Sockets (clients) can join a specific room and there’s a way to emit information to just thos sockets in a specific room. That sounds nice, so I tried it. Changed the pusher script to this:

var sys = require('sys');
var net = require('net');
var mqtt = require('mqtt');

var io  = require('socket.io').listen(5000);
var client = new mqtt.MQTTClient(1883, '127.0.0.1', 'pusher');

io.sockets.on('connection', function (socket) {
  socket.on('subscribe', function (data) {
    console.log('Subscribing to '+data.topic);
    socket.join(data.topic);
    client.subscribe(data.topic);
  });
});

client.addListener('mqttData', function(topic, payload){
  sys.puts(topic+'='+payload);
  io.sockets.in(topic).emit('mqtt',{'topic': String(topic),
    'payload':String(payload) });
});
As you can see, line 11 is added and line 17 (old) has been changed to line 18. That’s all, now none of the pages gets information it didn’t ask for; great, this can definitely be a very good Ajax replacement!
Source : hekkers.net
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s