Skip to content
This repository has been archived by the owner on Nov 16, 2020. It is now read-only.

phyunsj/node-red-custom-dashboard-system-page

Repository files navigation

Node-Red Custom Dashboard Page + node-red-contrib-os

Dependencies

  • Node-RED v0.18.6
  • Node.js v8.11.2
  • node-red-contrib-os
  • bootstrap v3.3.7
  • jquery v2.2.4
  • Odometer

In Action

Flow

[{"id":"7f6aafad.dbf63","type":"http in","z":"b038fb61.944c48","name":"","url":"/benchmark","method":"get","upload":false,"swaggerDoc":"","x":110,"y":363.2222309112549,"wires":[["ec4a9465.b44c28"]]},{"id":"24d04112.87940e","type":"function","z":"b038fb61.944c48","name":"OS version","func":"//msg.payload =  \n//{ hostname: '4ZRBQ72',\n//  type: 'Windows_NT',\n//  platform: 'win32',\n//  arch: 'x64',\n//  release: '10.0.10586',\n//  endianness: 'LE'\n//}\n\nvar sysinfo = msg.payload;\n\nmsg.payload = {};\nmsg.payload.os = { \n    hostType : sysinfo.type,\n    platform : sysinfo.platform,\n    arch : sysinfo.arch\n};\n\n//console.log(msg);\nreturn msg;","outputs":1,"noerr":0,"x":298.0001106262207,"y":426.2222595214844,"wires":[["fced9b3c.226228","7cf1913b.82146"]]},{"id":"413ce72f.1610c8","type":"template","z":"b038fb61.944c48","name":"CSS","field":"payload.style","fieldType":"msg","format":"html","syntax":"mustache","template":"body{\n  font-family: 'Droid Sans', 'Helvetica', Arial, sans-serif;\n  margin:3px;\n\n}\n.carousel{\n    background: #2f4357;\n    margin-top: 20px;\n}\n.carousel .item{\n    min-height: 300px; /* Prevent carousel from being distorted if for some reason image doesn't load */\n}\n.carousel .item img{\n    margin: 0 auto; /* Align slide image horizontally center */\n}\n\n.odometer {\n    font-size: 30px;\n}","x":491.00000381469727,"y":364.2222318649292,"wires":[["f2998092.6df02"]]},{"id":"7cf1913b.82146","type":"template","z":"b038fb61.944c48","name":"JavaScript","field":"payload.script","fieldType":"msg","format":"javascript","syntax":"plain","template":"(function ($) {\n\n/////////////////////////////////\nvar loc = window.location;\nvar ws;\nvar wsUri = \"ws:\";\n\nif (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n// This needs to point to the web socket in the Node-RED flow\n// ... in this case it's ws/simple\nwsUri += \"//\" + loc.host + loc.pathname.replace(\"benchmark\",\"ws/alert\");\n\n///////////////////////////////////////////////\n// WebSocket \nfunction init() {\n    console.log(\"connect\",wsUri);\n    ws = new WebSocket(wsUri);\n\n    ws.onopen = function() {\n       console.log(\"connected\");\n    }\n    \n    ws.onclose = function() {\n        setTimeout(wsConnect,5000);\n    }\n    \n    ws.onmessage = function(msg) {\n        var payload = JSON.parse(msg.data);\n        response ( payload );\n    }\n}\n\nfunction request(m) {\n    // Browser -> Server\n    // Nothing has been defined yet\n    if (ws) { ws.send(m); }\n}\n \nfunction response(payload) {\n    // console.log(payload);\n    // Browser <- Server\n    if (payload.hasOwnProperty('uptime')) {\n        //console.log(payload.uptime);\n        uptime_meter.innerHTML = payload.uptime.uptime;\n    }\n    if (payload.hasOwnProperty('cpu')) {\n        // console.log(payload.cpu.cpus[0]);\n        var cpu = payload.cpu.cpus[0];\n        // model, speed, times { user:, nice:, sys:, idle: }\n        $('#cpuModel').html(cpu.model.substr(0, cpu.model.indexOf('@')));\n        \n        var cpuSpeed = cpu.speed / 1000; \n        $('#cpuSpeed').html(cpuSpeed);\n        \n        // Performance\n        $('#cpuUser').html(cpu.times.user);\n        $('#cpuSys').html(cpu.times.sys);\n        $('#cpuIdle').html(cpu.times.idle);\n    }\n    if (payload.hasOwnProperty('load')) {\n \n    }\n    if (payload.hasOwnProperty('memory')) {\n        // console.log(payload.memory);\n        // totalmem, freemem, memusage (%)\n        var total_m = parseFloat(payload.memory.totalmem / 1073741824).toFixed( 2 );\n        var free_m = parseFloat(payload.memory.freemem / 1073741824).toFixed( 2 );\n        var used_m = parseFloat(total_m - free_m).toFixed( 2 ) ;\n        \n        $('#totalMem').html(total_m);\n        $('#freeMem').html(free_m);\n        $('#memUsage').html(payload.memory.memusage);\n        $('#memUsageGB').html(used_m);\n        \n    }\n    if (payload.hasOwnProperty('network')) {\n        console.log(payload.network);\n        var wireless = payload.network.networkInterfaces[\"Wi-Fi\"];\n        var address = wireless[1].address;\n        var family = wireless[1].family;\n        var mac = wireless[1].mac;\n        var netmask = wireless[1].netmask;\n        \n        $('#nAddress').html(address);\n        $('#nFamily').html(family);\n        $('#nMac').html(mac);\n        $('#nNetmask').html(netmask);\n    }\n}\n  \n$(window).load(init);\n  \n}(jQuery));\n","x":337.0000534057617,"y":363.2222309112549,"wires":[["413ce72f.1610c8"]]},{"id":"f2998092.6df02","type":"template","z":"b038fb61.944c48","name":"HTML","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!doctype html>\n<html>\n<head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n\n    <!-- Bootstrap CSS -->\n    <!-- Latest compiled and minified CSS -->\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">\n    <link href=\"https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css\" rel=\"stylesheet\" integrity=\"sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN\" crossorigin=\"anonymous\">\n    <style>{{{payload.style}}}</style>\n    \n    <!-- jQuery first, then Bootstrap JS -->\n    <script src=\"https://code.jquery.com/jquery-2.2.4.js\" integrity=\"sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=\"  crossorigin=\"anonymous\"></script> <!-- Latest compiled and minified JavaScript -->\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js\" integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\" crossorigin=\"anonymous\"></script>\n\n    <!-- Odometr includes -->\n    <link rel=\"stylesheet\" href=\"http://github.hubspot.com/odometer/themes/odometer-theme-train-station.css\" />\n    <script src=\"http://github.hubspot.com/odometer/odometer.js\"></script>\n\n    <script>{{{payload.script}}}</script>\n</head>\n<body>    <!-- Fixed navbar -->\n    <nav class=\"navbar navbar-default navbar-fixed-top\">\n        <div class=\"container\">\n        <div id=\"navbar\" class=\"navbar-collapse collapse\">\n          <ul class=\"nav navbar-nav\">\n            <!-- <li><a href=\"#\">Host Type <button class=\"btn btn-default navbar-btn\" >{{{payload.os.hostType}}}</button></button></a></li> -->\n            <li><a href=\"#\">Platform <button class=\"btn btn-default navbar-btn\" >{{{payload.os.platform}}}</button></a></li>\n            <li><a href=\"#\">Arch <button class=\"btn btn-default navbar-btn\" >{{{payload.os.arch}}}</button></a></li>\n          </ul>\n        </div><!--/.nav-collapse -->\n        </div>\n    </nav>\n<div>\n    <div id=\"myCarousel\" class=\"carousel slide\" data-interval=\"3000\" data-ride=\"carousel\">\n    \t<!-- Carousel indicators -->\n        <ol class=\"carousel-indicators\">\n            <li data-target=\"#myCarousel\" data-slide-to=\"0\" class=\"active\"></li>\n            <li data-target=\"#myCarousel\" data-slide-to=\"1\"></li>\n            <li data-target=\"#myCarousel\" data-slide-to=\"2\"></li>\n        </ol>   \n        <!-- Wrapper for carousel items -->\n        <div class=\"carousel-inner\">\n            <div class=\"active item\">\n                <div class=\"carousel-caption\">\n                    <h3>CPU</h3>\n                    <div>Model  <span id=\"cpuModel\" class=\"label label-default\">Intel</span></div>\n                    <div>Speed <span id=\"cpuSpeed\" class=\"label label-default\">0</span> GHz</div>\n\n                    <h3>Performance</h3>\n                    <div>User <span id=\"cpuUser\" class=\"label label-warning\" >0</span>\n                        Sys  <span id=\"cpuSys\" class=\"label label-warning\">0</span>\n                        Idle  <span id=\"cpuIdle\" class=\"label label-primary\">0</span>\n                    </div>\n                </div>\n            </div>\n            <div class=\"item\">\n                <div class=\"carousel-caption\">\n                  <h3>Memory</h3>\n                  <div>Total <span id=\"totalMem\" class=\"label label-primary\">0</span> GB </div>\n                  <div>Free  <span id=\"freeMem\" class=\"label label-primary\">0</span> GB</div>\n                  <br>\n                  <div>Usage  <span id=\"memUsageGB\" class=\"label label-warning\">0</span>GB <span id=\"memUsage\" class=\"label label-warning\">0</span> %</div>\n                  \n                </div>\n            </div>\n            <div class=\"item\">\n                <div class=\"carousel-caption\">\n                  <h3>Wi-Fi Network</h3>\n                  <div>Family   <span id=\"nFamily\" class=\"label label-primary\">IPv4</span></div>\n                  <div>Address  <span id=\"nAddress\" class=\"label label-primary\">0:0:0:0</span></div>\n                  <div>Netmask  <span id=\"nNetmask\" class=\"label label-primary\">0:0:0:0</span></div>\n                  <br>\n                  <div>Mac  <span id=\"nMac\" class=\"label label-primary\">0:0:0:0:0:0</span></div>\n                  </div>\n            </div>\n        </div>\n        <!-- Carousel controls -->\n        <a class=\"carousel-control left\" href=\"#myCarousel\" data-slide=\"prev\">\n            <span class=\"glyphicon glyphicon-chevron-left\"></span>\n        </a>\n        <a class=\"carousel-control right\" href=\"#myCarousel\" data-slide=\"next\">\n            <span class=\"glyphicon glyphicon-chevron-right\"></span>\n        </a>\n    </div>\n  </div>\n</div> \n<br>\n<div class=\"container\">\n    <div class=\"row\">\n        <div  class=\"col-lg-6 col-lg-offset-3 text-center\">\n        <span ><font size=\"4\">Uptime</font></span> <div id=\"uptime_meter\" class=\"odometer\">8888.88</div>  \n        </div>\n    </div>\n</div>\n</body>\n</html>","output":"str","x":625.0000591278076,"y":365.2222309112549,"wires":[["c3d4f2ba.80bce"]]},{"id":"97927252.ccf6a","type":"comment","z":"b038fb61.944c48","name":"Extract OS Info (Static Info )","info":"","x":207.00003051757812,"y":466.2222328186035,"wires":[]},{"id":"2b7eb011.5a38c","type":"comment","z":"b038fb61.944c48","name":"http://localhost:1880/benchmark","info":"","x":163,"y":319.222204208374,"wires":[]},{"id":"5551eb83.09fcf4","type":"comment","z":"b038fb61.944c48","name":"Message to Browser","info":"","x":736.0000076293945,"y":533.2222328186035,"wires":[]},{"id":"4b32c04b.afc31","type":"comment","z":"b038fb61.944c48","name":"System Monitoring Site","info":"","x":383,"y":268.222204208374,"wires":[]},{"id":"1a19686b.0696a8","type":"comment","z":"b038fb61.944c48","name":"System Monitor","info":"","x":96.16665649414062,"y":596.3333978652954,"wires":[]},{"id":"863c0c88.261fe","type":"inject","z":"b038fb61.944c48","name":"","topic":"","payload":"","payloadType":"date","repeat":"3","crontab":"","once":false,"onceDelay":0.1,"x":107,"y":656.1112308502197,"wires":[["62cf35d7.25743c","65032b5f.0dcc54","ca86d276.86751","636732a9.866fec","8c497129.df344"]]},{"id":"eb69f34b.b6f84","type":"debug","z":"b038fb61.944c48","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":727.1666717529297,"y":741.0000114440918,"wires":[]},{"id":"c02c8662.1b2448","type":"websocket out","z":"b038fb61.944c48","name":"","server":"d53abbe8.b7e5e8","client":"","x":739.1666717529297,"y":572.8888988494873,"wires":[]},{"id":"ec4a9465.b44c28","type":"OS","z":"b038fb61.944c48","name":"","x":148.16665267944336,"y":426.00003719329834,"wires":[["24d04112.87940e"]]},{"id":"62cf35d7.25743c","type":"Uptime","z":"b038fb61.944c48","name":"","x":319.1666717529297,"y":554.0000114440918,"wires":[["6c51054a.57b07c"]]},{"id":"65032b5f.0dcc54","type":"CPUs","z":"b038fb61.944c48","name":"","x":328.1666679382324,"y":605.0000114440918,"wires":[["2be22056.a552"]]},{"id":"c3d4f2ba.80bce","type":"http response","z":"b038fb61.944c48","name":"","statusCode":"","headers":{},"x":765.1666717529297,"y":364.555645942688,"wires":[]},{"id":"ca86d276.86751","type":"Loadavg","z":"b038fb61.944c48","name":"","x":319.1666717529297,"y":652.8889007568359,"wires":[["b1450aa1.41a2e8"]]},{"id":"636732a9.866fec","type":"Memory","z":"b038fb61.944c48","name":"","x":315.1666717529297,"y":708.8889007568359,"wires":[["7ff09234.40e4cc"]]},{"id":"8c497129.df344","type":"NetworkIntf","z":"b038fb61.944c48","name":"Network - Wifi","x":307.1666679382324,"y":759.8889017105103,"wires":[["d65a17f.d1a96e8"]]},{"id":"fced9b3c.226228","type":"debug","z":"b038fb61.944c48","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":504.1666717529297,"y":427.00000953674316,"wires":[]},{"id":"6c51054a.57b07c","type":"function","z":"b038fb61.944c48","name":"UpTime","func":"//msg.payload =  \n//{ uptime: 4121.0176141 }\n\nmsg.topic = \"uptime\";\nreturn msg;","outputs":1,"noerr":0,"x":456.16669845581055,"y":553.3333988189697,"wires":[["9a03c38.50bc24"]]},{"id":"9a03c38.50bc24","type":"function","z":"b038fb61.944c48","name":"Collector","func":"context.data = context.data || new Object();\n\nvar ws_connected = false;\n\n// ws out node\nvar WebSocketOutNode = RED.nodes.getNode(\"c02c8662.1b2448\");\n//console.log( WebSocketOutNode );\n// status check\nws_connected = WebSocketOutNode.connected;\n\nif (ws_connected )\n    node.status({fill:\"green\",shape:\"ring\",text: 'connected' });\nelse\n    node.status({fill:\"red\",shape:\"ring\",text: 'disconnected' });\n  \nswitch (msg.topic) {\n    case \"uptime\":\n        context.data.uptime = msg.payload;\n        msg = null;\n        break;\n    case \"cpu\":\n        context.data.cpu = msg.payload;\n        msg = null;\n        break;\n    case \"load\":\n        context.data.load = msg.payload;\n        msg = null;\n        break;\n    case \"memory\":\n        context.data.memory = msg.payload;\n        msg = null;\n        break;\n    case \"network\":\n        context.data.network = msg.payload;\n        msg = null;\n        break;\n    default:\n        msg = null;\n    \tbreak;\n}\n\nif ( ws_connected ) {\n    if( context.data.uptime !== null \n     && context.data.cpu    !== null \n     && context.data.load   !== null\n     && context.data.memory !== null \n     && context.data.network !== null \n    ) {\n\t    new_msg = new Object();\n        new_msg.payload = context.data;\n        context.data=null;\n        //console.log( new_msg );\n\t    return new_msg;\n    }  else return msg;\n} else return null;","outputs":1,"noerr":0,"x":658.1666717529297,"y":654.3333721160889,"wires":[["eb69f34b.b6f84","c02c8662.1b2448"]]},{"id":"2be22056.a552","type":"function","z":"b038fb61.944c48","name":"CPU","func":"//msg.payload =  \n//{ cpu : cpus[x] }\n// cpus[]\n//   model : \"Intel(R) ....\",\n//   spped : 2712\n//   times : { user : xxxx, nice : 0, sys : xxxx, idle: xxxx }\n\nmsg.topic = \"cpu\";\nreturn msg;\n","outputs":1,"noerr":0,"x":452.16669845581055,"y":602.3333988189697,"wires":[["9a03c38.50bc24"]]},{"id":"b1450aa1.41a2e8","type":"function","z":"b038fb61.944c48","name":"Performance","func":"//msg.payload =  \n//{ load : loadavg[x] }\n\nmsg.topic = \"load\";\nreturn msg;\n","outputs":1,"noerr":0,"x":469.1666946411133,"y":654.3333988189697,"wires":[["9a03c38.50bc24"]]},{"id":"7ff09234.40e4cc","type":"function","z":"b038fb61.944c48","name":"Memory","func":"//msg.payload =  \n//{ memory : { totalmem : xxx, freemen: xxx, memusage: xxx }}\n\nmsg.topic = \"memory\";\nreturn msg;\n","outputs":1,"noerr":0,"x":460.16669845581055,"y":709.3333992958069,"wires":[["9a03c38.50bc24"]]},{"id":"d65a17f.d1a96e8","type":"function","z":"b038fb61.944c48","name":"Network","func":"//msg.payload =  \n//{ network : networkInterfaces }\n// networkInterfaces\n//   Wi-Fi[0] IPv6\n//   Wi-Fi[1] IPv4\n//   Wi-Fi[1] { address: xxx, netmask:xxx, family, xxx, mac: xxx, ...} \nmsg.topic = \"network\";\nreturn msg;\n","outputs":1,"noerr":0,"x":468.16669845581055,"y":761.333399772644,"wires":[["9a03c38.50bc24"]]},{"id":"d53abbe8.b7e5e8","type":"websocket-listener","z":"","path":"/ws/alert","wholemsg":"false"}]

