How to add images to Node-RED dashboards when using FlowFuse

Import your images into your Node-RED dashboards, wherever you are running your instances

Back to Blog Posts
Image representing null

Using images in your Node-RED dashboards can significantly improve your users' experience. The most common method to add images to dashboards, is to store them within the filesystem of an Node-RED instance but sometimes that's not an option. How can you easily use images when working in a containerised environment such as Docker, Kubernetes, or FlowFuse?

When designing a dashboard, images allow you to significantly enrich your content. Some examples include:

  • displaying maps to guide engineers to a problem which needs resolving.

  • displaying pictures of specific hardware on a factory-floor which needs to be checked.

  • displaying physical tools which should be used to resolve a problem.

Why not just store them in Node-RED's host operating system?

Storing images locally can work well when you can access and edit the images on an operating system, but that approach doesn't scale if you are moving instances through a DevOps pipeline. It can also not work well when deploying to environments where you don't have easy access to the host operating system.

How can we include images in dashboards, and be confident that a given build of an application will show the correct images, no matter where your Node-RED instances are hosted?

Inspiration

There are various solutions to this problem, I wanted to share one I came across when working with a FlowFuse customer recently. I've modified the flows to make them more general in design, but the underlying principal is the same. I asked if I was OK to credit the customer but they said there was no need. Thanks for the inspiration, kind customer!

Solution explanation

There are three key sections to this solution:

  1. Pull the images we need from URLs

  2. Store those images in the temporary filesystem of Node-RED

  3. Serve up those images as needed in the dashboard

It is possible for us to skip step 2, but I wanted to have the images stored locally, in the Node-RED instance. storing the images locally will improve the loading times of the dashboard. This is especially beneficial when your dashboard is dynamically displaying relevant images, e.g. to show an image of a specific machine which needs to be attended to.

The key benefit of pulling the images from URLs this way is, no matter where you are running Node-RED, the correct images will be shown in your dashboard.

File and file-in nodes

I've included the flows as json below so you can try them out yourself. Please note, I'm using FlowFuse's own file and file-in nodes in these examples. If you want to use these flows on hosting other than FlowFuse, you will need to replace the nodes with the standard Node-RED file and file-in nodes.

Custom nodes used

These flows use a few very useful custom nodes which you will need to add manually via the palette manager, they are:

The flows

The first flow takes image URLs in an array, each image is downloaded, processed, then saved to the local file storage. Let's take a look at the flow:

Download the images and save them to disk

You can import this flow into Node-RED using the code below:

