HowTo: Node Red / Magic Mirror - Displaying Node Red Data on the Mirror

For a long time, I was looking for a way to easily display the data that I collect with NodeRed from my SmartHome on the MagicMirror.
Thanks to the many plugins for the MagicMirror and NodeRed this was implemented faster than expected. How it works is described in the following article.

Hints for our lovely english readers: Basically, many of the articles on Nerdiy.de are translations from the original german articles. Therefore, it may happen here and there that some illustrations are not available in english and that some translations are weird/strange/full of mistakes or generally totaly wrong. So if you find some obvious (or also not obvious) mistakes don't hesitate to leave us a hint about that in the comment section. 
Also please don't get confused, that instead of a "dot" often a "comma" is used as decimal separator. 🙂


Safety instructions

I know the following hints are always a bit annoying and seem unnecessary. But unfortunately, many people who knew it "better" from carelessness lost their eyes, fingers or other things or hurt themselves. In comparison, a loss of data is almost not worth mentioning, but even these can be really annoying. Therefore, please take five minutes to read the safety instructions. Even the coolest project is worth no injury or other annoyance. https://www.nerdiy.de/en/sicherheitshinweise/

Affiliate links / advertising links

The links to online stores listed here are so-called affiliate links. If you click on such an affiliate link and store via this link, Nerdiy.de receives a commission from the online store or provider concerned. The price doesn't change for you. If you do your purchases via these links, you will support Nerdiy.de in being able to offer further useful projects in the future. 🙂


Requirements

Helpful Articles:
Before you start with the installation, you should have prepared the RaspberryPi so far that it can be reached via the network and controlled by SSH.

The following three articles describe what to do to prepare the RaspberryPi:
RaspberryPi - Setting up for Nerdiys!
RaspberryPi - The First Configuration!
RaspberryPi - Control the RaspberryPi via SSH
MagicMirror - Installation of the required software
MagicMirror - install 3rd party modules

Required material:

In the following list you will find all the parts you need to implement this article.


Log in to the NodeRed configuration interface

Before you can edit your NodeRed configuration you must - if activated - first log in to the NodeRed configuration interface.

View of the login screen. Here you have to enter the login details that you entered during the configuration of the login. Information about this can be found in the article NodeRed - User Login Setup.

Create the data source in NodeRed as JSON

In this example, data of the RaspberryPI(which runs NodeRed) is displayed on the MagicMirror.
NodeRed provides this data as JSON, which the MagicMirror collects at regular intervals and displays on its display. You do not need to install new nodes because the data source is built from the standard nodes.

You have to build the following flow for this.

It is easier to insert the following node code:

