Skip to content

Instantly share code, notes, and snippets.

@gestadieu
Last active July 19, 2023 23:37
Show Gist options
  • Save gestadieu/25af5334a79d6c02d6413968a8bff572 to your computer and use it in GitHub Desktop.
Save gestadieu/25af5334a79d6c02d6413968a8bff572 to your computer and use it in GitHub Desktop.
Raspberry Pi Control Dashboard

Requirement: node-red-dashboard. Obviously you will need a Raspberry Pi too!

This is a simple but very useful dashboard to control a Raspberry Pi (similar to Cayenne dashboard for RPi), it includes so far:

  • CPU Temperature
  • CPU Load %
  • Free RAM %
  • Disk Usage %
  • Actions: Shutdown and Reboot buttons

Feel free to fork and and more stuff ;-) You can get some info and screenshots here

[
{
"id": "2653a0b0.26d638",
"type": "ui_gauge",
"z": "a9ef8731.662048",
"name": "",
"group": "1890881e.83819",
"order": 2,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "CPU Temperature",
"label": "C",
"format": "{{value}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"x": 730,
"y": 140,
"wires": []
},
{
"id": "fba68adf.14e13",
"type": "exec",
"z": "a9ef8731.662048",
"command": "vcgencmd measure_temp",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "RPi Temp.",
"x": 370,
"y": 140,
"wires": [
[
"fa5b499.e176cb8"
],
[],
[]
]
},
{
"id": "7c8379de.068868",
"type": "inject",
"z": "a9ef8731.662048",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "10",
"crontab": "",
"once": false,
"x": 164.5,
"y": 148.25,
"wires": [
[
"fba68adf.14e13",
"972ece2a.3dbe8",
"6242be99.26ac88"
]
]
},
{
"id": "fa5b499.e176cb8",
"type": "function",
"z": "a9ef8731.662048",
"name": "",
"func": "str = msg.payload\nmsg.payload = str.substring(5,9);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 550,
"y": 140,
"wires": [
[
"2653a0b0.26d638",
"28b64a2c.b32116"
]
]
},
{
"id": "683a2b05.736204",
"type": "ui_button",
"z": "a9ef8731.662048",
"name": "",
"group": "c5f1b8aa.45bc08",
"order": 2,
"width": 0,
"height": 0,
"label": "Reboot",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "",
"x": 140,
"y": 520,
"wires": [
[
"1cf31554.2aaa63"
]
]
},
{
"id": "1cf31554.2aaa63",
"type": "exec",
"z": "a9ef8731.662048",
"command": "sudo reboot",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "Reboot",
"x": 358,
"y": 520,
"wires": [
[],
[],
[]
]
},
{
"id": "38e53dbf.ca594a",
"type": "ui_button",
"z": "a9ef8731.662048",
"name": "",
"group": "c5f1b8aa.45bc08",
"order": 3,
"width": 0,
"height": 0,
"label": "Shutdown",
"color": "",
"bgcolor": "red",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "",
"x": 148.5,
"y": 564.25,
"wires": [
[
"c409cae5.8e4128"
]
]
},
{
"id": "c409cae5.8e4128",
"type": "exec",
"z": "a9ef8731.662048",
"command": "sudo shutdown -h now",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "Shutdown",
"x": 369.5,
"y": 582.25,
"wires": [
[],
[],
[]
]
},
{
"id": "28b64a2c.b32116",
"type": "ui_chart",
"z": "a9ef8731.662048",
"name": "",
"group": "1890881e.83819",
"order": 3,
"width": 0,
"height": 0,
"label": "",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"ymin": "",
"ymax": "",
"removeOlder": "24",
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"x": 730,
"y": 180,
"wires": [
[],
[]
]
},
{
"id": "972ece2a.3dbe8",
"type": "exec",
"z": "a9ef8731.662048",
"command": "top -d 0.5 -b -n2 | grep \"Cpu(s)\"|tail -n 1 | awk '{print $2 + $4}'",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "CPU Load",
"x": 370,
"y": 220,
"wires": [
[
"b9372186.ed1a5"
],
[],
[]
]
},
{
"id": "6242be99.26ac88",
"type": "exec",
"z": "a9ef8731.662048",
"command": "free | grep Mem | awk '{print 100*($4+$6+$7)/$2}'",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "Free Memory",
"x": 370,
"y": 300,
"wires": [
[
"9b301b09.8c0468"
],
[],
[]
]
},
{
"id": "b9372186.ed1a5",
"type": "ui_gauge",
"z": "a9ef8731.662048",
"name": "",
"group": "1890881e.83819",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "Processor",
"label": "CPU",
"format": "{{value}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"x": 730,
"y": 220,
"wires": []
},
{
"id": "9b301b09.8c0468",
"type": "ui_gauge",
"z": "a9ef8731.662048",
"name": "",
"group": "9a96a8b1.92db78",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "Memory",
"label": "RAM",
"format": "{{value.toFixed(1)}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"x": 730,
"y": 300,
"wires": []
},
{
"id": "270f61f0.9af05e",
"type": "exec",
"z": "a9ef8731.662048",
"command": "df -h",
"addpay": false,
"append": "",
"useSpawn": "",
"timer": "",
"name": "Disk Usage",
"x": 370,
"y": 380,
"wires": [
[
"d70b7556.a0a9e"
],
[],
[]
]
},
{
"id": "7ca6ecb.7512014",
"type": "ui_gauge",
"z": "a9ef8731.662048",
"name": "",
"group": "72fc319.cc425d",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "Disk",
"label": "Usage",
"format": "{{value}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"x": 730,
"y": 380,
"wires": []
},
{
"id": "d70b7556.a0a9e",
"type": "function",
"z": "a9ef8731.662048",
"name": "",
"func": "var re = /([0-9]{2})%/\nvar idx = msg.payload.search(re);\nvar str = msg.payload;\nif (idx >=0) {\n str = msg.payload.substring(idx, idx + 2);\n}\nmsg.payload = str;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 550,
"y": 380,
"wires": [
[
"7ca6ecb.7512014"
]
]
},
{
"id": "59103f97.07fed",
"type": "inject",
"z": "a9ef8731.662048",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "60",
"crontab": "",
"once": false,
"x": 170,
"y": 380,
"wires": [
[
"270f61f0.9af05e"
]
]
},
{
"id": "1890881e.83819",
"type": "ui_group",
"z": "",
"name": "Col1",
"tab": "c3173234.2636e",
"order": 1,
"disp": false,
"width": "6"
},
{
"id": "c5f1b8aa.45bc08",
"type": "ui_group",
"z": "",
"name": "Actions",
"tab": "c3173234.2636e",
"order": 4,
"disp": true,
"width": "6"
},
{
"id": "9a96a8b1.92db78",
"type": "ui_group",
"z": "",
"name": "Col2",
"tab": "c3173234.2636e",
"order": 2,
"disp": false,
"width": "6"
},
{
"id": "72fc319.cc425d",
"type": "ui_group",
"z": "",
"name": "Col3",
"tab": "c3173234.2636e",
"order": 3,
"disp": false,
"width": "6"
},
{
"id": "c3173234.2636e",
"type": "ui_tab",
"z": "",
"name": "RPi Control",
"icon": "dashboard",
"order": 1
}
]
@danbicks
Copy link

