@bitpoolos/edge-bacnet 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bacnet_client.js +299 -315
- package/bacnet_device.js +41 -15
- package/bacnet_gateway.html +88 -42
- package/bacnet_gateway.js +80 -27
- package/bacnet_read.html +110 -34
- package/bacnet_server.js +321 -0
- package/bacnet_write.html +14 -9
- package/common.js +34 -3
- package/edge-bacnet-datastore.cfg +0 -0
- package/package.json +1 -1
package/bacnet_device.js
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
1
|
class BacnetDevice {
|
|
2
|
-
constructor(config) {
|
|
2
|
+
constructor(fromImport, config) {
|
|
3
3
|
let that = this;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
that.
|
|
7
|
-
|
|
8
|
-
that.
|
|
9
|
-
that.
|
|
4
|
+
|
|
5
|
+
if(fromImport == true) {
|
|
6
|
+
that.address = config.address;
|
|
7
|
+
that.isMstp = config.isMstp;
|
|
8
|
+
that.deviceId = config.deviceId;
|
|
9
|
+
that.maxApdu = config.maxApdu;
|
|
10
|
+
that.segmentation = config.segmentation;
|
|
11
|
+
that.vendorId = config.vendorId;
|
|
12
|
+
that.lastSeen = config.lastSeen;
|
|
13
|
+
that.deviceName = config.deviceName;
|
|
14
|
+
that.pointsList = config.pointsList;
|
|
15
|
+
that.pointListUpdateTs = config.pointListUpdateTs;
|
|
16
|
+
that.manualDiscoveryMode = config.manualDiscoveryMode;
|
|
17
|
+
|
|
18
|
+
} else if(fromImport == false) {
|
|
19
|
+
|
|
20
|
+
if(config.header.source) {
|
|
21
|
+
that.address = {address: config.header.sender.address, net: config.header.source.net, adr: config.header.source.adr};
|
|
22
|
+
that.isMstp = true;
|
|
23
|
+
} else {
|
|
24
|
+
that.address = config.header.sender.address;
|
|
25
|
+
that.isMstp = false;
|
|
26
|
+
}
|
|
27
|
+
that.deviceId = config.payload.deviceId;
|
|
28
|
+
that.maxApdu = config.payload.maxApdu;
|
|
29
|
+
that.segmentation = config.payload.segmentation;
|
|
30
|
+
that.vendorId = config.payload.vendorId;
|
|
31
|
+
that.lastSeen = null;
|
|
32
|
+
that.deviceName = null;
|
|
33
|
+
that.pointsList = [];
|
|
34
|
+
that.pointListUpdateTs = null;
|
|
35
|
+
that.manualDiscoveryMode = false;
|
|
10
36
|
}
|
|
11
|
-
that.deviceId = config.payload.deviceId;
|
|
12
|
-
that.maxApdu = config.payload.maxApdu;
|
|
13
|
-
that.segmentation = config.payload.segmentation;
|
|
14
|
-
that.vendorId = config.payload.vendorId;
|
|
15
|
-
that.lastSeen = null;
|
|
16
|
-
that.deviceName = null;
|
|
17
|
-
that.pointsList = [];
|
|
18
|
-
that.pointListUpdateTs = null;
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
updateDeviceConfig(config) {
|
|
@@ -32,6 +50,14 @@ class BacnetDevice {
|
|
|
32
50
|
if(Number.isInteger(config.vendorId)) this.vendorId = config.payload.vendorId;
|
|
33
51
|
}
|
|
34
52
|
|
|
53
|
+
setManualDiscoveryMode(bool) {
|
|
54
|
+
this.manualDiscoveryMode = bool;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getManualDiscoveryMode() {
|
|
58
|
+
return this.manualDiscoveryMode;
|
|
59
|
+
}
|
|
60
|
+
|
|
35
61
|
setPointListUpdateTS(ts) {
|
|
36
62
|
this.pointListUpdateTs = ts;
|
|
37
63
|
}
|
package/bacnet_gateway.html
CHANGED
|
@@ -95,17 +95,21 @@
|
|
|
95
95
|
maxSegments: {value: "0x50", required: true},
|
|
96
96
|
broadCastAddr: {value: "255.255.255.255", required: true},
|
|
97
97
|
toLogIam: {value: true},
|
|
98
|
-
//toRestartNodeRed: {value: false},
|
|
99
98
|
discover_polling_schedule: {value: ""},
|
|
100
99
|
discover_polling_schedule_value: {value: "1", required: true},
|
|
101
100
|
discover_polling_schedule_options: {value: "Minutes", required: true},
|
|
102
101
|
device_id_range_enabled: {value: false},
|
|
103
102
|
device_id_range_start: {value: 0},
|
|
104
103
|
device_id_range_end: {value: 4194303},
|
|
105
|
-
deviceId: {value:
|
|
104
|
+
deviceId: {value: 817001, required: true},
|
|
106
105
|
manual_instance_range_enabled: {value: false},
|
|
107
106
|
manual_instance_range_start: {value: 0},
|
|
108
107
|
manual_instance_range_end: {value: 10000},
|
|
108
|
+
logErrorToConsole: {value: false},
|
|
109
|
+
serverEnabled: {value: false},
|
|
110
|
+
bacnetServerRebuildSchedule: {value: ""},
|
|
111
|
+
bacnetServerRebuildSchedule_value: {value: "1", required: true},
|
|
112
|
+
bacnetServerRebuildSchedule_options: {value: "Hours", required: true}
|
|
109
113
|
},
|
|
110
114
|
networkInterfaces: [],
|
|
111
115
|
inputs: 1,
|
|
@@ -141,8 +145,11 @@
|
|
|
141
145
|
label: "Discovery"
|
|
142
146
|
});
|
|
143
147
|
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
tabs.addTab(
|
|
149
|
+
{
|
|
150
|
+
id: "read-server-tab",
|
|
151
|
+
label: "Server"
|
|
152
|
+
});
|
|
146
153
|
|
|
147
154
|
if (node.networkInterfaces && node.networkInterfaces.length > 0) {
|
|
148
155
|
let nicSelector = document.getElementById("node-input-local_device_address");
|
|
@@ -179,17 +186,17 @@
|
|
|
179
186
|
|
|
180
187
|
queryAdapters();
|
|
181
188
|
|
|
182
|
-
function setBroadCastAddress() {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
189
|
+
// function setBroadCastAddress() {
|
|
190
|
+
// let nicSelector = document.getElementById("node-input-local_device_address");
|
|
191
|
+
// nicSelector.onchange = function(e) {
|
|
192
|
+
// if(typeof e.target.value == "string" && e.target.value !== ""){
|
|
193
|
+
// let broadcastAddrPrefill = e.target.value.split(".").slice(0, 3).join(".") + ".255";
|
|
194
|
+
// document.getElementById("node-input-broadCastAddr").value = broadcastAddrPrefill;
|
|
195
|
+
// }
|
|
196
|
+
// };
|
|
197
|
+
// }
|
|
191
198
|
|
|
192
|
-
setBroadCastAddress();
|
|
199
|
+
// setBroadCastAddress();
|
|
193
200
|
|
|
194
201
|
function setDeviceIdRangeState(state) {
|
|
195
202
|
let deviceIdRangeStart = $("#node-input-device_id_range_start");
|
|
@@ -225,14 +232,7 @@
|
|
|
225
232
|
|
|
226
233
|
$("#node-input-manual_instance_range_enabled").change(function(e) {
|
|
227
234
|
setManualInstanceRangeState(this.checked);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// document.getElementById('restart-nr-button').onclick = function () {
|
|
231
|
-
// this.disabled = true;
|
|
232
|
-
// document.getElementById("node-input-toRestartNodeRed").checked = true;
|
|
233
|
-
// }
|
|
234
|
-
|
|
235
|
-
// console.log("toRestartNodeRed: ", document.getElementById("node-input-toRestartNodeRed").checked);
|
|
235
|
+
});
|
|
236
236
|
|
|
237
237
|
},
|
|
238
238
|
oneditsave: function (test) {
|
|
@@ -242,6 +242,11 @@
|
|
|
242
242
|
document.getElementById("node-input-discover_polling_schedule_value").value,
|
|
243
243
|
document.getElementById("node-input-discover_polling_schedule_options").value
|
|
244
244
|
);
|
|
245
|
+
|
|
246
|
+
document.getElementById("node-input-bacnetServerRebuildSchedule").value = getTimePeriodInSeconds(
|
|
247
|
+
document.getElementById("node-input-bacnetServerRebuildSchedule_value").value,
|
|
248
|
+
document.getElementById("node-input-bacnetServerRebuildSchedule_options").value
|
|
249
|
+
);
|
|
245
250
|
}
|
|
246
251
|
});
|
|
247
252
|
|
|
@@ -295,6 +300,10 @@
|
|
|
295
300
|
margin-left: 50px;
|
|
296
301
|
}
|
|
297
302
|
|
|
303
|
+
.red-ui-editor label {
|
|
304
|
+
font-size: 12px;
|
|
305
|
+
}
|
|
306
|
+
|
|
298
307
|
</style>
|
|
299
308
|
|
|
300
309
|
<div class='form-row node-input-read-tabs-row'>
|
|
@@ -330,7 +339,7 @@
|
|
|
330
339
|
|
|
331
340
|
<div class="form-row">
|
|
332
341
|
<label for="node-input-deviceId"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.deviceId"></span> Device ID </label>
|
|
333
|
-
<input type="text" id="node-input-deviceId" placeholder="
|
|
342
|
+
<input type="text" id="node-input-deviceId" placeholder="817001">
|
|
334
343
|
</div>
|
|
335
344
|
|
|
336
345
|
<div class="form-row deviceIdRange">
|
|
@@ -338,7 +347,6 @@
|
|
|
338
347
|
<input type="checkbox" id="node-input-device_id_range_enabled" style="width: auto;"/>
|
|
339
348
|
<a style="padding-left: 60px;">Start: </a><input type="number" id="node-input-device_id_range_start" style="width: 125px;" min="0" max="4194303"/>
|
|
340
349
|
<a style="padding-left: 35px;">End: </a><input type="number" id="node-input-device_id_range_end" style="width: 125px;" min="1" max="4194303"/>
|
|
341
|
-
|
|
342
350
|
</div>
|
|
343
351
|
</div>
|
|
344
352
|
|
|
@@ -376,7 +384,7 @@
|
|
|
376
384
|
</div>
|
|
377
385
|
|
|
378
386
|
<div class="form-row" style="align-items: center; display: flex;">
|
|
379
|
-
<label for="node-input-discover_polling_schedule_value"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnet_polling_schedule"></span>
|
|
387
|
+
<label for="node-input-discover_polling_schedule_value"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnet_polling_schedule"></span>Discover Frequency</label>
|
|
380
388
|
<p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
|
|
381
389
|
<input type="text" id="node-input-discover_polling_schedule" style="display: none;">
|
|
382
390
|
<input type="text" id="node-input-discover_polling_schedule_value" placeholder="5" style="width: 70px; margin-right: 5px;">
|
|
@@ -388,12 +396,12 @@
|
|
|
388
396
|
</select>
|
|
389
397
|
</div>
|
|
390
398
|
|
|
391
|
-
|
|
392
|
-
<label for="node-input-device_id_range"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span>
|
|
399
|
+
<div class="form-row deviceIdRange">
|
|
400
|
+
<label for="node-input-device_id_range"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span>Point Discovery Range </label>
|
|
393
401
|
<input type="checkbox" id="node-input-manual_instance_range_enabled" style="width: auto;"/>
|
|
394
402
|
<a style="padding-left: 60px;">Start: </a><input type="number" id="node-input-manual_instance_range_start" style="width: 125px;" min="0" max="100000"/>
|
|
395
403
|
<a style="padding-left: 35px;">End: </a><input type="number" id="node-input-manual_instance_range_end" style="width: 125px;" min="1" max="100000"/>
|
|
396
|
-
</div>
|
|
404
|
+
</div>
|
|
397
405
|
|
|
398
406
|
<div class="form-row">
|
|
399
407
|
<label for="node-input-toLog">
|
|
@@ -401,35 +409,73 @@
|
|
|
401
409
|
</label>
|
|
402
410
|
<input type="checkbox" id="node-input-toLogIam" style="width: auto;"/>
|
|
403
411
|
</div>
|
|
404
|
-
</div>
|
|
405
|
-
|
|
406
|
-
|
|
407
412
|
|
|
408
|
-
|
|
413
|
+
<div class="form-row">
|
|
414
|
+
<label for="node-input-logErrorToConsole">
|
|
415
|
+
Log BACnet errors to console:
|
|
416
|
+
</label>
|
|
417
|
+
<input type="checkbox" id="node-input-logErrorToConsole" style="width: auto;"/>
|
|
418
|
+
</div>
|
|
419
|
+
|
|
420
|
+
</div>
|
|
421
|
+
<div id='read-server-tab' style='display:none'>
|
|
422
|
+
<div class="form-row">
|
|
423
|
+
<label for="node-input-serverEnabled">
|
|
424
|
+
Enabled:
|
|
425
|
+
</label>
|
|
426
|
+
<input type="checkbox" id="node-input-serverEnabled" style="width: auto;"/>
|
|
427
|
+
</div>
|
|
409
428
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
429
|
+
<div class="form-row" style="align-items: center; display: flex;">
|
|
430
|
+
<label for="node-input-bacnetServerRebuildSchedule_value"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnetServerRebuildSchedule"></span>Clear Server Points:</label>
|
|
431
|
+
<p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
|
|
432
|
+
<input type="text" id="node-input-bacnetServerRebuildSchedule" style="display: none;">
|
|
433
|
+
<input type="text" id="node-input-bacnetServerRebuildSchedule_value" placeholder="5" style="width: 70px; margin-right: 5px;">
|
|
434
|
+
<select name="timePeriod" id="node-input-bacnetServerRebuildSchedule_options" style="width: 120px; margin-right: 5px;">
|
|
435
|
+
<option value="Seconds">Seconds</option>
|
|
436
|
+
<option value="Minutes">Minutes</option>
|
|
437
|
+
<option value="Hours">Hours</option>
|
|
438
|
+
<option value="Days">Days</option>
|
|
439
|
+
</select>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
417
442
|
|
|
418
443
|
</script>
|
|
419
444
|
<script type="text/html" data-help-name="Bacnet-Gateway">
|
|
420
445
|
<p> This node is the brain of the Bitpool BACnet node collection. It acts are the gateway for all BACnet communications and functionality for the collection. </p>
|
|
421
446
|
|
|
422
|
-
<h3><strong>
|
|
423
|
-
<
|
|
447
|
+
<h3><strong>Gateway Tab</strong></h3>
|
|
448
|
+
<ul class="node-ports">
|
|
424
449
|
<li>Network Interface - the desired interface for the bacstack client to bind to. This interface must not have any other BACnet clients bound to it.</li>
|
|
425
450
|
<li>Broadcast Address - the desired subnet for global msgs to be broadcast and recieved on. This should be as strict as possible. Use 255.255.255.255 if unsure.</li>
|
|
426
451
|
<li>Local Device Port - the port to be used for BACnet comms. Default is 47808</li>
|
|
452
|
+
|
|
453
|
+
</ul>
|
|
454
|
+
|
|
455
|
+
<h3><strong>Discovery Tab</strong></h3>
|
|
456
|
+
<ul class="node-ports">
|
|
427
457
|
<li>APDU Timeout - BACnet msg timeout option</li>
|
|
428
458
|
<li>Max APDU Size - BACnet max apdu size</li>
|
|
429
459
|
<li>Max Segments - BACnet max segments</li>
|
|
430
460
|
<li>Global Discover Frequency - the frequency at which the gateway issues global WhoIs BACnet commands. This should be limited to the least amount possible, as over-loading a network can be a serious issue with BACnet commmunications.</li>
|
|
461
|
+
<li>Manual Point Discovery Instance Range - if a BACnet device doesnt have a Object list (BACnet objectType:propertyId - 8:76), the this bacnet client will enter into manual discovery mode, where it iterates through types and instnace ranges. This range can be used to limit this manual scanning </li>
|
|
431
462
|
<li>Log Device Found - toggles logging of found devices to the node-red debug tab.</li>
|
|
432
|
-
|
|
463
|
+
<li>Log BACnet Errors to Console - toggles logging of BACnet related errors to the node-red console</li>
|
|
464
|
+
</ul>
|
|
465
|
+
|
|
466
|
+
<h3><strong>Server Tab</strong></h3>
|
|
467
|
+
<p>This section provides the ability to simulate a BACnet device and BACnet points using node-red. </p>
|
|
468
|
+
<p>Injecting a msg.topic and msg.payload into the gateway node will create a virtual point that can be discovered by other devices via BACnet/IP</p>
|
|
469
|
+
<p>This node only supports 2 BACnet object types, Analog Value - to show numeric data, and a Character String - to show string data.</p>
|
|
470
|
+
<ul class="node-ports">
|
|
471
|
+
<li>Enabled - toggles whether or not the local BACnet server is started or not. </li>
|
|
472
|
+
<li>Clear Server Points - a schedule for the locally generated BACnet points to get cleared from the node object store</li>
|
|
473
|
+
</ul>
|
|
474
|
+
|
|
475
|
+
<h3><strong>Examples</strong></h3>
|
|
476
|
+
<p>For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu on top right -> Import -> Examples -> @bitpoolos/edge-bacnet</p>
|
|
477
|
+
<p>To find screen shot examples of settings and flows, please go to our wiki <a href="https://wiki.bitpool.com/en/edge/apps/bitpool-edge/nr-bacnet">here</a></p>
|
|
478
|
+
|
|
433
479
|
|
|
434
480
|
<h3>Resources:</h3>
|
|
435
481
|
<h4><strong>Online Docs:</strong></h4>
|
package/bacnet_gateway.js
CHANGED
|
@@ -6,6 +6,7 @@ module.exports = function (RED) {
|
|
|
6
6
|
const { BacnetClient } = require('./bacnet_client');
|
|
7
7
|
const { BacnetClientConfig, getIpAddress, doNodeRedRestart } = require('./common');
|
|
8
8
|
const { exec } = require("child_process");
|
|
9
|
+
const { BacnetServer } = require("./bacnet_server.js");
|
|
9
10
|
|
|
10
11
|
function BitpoolBacnetGatewayDevice (config) {
|
|
11
12
|
RED.nodes.createNode(this, config);
|
|
@@ -30,6 +31,10 @@ module.exports = function (RED) {
|
|
|
30
31
|
this.nodeName = config.name;
|
|
31
32
|
this.toRestartNodeRed = config.toRestartNodeRed;
|
|
32
33
|
this.deviceId = config.deviceId;
|
|
34
|
+
this.logErrorToConsole = config.logErrorToConsole;
|
|
35
|
+
this.bacnetServerEnabled = config.serverEnabled;
|
|
36
|
+
this.bacnetServerRebuildSchedule = config.bacnetServerRebuildSchedule;
|
|
37
|
+
this.bacnetServer = nodeContext.get("bacnetServer") || null;
|
|
33
38
|
|
|
34
39
|
//client and config store
|
|
35
40
|
this.bacnetConfig = nodeContext.get("bacnetConfig");
|
|
@@ -68,22 +73,11 @@ module.exports = function (RED) {
|
|
|
68
73
|
node.deviceId,
|
|
69
74
|
node.manual_instance_range_enabled,
|
|
70
75
|
node.manual_instance_range_start,
|
|
71
|
-
node.manual_instance_range_end
|
|
76
|
+
node.manual_instance_range_end,
|
|
77
|
+
node.bacnetServerEnabled
|
|
72
78
|
);
|
|
73
|
-
nodeContext.set("bacnetConfig", node.bacnetConfig);
|
|
74
|
-
|
|
75
|
-
//console.log("toRestartNodeRed: ", node.toRestartNodeRed);
|
|
76
|
-
|
|
77
|
-
// if(node.toRestartNodeRed == true) {
|
|
78
|
-
|
|
79
|
-
// doNodeRedRestart().then(function(result) {
|
|
80
|
-
// console.log("restart result: ", result);
|
|
81
|
-
// }).catch(function(error) {
|
|
82
|
-
// console.log("restart error: ", error);
|
|
83
|
-
// });
|
|
84
79
|
|
|
85
|
-
|
|
86
|
-
// }
|
|
80
|
+
nodeContext.set("bacnetConfig", node.bacnetConfig);
|
|
87
81
|
|
|
88
82
|
if(typeof node.bacnetClient !== 'undefined') {
|
|
89
83
|
node.bacnetClient.removeAllListeners();
|
|
@@ -94,6 +88,20 @@ module.exports = function (RED) {
|
|
|
94
88
|
nodeContext.set("bacnetClient", node.bacnetClient);
|
|
95
89
|
}
|
|
96
90
|
|
|
91
|
+
if(node.bacnetServerEnabled == true && node.bacnetClient && node.bacnetServer) {
|
|
92
|
+
node.bacnetServer.deviceId = node.deviceId;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
node.bacnetClient.bacnetServerEnabled = node.bacnetServerEnabled;
|
|
97
|
+
|
|
98
|
+
if(node.bacnetServerEnabled == true && node.bacnetClient) {
|
|
99
|
+
if(node.bacnetServer == null) {
|
|
100
|
+
node.bacnetServer = new BacnetServer(node.bacnetClient, node.deviceId, node.bacnetServerRebuildSchedule, RED.version());
|
|
101
|
+
nodeContext.set("bacnetServer", node.bacnetServer);
|
|
102
|
+
}
|
|
103
|
+
} else if(node.bacnetServerEnabled == false) {
|
|
104
|
+
node.bacnetServer = null;
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
// Clears event handlers of all listeners, avoiding memory leak
|
|
@@ -105,9 +113,9 @@ module.exports = function (RED) {
|
|
|
105
113
|
if (outputType.json && !outputType.mqtt) {
|
|
106
114
|
if(objectPropertyType.fullObject && objectPropertyType.simplePayload) {
|
|
107
115
|
sendSimpleJson(values);
|
|
108
|
-
|
|
116
|
+
sendJsonAsMqtt(values);
|
|
109
117
|
} else if(objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
110
|
-
|
|
118
|
+
sendJsonAsMqtt(values);
|
|
111
119
|
} else if(!objectPropertyType.fullObject && objectPropertyType.simplePayload) {
|
|
112
120
|
sendSimpleJson(values);
|
|
113
121
|
}
|
|
@@ -135,15 +143,25 @@ module.exports = function (RED) {
|
|
|
135
143
|
}
|
|
136
144
|
});
|
|
137
145
|
|
|
146
|
+
node.bacnetClient.on('bacnetErrorLog', (param1, param2) => {
|
|
147
|
+
logOut(param1, param2);
|
|
148
|
+
});
|
|
149
|
+
|
|
138
150
|
node.status({});
|
|
139
151
|
|
|
140
152
|
} else {
|
|
141
|
-
console.log("Issue with client info: ", node);
|
|
142
153
|
// No client information found
|
|
143
154
|
node.status({fill:"red",shape:"dot",text:"Please define client"})
|
|
144
155
|
}
|
|
145
156
|
|
|
146
157
|
node.on('input', function(msg) {
|
|
158
|
+
|
|
159
|
+
if(msg.topic && msg.payload) {
|
|
160
|
+
if(node.bacnetServer) {
|
|
161
|
+
node.bacnetServer.addObject(msg.topic, msg.payload);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
147
165
|
if(msg.type == "Read") {
|
|
148
166
|
|
|
149
167
|
node.bacnetClient.doRead(msg.options, msg.outputType, msg.objectPropertyType, msg._msgid);
|
|
@@ -155,7 +173,7 @@ module.exports = function (RED) {
|
|
|
155
173
|
|
|
156
174
|
} else if(msg.doDiscover == true) {
|
|
157
175
|
|
|
158
|
-
node.status({fill:"blue",shape:"dot",text:"
|
|
176
|
+
node.status({fill:"blue",shape:"dot",text:"Sending global Who is"})
|
|
159
177
|
|
|
160
178
|
node.bacnetClient.globalWhoIs();
|
|
161
179
|
|
|
@@ -171,7 +189,7 @@ module.exports = function (RED) {
|
|
|
171
189
|
//route handler for network data
|
|
172
190
|
RED.httpAdmin.get('/bitpool-bacnet-data/getNetworkTree', function(req, res) {
|
|
173
191
|
if(!node.bacnetClient) {
|
|
174
|
-
|
|
192
|
+
logOut("Issue with the bacnetClient: ", node.bacnetClient);
|
|
175
193
|
//no bacnet client present
|
|
176
194
|
node.status({fill:"red",shape:"dot",text:"Please define client"});
|
|
177
195
|
res.send(false);
|
|
@@ -180,7 +198,7 @@ module.exports = function (RED) {
|
|
|
180
198
|
res.send(result);
|
|
181
199
|
}).catch(function(error) {
|
|
182
200
|
res.send(error);
|
|
183
|
-
|
|
201
|
+
logOut("Error getting network data: ", error);
|
|
184
202
|
});
|
|
185
203
|
}
|
|
186
204
|
});
|
|
@@ -188,7 +206,7 @@ module.exports = function (RED) {
|
|
|
188
206
|
//route handler for rebuild data model command
|
|
189
207
|
RED.httpAdmin.get('/bitpool-bacnet-data/rebuildDataModel', function(req, res) {
|
|
190
208
|
if(!node.bacnetClient) {
|
|
191
|
-
|
|
209
|
+
logOut("Issue with the bacnetClient: ", node.bacnetClient);
|
|
192
210
|
//no bacnet client present
|
|
193
211
|
node.status({fill:"red",shape:"dot",text:"Please define client"});
|
|
194
212
|
res.send(false);
|
|
@@ -197,7 +215,7 @@ module.exports = function (RED) {
|
|
|
197
215
|
res.send(result);
|
|
198
216
|
}).catch(function(error) {
|
|
199
217
|
res.send(error);
|
|
200
|
-
|
|
218
|
+
logOut("Error getting network data: ", error);
|
|
201
219
|
});
|
|
202
220
|
}
|
|
203
221
|
});
|
|
@@ -207,7 +225,7 @@ module.exports = function (RED) {
|
|
|
207
225
|
getIpAddress().then(function(result) {
|
|
208
226
|
res.send(result);
|
|
209
227
|
}).catch(function(error) {
|
|
210
|
-
|
|
228
|
+
logOut("Error getting network interfaces for client: ", error);
|
|
211
229
|
});
|
|
212
230
|
});
|
|
213
231
|
|
|
@@ -221,9 +239,9 @@ module.exports = function (RED) {
|
|
|
221
239
|
if (outputType.json && !outputType.mqtt) {
|
|
222
240
|
if(objectPropertyType.fullObject && objectPropertyType.simplePayload) {
|
|
223
241
|
sendSimpleJson(values);
|
|
224
|
-
|
|
242
|
+
sendJsonAsMqtt(values);
|
|
225
243
|
} else if(objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
226
|
-
|
|
244
|
+
sendJsonAsMqtt(values);
|
|
227
245
|
} else if(!objectPropertyType.fullObject && objectPropertyType.simplePayload) {
|
|
228
246
|
sendSimpleJson(values);
|
|
229
247
|
}
|
|
@@ -245,6 +263,18 @@ module.exports = function (RED) {
|
|
|
245
263
|
});
|
|
246
264
|
}
|
|
247
265
|
|
|
266
|
+
function logOut(param1, param2) {
|
|
267
|
+
if(node.logErrorToConsole == true) {
|
|
268
|
+
if(arguments.length == 1) {
|
|
269
|
+
console.log("BACnet Error: ");
|
|
270
|
+
console.log(param1);
|
|
271
|
+
} else if(arguments.length == 2) {
|
|
272
|
+
console.log("BACnet Error: ");
|
|
273
|
+
console.log(param1, param2);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
248
278
|
// Returns true if any config values have changed
|
|
249
279
|
function configHasChanged() {
|
|
250
280
|
if(node.bacnetConfig == null){ return true;}
|
|
@@ -262,11 +292,13 @@ module.exports = function (RED) {
|
|
|
262
292
|
if(node.manual_instance_range_enabled !== node.bacnetConfig.manual_instance_range_enabled){ return true;}
|
|
263
293
|
if(node.manual_instance_range_start !== node.bacnetConfig.manual_instance_range_start){ return true;}
|
|
264
294
|
if(node.manual_instance_range_end !== node.bacnetConfig.manual_instance_range_end){ return true;}
|
|
295
|
+
if(node.bacnetServerEnabled !== node.bacnetConfig.bacnetServerEnabled){ return true;}
|
|
296
|
+
if(node.deviceId !== node.bacnetConfig.deviceId){ return true;}
|
|
265
297
|
|
|
266
298
|
return false;
|
|
267
299
|
};
|
|
268
300
|
|
|
269
|
-
sendSimpleMqtt = function(values){
|
|
301
|
+
sendSimpleMqtt = function(values) {
|
|
270
302
|
let devices = Object.keys(values);
|
|
271
303
|
devices.forEach(function(device) {
|
|
272
304
|
if(device !== "_msgid") {
|
|
@@ -294,7 +326,6 @@ module.exports = function (RED) {
|
|
|
294
326
|
});
|
|
295
327
|
};
|
|
296
328
|
|
|
297
|
-
|
|
298
329
|
// Breaks down response JSON object into mqtt topic / payload
|
|
299
330
|
sendAsMqtt = function(values) {
|
|
300
331
|
let devices = Object.keys(values);
|
|
@@ -347,6 +378,28 @@ module.exports = function (RED) {
|
|
|
347
378
|
});
|
|
348
379
|
};
|
|
349
380
|
|
|
381
|
+
sendJsonAsMqtt = function(values) {
|
|
382
|
+
if(typeof values == "object") {
|
|
383
|
+
let keys = Object.keys(values);
|
|
384
|
+
keys.forEach(function(key) {
|
|
385
|
+
let points = values[key];
|
|
386
|
+
let msgg = {};
|
|
387
|
+
|
|
388
|
+
if(node.nodeName !== "gateway" &&
|
|
389
|
+
node.nodeName !== "" &&
|
|
390
|
+
node.nodeName !== "null" &&
|
|
391
|
+
node.nodeName !== "undefined" &&
|
|
392
|
+
typeof node.nodeName == "string") {
|
|
393
|
+
msgg.topic = `${node.nodeName}/${key}`;
|
|
394
|
+
} else {
|
|
395
|
+
msgg.topic = `BITPOOL_BACNET_GATEWAY/${key}`;
|
|
396
|
+
}
|
|
397
|
+
msgg.payload = points;
|
|
398
|
+
node.send(msgg);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
350
403
|
};
|
|
351
404
|
|
|
352
405
|
RED.nodes.registerType('Bacnet-Gateway', BitpoolBacnetGatewayDevice);
|