Sunday, March 06, 2016

Digital signage with node-red and MQTT

A couple of months ago, a good friend of mine asked me to setup a digital signage system for his coffee shop.  The place is not a franchise, it's totally self owned and so the system would only be for one shop. There are currently three screens available , two larger TV screens on the wall, and a smaller one standing on the counter. Each of the screens has an Android device plugged into the HDMI port.

Instead of buying a dedicated system I decided to go for a quick home grown solution, so that I could improve and customize it later on should the need for that arise.

Digital signage consists of a content server/controller, and then one or more so called "players".


The players.

Let's start with the players. I still had an Android application lying around to display web pages based on a certain MQTT Topic. 
Meanwhile for convenience this application is also available on Google Play. 
https://play.google.com/store/apps/details?id=com.tulinsystems.mqttpanel 

In the settings of mqttpanel, choose a default prefix , maybe call it "coffeeshop" or "myrestaurant". We will fill in the broker settings in the next paragraph.




The content server. 


To keep it simple, I only allow for webpages to be displayed on the Android screens. In a later post I will describe how we created the signs with free and existing cloud tools. So the content server is basically the world wide web, or potentially any web server in the intranet.

We are going to control the schedule and the content using an MQTT broker, so we are going to need one that we can use on the cloud.
In the case of my friend's coffee shop, we used an internal server running Ubuntu Core with  Mosquitto installed.  If you want to run this from the cloud there are a few hosted MQTT services with a free plan available. CloudMQTT is one of them, you can have up to 10 connections for free.
The MQTT broker is basically the hub of the wheel, and all the other components , such as the screens and the control applications are spokes of that wheel.
Go the settings of mqttpanel, and fill in the details for your broker : host name, username and password.

Lastly, we need some sort of application that can control which pages are displayed on which screens, for how long, when , etc. Instead of writing an application from scratch I choose to use node-red , which is perfectly suitable for a quick setup like this. It is installed on the same mini server box as the MQTT broker. As a server a Raspberry PI  or a fan-less low power industrial box PC are just fine for this.
If you wanna keep the whole thing in the cloud, again there is a hosted version of node-red right here : FRED (Front End for node-Red). It works just like node-red, and it runs 24/7 for you in the cloud.

Getting node-red installed and running is out of the scope of this article, but is very well described in the documentation. If you are using FRED, then you can start right away. The principle of node-red is to visually connect several nodes to create a flow for data and events. In our case, for the first simple app, we just want to display a list of URL's on all of the screens, switching URL's at a preset time interval. This is of course just an example, you could basically achieve any sort of scheme by reprogramming the flow.

1.) Select an "injector node" 


Decide on a list of URL's that have to be displayed, and then organize them in a string formatted as JSON , for example :

[ {"url":"www.google.com"}, {"url":"http://twitter.com"}, {"url":"http://facebook"}]


The injector node allows to setup a time, and an interval, which is perfect for our Digital signage project : we want it to switch every 5 minutes, during all the opening days.

This is what the whole flow looks like :


2.) Convert the string to a JavaScript object. 

Pick this node from the list of function nodes. We just need a way to convert our string into a real JavaScript object.

3.) Create a function.

Pick the "function" node from the list, and add the following code : 

1:  var item = this.context.global['item'] || 0;  
2:    
3:    
4:  if ( item > msg.payload.length-1) {   
5:   item =0;  
6:   this.context.global.item = 0;  
7:  }   
8:    
9:  var cleanMessage = {};  
10:  cleanMessage.payload = msg.payload[item].url  
11:    
12:  this.context.global.item = item +1;   
13:    
14:  return cleanMessage;  

This JavaScript function will iterate through the list one by one, round-robin.

4.) Debug node.

Add a debug node, just to see if everything is working fine. It's basically receiving each of the URL's we send. 

5.) MQTT output. 

Finally , after we get URL-by-URL from the little function we wrote, we have to send it to the actual panel. Check on the "Connection Status" screen of mqttpanel to see what the exact MQTT topic is for each screen and add an MQTT output node for each. 



Voila, that's it.





Monday, September 14, 2015