Nodered MQTT (sparkplug) flow

Hi,
I just wanted to share a fully working sparkplug flow for those of you considering using nodered as an Ignition interface.

Here you can test inputs, outputs, DBirth, DDeath, rebirth and probably more…

Screenshot:

I suggest using NPM and installing sparkplug client first like this:

npm install --unsafe-perm sparkplug-client
npm install --unsafe-perm node-red-contrib-sparkplug

I am not completely sure, but my assumption is that you get the latest sparkplug-client this way. contrib-sparkplug is a bit outdated…

Flow: (import flow > paste from clipboard):

[{"id":"67ff7c1a.40a404","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"a81c4e59.6a453","type":"function","z":"67ff7c1a.40a404","name":"Birth message for this device","func":"var msg={\"topic\":\"myMultiSensor01/DBIRTH\",\n\"payload\":{\n    \"timestamp\": Date.now(),\n    \"metrics\":[{\n        \"name\":\"Temperature01\",\n        \"value\":1337,\n        \"type\":\"float\",\n        \"properties\":{\n            \"engUnit\":{\"value\":\"C\",\"type\":\"string\"},\n            \"engHigh\":{\"value\":100,\"type\":\"double\"},\n            \"engLow\":{\"value\":0,\"type\":\"double\"}\n            }\n        },\n        {\n        \"name\":\"Temperature02\",\n        \"value\":1338,\n        \"type\":\"float\",\n        \"properties\":{\n            \"engUnit\":{\"value\":\"C\",\"type\":\"string\"},\n            \"engHigh\":{\"value\":100,\"type\":\"double\"},\n            \"engLow\":{\"value\":0,\"type\":\"double\"}\n            }\n        },\n        {\n        \"name\":\"Output01\",\n        \"value\":false,\n        \"type\":\"boolean\",\n        }]\n    }\n    \n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":940,"y":200,"wires":[["3abcfd2d.b8c002","afc60000.92d74"]]},{"id":"4d95b97.6f42b48","type":"inject","z":"67ff7c1a.40a404","name":"First scan","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":620,"y":200,"wires":[["a81c4e59.6a453"]]},{"id":"3abcfd2d.b8c002","type":"debug","z":"67ff7c1a.40a404","name":"Birth message","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1260,"y":200,"wires":[]},{"id":"b7f3b713.742968","type":"function","z":"67ff7c1a.40a404","name":"Metric value for measurement 1","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Temperature01\",\n    \"value\":msg.payload,\n    \"type\":\"float\"}]},\n\"topic\":\"myMultiSensor01/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":930,"y":320,"wires":[["fa0e50aa.109fd","afc60000.92d74"]]},{"id":"18f8e72c.56de49","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1338","payloadType":"num","x":610,"y":320,"wires":[["b7f3b713.742968"]]},{"id":"fa0e50aa.109fd","type":"debug","z":"67ff7c1a.40a404","name":"metric 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1260,"y":320,"wires":[]},{"id":"5d3a0180.3c557","type":"function","z":"67ff7c1a.40a404","name":"Metric value for measurement 2","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Temperature02\",\n    \"value\":msg.payload,\n    \"type\":\"float\"}]},\n\"topic\":\"myMultiSensor01/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":930,"y":380,"wires":[["b3074479.430578","afc60000.92d74"]]},{"id":"d24604eb.11c758","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1338","payloadType":"num","x":610,"y":380,"wires":[["5d3a0180.3c557"]]},{"id":"b3074479.430578","type":"debug","z":"67ff7c1a.40a404","name":"metric 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1260,"y":380,"wires":[]},{"id":"8e01dfde.f35da","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor (output feedback)","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":560,"y":440,"wires":[["46e856f8.96bf88"]]},{"id":"46e856f8.96bf88","type":"function","z":"67ff7c1a.40a404","name":"Metric value for output","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Output01\",\n    \"value\":msg.payload,\n    \"type\":\"boolean\"}]},\n\"topic\":\"myMultiSensor01/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":960,"y":440,"wires":[["afc60000.92d74"]]},{"id":"9b5408a7.e077c8","type":"function","z":"67ff7c1a.40a404","name":"Output (from ignition)","func":"if (msg.topic==\"myMultiSensor01\"){\n    if (msg.payload.metrics[0].name==\"Output01\"){\n        newMsg={};\n        newMsg.payload=msg.payload.metrics[0].value;\n        return newMsg;\n    }\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1780,"y":280,"wires":[["398adbd.45a1724"]]},{"id":"398adbd.45a1724","type":"debug","z":"67ff7c1a.40a404","name":"value to sensor","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2000,"y":280,"wires":[]},{"id":"36701b5e.437424","type":"inject","z":"67ff7c1a.40a404","name":"trigger rebirth","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":610,"y":160,"wires":[["a81c4e59.6a453"]]},{"id":"965067a.11efb98","type":"function","z":"67ff7c1a.40a404","name":"DDEATH","func":"let EquipmentName = \"myMultiSensor01\"\n\nreturn { \"topic\" : EquipmentName+\"/DDEATH\",'payload': {\"timestamp\" : Date.now()} };\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1000,"y":120,"wires":[["afc60000.92d74"]]},{"id":"b911110c.4f163","type":"inject","z":"67ff7c1a.40a404","name":"trigger Death","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":610,"y":100,"wires":[["965067a.11efb98"]]},{"id":"deb5ccdd.a451a","type":"debug","z":"67ff7c1a.40a404","name":"Sparkplug Diag","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1760,"y":380,"wires":[]},{"id":"836db305.a26ba","type":"sparkplug","z":"67ff7c1a.40a404","name":"","broker":"tcp://192.168.0.99","port":"1883","clientid":"NodeREDSimpleEdgeNode","groupid":"Sparkplug Devices","edgenode":"Node-RED Edge Node","version":"spBv1.0","enablecache":"false","publishdeath":"true","user":"myUser","password":"__PWRD__","x":1480,"y":500,"wires":[["9b5408a7.e077c8","deb5ccdd.a451a","d4f8fb29.30ee18","7e8c8c04.8b0314"]]},{"id":"d4f8fb29.30ee18","type":"function","z":"67ff7c1a.40a404","name":"external rebirth of all devices from this node","func":"if (msg.topic==\"rebirth\"){\n    return msg\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1850,"y":460,"wires":[["4d1cdf3e.850b4"]]},{"id":"4d1cdf3e.850b4","type":"link out","z":"67ff7c1a.40a404","name":"","links":["8f8845ad.a6ab38","e31740a6.3a29e"],"x":2095,"y":460,"wires":[]},{"id":"8f8845ad.a6ab38","type":"link in","z":"67ff7c1a.40a404","name":"","links":["4d1cdf3e.850b4"],"x":755,"y":260,"wires":[["a81c4e59.6a453"]]},{"id":"90061fa9.fab9","type":"function","z":"67ff7c1a.40a404","name":"Birth message for this device","func":"var msg={\"topic\":\"myMultiSensor02/DBIRTH\",\n\"payload\":{\n    \"timestamp\": Date.now(),\n    \"metrics\":[{\n        \"name\":\"Temperature01\",\n        \"value\":1337,\n        \"type\":\"float\",\n        \"properties\":{\n            \"engUnit\":{\"value\":\"C\",\"type\":\"string\"},\n            \"engHigh\":{\"value\":100,\"type\":\"double\"},\n            \"engLow\":{\"value\":0,\"type\":\"double\"}\n            }\n        },\n        {\n        \"name\":\"Temperature02\",\n        \"value\":1338,\n        \"type\":\"float\",\n        \"properties\":{\n            \"engUnit\":{\"value\":\"C\",\"type\":\"string\"},\n            \"engHigh\":{\"value\":100,\"type\":\"double\"},\n            \"engLow\":{\"value\":0,\"type\":\"double\"}\n            }\n        },\n        {\n        \"name\":\"Output01\",\n        \"value\":false,\n        \"type\":\"boolean\",\n        }]\n    }\n    \n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":960,"y":700,"wires":[["938bc35d.9c5ff","9fafc8a4.923c08"]]},{"id":"ad1a3789.3c0128","type":"inject","z":"67ff7c1a.40a404","name":"First scan","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":640,"y":700,"wires":[["90061fa9.fab9"]]},{"id":"938bc35d.9c5ff","type":"debug","z":"67ff7c1a.40a404","name":"Birth message","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1260,"y":700,"wires":[]},{"id":"dad285c8.ac0a58","type":"function","z":"67ff7c1a.40a404","name":"Metric value for measurement 1","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Temperature01\",\n    \"value\":msg.payload,\n    \"type\":\"float\"}]},\n\"topic\":\"myMultiSensor02/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":950,"y":820,"wires":[["b94758a0.8dbee8","9fafc8a4.923c08"]]},{"id":"33b62af6.aadbc6","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1338","payloadType":"num","x":630,"y":820,"wires":[["dad285c8.ac0a58"]]},{"id":"b94758a0.8dbee8","type":"debug","z":"67ff7c1a.40a404","name":"metric 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1240,"y":820,"wires":[]},{"id":"7d2171b.3e6e19","type":"function","z":"67ff7c1a.40a404","name":"Metric value for measurement 2","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Temperature02\",\n    \"value\":msg.payload,\n    \"type\":\"float\"}]},\n\"topic\":\"myMultiSensor02/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":950,"y":880,"wires":[["e73c59cb.404988","9fafc8a4.923c08"]]},{"id":"57d8d78.cbbd728","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1338","payloadType":"num","x":630,"y":880,"wires":[["7d2171b.3e6e19"]]},{"id":"e73c59cb.404988","type":"debug","z":"67ff7c1a.40a404","name":"metric 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1240,"y":880,"wires":[]},{"id":"aa2e5891.35cc08","type":"inject","z":"67ff7c1a.40a404","name":"Value from sensor (output feedback)","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":580,"y":940,"wires":[["d6a62d37.916f6"]]},{"id":"d6a62d37.916f6","type":"function","z":"67ff7c1a.40a404","name":"Metric value for output","func":"var msg={\"payload\":\n{\"timestamp\": Date.now(),\n\"metrics\":[{\n    \"name\":\"Output01\",\n    \"value\":msg.payload,\n    \"type\":\"boolean\"}]},\n\"topic\":\"myMultiSensor02/DDATA\"}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":980,"y":940,"wires":[["9fafc8a4.923c08"]]},{"id":"7e8c8c04.8b0314","type":"function","z":"67ff7c1a.40a404","name":"Output (from ignition)","func":"if (msg.topic==\"myMultiSensor02\"){\n    if (msg.payload.metrics[0].name==\"Output01\"){\n        newMsg={};\n        newMsg.payload=msg.payload.metrics[0].value;\n        return newMsg;\n    }\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1800,"y":660,"wires":[["4d2fe7ca.bcf5f8"]]},{"id":"4d2fe7ca.bcf5f8","type":"debug","z":"67ff7c1a.40a404","name":"value to sensor","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2040,"y":660,"wires":[]},{"id":"233c2e41.6edff2","type":"inject","z":"67ff7c1a.40a404","name":"trigger rebirth","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":630,"y":660,"wires":[["90061fa9.fab9"]]},{"id":"8baf8d54.c730d","type":"function","z":"67ff7c1a.40a404","name":"DDEATH","func":"let EquipmentName = \"myMultiSensor02\"\n\nreturn { \"topic\" : EquipmentName+\"/DDEATH\",'payload': {\"timestamp\" : Date.now()} };\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1020,"y":620,"wires":[["9fafc8a4.923c08"]]},{"id":"2972a704.992e48","type":"inject","z":"67ff7c1a.40a404","name":"trigger Death","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1337","payloadType":"num","x":630,"y":600,"wires":[["8baf8d54.c730d"]]},{"id":"e31740a6.3a29e","type":"link in","z":"67ff7c1a.40a404","name":"","links":["1f7d5357.830b6d","4d1cdf3e.850b4"],"x":775,"y":760,"wires":[["90061fa9.fab9"]]},{"id":"8a06951f.dc4278","type":"link in","z":"67ff7c1a.40a404","name":"","links":["9fafc8a4.923c08","afc60000.92d74"],"x":1305,"y":500,"wires":[["836db305.a26ba"]]},{"id":"9fafc8a4.923c08","type":"link out","z":"67ff7c1a.40a404","name":"","links":["8a06951f.dc4278"],"x":1195,"y":780,"wires":[]},{"id":"afc60000.92d74","type":"link out","z":"67ff7c1a.40a404","name":"","links":["8a06951f.dc4278"],"x":1215,"y":280,"wires":[]}]
7 Likes

Hi!
Everything works well, except that I get "ReferenceError: options is not defined" error when sending a DDEATH message. No errors when sending DBIRTH or DDATA messages.

I'm stumped! Any ideas?

Hi,

Reviving an old thread.

I used the above Flow and modified it somewhat. It works well, but how can I know if connection to the broker is lost?

image

I manually disabled the MQTT Distributor. The sparkplug node sees that it is lost, but no message is sent (debug node did nothing). Is there a way to pick that connecting status up and do something with it?

Thanks,
Deon

Just add the “status” node to your flow. It’s included by default in Nodered.

That was easy. Thanks.