[{"id":"cc7a1b10.a7c038","type":"http in","z":"8c9f8f17.13eb78","name":"","url":"/daten.json","method":"get","upload":false,"swaggerDoc":"","x":320,"y":460,"wires":[["61e489ce.08eb68"]]},{"id":"89f4552e.8cc4f8","type":"http response","z":"8c9f8f17.13eb78","name":"","x":1040,"y":460,"wires":[]},{"id":"ced95c01.75153","type":"change","z":"8c9f8f17.13eb78","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"application/json","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":880,"y":460,"wires":[["89f4552e.8cc4f8"]]},{"id":"a5b108a6.e68c88","type":"template","z":"8c9f8f17.13eb78", "name": "page", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template":"{"data": \"RPi Temp\",\n \"value\": \"{{temp}}°C\",\n \"lastUpdate\": \"{{temp-timestamp}}\"\n },\n \"name\": \"CPU Load\",\n \"value\": \"{{load}}%\",\n \"lastUpdate\": \"{{load-timestamp}}\"\n },\n \"name\": \"Free Memory\",\n \"value\": \"{{free}}MB\",\n \"lastUpdate\": \"{{free-timestamp}}\"\n }\n ]\n}","output":"str","x":720,"y":460,"wires":[["ced95c01.75153"]]},{"id":"c088c2a8.b53bc", "type": "comment", "z": "8c9f8f17.13eb78", "name": "Json Feed to feed the MagicMirror", "info":"", "x":240, "y":80, "wires":[]},{"id": "61e489ce.08eb68","type":"change","z":"8c9f8f17.13eb78","name":"Copy time","rules":[{"t":"set","p":"temp","pt":"msg","to":"temp","tot":"flow"},{"t":"set","p":"temp-timestamp","pt":"msg","to":"temp-timestamp","tot":"flow"},{"t":"set","p":"load","pt":"msg","to":"load","tot":"flow"},{"t":"set","p":"load-timestamp","pt":"msg","to":"load-timestamp","tot":"flow"},{"t":"set","p":"free","pt":"msg","to":"free","tot":"flow"},{"t":"set","p":"free-timestamp","pt":"msg","to":"free-timestamp","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":460,"wires":[["a5b108a6.e68c88"]]},{"id": "b64f17d1.b71778", "type": "comment", "z": "8c9f8f17.13eb78", "name": "Incoming data is cached here for later sending", "info":"", "x":480, "y":140, "wires":[]},{"id": "9eede084.b713a", "type": "comment", "z": "8c9f8f17.13eb78", "name": "Here the stored data are delivered as Json", "info":"", "x":410, "y":420, "wires":[]},{"id": "877b026b.7bbd9","type":"exec","z":"8c9f8f17.13eb78","command":"vcgencmd measure_temp","addpay":false,"append":"","useSpawn":"","timer":"","name":"RPi Temp.","x":510,"y":220,"wires":[["c71030c9.e8723"],[],[]]},{"id":"e2c23c0f.e6896","type":"inject","z":"8c9f8f17.13eb78","name":"","topic":"","payload":"","payloadType":"date","repeat":"10","crontab":"","once":false,"onceDelay":"","x":310,"y":220,"wires":[["877b026b.7bbd9","bd2a3aa8.b05be8","f6021bf6.b47108"]]},{"id":"c71030c9.e8723","type":"function","z":"8c9f8f17.13eb78","name":"cutString","func":"str = msg.payload\nmsg.payload = str.substring(5,9);\nreturn msg;","outputs":1,"noerr":0,"x":700,"y":220,"wires":[["38abd283.af271e"]]},{"id":"bd2a3aa8.b05be8","type":"exec","z":"8c9f8f17.13eb78", "command": "top -d 1 -b -n2 | grep \"Cpu(s)\"|tail -n 1 | awk '{print $2 + $4}'", "addpay":false,"append":"","useSpawn":"","timer":"","oldrc":false,"name":"CPU Load","x":510,"y":280,"wires":[["966babc4.47d538"],[],[]]},{"id":"f6021bf6.b47108","type":"exec","z":"8c9f8f17.13eb78", "command": "free | grep Mem | awk '{print 100*($4+$6+$7)/$2}'", "addpay":false, "append":"", "useSpawn":"", "timer":"", "name": "Free Memory", "x":510, "y":340, "wires":[["350be0e6.dc723"],[],[]]},{"id":"ff73e7b0.560078","type":"change","z":"8c9f8f17.13eb78","name":"Store time","rules":[{"t":"set","p":"temp","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"temp-timestamp","pt":"flow","to":"timestamp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":220,"wires":[[]]},{"id":"ec6a82fb.238ff","type":"change","z":"8c9f8f17.13eb78","name":"Store time","rules":[{"t":"set","p":"load","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"load-timestamp","pt":"flow","to":"timestamp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":280,"wires":[[]]},{"id":"bd9b96f7.e4c268","type":"change","z":"8c9f8f17.13eb78","name":"Store time","rules":[{"t":"set","p":"free","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"free-timestamp","pt":"flow","to":"timestamp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":340,"wires":[[]]},{"id":"38abd283.af271e", "type": "function", "z": "8c9f8f17.13eb78", "name": "addTimestamp", "func": "msg.payload = msg.payload;\nvar now = new Date();\nvar Hours=now.getHours();\nvar Minutes=now.getMinutes();\nvar Seconds=now.getSeconds();\n\n if (Seconds<10)\n Seconds=\"0\"+Seconds;\n \n if (Minutes<10)\n Minutes=\"0\"+Minutes;\n \n if (Hours<10)\n Hours=\"0\"+Hours;\n \nmsg.timestamp=Hours+\":\"+Minutes+\":\"+Seconds;\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":220,"wires":[["ff73e7b0.560078"]]},{"id":"9a625c6e.b43da","type":"function","z":"8c9f8f17.13eb78","name":"addTimestamp","func":"msg.payload = msg.payload;\nvar now = new Date();\nvar Hours=now.getHours();\nvar Minutes=now.getMinutes();\nvar Seconds=now.getSeconds();\n\n if (Seconds<10)\n Seconds=\"0\"+Seconds;\n \n if (Minutes<10)\n Minutes=\"0\"+Minutes;\n \n if (Hours<10)\n Hours=\"0\"+Hours;\n \nmsg.timestamp=Hours+\":\"+Minutes+\":\"+Seconds;\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":280,"wires":[["ec6a82fb.238ff"]]},{"id":"a85eaa63.cad4a8","type":"function","z":"8c9f8f17.13eb78","name":"addTimestamp","func":"msg.payload = msg.payload;\nvar now = new Date();\nvar Hours=now.getHours();\nvar Minutes=now.getMinutes();\nvar Seconds=now.getSeconds();\n\n if (Seconds<10)\n Seconds=\"0\"+Seconds;\n \n if (Minutes<10)\n Minutes=\"0\"+Minutes;\n \n if (Hours<10)\n Hours=\"0\"+Hours;\n \nmsg.timestamp=Hours+\":\"+Minutes+\":\"+Seconds;\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":340,"wires":[["bd9b96f7.e4c268"]]},{"id":"350be0e6.dc723","type":"function","z":"8c9f8f17.13eb78","name":"deleteWhitespace","func":"str = msg.payload\nmsg.payload = str.trim();\nreturn msg;", "outputs":1, "noerr":0, "x":730, "y":340, "wires":[["a85eaa63.cad4a8"]]},{"id":"966babc4.47d538","type":"function","z":"8c9f8f17.13eb78","name":"deleteWhitespace","func":"str = msg.payload\nmsg.payload = str.trim();\nreturn msg;","outputs":1,"noerr":0,"x":730,"y":280,"wires":[["9a625c6e.b43da"]]}]

Now you will see a JSON with the data entered by you at the following address.

https://IP_EURER_NODE_RED_INSTALLATION:1880/daten.json

This can now be displayed by a MagicMirror plugin. Of course you have to replace the "IP_EURER_NODE_RED_INSTALLATION"-part by the IP address of your NodeRed Server. It is also important that you check if you need an "https://" or "http://" in front of your IP address. This depents weather you have your NodeRed-connection encrypted or not.

JSON data as displayed to you in the Firefox browser. This one is good for debugging because it also displays errors in the JSON structure.

Installation of the module

In order for you to be able to view the data provided to you by NodeRed as JSON on the MagicMirror, you must then install the "MMM-JsonTable" module. You can find it at https://github.com/timdows/MMM-JsonTable.

Install this on your RaspberryPi. How to install your module is described in the following article:
MagicMirror - install 3rd party modules


Configuration of the module

The configuration of the module is kept simple, as the structure of the displayed data is given by the JSON.

sudo nano ~/MagicMirror/config/config.js
Open the configuration file of your MagicMirror and insert the module configuration.
{
   module: 'MMM-JsonTable',
   position: 'top_right',
   header: 'raspi-status',
   config: {
      url: 'https://IP_EURER_NODE_RED_INSTALLATION:1880/daten.json', // Required
      arrayName: 'data', // Optional
      tryFormatDate: false
   }
}
Of course you will replace "IP_EURER_NODE_RED_INSTALLATION" with the IP address of the RaspberryPi on which your MagicMirror is running.

Modification of the module for self-signed SSL certificates

Unfortunately, there is a problem with the MagicMirror plugin (currently: November 2018). This does not allow HTTPS connections if the SSL certificate is self-signed.
In other words, if you have your NodeRed installation secured by a self-signed SSL certificate as described in the article NodeRed - Encrypting Connectionthe MagicMirror plugin will not be able to load or display the data from the JSON.

To solve this problem, there is a small workaround that shuts off this security feature. This means that the MagicMirror plugin can also accept self-signed SSL certificates and display the data of your JSON.

Go to the module folder of the MagicMirror module you just installed.

cd MagicMirror/modules/MMM-JsonTable/

There you open the file "node_helper.js" with the following command:

sudo nano node_helper.js

In the opened file you must now find the line with the following content:

request({ url: url, method: 'GET'}, function (error, response, body) {
In the uncorrected file you have to find the line with "request ({url: url, method: 'GET'}, function (error, response, body) {".

Now in this line you have to insert the command ", rejectUnauthorized: false" after the "... method: 'GET'".
The line should look like this:

 request({ url: url, method: 'GET', rejectUnauthorized: false}, function (error, response, body){
The corrected line looks like this.
Then you save the file again by pressing "CTRL + X", then confirm with "J"(Or "y") ...
... and leave the file with "Enter".

Last but not least, you have to restart your MagicMirror installation by entering the following command:

pm2 restart mm

After restarting and reloading the MagicMirror view, the data from the JSON will be displayed. 🙂


Additional Information

https://github.com/MichMich/MagicMirror
https://github.com/timdows/MMM-JsonTable


Have fun with the project

I hope everything worked as described. If not or you have any other questions or suggestions, please let me know in the comments. Also, ideas for new projects are always welcome. 🙂

P.S. Many of these projects - especially the hardware projects - cost a lot of time and money. Of course I do this because I enjoy it, but if you appreciate that I share this information with you, I would be happy about a small donation to the coffee box. 🙂

Buy Me a Coffee at ko-fi.com   

9 comments

  1. Hi, great site! I'm just starting with RedNote and came across your site by accident. Top!
    Magicmirror I run a little longer and my question is, can I display other JSon data ?

    Greeting Stefan

    1. Hi Stefan, thanks I'm glad 🙂
      Of course you can change the data that is displayed. In principle you only have to change the data that is forwarded to the "cutString or "deleteWhitespace" nodes.
      Best regards
      Fabian

  2. Great, thank you very much. Then I try h that times...
    But I am still struggling with the Weatherground. I can't get it to display correctly.

    Greeting Stefan

      1. Hi, sorry I meant your openweathermap.org... 😉
        I somehow do not get it displayed under each other and also not everything.
        But it'll be fine, I'll have to fiddle with it a bit.

        Do you actually have a forum or something here where you can exchange ideas ?

        1. Hey,
          no problem. 🙂 What do you not get each other? The view in the dashboard?
          Yes, I have once set up a forum. But must still expand something. I'll take care of it tomorrow. 🙂
          Best regards
          Fab

  3. Thanks for the tutorial!
    I had the bug that the module only showed "Awaiting json data..." at the beginning.
    A reboot fixed that.

Kommentar hinterlassen

Your email address will not be published. Erforderliche Felder sind mit * markiert