The node-bacnet-contrib-extended is built on top of node-bacnet javascript library, in contrast to other bacnet plugins available in Node-red it provides additional functionality such as bacnet COV node to utilize bacnet Change of value (COV) feature.
Github link -> https://github.com/asad-boutique/node-bacnet-contrib-extended
Node-Red Pallete -> https://flows.nodered.org/node/node-bacnet-contrib-extended
This Plugin provides the following nodes.
discover – devices
The discover-devices node would discover all the bacnet devices on a network and would display there bacnet ids and address.
read-single-device
The read-sigle-device node would take deviceId and address as an argument and would read the whole contents of that device.
example parameters:
{
msg.deviceId = 9000;
msg.address = “192.168.20.242”;
}
read-all-devices
The read-all-devices node would read the complete data of all the available bacnet devices on the network.
read-single-point
The read-single-point node would read the data of the single node or object, it would take inputType, bacnetId and address as an input arguments via a function node.
example parameters:
{
msg.inputType = 3;
msg.bacnetId = 8;
msg.address = “192.168.20.242”;
}
read-objects-list-within-device
The read-objects-list-within-device node would take deviceId and address as an arguments and read all the object/points within that device.
example parameters:
{
msg.deviceId = 9000;
msg.address = “192.168.20.242”;
}
read-object-properties
The read-object-properties node would take requestArray as an argument including inputType, bacnetID and read all the object properties defined within requestArray.
example parameters:
{
const requestArray = [ { objectId: { type: msg.inputType, instance: msg.bacnetID }, properties: bacnetProperties } ];
msg.requestArray = requestArray
}
change-of-value
The change-of-value node would take address, inputType, bacnetId and COVtimeout as input and would create and renew subcriptions for the Bacnet change of value, for example whenever the value of binary input would get changed the change-of-value node would trigger an output.
Data Transformation:
The data transformation script can be used in contrast to read-object-properties to show property list in a human readable form.
Example Usage Flow for all the nodes:
[{"id":"e59ccc493ab8713f","type":"tab","label":"node-bacnet-contrib-extended example flow","disabled":false,"info":"","env":[]},{"id":"74bf69659e1974a1","type":"debug","z":"e59ccc493ab8713f","name":"debug 20","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":180,"wires":[]},{"id":"fa17fb916284cf19","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":180,"wires":[["08257e5542d39440"]]},{"id":"411aed243f057296","type":"discover-devices","z":"e59ccc493ab8713f","name":"","x":730,"y":180,"wires":[["74bf69659e1974a1"]]},{"id":"e942e51ca4b4090f","type":"read-all-devices","z":"e59ccc493ab8713f","name":"","x":720,"y":360,"wires":[["3eecc0c9baf5b834"]]},{"id":"c2c992dcda54245d","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":360,"wires":[["62bd1186e7eaad41"]]},{"id":"62bd1186e7eaad41","type":"function","z":"e59ccc493ab8713f","name":"Inject Parameters","func":"// msg.communicationPort = 47808;\n// msg.interface = '0.0.0.0';\n// msg.broadcastAddress = '255.255.255.255';\n// msg.apduTimeout = 7000;\n// msg.reuseAddr = true;\n// msg.getAllPropertiesManually = \"true\";\n\n//msg.transportClosedDuration = 90000;\n\n\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":360,"wires":[["e942e51ca4b4090f"]]},{"id":"3eecc0c9baf5b834","type":"debug","z":"e59ccc493ab8713f","name":"debug 21","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":360,"wires":[]},{"id":"4494f2fbdd6bcf29","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":260,"wires":[["4fb6bf9552d1c542"]]},{"id":"4fb6bf9552d1c542","type":"function","z":"e59ccc493ab8713f","name":"Inject Parameters","func":"// var randNum = Math.floor(Math.random() * 5100);\n// msg.communicationPort = 47809 + randNum;\n// msg.interface = '0.0.0.0';\n// msg.broadcastAddress = '255.255.255.255';\n// msg.apduTimeout = 3000;\n// msg.reuseAddr = true;\n// msg.transportClosedDuration = 90000;\n//msg.getAllPropertiesManually = \"true\";\n\nmsg.deviceId = 2051;\nmsg.address = \"192.168.10.51\";\n\nmsg.apduTimeout = 20000;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":260,"wires":[["ede5e2d97a9ff630"]]},{"id":"177ff63bf3091b0f","type":"debug","z":"e59ccc493ab8713f","name":"debug 22","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":260,"wires":[]},{"id":"ede5e2d97a9ff630","type":"read-single-device","z":"e59ccc493ab8713f","name":"","x":730,"y":260,"wires":[["177ff63bf3091b0f"]]},{"id":"3ed9cb3c68c88c50","type":"read-single-point","z":"e59ccc493ab8713f","name":"","x":730,"y":460,"wires":[["56dcc0c93d7edcc8"]]},{"id":"dfdf9cfae6db316a","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":260,"y":460,"wires":[["8b01e8719e4d6d6b"]]},{"id":"8b01e8719e4d6d6b","type":"function","z":"e59ccc493ab8713f","name":"Inject Parameters","func":"// msg.communicationPort = 47811;\n// msg.interface = '0.0.0.0';\n// msg.broadcastAddress = '255.255.255.255';\n// msg.apduTimeout = 4000;\n// msg.reuseAddr = true;\n\n \n// msg.transportClosedDuration = 9000;\n\n\n// msg.inputType = 2;\n// msg.bacnetId = 103;\n// msg.address = \"192.168.10.52\";\n\nmsg.inputType = 2;\nmsg.bacnetId = 26;\nmsg.address = \"192.168.10.50\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":460,"wires":[["3ed9cb3c68c88c50"]]},{"id":"56dcc0c93d7edcc8","type":"debug","z":"e59ccc493ab8713f","name":"debug 23","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":460,"wires":[]},{"id":"08257e5542d39440","type":"function","z":"e59ccc493ab8713f","name":"Inject Parameters","func":"// msg.communicationPort = 47808;\n// msg.interface = '0.0.0.0';\n// msg.broadcastAddress = '255.255.255.255';\n//msg.apduTimeout = 7000;\nmsg.reuseAddr = true;\nmsg.transportClosedDuration = 8000;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":180,"wires":[["411aed243f057296"]]},{"id":"d4e184b3ed27c65c","type":"read-objects-list-within-device","z":"e59ccc493ab8713f","name":"","x":830,"y":580,"wires":[["e2c2a2fd6e536531"]]},{"id":"5515866ca25b964a","type":"read-object-properties","z":"e59ccc493ab8713f","name":"","x":800,"y":660,"wires":[["bf874e495e86a417"]]},{"id":"cfa436b22edec71a","type":"change-of-value","z":"e59ccc493ab8713f","d":true,"name":"","address":"192.168.10.54","inputType":"5","bacnetId":"22","COVtimeout":"120000","x":760,"y":760,"wires":[["1aa268f1a0438dce"]]},{"id":"42ba49ea2bb49724","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":580,"wires":[["d881f01805f8f779"]]},{"id":"d881f01805f8f779","type":"function","z":"e59ccc493ab8713f","name":"Inject Device Id and Address","func":"msg.deviceId = 2054;\nmsg.address = \"192.168.10.54\";\n\n//msg.communicationPort = 47808;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":580,"wires":[["d4e184b3ed27c65c"]]},{"id":"e2c2a2fd6e536531","type":"debug","z":"e59ccc493ab8713f","name":"debug 24","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":580,"wires":[]},{"id":"f53d617dd251dd64","type":"function","z":"e59ccc493ab8713f","name":"Inject Id + Type + Properties","func":"msg.deviceId = 2054;\nmsg.address = \"192.168.10.54\";\nmsg.inputType = 5;\nmsg.bacnetID = 22;\n\nconst bacnetProperties = [\n { id: 77 }, // OBJECT_NAME\n // { id: 79 }, // OBJECT_TYPE OR INPUT TYPE\n { id: 85 }, // PRESENT_VALUE\n];\n\n\nconst requestArray = [\n { objectId: { type: msg.inputType, instance: msg.bacnetID }, properties: bacnetProperties }\n];\n\nmsg.requestArray = requestArray \n \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":660,"wires":[["5515866ca25b964a"]]},{"id":"d8d1549a7fbecea0","type":"inject","z":"e59ccc493ab8713f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":660,"wires":[["f53d617dd251dd64"]]},{"id":"bf874e495e86a417","type":"debug","z":"e59ccc493ab8713f","name":"debug 25","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1040,"y":660,"wires":[]},{"id":"1aa268f1a0438dce","type":"debug","z":"e59ccc493ab8713f","name":"debug 26","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1000,"y":760,"wires":[]}]
Example usage flow with a coupling of read-object-properties with Transformation Script:-
[{"id":"19b30a6ef4e257f2","type":"tab","label":"coupling of read-object-properties with Transformation Script","disabled":false,"info":"","env":[]},{"id":"1b15b9eb8d4e859f","type":"read-object-properties","z":"19b30a6ef4e257f2","name":"","x":740,"y":320,"wires":[["63de82d1703dcede","98756e5bb72a3685"]]},{"id":"f2ab79c87df39de3","type":"function","z":"19b30a6ef4e257f2","name":"Inject Id + Type + Properties","func":"msg.deviceId = 2054;\nmsg.address = \"192.168.10.54\";\nmsg.inputType = 5;\nmsg.bacnetID = 22;\n\nconst bacnetProperties = [\n { id: 77 }, // OBJECT_NAME\n // { id: 79 }, // OBJECT_TYPE OR INPUT TYPE\n { id: 85 }, // PRESENT_VALUE\n];\n\n\nconst requestArray = [\n { objectId: { type: msg.inputType, instance: msg.bacnetID }, properties: bacnetProperties }\n];\n\nmsg.requestArray = requestArray \n \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":320,"wires":[["1b15b9eb8d4e859f"]]},{"id":"a8a816e74c2d2519","type":"inject","z":"19b30a6ef4e257f2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":320,"wires":[["f2ab79c87df39de3"]]},{"id":"63de82d1703dcede","type":"debug","z":"19b30a6ef4e257f2","name":"debug 27","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":980,"y":320,"wires":[]},{"id":"98756e5bb72a3685","type":"function","z":"19b30a6ef4e257f2","name":"Data Transformation","func":"var object = msg.payload;\n\nvar myArray = {};\n\nmyArray[\"BacnetID\"] = msg.bacnetID;\nmyArray[\"InputType\"] = msg.inputType;\n\n\nfor(var j = 0; j < object.values[0].values.length; j++){\n \n \n \n var k1 = object.values[0].values[j].id.toString();\n \n //str = str + k1 + \" ----- \";\n \n var v1 = object.values[0].values[j].value[0].value;\n \n var k1str = ConvertPropertyIdWithString(k1);\n \n myArray[k1str] = v1;\n \n}\n\n\n//msg.payload = str;\n\nmsg.payload = myArray;\n\nreturn msg;\n\n\n\nfunction ConvertPropertyIdWithString(id){\n \n var convertedValue = \" PPPP \";\n \n if(id == 0){\n convertedValue = \"ACKED_TRANSITIONS\";\n }\n \n else if(id == 4){\n convertedValue = \"ACTIVE_TEXT\";\n }\n \n else if(id == 6){\n convertedValue = \"ALARM_VALUE\";\n }\n \n else if(id == 15){\n convertedValue = \"CHANGE_OF_STATE_COUNT\";\n }\n \n else if(id == 16){\n convertedValue = \"CHANGE_OF _STATE_TIME\";\n }\n \n else if(id == 17){\n convertedValue = \"NOTIFICATION_CLASS\";\n }\n \n else if(id == 22){\n convertedValue = \"COV_INCREMENT\";\n }\n\n else if(id == 25){\n convertedValue = \"DEADBAND\";\n }\n\n else if(id == 28){\n convertedValue = \"DESCRIPTION\";\n }\n \n else if(id == 31){\n convertedValue = \"DEVICE_TYPE\";\n }\n \n else if(id == 33){\n convertedValue = \"ELAPSED_ACTIVE_TIME\";\n }\n \n else if(id == 35){\n convertedValue = \"EVENT_ENABLE\";\n }\n \n else if(id == 36){\n convertedValue = \"EVENT_STATE\";\n }\n\n else if(id == 45){\n convertedValue = \"HIGH_LIMIT\";\n }\n \n else if(id == 46){\n convertedValue = \"INACTIVE_TEXT\";\n }\n\n else if(id == 52){\n convertedValue = \"LIMIT_ENABLE\";\n }\n\n else if(id == 59){\n convertedValue = \"LOW_LIMIT\";\n }\n\n else if(id == 65){\n convertedValue = \"MAX_PRES_VALUE\";\n }\n\n else if(id == 69){\n convertedValue = \"MIN_PRES_VALUE\";\n }\n \n else if(id == 72){\n convertedValue = \"NOTIFY_TYPE\";\n }\n \n else if(id == 75){\n convertedValue = \"OBJECT_IDENTIFIER\";\n }\n \n else if(id == 77){\n convertedValue = \"OBJECT_NAME\";\n }\n \n else if(id == 79){\n convertedValue = \"OBJECT_TYPE\";\n }\n \n else if(id == 81){\n convertedValue = \"OUT_OF_SERVICE\";\n }\n \n else if(id == 84){\n convertedValue = \"POLARITY\";\n }\n \n else if(id == 85){\n convertedValue = \"PRESENT_VALUE\";\n }\n \n else if(id == 103){\n convertedValue = \"RELIABILITY\";\n }\n\n else if(id == 106){\n convertedValue = \"RESOLUTION\";\n }\n \n else if(id == 111){\n convertedValue = \"STATUS_FLAGS\";\n }\n \n else if(id == 113){\n convertedValue = \"TIME_DELAY\";\n }\n \n else if(id == 114){\n convertedValue = \"TIME_OF_ACTIVE_TIME_RESET\";\n }\n \n else if(id == 115){\n convertedValue = \"TIME_OF_STATE_COUNT_RESET\";\n }\n\n else if(id == 117){\n convertedValue = \"UNITS\";\n }\n\n else if(id == 118){\n convertedValue = \"UPDATE_INTERVAL\";\n }\n \n else if(id == 130){\n convertedValue = \"EVENT_TIME_STAMPS\";\n }\n \n else if(id == 351){\n convertedValue = \"EVENT_MESSAGE_TEXTS\";\n }\n \n else if(id == 352){\n convertedValue = \"EVENT_MESSAGE_TEXTS_CONFIGS\";\n }\n \n else if(id == 353){\n convertedValue = \"EVENT_DETECTION_ENABLE\";\n }\n \n else if(id == 354){\n convertedValue = \"EVENT_ALGORITHM_INHIBIT\";\n }\n \n else if(id == 355){\n convertedValue = \"EVENT_ALGORITHM_INHIBIT_REF\";\n }\n \n else if(id == 356){\n convertedValue = \"TIME_DELAY_NORMAL\";\n }\n \n return convertedValue;\n \n \n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":420,"wires":[["3b068278ea802094"]]},{"id":"3b068278ea802094","type":"debug","z":"19b30a6ef4e257f2","name":"debug 28","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1100,"y":420,"wires":[]}]