[{"id":"6b8059f703d0f574","type":"group","z":"c6f2a894be05d857","name":"Write the images to disk from the URLs","style":{"label":true},"nodes":["04fb6911559797a0","8a3c077f0f85a905","22c5026dd58e418b","6fcca5cfee2bcb89"],"x":38,"y":53,"w":1004,"h":434},{"id":"04fb6911559797a0","type":"group","z":"c6f2a894be05d857","g":"6b8059f703d0f574","name":"Inject the image URLs to download","style":{"label":true},"nodes":["e635ceb0577a86d5","29fe40a054be5b2b","1e81a35c27aae6ad"],"x":74,"y":79,"w":502,"h":82},{"id":"e635ceb0577a86d5","type":"inject","z":"c6f2a894be05d857","g":"04fb6911559797a0","name":"Send in image URLs as an array","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"https://openjsf.org/wp-content/uploads/sites/84/2023/02/ff-logo-wordmark-light_4x.png\",\"https://nodered.org/images/nr-image-1.png\",\"/img/screen-pseudo-overview-2QvTVle3Mr-384.avif\"]","payloadType":"json","x":250,"y":120,"wires":[["29fe40a054be5b2b"]]},{"id":"29fe40a054be5b2b","type":"split","z":"c6f2a894be05d857","g":"04fb6911559797a0","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":450,"y":120,"wires":[["1e81a35c27aae6ad"]]},{"id":"1e81a35c27aae6ad","type":"link out","z":"c6f2a894be05d857","g":"04fb6911559797a0","name":"link out 3","mode":"link","links":["f582702ec222069c"],"x":535,"y":120,"wires":[]},{"id":"8a3c077f0f85a905","type":"group","z":"c6f2a894be05d857","g":"6b8059f703d0f574","name":"Download the images","style":{"label":true},"nodes":["453f3b9d7d312bd2","ecbd7b1a410ecd9d","4d650baa2118036e","f582702ec222069c"],"x":84,"y":179,"w":532,"h":82},{"id":"453f3b9d7d312bd2","type":"http request","z":"c6f2a894be05d857","g":"8a3c077f0f85a905","name":"Get the image","method":"GET","ret":"bin","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":460,"y":220,"wires":[["4d650baa2118036e"]]},{"id":"ecbd7b1a410ecd9d","type":"change","z":"c6f2a894be05d857","g":"8a3c077f0f85a905","name":"Set URL to download","rules":[{"t":"move","p":"payload","pt":"msg","to":"url","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":220,"wires":[["453f3b9d7d312bd2"]]},{"id":"4d650baa2118036e","type":"link out","z":"c6f2a894be05d857","g":"8a3c077f0f85a905","name":"link out 1","mode":"link","links":["8bc38803dec97185"],"x":575,"y":220,"wires":[]},{"id":"f582702ec222069c","type":"link in","z":"c6f2a894be05d857","g":"8a3c077f0f85a905","name":"link in 3","links":["1e81a35c27aae6ad"],"x":125,"y":220,"wires":[["ecbd7b1a410ecd9d"]]},{"id":"22c5026dd58e418b","type":"group","z":"c6f2a894be05d857","g":"6b8059f703d0f574","name":"Save the images to the local storage","style":{"label":true},"nodes":["95c819560d22f394","0fe7f013b6356c5d","7edc6cb2b0d243db","829bfc8e6e293ada","8bc38803dec97185","98980d88013c6e12"],"x":84,"y":279,"w":932,"h":82},{"id":"95c819560d22f394","type":"base64","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"convert to base64","action":"str","property":"payload","x":250,"y":320,"wires":[["829bfc8e6e293ada"]]},{"id":"0fe7f013b6356c5d","type":"file","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"Write file to storage","filename":"filename","filenameType":"msg","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":850,"y":320,"wires":[["98980d88013c6e12"]]},{"id":"7edc6cb2b0d243db","type":"string","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"Get filename from the URL","methods":[{"name":"getRightMost","params":[{"type":"str","value":"/"}]}],"prop":"responseUrl","propout":"filename","object":"msg","objectout":"msg","x":620,"y":320,"wires":[["0fe7f013b6356c5d"]]},{"id":"829bfc8e6e293ada","type":"image","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"preview","width":"150","data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":true,"outputs":1,"x":420,"y":320,"wires":[["7edc6cb2b0d243db"]]},{"id":"8bc38803dec97185","type":"link in","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"link in 1","links":["4d650baa2118036e"],"x":125,"y":320,"wires":[["95c819560d22f394"]]},{"id":"98980d88013c6e12","type":"link out","z":"c6f2a894be05d857","g":"22c5026dd58e418b","name":"link out 2","mode":"link","links":["1e94b5bab542830a"],"x":975,"y":320,"wires":[]},{"id":"6fcca5cfee2bcb89","type":"group","z":"c6f2a894be05d857","g":"6b8059f703d0f574","name":"Output a debug once all images have been processed","style":{"label":true},"nodes":["d1a6feea3ac829c6","119f8008752bc4fb","1e94b5bab542830a"],"x":64,"y":379,"w":382,"h":82},{"id":"d1a6feea3ac829c6","type":"debug","z":"c6f2a894be05d857","g":"6fcca5cfee2bcb89","name":"debug 140","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":330,"y":420,"wires":[]},{"id":"119f8008752bc4fb","type":"join","z":"c6f2a894be05d857","g":"6fcca5cfee2bcb89","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":190,"y":420,"wires":[["d1a6feea3ac829c6"]]},{"id":"1e94b5bab542830a","type":"link in","z":"c6f2a894be05d857","g":"6fcca5cfee2bcb89","name":"link in 2","links":["98980d88013c6e12"],"x":105,"y":420,"wires":[["119f8008752bc4fb"]]}]

We've now downloaded the images we need, and saved them to our local storage, to make them load more quickly when a user views them in the dashboard.

Onto the second flow, which will get the images from the local storage and then load them into the dashboard. Let's take a look at it:

Get the images from the local storage and place them in a dashboard

You can import this flow into Node-RED using the code below:

[{"id":"c0f2a076e4449f10","type":"group","z":"c6f2a894be05d857","name":"Get the images from the filestore and display in the Dashboard","style":{"label":true},"nodes":["a671e373b7ca0be8","767590694c5a17f7","fb1ce2ca6b73d950","fee0b4a8fff9f4aa","c9930135726cf256","806b98a5bdf7ceea","b58daed1ee453873"],"x":48,"y":513,"w":954,"h":654},{"id":"a671e373b7ca0be8","type":"junction","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","x":320,"y":560,"wires":[[]]},{"id":"767590694c5a17f7","type":"junction","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","x":320,"y":640,"wires":[[]]},{"id":"fb1ce2ca6b73d950","type":"group","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","name":"Get the images from the local storage","style":{"label":true},"nodes":["924666bcda6c633b","e6f985ed4ff557b5","bee4039410549ec8","83477da8696ae6e7"],"x":84,"y":679,"w":492,"h":82},{"id":"924666bcda6c633b","type":"image","z":"c6f2a894be05d857","g":"fb1ce2ca6b73d950","name":"preview","width":"150","data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":true,"outputs":1,"x":440,"y":720,"wires":[["83477da8696ae6e7"]]},{"id":"e6f985ed4ff557b5","type":"file in","z":"c6f2a894be05d857","g":"fb1ce2ca6b73d950","name":"Read file from storage","filename":"payload","filenameType":"msg","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":260,"y":720,"wires":[["924666bcda6c633b"]]},{"id":"bee4039410549ec8","type":"link in","z":"c6f2a894be05d857","g":"fb1ce2ca6b73d950","name":"link in 4","links":["b669ea3caf594f9a"],"x":125,"y":720,"wires":[["e6f985ed4ff557b5"]]},{"id":"83477da8696ae6e7","type":"link out","z":"c6f2a894be05d857","g":"fb1ce2ca6b73d950","name":"link out 5","mode":"link","links":["044af6d97af553e4"],"x":535,"y":720,"wires":[]},{"id":"fee0b4a8fff9f4aa","type":"group","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","name":"Prepare each image to be shown in the dashboard","style":{"label":true},"nodes":["8cb8c95c2f5a1591","6eabd7a88e3863d3","044af6d97af553e4","264eb6e2f10c1ab5"],"x":84,"y":779,"w":832,"h":82},{"id":"8cb8c95c2f5a1591","type":"change","z":"c6f2a894be05d857","g":"fee0b4a8fff9f4aa","name":"Add the file type to the mimetype, add to image content","rules":[{"t":"set","p":"mimetype","pt":"msg","to":"\"data:image/\"&msg.filetype&\";base64,\"","tot":"jsonata"},{"t":"set","p":"output","pt":"msg","to":"msg.mimetype&msg.payload","tot":"jsonata"},{"t":"move","p":"output","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":820,"wires":[["264eb6e2f10c1ab5"]]},{"id":"6eabd7a88e3863d3","type":"string","z":"c6f2a894be05d857","g":"fee0b4a8fff9f4aa","name":"Get file type from file name","methods":[{"name":"getRightMost","params":[{"type":"str","value":"."}]}],"prop":"filename","propout":"filetype","object":"msg","objectout":"msg","x":280,"y":820,"wires":[["8cb8c95c2f5a1591"]]},{"id":"044af6d97af553e4","type":"link in","z":"c6f2a894be05d857","g":"fee0b4a8fff9f4aa","name":"link in 5","links":["83477da8696ae6e7"],"x":125,"y":820,"wires":[["6eabd7a88e3863d3"]]},{"id":"264eb6e2f10c1ab5","type":"link out","z":"c6f2a894be05d857","g":"fee0b4a8fff9f4aa","name":"link out 6","mode":"link","links":["e95c6d9464521102"],"x":875,"y":820,"wires":[]},{"id":"c9930135726cf256","type":"group","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","name":"Send the images to the correct section of the dashboard","style":{"label":true},"nodes":["ecf3cb2b1bc5096e","0629532fdd62fd03","3a790fd52e77cb43","3613df20a3a361e2","e95c6d9464521102","2728c1ee286a404b"],"x":84,"y":879,"w":892,"h":162},{"id":"ecf3cb2b1bc5096e","type":"ui_template","z":"c6f2a894be05d857","g":"c9930135726cf256","group":"8c5b99709c90620a","name":"Display the image on the Dashboard","order":1,"width":0,"height":0,"format":"<!DOCTYPE html>\n<html>\n<head>\n<style>\ndiv.parent {\n  position: relative;\n  height: 200px ;\n  //width: 600px;\n}\ndiv.absolute {\n  position: absolute;\n  width: 100%;\n  bottom: 0px;\n} \nimg{\n  border-radius: 10px;\n}\n\n</style>\n</head>\n<body>\n    <div class=\"parent\">\n        <div class=\"relative\" >\n          \n        <img src= \"\" alt=\"Image loaded from the filestore\" style=\"width:100%\"><br>\n        </div>\n    </div>\n</body>\n</html>\n\n","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":750,"y":920,"wires":[["2728c1ee286a404b"]]},{"id":"0629532fdd62fd03","type":"ui_template","z":"c6f2a894be05d857","g":"c9930135726cf256","group":"8c5b99709c90620a","name":"Display the image on the Dashboard","order":4,"width":3,"height":4,"format":"<!DOCTYPE html>\n<html>\n<head>\n<style>\ndiv.parent {\n  position: relative;\n  height: 200px ;\n  //width: 600px;\n}\ndiv.absolute {\n  position: absolute;\n  width: 100%;\n  bottom: 0px;\n} \nimg{\n  border-radius: 10px;\n}\n\n</style>\n</head>\n<body>\n    <div class=\"parent\">\n        <div class=\"relative\" >\n          \n        <img src= \"\" alt=\"Image loaded from the filestore\" style=\"width:100%\"><br>\n        </div>\n    </div>\n</body>\n</html>\n\n","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":750,"y":960,"wires":[["2728c1ee286a404b"]]},{"id":"3a790fd52e77cb43","type":"ui_template","z":"c6f2a894be05d857","g":"c9930135726cf256","group":"8c5b99709c90620a","name":"Display the image on the Dashboard","order":5,"width":3,"height":4,"format":"<!DOCTYPE html>\n<html>\n<head>\n<style>\ndiv.parent {\n  position: relative;\n  height: 200px ;\n  //width: 600px;\n}\ndiv.absolute {\n  position: absolute;\n  width: 100%;\n  bottom: 0px;\n} \nimg{\n  border-radius: 10px;\n}\n\n</style>\n</head>\n<body>\n    <div class=\"parent\">\n        <div class=\"relative\" >\n          \n        <img src= \"\" alt=\"Image loaded from the filestore\" style=\"width:100%\"><br>\n        </div>\n    </div>\n</body>\n</html>\n\n","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":750,"y":1000,"wires":[["2728c1ee286a404b"]]},{"id":"3613df20a3a361e2","type":"switch","z":"c6f2a894be05d857","g":"c9930135726cf256","name":"Send the image to the correct section of the dashboard","property":"filename","propertyType":"msg","rules":[{"t":"eq","v":"ff-logo-wordmark-light_4x.png","vt":"str"},{"t":"eq","v":"screen-pseudo-overview-2QvTVle3Mr-384.avif","vt":"str"},{"t":"eq","v":"nr-image-1.png","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":370,"y":960,"wires":[["ecf3cb2b1bc5096e"],["0629532fdd62fd03"],["3a790fd52e77cb43"]]},{"id":"e95c6d9464521102","type":"link in","z":"c6f2a894be05d857","g":"c9930135726cf256","name":"link in 6","links":["264eb6e2f10c1ab5"],"x":125,"y":960,"wires":[["3613df20a3a361e2"]]},{"id":"2728c1ee286a404b","type":"link out","z":"c6f2a894be05d857","g":"c9930135726cf256","name":"link out 7","mode":"link","links":["d4c41d5c9f332ba4"],"x":935,"y":960,"wires":[]},{"id":"8c5b99709c90620a","type":"ui_group","name":"Default","tab":"4c70ce602964b5fb","order":1,"disp":false,"width":"6","collapse":false,"className":""},{"id":"4c70ce602964b5fb","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false},{"id":"806b98a5bdf7ceea","type":"group","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","name":"Output a debug once all images have been processed","style":{"label":true},"nodes":["d4c41d5c9f332ba4","b40f5d5e5df0074d","f2f386a2615e5698"],"x":74,"y":1059,"w":392,"h":82},{"id":"d4c41d5c9f332ba4","type":"link in","z":"c6f2a894be05d857","g":"806b98a5bdf7ceea","name":"link in 7","links":["2728c1ee286a404b"],"x":115,"y":1100,"wires":[["b40f5d5e5df0074d"]]},{"id":"b40f5d5e5df0074d","type":"join","z":"c6f2a894be05d857","g":"806b98a5bdf7ceea","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":200,"y":1100,"wires":[["f2f386a2615e5698"]]},{"id":"f2f386a2615e5698","type":"debug","z":"c6f2a894be05d857","g":"806b98a5bdf7ceea","name":"debug 141","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":350,"y":1100,"wires":[]},{"id":"b58daed1ee453873","type":"group","z":"c6f2a894be05d857","g":"c0f2a076e4449f10","name":"Inject the image files' names","style":{"label":true},"nodes":["9cf7532041d938d2","0ec6e6d3e7b31ad7","b669ea3caf594f9a","bca6faef579bc33d","89abee9a3f6cd7e5"],"x":74,"y":539,"w":782,"h":122},{"id":"9cf7532041d938d2","type":"inject","z":"c6f2a894be05d857","g":"b58daed1ee453873","name":"Inject","props":[],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","x":170,"y":580,"wires":[["89abee9a3f6cd7e5"]]},{"id":"0ec6e6d3e7b31ad7","type":"split","z":"c6f2a894be05d857","g":"b58daed1ee453873","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":730,"y":580,"wires":[["b669ea3caf594f9a"]]},{"id":"b669ea3caf594f9a","type":"link out","z":"c6f2a894be05d857","g":"b58daed1ee453873","name":"link out 4","mode":"link","links":["bee4039410549ec8"],"x":815,"y":580,"wires":[]},{"id":"bca6faef579bc33d","type":"ui_ui_control","z":"c6f2a894be05d857","g":"b58daed1ee453873","name":"Update images on dashboard open","events":"connect","x":240,"y":620,"wires":[["89abee9a3f6cd7e5"]]},{"id":"89abee9a3f6cd7e5","type":"change","z":"c6f2a894be05d857","g":"b58daed1ee453873","name":"Image file names as an array","rules":[{"t":"set","p":"payload","pt":"msg","to":"[\"ff-logo-wordmark-light_4x.png\",\"screen-pseudo-overview-2QvTVle3Mr-384.avif\",\"nr-image-1.png\"]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":580,"wires":[["0ec6e6d3e7b31ad7"]]},{"id":"c65a9370f1fec257","type":"group","z":"c6f2a894be05d857","name":"Chart showing CPU load","style":{"label":true},"nodes":["4b5271c11b0b1bba","5bf4c21f882eccd0","775403922e7c51f4","3789d7b7f40e8596","3be771b04a805b19","96a1d087230c4631","b82cd8fb933d1f1b"],"x":54,"y":1179,"w":1012,"h":122},{"id":"4b5271c11b0b1bba","type":"inject","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":1220,"wires":[["775403922e7c51f4"]]},{"id":"5bf4c21f882eccd0","type":"ui_chart","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","group":"8c5b99709c90620a","order":2,"width":3,"height":4,"label":"CPU Load %","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":790,"y":1220,"wires":[["3789d7b7f40e8596"]]},{"id":"775403922e7c51f4","type":"Loadavg","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","x":320,"y":1220,"wires":[["3be771b04a805b19"]]},{"id":"3789d7b7f40e8596","type":"debug","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"debug 142","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":950,"y":1220,"wires":[]},{"id":"3be771b04a805b19","type":"change","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.loadavg[0]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":1220,"wires":[["b82cd8fb933d1f1b"]]},{"id":"96a1d087230c4631","type":"ui_gauge","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","group":"8c5b99709c90620a","order":3,"width":3,"height":4,"gtype":"gage","title":"CPU Load","label":"units","format":"%","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":790,"y":1260,"wires":[]},{"id":"b82cd8fb933d1f1b","type":"calculator","z":"c6f2a894be05d857","g":"c65a9370f1fec257","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"mult","constant":"100","round":true,"decimals":0,"x":640,"y":1220,"wires":[["96a1d087230c4631","5bf4c21f882eccd0"]]}]

I have also included some simple dashboard elements you can view alongside the images. Let's take a look at the dashboard:

The dashboard showing our images alongside other standard elements

If you import these flows into Node-RED, you should see the images automatically loaded into the dashboard when you view it. You can also replace the URLs and file paths to try using some different images if you'd like to.

More things to try

In this example, the images are static but it's simple to load images depending on the state of the flow. As mentioned in this article's introduction, you could display context aware images guiding the user of the dashboard to a specific location on a map, to complete a maintenance task. If you're interested in seeing examples of dynamic image loading please comment below.

Conclusion

Images can add a lot of value to dashboards, but depending on how you host a given Node-RED instance it can be challenging to ensure the correct images are shown, especially when working with your flows in a DevOps pipeline. The techniques I've discussed above allow you to use images in dashboards, even in containerised environments.

I'd love to hear your comments and suggestions on this article. please tell us what you think about this article, and how you might use these techniques in the comments section below.

Written By:

Customer Success Manager

Published on:

Related Articles:

Sign up for updates