WebSocket Connection Status Detection

  • RED.nodes.getNode( flow ID ) in Function Node "Collector".
// ws out node
var WebSocketOutNode = RED.nodes.getNode("c02c8662.1b2448");
//console.log( WebSocketOutNode );
// status check
ws_connected = WebSocketOutNode.connected;

  • C:\Users\<your-name>\AppData\Roaming\npm\node_modules\node-red\nodes\core\core\io\22-websocket.js
function WebSocketOutNode(n) {
        RED.nodes.createNode(this,n);
        var node = this;
        this.server = (n.client)?n.client:n.server;
        this.serverConfig = RED.nodes.getNode(this.server);
+       this.connected = false;
        if (!this.serverConfig) {
            return this.error(RED._("websocket.errors.missing-conf"));
        }
        else {
            // TODO: nls
            this.serverConfig.on('opened', function(n) { 
 +               node.connected = true; 
                 node.status({fill:"green",shape:"dot",text:"connected "+n}); });
            this.serverConfig.on('erro', function() { 
 +                node.connected = false; 
                  node.status({fill:"red",shape:"ring",text:"error"}); });
            this.serverConfig.on('closed', function(n) {
                if (n > 0) { 
 +                 node.connected = true; 
                   node.status({fill:"green",shape:"dot",text:"connected "+n}); 
                } else { 
 +                 node.connected = false; 
                   node.status({fill:"red",shape:"ring",text:"disconnected"}); 
                }
            });
        }
  • C:\Users\<your-name>\AppData\Roaming\npm\node_modules\node-red\nodes\core\core\80-function.js
        RED: {
                util: RED.util,
+               nodes : RED.nodes
 
            },

Releases

No releases published

Packages

No packages published