This is great, what changes are required to accuratly display information on a Raspberry PI 3 that has quad core and 1GB memory ?

Cheers

D

@cavalleydude
Copy link

cavalleydude commented Jan 22, 2018

Thank you for this flow, it's great. However, on my Raspberry Pi 3 with 1GB RAM and running the free command, I think there is new column causing the "Memory" graph to be incorrect, I think.

total used free shared buff/cache available Mem: 945520 174840 514604 19052 256076 699772 Swap: 102396 0 102396

The Memory exec is currently running this command:
free | grep Mem | awk '{print 100*($4+$6+$7)/$2}'

The calculation is 100*(USED/TOTAL), where $2 is the "total" column and $4 = free, $6 = buff/cache, and $7 = available. Then the calculation is wrong, it's showing over 150% used.

I think it should be using $3 = used, $5 = shared, and $6 buff/cache.
free | grep Mem | awk '{print 100*($3+$5+$6)/$2}'

shows 47% used in the graph.

Also, see this link describing the latest free cmd changes.
https://andythemoron.com/blog/2017-04-23/Understanding-Linux-Memory-Usage

My "free" command version is 3.3.12

@Humancell
Copy link

Yes ... this is a great example flow!

I also found one other issue in the Memory Gauge node.

The Value format that is set to {{value.toFixed(1)}} is causing errors. I had to update this to be {{value | number:1}} to have it work correctly without errors.

@ampledata
Copy link

This is great, what changes are required to accuratly display information on a Raspberry PI 3 that has quad core and 1GB memory ?

Cheers

D

Better late than never?

[
    {
        "id": "a5da1eb0f58fe89a",
        "type": "function",
        "z": "94cf869050128770",
        "name": "Average CPUs",
        "func": "const pl = msg.payload;\n\nconst loads = pl.split(\"\\n\").filter(n => n)\n\nvar total = 0;\nfor (var i = 0; i < loads.length; i++) {\n    total += loads[i];\n}\nvar avg = total / loads.length;\n\n\nmsg.payload = loads;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 520,
        "y": 680,
        "wires": [
            [
                "b9372186.ed1a5",
                "435126adc3e77f5e"
            ]
        ]
    },
    {
        "id": "972ece2a.3dbe8",
        "type": "exec",
        "z": "94cf869050128770",
        "command": "top -d 0.5 -b -n2 | grep \"Cpu(s)\"| awk '{print $2 + $4}'",
        "addpay": false,
        "append": "",
        "useSpawn": "",
        "timer": "",
        "winHide": false,
        "name": "CPU Load",
        "x": 330,
        "y": 680,
        "wires": [
            [
                "a5da1eb0f58fe89a",
                "1d0556aa4602c25b"
            ],
            [],
            []
        ]
    }
]

This code removes the tail -n 1 call from the exec, and averages CPU load across all CPUs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment