Re: Combine MQTT messages / Node-Red Dashboard

2,743 views
Skip to first unread message
Message has been deleted

steve rickus

unread,
Jun 7, 2017, 8:52:39 AM6/7/17
to Node-RED
Typically, I would use the ng-repeat directive in a ui_template node to render this array as an html table:

<table style="width: 100%;">
   
<thead>
       
<tr>
           
<th>Topic</th>
           
<th>Online</th>
           
<th>QoS</th>
           
<th>Retain</th>
       
</tr>
   
</thead>
   
<tbody>
       
<tr ng-repeat="row in msg.payload">
           
<td>{{row.topic.replace("/$online","")}}</td>
           
<td>{{row.payload}}</td>
           
<td>{{row.qos}}</td>
           
<td>{{row.retain}}</td>
       
</tr>
   
</tbody>
</table>

Untested (especially the replace function bit) -- but should be close to what you need.
--
Steve


On Wednesday, June 7, 2017 at 8:36:14 AM UTC-4, Lennart Hennigs wrote:

Hey guys,
I want to display a list of (connected & online) devices in the Node-Red dashboard.
The devices are ESPs that use MQTT to transfer data.
If I subscribe to this topic "homie/+/$online" I get messages like these, one for each device:

topic"homie/esp04/$online",payload"false"qos1retaintrue,_msgid"785e78c4.4ddf28" }
topic"homie/esp05/$online",payload"true"qos1retaintrue,_msgid"26973b83.d4e664" }

Now, I'd like to display the status of each device in the Dashboard in a list.
But if I use a text node I only get the status of the most recent message.

How would I turn this into a list?  
Can I do this directly via a dashboard template node? 
Or should I use a function node to and a global(?) array to store the status?

What do you think?

Cheers
l.

Lennart Hennigs

unread,
Jun 7, 2017, 11:28:47 AM6/7/17
to Node-RED
Hey Steve, 

thanks for the quick reply. 

Typically, I would use the ng-repeat directive in a ui_template node to render this array as an html table:

For now I get each message separately and not in an array.
You think the best way is to manually create an array for it (store each update in a global array I define) ? 
Or is there a node-red way to do it more elegantly? 

Cheers
l.

Colin Law

unread,
Jun 7, 2017, 12:36:45 PM6/7/17
to node...@googlegroups.com
Not in a global array, feed them into a node and use node context
variables. Possibly better, look at the join node which has a new
feature that allows it to remember the values passed with a number of
topics and each time a new message is received if passes on the values
for all the previously given topics, which you can then display as
appropriate.

Colin

>
> Cheers
> l.
>
> --
> http://nodered.org
>
> Join us on Slack to continue the conversation: http://nodered.org/slack
> ---
> You received this message because you are subscribed to the Google Groups
> "Node-RED" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to node-red+u...@googlegroups.com.
> To post to this group, send email to node...@googlegroups.com.
> Visit this group at https://groups.google.com/group/node-red.
> To view this discussion on the web, visit
> https://groups.google.com/d/msgid/node-red/28446f7e-3348-4129-8594-b10c409ff14b%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

David Caparrós

unread,
Jun 7, 2017, 1:37:14 PM6/7/17
to Node-RED
Hi mate,

I have done something similar, I have several ESP modules connected via MQTT and too look at the status I made that each module send a message every 2 minutes to his topic starting with his module name.

On my dashboard I have created a text message for each module that is watching at this message, if in 3 min is not getting the message then displays that module is lost.

I see you wanted to do something very similar and maybe helps you, just subscribe each line to homie/esp04   or 5,6.....whatever.

Just for your information I made that all information returned is always displayed on yellow colour.

I'm going to put you a screenshot attached and the flow so you can just copy paste to view yourself, maybe helps you.


