Tuesday, December 1, 2015

Events events events...

Hi there,

As some of you might know I love the Internet of Things and so I have a couple of sensors around that measures different kind of data. I'm also a big fan of MQTT because it makes things so easy and with it's publish and subscribe model it seems to be a natural fit for a lot of IoT projects.

When playing with my own stuff on my server and on my home network I'm totally fine with using MQTT for all of my IoT related communications. 

BUT...if you ever spoke at conference venues like hotels you will find out that they are very strict with their network...means usually the ports you need for your MQTT communication are not open :(
Or if you work in a company with very strict rules you might have the same problem with the port availability.
For this years JavaOne I was playing around with an Application Container Cloud Service where I again had the same problem...only port 80/443 have been available for all communications.

So I remembered a conversation that I had with David Delabassee at JavaOne Brazil this year in June. He mentioned SSE (Server Sent Events) and that it might be a possible solution for these kind of problems. 

Hey hipsters...sure you can use WebSockets...BUT you might run into problems with Proxy Servers. And using WebSockets is not always needed. In my case I would like to visualize data that is coming from either a sensor or an IoT gateway. Usually I don't need to send data to these devices and even if I have to send data it will be rare.
So for such a use case SSE is a perfect fit because it is a unidirectional event stream from the server to the client.

My idea was to write some code that subscribes to MQTT topics on a given broker and forwards them to connected clients via SSE. Sounds easy...and it is easy :)

To be able to subscribe to specific topics I needed a simple REST endpoint in my code that accepts POST calls from the client. The POST endpoint takes the topic and the qos (Quality of Service) for the subscription as parameters.
The program will add the client with the subscribed topic to a map and everytime a new MQTT message arrives on the broker the message will be pushed to all subscribed SSE clients.

The following image hopefully explains what I had on my mind...

As you can see on the image above you need at least a MQTT broker and a server that runs either Java SE or node.js or both :)

So I've implemented my little MQTT to SSE application in node and Java SE. Yes you read it right...Java SE...no Java EE :)
Don't get me wrong, Java EE is fine for a lot of things but if you just need something like I do here, it's just overkill and things like Spring Boot do better.

On Java EE it's also not that easy to make use of MQTT but on Java SE it's very easy if you use libraries like Eclipse Paho, FuseSource etc.

If you are not afraid of using JavaScript node.js is also a really good fit for stuff like this (even if I'm not the best JavaScript programmer I was able to write this app).

For those of you that can't wait...here are the links to the repositories.

MQTT to REST/SSE bridge and Java SE SSE client:

So in principle the whole app has only two methods one to publish a message via REST POST and one to subscribe to a topic via SSE.

In addition I've also created a HTML page and a Java SE client that both publish and subscribe messages to the MQTT broker using REST POST and SSE.

Set it up...

1. Setup a MQTT broker
If you don't have a broker yourself you might want to setup a free version over at www.cloudmqtt.com
After you signed up for the free Cute Cat plan you will find the settings of your MQTT broker in the Control Panel under details. There should be something like this...

Just note the Server, User, Password and Port

2. Configure and Start the REST service

The node.js version:
If you use the node.js app you will find a file named config.js in the project. In this config.js file please add the url, user, password and port of your MQTT broker or the broker you host at cloudmqtt. This should look similar to the following picture...

In principle you are now ready to start and if you've put the right credentials for your broker in the config.js file you should now be able to start the mqtt2sse.js file by calling

node mqtt2sse.js

on the command line or you start it from your preferred IDE.

The Java SE version:
If you use the Java SE based version you should find a config.properties file in the project directory. 
Just put the data like url, port, user and password of your MQTT broker or the broker you host at cloudmqtt in this file. It should look similar to the following one...

Now you are ready to start the file eu.hansolo.mqtt2sse.Main either in your preferred IDE or you can also build the project and start the created fat jar from the command line as follows...

java -Dserver.port=8080 -jar mqtt2sse-1.0.jar

The application will make use of Spring Boot for the REST service and will simply output incoming messages on the command line.

3. Publish and Subscribe some messages via HTML/JavaScript
In both projects you will find a test.html file which simply displays incoming messages and will publish messages with random data every 5 seconds.

It will subscribe to the MQTT topic: 


which means it will receive every of the following messages...


The + is a MQTT wildcard and you can find more information about MQTT and topics over at the awesome guys from dc-square (creators of hivemq), here is a the link.

The HTML/JavaScript client will also publish messages every 5 seconds to the MQTT topic:


The data it will publish looks like this...

  'temperature' : 23.24234,
  'pressure' : 1002.12312,
  'humidity' : 65.23414

So if you start it you should see something like the following in your browser...

4. Publish and Subscribe some messages via Java
This Java app makes use of the jersey libraries to subscribe to SSE and HttpURLConnection to make the REST POST calls. The functionality is the same as with the HTML/JavaScript client, means it subscribes the MQTT topic


and publishes data to the MQTT topic


So every 5 seconds it will publish a messgae to the MQTT topic above. If you start the app you should see something similar on the console...

As you can see it's in principle the same as with the HTML/JavaScript client.

5. Manually publish messages via REST POST
Finally you could also use a REST client like the Chrome App Postman (get it here) to manually publish a MQTT message via REST. 
On the following screenshot you can see how it looks like...

So you have to add one header as follows...

Select POST as the method to use and the following url: 


Now go to the Body tab and select raw. To publish something on the MQTT topic


put the following in the textarea...

  "topic"   : "sensor/Postman",
  "msg"     : "{\"temperature\":23.0,\"pressure\":1005.2,\"humidity\":60.0}",
  "qos"     : 0,
  "retained": false


If you now press the Send button you should see the new message in the HTML/JavaScript and the Java Client like on the following pictures...

You could also use all clients at the same time and should see something like this...

Because each client is subscribed to the MQTT topic sensor/+ it will show messages that arrive from itself and each other client.

6. Publish/Subscribe the messages in a MQTT client
Of course one could also use MQTT directly to publish/subscribe. Therefor I can recommend using MQTT.FX from Jens Deters. This tools is written in JavaFX and so it will run on all platforms. 

So if you publish messages from MQTT.FX it could look like this...

And if the Java SE client is running the messages will appear like you can see here...

And because the Java SE client is sending messages every 5 seconds you will also see the messages in MQTT.FX if you subscribe to the MQTT topic sensor/+

So as you can see with this MQTT <-> SSE bridge kind of code you could use MQTT via REST and SSE. This might not be the ultimate solution but for my use case it's a perfect fit and if you like it...feel free to fork it...

Here are the links to the repositories:

MQTT to REST/SSE bridge and Java SE SSE client:

That's it for today...keep coding... 

No comments:

Post a Comment