[{"id":"2bd502dd.44c4ae","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"ESP3","qos":"2","broker":"32ed8c49.582164","x":310,"y":680,"wires":[["4da2501f.3173e"]]},{"id":"4da2501f.3173e","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE   LOST","op1type":"str","op2type":"str","duration":"3","extend":true,"units":"min","reset":"","name":"","x":490,"y":680,"wires":[["3d97e237.8a38fe","c3a6362f.6555c8"]]},{"id":"3d97e237.8a38fe","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":14,"width":0,"height":0,"name":"","label":"ESP3 STATUS","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":680,"wires":[]},{"id":"9d477193.b63aa","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"ESP2","qos":"2","broker":"32ed8c49.582164","x":310,"y":640,"wires":[["6ce22ce5.ae3194"]]},{"id":"6ce22ce5.ae3194","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE   LOST","op1type":"str","op2type":"str","duration":"3","extend":true,"units":"min","reset":"","name":"","x":490,"y":640,"wires":[["4df2790c.baeed8","c3a6362f.6555c8"]]},{"id":"4df2790c.baeed8","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":13,"width":0,"height":0,"name":"","label":"ESP2 STATUS","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":640,"wires":[]},{"id":"cf924c8.43ea0b","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"ESP1","qos":"2","broker":"32ed8c49.582164","x":310,"y":600,"wires":[["e3fadea2.74b63"]]},{"id":"e3fadea2.74b63","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE  LOST","op1type":"str","op2type":"str","duration":"3","extend":true,"units":"min","reset":"","name":"","x":490,"y":600,"wires":[["3395a2c8.5c298e","c3a6362f.6555c8"]]},{"id":"3395a2c8.5c298e","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":12,"width":0,"height":0,"name":"","label":"ESP1 STATUS","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":600,"wires":[]},{"id":"4c8f2443.cf11fc","type":"inject","z":"2f7fb3d3.985d9c","name":"","topic":"","payload":"MODULE    LOST","payloadType":"str","repeat":"","crontab":"","once":true,"x":100,"y":720,"wires":[["3395a2c8.5c298e","4df2790c.baeed8","3d97e237.8a38fe","4df7c543.1d8e9c","7fe6084e.d59508","99cde6a6.a233c8","2872164f.ee0bfa"]]},{"id":"43d7b5f2.c9395c","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"ESP4","qos":"2","broker":"32ed8c49.582164","x":310,"y":720,"wires":[["ef2469bf.ed66e8"]]},{"id":"ef2469bf.ed66e8","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE  LOST","op1type":"str","op2type":"str","duration":"3","extend":true,"units":"min","reset":"","name":"","x":490,"y":720,"wires":[["4df7c543.1d8e9c","c3a6362f.6555c8"]]},{"id":"4df7c543.1d8e9c","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":15,"width":0,"height":0,"name":"","label":"ESP4 STATUS","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":720,"wires":[]},{"id":"95a4b811.a7ccb8","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"ESP5","qos":"2","broker":"32ed8c49.582164","x":310,"y":760,"wires":[["3a9036f1.e1ad7a"]]},{"id":"3a9036f1.e1ad7a","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE  LOST","op1type":"str","op2type":"str","duration":"3","extend":true,"units":"min","reset":"","name":"","x":490,"y":760,"wires":[["7fe6084e.d59508","c3a6362f.6555c8"]]},{"id":"7fe6084e.d59508","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":16,"width":0,"height":0,"name":"","label":"ESP5 STATUS","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":760,"wires":[]},{"id":"deda736e.434b2","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"tele/sonoffbaño/STATE","qos":"2","broker":"32ed8c49.582164","x":360,"y":820,"wires":[["5243b578.6fa9ec"]]},{"id":"5243b578.6fa9ec","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE  LOST","op1type":"str","op2type":"str","duration":"10","extend":true,"units":"min","reset":"","name":"","x":600,"y":820,"wires":[["99cde6a6.a233c8","c3a6362f.6555c8"]]},{"id":"99cde6a6.a233c8","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":16,"width":0,"height":0,"name":"","label":"SONOFF BAÑO","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":820,"wires":[]},{"id":"1da47b24.52b7d5","type":"mqtt in","z":"2f7fb3d3.985d9c","name":"","topic":"tele/sonoffpasillo/STATE","qos":"2","broker":"32ed8c49.582164","x":370,"y":860,"wires":[["f9fcbc2.243d34"]]},{"id":"f9fcbc2.243d34","type":"trigger","z":"2f7fb3d3.985d9c","op1":"MODULE  CONNECTED","op2":"MODULE  LOST","op1type":"str","op2type":"str","duration":"10","extend":true,"units":"min","reset":"","name":"","x":600,"y":860,"wires":[["2872164f.ee0bfa"]]},{"id":"2872164f.ee0bfa","type":"ui_text","z":"2f7fb3d3.985d9c","group":"6977e773.ba2438","order":16,"width":0,"height":0,"name":"","label":"SONOFF PASIL","format":"<font color=YELLOW>{{msg.payload}}</font>","layout":"row-spread","x":800,"y":860,"wires":[]},{"id":"32ed8c49.582164","type":"mqtt-broker","z":"","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"6977e773.ba2438","type":"ui_group","z":"","name":"system","tab":"5f054619.865f78","order":1,"disp":true,"width":"6"},{"id":"5f054619.865f78","type":"ui_tab","z":"","name":"SYSTEM","icon":"fa-cog","order":6}]


Best regards
Screen Shot 06-07-17 at 07.34 PM.PNG

Pedro Reboredo

unread,
Jun 8, 2017, 3:28:31 PM6/8/17
to Node-RED
Hi,

alternatively you could also generate the HTML code for e.g. a table within a Node-Red function node.
This can serve e.g. as an Input for a Template node.

Cheers

Julian Knight

unread,
Jun 8, 2017, 3:49:27 PM6/8/17
to Node-RED
As an alternative, maybe try using the topic name as an ID on html elements (you may need to replace invalid ID chars). Not sure if this is easy to do with Angular but it is easy to do with JQuery and there is an example in the flows library from me (TotallyInformation) from before Dashboard or even UI was a thing - look for the debug web page output example. You will see that it receives messages and uses the topic to either create or update a div so you don't need to worry about having the msgs come in separately. 

Lennart Hennigs

unread,
Jun 9, 2017, 10:55:28 AM6/9/17
to Node-RED


Hey guys,

thanks for all your help. It is working now. I used a mashup of your ideas & suggestions.
Here is how it is implemented now:

With the mqtt node I get automatic messages from all ESPs running homie

This is similar to the suggestion from David, but I didn't want to hardwire my devices so I can add or remove devices withouut changing the flow. Hence I used the wildcard.


The function node stores the data in the context and sends it on to the template node like Colin suggested.



There I use it to generate a table reusing bits of Steve's code:


The result now looks like this:



This is exactly what I was looking for. Thanks.

Here is the source:


[{"id":"86ef05b.41e0af8","type":"mqtt in","z":"b3c692d7.9e1bf","name":"","topic":"axure/+/$online","qos":"2","broker":"20b4bf75.197a","x":140,"y":100,"wires":[["30d90fac.5b27f","2be3948.a1bd06c"]]},{"id":"30d90fac.5b27f","type":"function","z":"b3c692d7.9e1bf","name":"store status","func":"var deviceStatus = context.get('deviceStatus') || {};\n\nvar parts = msg.topic.split(\"/\");\ndeviceStatus[parts[1]] = (msg.payload == \"true\") ? \"online\" : \"offline\";\ncontext.set(\"deviceStatus\", deviceStatus);\n\nmsg.topic = \"deviceStatus\";\nmsg.payload = deviceStatus;\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":100,"wires":[["bb837253.0a60c","c2c8fbdb.e9b3b8"]]},{"id":"2be3948.a1bd06c","type":"debug","z":"b3c692d7.9e1bf","name":"","active":true,"console":"false","complete":"true","x":310,"y":140,"wires":[]},{"id":"2326e758.3682b8","type":"comment","z":"b3c692d7.9e1bf","name":"monitor online status","info":"","x":140,"y":60,"wires":[]},{"id":"bb837253.0a60c","type":"ui_template","z":"b3c692d7.9e1bf","group":"e536ee0f.6b586","name":"Device Status Table","order":0,"width":0,"height":0,"format":"\n<table style=\"width: 50%\">\n    <thead>\n        <tr>\n            <th style=\"text-align: left\">Device</th>\n            <th style=\"text-align: left; width: 10%\">Online</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr ng-repeat=\"(key, value) in msg.payload\">\n            <td>{{key}}</td>\n            <td ng-switch on=\"value\">\n            <span ng-switch-when=\"online\"><ng-md-icon icon=\"check_circle\" style=\"color: green\" size=\"20\"></ng-md-icon></span>\n            <span ng-switch-when=\"offline\"><ng-md-icon icon=\"error\" style=\"color: red\" size=\"20\"></ng-md-icon></span>\n            </td>\n        </tr>\n    </tbody>\n</table>","storeOutMessages":true,"fwdInMessages":true,"x":550,"y":100,"wires":[[]]},{"id":"c2c8fbdb.e9b3b8","type":"debug","z":"b3c692d7.9e1bf","name":"","active":true,"console":"false","complete":"true","x":510,"y":140,"wires":[]},{"id":"20b4bf75.197a","type":"mqtt-broker","z":"","broker":"192.168.42.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":""},{"id":"e536ee0f.6b586","type":"ui_group","z":"","name":"Axure Dashboard","tab":"3a8ca5f4.05522a","disp":true,"width":"8"},{"id":"3a8ca5f4.05522a","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}]

 

Cheers

l.

Dave C-J

unread,
Jun 9, 2017, 11:25:27 AM6/9/17
to node...@googlegroups.com
Sweet !
nice and "simple"

Julian Knight

unread,
Jun 9, 2017, 4:04:58 PM6/9/17
to Node-RED
Looks good and may be (OK, lets be honest - IS) a little simpler than the way I do it.

My ESP's all have an initial msg and a last will and testament defined in their connection so that they publish an Online message against their hardware ID when they start up and if they go offline, the broker changes the status to Offline. That way, if I want to expose those, I can simply listen directly for the Online/Offline message.

I also have a set of flows that listen to other hardware inputs (not network enabled) from multiple sources. That flow normalises and enhances the incoming data and republishes on a new topic with a unified hardware ID.

A second set of flows takes the unified topics and spits out more specific topics such as Temperature, command status, etc. But it also splits early on and has a separate branch that feeds each non-networked hardware ID into a timer that is reset when a new msg from that id comes in, if the time expires, I send an Offline MQTT msg otherwise the first msg received sends an Online msg.

It is all pretty robust, accounts for non-MQTT enabled devices and makes sure everything is disaggregated for maximum flexibility.

Lennart Hennigs

unread,
Jun 14, 2017, 11:03:43 AM6/14/17
to Node-RED
Hey guys, thank your for your comments.

I tweaked the flow a bit more because I wanted to show some addition information in the table:
-  the device's name
-  what is connected to it
-  it's battery status
- the online status

The homie library on the ESPs takes care of tracking the online/offline status and keeps a description of the ESPs as "device properties".
To calculate the battery level I use a voltage divider circuit as described here and create a separate topic for it which is updated every 5 seconds, or so.


In the function nodes I store each message in an flow context array. 



The trigger node creates and updated the table also every 5 seconds.

The resulting table now looks like this:


The resulting table now looks like this:


Offline devices are grey, and low and critical battery statuses are indicated.


Cheers

l.






urs.epp...@switch.ch

unread,
Jun 15, 2017, 12:04:16 AM6/15/17
to Node-RED
Hello Lennart

Congratulatins, this looks very nice.
I follow the homie development loosely, since I run a similar infrastructure at home.
I went for another structure with the topics, but might change it to the homie convention in the future, we'll see.

I would like to learn from your code. Would you please post it in the flows library on flows.nodered.org ?
It does not need to be perfect.

Kind regards,

Urs.

Julian Knight

unread,
Jun 15, 2017, 12:32:19 PM6/15/17
to Node-RED
I'll second that. And thanks to you for prompting me to go back and look at Homie again. Having done so, I've already started building my next sensor platform using it as I'm really impressed. I will have to change my device topic structure but Homie is actually using one quite similar to the one I'd designed for my next rework of my HA platform anyway.

I think it took about an hour of messing around to work up a mashup between my old code (for the sensors parts) and Homie (for everything else). Most of that was me messing. I have temperature, humidity and light all working, need to add pressure and PIR. Then I need to make them all optional and controlled by a JSON configuration file so I only need one codebase. Also want to add input commands which I never got round to properly with my first gen sensors. Homie helps with that too and it will all happen via MQTT of course. And finally, I want to add a nicer web page for each sensor that the 1st gen version I had.

Lennart Hennigs

unread,
Jun 23, 2017, 4:48:52 AM6/23/17
to Node-RED
Hey guys, 

Cheers
l.

Julian Knight

unread,
Jun 24, 2017, 3:54:32 PM6/24/17
to Node-RED
That's great, thanks for sharing with the community, very helpful.

I'm really liking Homie by the way and I'm about to start re-engineering the inputs from my non-ESP8266 devices to use the same format so that I can rework my entire home automation to something rather simpler.

I'm also working on a single code-base for my ESP8266 sensors that uses Home and all all the possible sensor code I might need in place but is able to exclude code based on settings in the json file. That way I can also publish the code without revealing private information for each sensor. I've also just ordered some TI HDC1080 based temp/humidity sensors that are a lot more accurate than the DHT22's I've got in most places.
Reply all
Reply to author
Forward
0 new messages