@bitpoolos/edge-bacnet 1.2.5 → 1.2.7
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/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/bacnet_client.js +414 -200
- package/bacnet_device.js +52 -0
- package/bacnet_gateway.html +836 -602
- package/bacnet_gateway.js +223 -128
- package/bacnet_read.html +64 -34
- package/bacnet_read.js +8 -3
- package/bacnet_server.js +193 -40
- package/bacnet_write.html +125 -33
- package/bacnet_write.js +1 -1
- package/common.js +152 -131
- package/package.json +2 -3
- package/resources/icons/icon-read.svg +19 -0
- package/resources/icons/icon-write.svg +16 -0
- package/resources/node-bacstack-ts/dist/lib/client.js +3 -3
- package/resources/style.css +11 -0
package/bacnet_client.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
|
-
MIT License Copyright 2021,
|
|
2
|
+
MIT License Copyright 2021, 2024 - Bitpool Pty Ltd
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const bacnet = require('./resources/node-bacstack-ts/dist/index.js');
|
|
6
6
|
const baEnum = bacnet.enum;
|
|
7
7
|
const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
|
|
8
8
|
const { EventEmitter } = require('events');
|
|
9
|
-
const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync } = require('./common');
|
|
9
|
+
const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber } = require('./common');
|
|
10
10
|
const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
|
|
11
11
|
const { BacnetDevice } = require('./bacnet_device');
|
|
12
12
|
const {Mutex} = require("async-mutex");
|
|
@@ -27,19 +27,24 @@ class BacnetClient extends EventEmitter {
|
|
|
27
27
|
that.mutex = new Mutex();
|
|
28
28
|
that.manualMutex = new Mutex();
|
|
29
29
|
that.pollInProgress = false;
|
|
30
|
+
that.scanMatrix = [];
|
|
31
|
+
that.renderListCount = 0;
|
|
30
32
|
|
|
31
33
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if(cachedData
|
|
36
|
-
|
|
37
|
-
cachedData.deviceList
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
|
|
35
|
+
if(config.cacheFileEnabled) {
|
|
36
|
+
let cachedData = JSON.parse(Read_Config_Sync());
|
|
37
|
+
if(cachedData && typeof cachedData == "object") {
|
|
38
|
+
if(cachedData.renderList) that.renderList = cachedData.renderList;
|
|
39
|
+
if(cachedData.deviceList) {
|
|
40
|
+
cachedData.deviceList.forEach(function(device) {
|
|
41
|
+
let newBacnetDevice = new BacnetDevice(true, device);
|
|
42
|
+
that.deviceList.push(newBacnetDevice);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if(cachedData.pointList) that.networkTree = cachedData.pointList;
|
|
46
|
+
if(cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
|
|
41
47
|
}
|
|
42
|
-
if(cachedData.pointList) that.networkTree = cachedData.pointList;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
that.config = config;
|
|
@@ -47,9 +52,6 @@ class BacnetClient extends EventEmitter {
|
|
|
47
52
|
that.apduSize = config.apduSize;
|
|
48
53
|
that.maxSegments = config.maxSegments;
|
|
49
54
|
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
50
|
-
that.device_id_range_enabled = config.device_id_range_enabled;
|
|
51
|
-
that.device_id_range_start = config.device_id_range_start;
|
|
52
|
-
that.device_id_range_end = config.device_id_range_end;
|
|
53
55
|
that.deviceId = config.deviceId;
|
|
54
56
|
that.broadCastAddr = config.broadCastAddr;
|
|
55
57
|
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
@@ -59,12 +61,12 @@ class BacnetClient extends EventEmitter {
|
|
|
59
61
|
that.deviceRetryCount = parseInt(config.retries);
|
|
60
62
|
|
|
61
63
|
that.readPropertyMultipleOptions = {
|
|
62
|
-
maxSegments:
|
|
63
|
-
maxApdu:
|
|
64
|
+
maxSegments: 112,
|
|
65
|
+
maxApdu: 5
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
try {
|
|
67
|
-
|
|
69
|
+
|
|
68
70
|
that.client = new bacnet.Client({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
|
|
69
71
|
that.setMaxListeners(1);
|
|
70
72
|
|
|
@@ -88,7 +90,9 @@ class BacnetClient extends EventEmitter {
|
|
|
88
90
|
|
|
89
91
|
//buildNetworkTreeData task
|
|
90
92
|
const buildNetworkTree = new Task('simple task', () => {
|
|
91
|
-
that.buildNetworkTreeData()
|
|
93
|
+
that.buildNetworkTreeData().then(function() {
|
|
94
|
+
that.countDevices();
|
|
95
|
+
});
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
|
|
@@ -100,31 +104,41 @@ class BacnetClient extends EventEmitter {
|
|
|
100
104
|
setTimeout(() => {
|
|
101
105
|
that.queryDevices();
|
|
102
106
|
that.sanitizeDeviceList();
|
|
103
|
-
that.buildNetworkTreeData()
|
|
107
|
+
that.buildNetworkTreeData().then(function() {
|
|
108
|
+
that.countDevices();
|
|
109
|
+
});
|
|
104
110
|
}, "5000")
|
|
105
111
|
|
|
106
112
|
} catch(e) {
|
|
107
|
-
console.log("Issue initializing client: ", e)
|
|
108
113
|
that.logOut("Issue initializing client: ", e)
|
|
109
114
|
}
|
|
110
115
|
|
|
111
116
|
//who is callback
|
|
112
117
|
that.client.on('iAm', (device) => {
|
|
118
|
+
//console.log("found iAm device: ", device);
|
|
113
119
|
if(device.address !== that.config.localIpAdrress) {
|
|
114
|
-
if(that.
|
|
115
|
-
|
|
120
|
+
if(that.scanMatrix.length > 0) {
|
|
121
|
+
let matrixMap = that.scanMatrix.filter(ele => device.deviceId >= ele.start && device.deviceId <= ele.end);
|
|
122
|
+
if(matrixMap.length > 0) {
|
|
116
123
|
//only add unique device to array
|
|
117
124
|
let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
|
|
118
125
|
if(foundIndex == -1) {
|
|
119
126
|
let newBacnetDevice = new BacnetDevice(false, device);
|
|
120
127
|
newBacnetDevice.setLastSeen(Date.now());
|
|
121
128
|
that.updateDeviceName(newBacnetDevice);
|
|
129
|
+
if(newBacnetDevice.getIsMstpDevice()) {
|
|
130
|
+
that.addToParentMstpNetwork(newBacnetDevice);
|
|
131
|
+
}
|
|
122
132
|
that.deviceList.push(newBacnetDevice);
|
|
123
133
|
|
|
124
134
|
} else if(foundIndex !== -1) {
|
|
125
135
|
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
126
136
|
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
127
137
|
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
138
|
+
|
|
139
|
+
if(that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
140
|
+
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
141
|
+
}
|
|
128
142
|
}
|
|
129
143
|
|
|
130
144
|
//emit event for node-red to log
|
|
@@ -137,11 +151,19 @@ class BacnetClient extends EventEmitter {
|
|
|
137
151
|
let newBacnetDevice = new BacnetDevice(false, device);
|
|
138
152
|
newBacnetDevice.setLastSeen(Date.now());
|
|
139
153
|
that.updateDeviceName(newBacnetDevice);
|
|
154
|
+
if(newBacnetDevice.getIsMstpDevice()) {
|
|
155
|
+
that.addToParentMstpNetwork(newBacnetDevice);
|
|
156
|
+
}
|
|
140
157
|
that.deviceList.push(newBacnetDevice);
|
|
141
158
|
} else if(foundIndex !== -1) {
|
|
142
159
|
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
143
160
|
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
144
161
|
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
162
|
+
|
|
163
|
+
if(that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
164
|
+
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
}
|
|
146
168
|
|
|
147
169
|
//emit event for node-red to log
|
|
@@ -167,6 +189,24 @@ class BacnetClient extends EventEmitter {
|
|
|
167
189
|
});
|
|
168
190
|
}
|
|
169
191
|
|
|
192
|
+
testFunction() {
|
|
193
|
+
console.log("test function ");
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
addToParentMstpNetwork(device) {
|
|
200
|
+
let that = this;
|
|
201
|
+
let address = device.getAddress().address;
|
|
202
|
+
let deviceId = device.getDeviceId();
|
|
203
|
+
let foundParentIndex = that.deviceList.findIndex(ele => ele.getAddress() == address);
|
|
204
|
+
if(foundParentIndex !== -1) {
|
|
205
|
+
that.deviceList[foundParentIndex].addChildDevice(deviceId);
|
|
206
|
+
device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
170
210
|
logOut(param1, param2) {
|
|
171
211
|
let that = this;
|
|
172
212
|
that.emit('bacnetErrorLog', param1, param2);
|
|
@@ -180,6 +220,7 @@ class BacnetClient extends EventEmitter {
|
|
|
180
220
|
that.renderList = [];
|
|
181
221
|
that.networkTree = {};
|
|
182
222
|
that.pollInProgress = false;
|
|
223
|
+
that.renderListCount = 0;
|
|
183
224
|
resolve(true);
|
|
184
225
|
} catch(e) {
|
|
185
226
|
that.logOut("Error clearing BACnet data model: ", e);
|
|
@@ -194,10 +235,11 @@ class BacnetClient extends EventEmitter {
|
|
|
194
235
|
that.pollInProgress = true;
|
|
195
236
|
|
|
196
237
|
let index = 0;
|
|
197
|
-
|
|
238
|
+
|
|
198
239
|
query(index);
|
|
199
240
|
|
|
200
241
|
function query(index) {
|
|
242
|
+
|
|
201
243
|
that.queryPriorityDevices().then(function() {
|
|
202
244
|
|
|
203
245
|
let device = that.deviceList[index];
|
|
@@ -218,8 +260,17 @@ class BacnetClient extends EventEmitter {
|
|
|
218
260
|
});
|
|
219
261
|
}).catch(function(e) {
|
|
220
262
|
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
221
|
-
|
|
222
|
-
|
|
263
|
+
device.setManualDiscoveryMode(true);
|
|
264
|
+
that.getDevicePointListWithoutObjectList(device).then(function() {
|
|
265
|
+
that.buildJsonObject(device, null).then(function() {
|
|
266
|
+
query(index);
|
|
267
|
+
}).catch(function(e) {
|
|
268
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
269
|
+
query(index);
|
|
270
|
+
});
|
|
271
|
+
}).catch(function(e){
|
|
272
|
+
query(index);
|
|
273
|
+
});
|
|
223
274
|
});
|
|
224
275
|
} catch(e) {
|
|
225
276
|
that.logOut("Error while querying devices: ", e);
|
|
@@ -239,10 +290,10 @@ class BacnetClient extends EventEmitter {
|
|
|
239
290
|
} else {
|
|
240
291
|
that.pollInProgress = false;
|
|
241
292
|
}
|
|
242
|
-
|
|
243
293
|
}
|
|
244
294
|
});
|
|
245
295
|
}
|
|
296
|
+
|
|
246
297
|
}
|
|
247
298
|
|
|
248
299
|
queryDevicesManually() {
|
|
@@ -398,9 +449,6 @@ class BacnetClient extends EventEmitter {
|
|
|
398
449
|
that.apduSize = config.apduSize;
|
|
399
450
|
that.maxSegments = config.maxSegments;
|
|
400
451
|
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
401
|
-
that.device_id_range_enabled = config.device_id_range_enabled;
|
|
402
|
-
that.device_id_range_start = config.device_id_range_start;
|
|
403
|
-
that.device_id_range_end = config.device_id_range_end;
|
|
404
452
|
that.deviceId = config.deviceId;
|
|
405
453
|
that.broadCastAddr = config.broadCastAddr;
|
|
406
454
|
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
@@ -444,6 +492,7 @@ class BacnetClient extends EventEmitter {
|
|
|
444
492
|
//buildNetworkTreeData task
|
|
445
493
|
const buildNetworkTree = new Task('simple task', () => {
|
|
446
494
|
that.buildNetworkTreeData();
|
|
495
|
+
that.countDevices();
|
|
447
496
|
});
|
|
448
497
|
|
|
449
498
|
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
|
|
@@ -474,11 +523,10 @@ class BacnetClient extends EventEmitter {
|
|
|
474
523
|
return newProps;
|
|
475
524
|
}
|
|
476
525
|
|
|
477
|
-
doRead(readConfig, outputType, objectPropertyType,
|
|
526
|
+
doRead(readConfig, outputType, objectPropertyType, readNodeName) {
|
|
478
527
|
let that = this;
|
|
479
528
|
that.roundDecimal = readConfig.precision;
|
|
480
529
|
let devicesToRead = Object.keys(readConfig.pointsToRead);
|
|
481
|
-
|
|
482
530
|
try {
|
|
483
531
|
let bacnetResults = {};
|
|
484
532
|
devicesToRead.forEach(function(key, index) {
|
|
@@ -493,18 +541,54 @@ class BacnetClient extends EventEmitter {
|
|
|
493
541
|
let bac_obj = that.getObjectType(readConfig.pointsToRead[key][pointName].meta.objectId.type);
|
|
494
542
|
let objectId = pointName + "_" + bac_obj + '_' + readConfig.pointsToRead[key][pointName].meta.objectId.instance;
|
|
495
543
|
let point = deviceObject[objectId];
|
|
496
|
-
|
|
544
|
+
|
|
545
|
+
that.updatePoint(device, point).then(function(result) {
|
|
546
|
+
if(isNumber(result.values[0].value)) {
|
|
547
|
+
point.presentValue = roundDecimalPlaces(result.values[0].value, that.roundDecimal);
|
|
548
|
+
} else {
|
|
549
|
+
point.presentValue = result.values[0].value;
|
|
550
|
+
}
|
|
551
|
+
bacnetResults[deviceName][pointName] = point;
|
|
552
|
+
}).catch(function(err) {
|
|
553
|
+
//do nothing for now
|
|
554
|
+
});
|
|
555
|
+
|
|
497
556
|
}
|
|
498
557
|
}
|
|
499
558
|
}
|
|
500
559
|
|
|
501
|
-
|
|
560
|
+
setTimeout(() => {
|
|
561
|
+
if(index == devicesToRead.length - 1 && Object.keys(readConfig.pointsToRead).length > 0) that.emit('values', bacnetResults, outputType, objectPropertyType, readNodeName);
|
|
562
|
+
}, 3000);
|
|
502
563
|
});
|
|
503
564
|
} catch(e) {
|
|
504
565
|
that.logOut("Issue doing read, see error: ", e);
|
|
505
566
|
}
|
|
506
567
|
}
|
|
507
568
|
|
|
569
|
+
updatePoint(device, point) {
|
|
570
|
+
let that = this;
|
|
571
|
+
return new Promise((resolve, reject) => {
|
|
572
|
+
|
|
573
|
+
that.client.readProperty(
|
|
574
|
+
device.getAddress(),
|
|
575
|
+
{type: point.objectID.type, instance: point.objectID.instance },
|
|
576
|
+
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
577
|
+
{},
|
|
578
|
+
(err, value) => {
|
|
579
|
+
if(err) {
|
|
580
|
+
//console.log("err ", err);
|
|
581
|
+
reject(err);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if(value) {
|
|
585
|
+
resolve(value);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
508
592
|
getDeviceAddress(device) {
|
|
509
593
|
switch(typeof device.getAddress()) {
|
|
510
594
|
case "object":
|
|
@@ -615,91 +699,49 @@ class BacnetClient extends EventEmitter {
|
|
|
615
699
|
let that = this;
|
|
616
700
|
|
|
617
701
|
return new Promise(function(resolve, reject) {
|
|
618
|
-
|
|
619
|
-
let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
|
|
702
|
+
|
|
620
703
|
let address = device.getAddress();
|
|
621
|
-
let
|
|
622
|
-
|
|
623
|
-
//let instanceRange = {start: 0, end: 100};
|
|
624
|
-
let instanceRange = device.getmDiscoverInstanceRange();
|
|
625
|
-
let requestArray = [];
|
|
626
|
-
let maxRequestThreshold = 1000;
|
|
627
|
-
let requestRate = 20;
|
|
628
|
-
let requestBuffer = [];
|
|
629
|
-
let sendBuffer = [];
|
|
630
|
-
|
|
631
|
-
if(that.manual_instance_range_enabled == true) {
|
|
632
|
-
instanceRange.start = that.manual_instance_range_start;
|
|
633
|
-
maxRequestThreshold = that.manual_instance_range_end;
|
|
634
|
-
if(that.manual_instance_range_end < requestRate) {
|
|
635
|
-
requestRate = that.manual_instance_range_end;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
704
|
+
let deviceId = device.getDeviceId();
|
|
705
|
+
let discoveredPointList = [];
|
|
638
706
|
|
|
639
|
-
|
|
640
|
-
let objectType = objectTypeList[typeListIndex];
|
|
641
|
-
for(let i = instanceRange.start; i <= instanceRange.end; i++) {
|
|
642
|
-
|
|
643
|
-
requestArray.push({
|
|
644
|
-
objectId: { type: objectType, instance: i },
|
|
645
|
-
properties: objectNameProperty
|
|
646
|
-
})
|
|
647
|
-
|
|
648
|
-
if(requestArray.length == requestRate ) {
|
|
649
|
-
requestBuffer.push(that._readObjectWithRequestArray(address, requestArray));
|
|
650
|
-
instanceRange.end += requestRate;
|
|
651
|
-
requestArray = [];
|
|
652
|
-
if(i >= maxRequestThreshold) {
|
|
653
|
-
if(typeListIndex == objectTypeList.length-1) {
|
|
654
|
-
device.setmDiscoverInstanceRange({start: instanceRange.end, end: instanceRange.end + 100})
|
|
655
|
-
send();
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
break;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
707
|
+
let index = 1;
|
|
662
708
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
function send() {
|
|
709
|
+
send(index);
|
|
710
|
+
|
|
666
711
|
|
|
667
|
-
|
|
668
|
-
let promise = requestBuffer[index];
|
|
669
|
-
try {
|
|
670
|
-
Promise.resolve(promise).then(function(result) {
|
|
671
|
-
for (const [key, value] of Object.entries(result)) {
|
|
672
|
-
if(key == "value" && typeof value == "object") {
|
|
673
|
-
for(let x = 0; x < value.values.length; x++) {
|
|
674
|
-
let ele = value.values[x];
|
|
675
|
-
let valueRoot = ele.values[0].value[0];
|
|
676
|
-
if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
|
|
677
|
-
sendBuffer.push({"value": ele.objectId, "type": 12});
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
}
|
|
712
|
+
function send(index) {
|
|
682
713
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
714
|
+
let readOptions = {
|
|
715
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
716
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
717
|
+
arrayIndex: index
|
|
718
|
+
}
|
|
686
719
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
720
|
+
that.client.readProperty(
|
|
721
|
+
address,
|
|
722
|
+
{type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
723
|
+
baEnum.PropertyIdentifier.OBJECT_LIST,
|
|
724
|
+
readOptions,
|
|
725
|
+
(err, value) => {
|
|
726
|
+
if(err) {
|
|
727
|
+
resolve(discoveredPointList);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if(value) {
|
|
731
|
+
discoveredPointList.push(value.values[0]);
|
|
732
|
+
index++;
|
|
733
|
+
send(index);
|
|
734
|
+
}
|
|
692
735
|
}
|
|
693
|
-
|
|
736
|
+
);
|
|
694
737
|
}
|
|
695
|
-
|
|
696
738
|
});
|
|
697
739
|
}
|
|
698
740
|
|
|
699
|
-
_readObjectWithRequestArray(deviceAddress, requestArray) {
|
|
741
|
+
_readObjectWithRequestArray(deviceAddress, requestArray, readOptions) {
|
|
700
742
|
let that = this;
|
|
701
743
|
return new Promise((resolve, reject) => {
|
|
702
|
-
this.client.readPropertyMultiple(deviceAddress, requestArray,
|
|
744
|
+
this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
|
|
703
745
|
resolve({
|
|
704
746
|
error: error,
|
|
705
747
|
value: value
|
|
@@ -708,7 +750,7 @@ class BacnetClient extends EventEmitter {
|
|
|
708
750
|
});
|
|
709
751
|
}
|
|
710
752
|
|
|
711
|
-
_readDeviceName(deviceAddress, deviceId, callback){
|
|
753
|
+
_readDeviceName(deviceAddress, deviceId, callback) {
|
|
712
754
|
let that = this;
|
|
713
755
|
that.client.readProperty(
|
|
714
756
|
deviceAddress,
|
|
@@ -719,7 +761,7 @@ class BacnetClient extends EventEmitter {
|
|
|
719
761
|
);
|
|
720
762
|
}
|
|
721
763
|
|
|
722
|
-
_readObjectList(deviceAddress, deviceId, callback) {
|
|
764
|
+
_readObjectList(deviceAddress, deviceId, readOptions, callback) {
|
|
723
765
|
let that = this;
|
|
724
766
|
|
|
725
767
|
try {
|
|
@@ -727,7 +769,7 @@ class BacnetClient extends EventEmitter {
|
|
|
727
769
|
deviceAddress,
|
|
728
770
|
{type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
729
771
|
baEnum.PropertyIdentifier.OBJECT_LIST,
|
|
730
|
-
|
|
772
|
+
readOptions,
|
|
731
773
|
callback
|
|
732
774
|
);
|
|
733
775
|
|
|
@@ -736,14 +778,14 @@ class BacnetClient extends EventEmitter {
|
|
|
736
778
|
}
|
|
737
779
|
}
|
|
738
780
|
|
|
739
|
-
_readObject(deviceAddress, type, instance, properties) {
|
|
781
|
+
_readObject(deviceAddress, type, instance, properties, readOptions) {
|
|
740
782
|
let that = this;
|
|
741
783
|
return new Promise((resolve, reject) => {
|
|
742
784
|
const requestArray = [{
|
|
743
785
|
objectId: { type: type, instance: instance },
|
|
744
786
|
properties: properties
|
|
745
787
|
}];
|
|
746
|
-
this.client.readPropertyMultiple(deviceAddress, requestArray,
|
|
788
|
+
this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
|
|
747
789
|
resolve({
|
|
748
790
|
error: error,
|
|
749
791
|
value: value
|
|
@@ -752,8 +794,12 @@ class BacnetClient extends EventEmitter {
|
|
|
752
794
|
});
|
|
753
795
|
}
|
|
754
796
|
|
|
755
|
-
_readObjectFull(deviceAddress, type, instance) {
|
|
797
|
+
_readObjectFull(device, deviceAddress, type, instance) {
|
|
756
798
|
let that = this;
|
|
799
|
+
const readOptions = {
|
|
800
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
801
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu
|
|
802
|
+
};
|
|
757
803
|
|
|
758
804
|
const allProperties = [
|
|
759
805
|
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
@@ -769,33 +815,71 @@ class BacnetClient extends EventEmitter {
|
|
|
769
815
|
];
|
|
770
816
|
|
|
771
817
|
return new Promise((resolve, reject) => {
|
|
772
|
-
that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }]).then(function(result) {
|
|
818
|
+
that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions).then(function(result) {
|
|
773
819
|
|
|
774
820
|
if(result.value) {
|
|
775
821
|
resolve(result);
|
|
776
822
|
}
|
|
777
823
|
|
|
778
824
|
if(result.error) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
properties: allProperties
|
|
782
|
-
}];
|
|
783
|
-
|
|
784
|
-
that._readObjectWithRequestArray(deviceAddress, requestArray).then(function(manualRequest) {
|
|
785
|
-
if(manualRequest.value) {
|
|
786
|
-
resolve(manualRequest);
|
|
787
|
-
}
|
|
788
|
-
if(manualRequest.error) {
|
|
789
|
-
reject(manualRequest.error);
|
|
790
|
-
}
|
|
791
|
-
})
|
|
825
|
+
let i = 0;
|
|
826
|
+
readIndividualProperties(i);
|
|
792
827
|
}
|
|
793
828
|
|
|
794
829
|
}).catch(function(error) {
|
|
795
|
-
|
|
830
|
+
let i = 0;
|
|
831
|
+
readIndividualProperties(i);
|
|
796
832
|
});
|
|
797
|
-
});
|
|
798
833
|
|
|
834
|
+
let resultArray = [];
|
|
835
|
+
let errorArray = [];
|
|
836
|
+
|
|
837
|
+
function readIndividualProperties(index) {
|
|
838
|
+
|
|
839
|
+
const property = allProperties[index];
|
|
840
|
+
|
|
841
|
+
that.client.readProperty(
|
|
842
|
+
deviceAddress,
|
|
843
|
+
{type: type, instance: instance },
|
|
844
|
+
property.id,
|
|
845
|
+
readOptions,
|
|
846
|
+
(err, value) => {
|
|
847
|
+
if(err) {
|
|
848
|
+
errorArray.push(err);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if(value) {
|
|
852
|
+
let formattedResult = {
|
|
853
|
+
len: value.len,
|
|
854
|
+
objectId: value.objectId,
|
|
855
|
+
values: [
|
|
856
|
+
{
|
|
857
|
+
id: value.property.id,
|
|
858
|
+
index: value.property.index,
|
|
859
|
+
value: value.values
|
|
860
|
+
}
|
|
861
|
+
]
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
resultArray.push({error: null, value: formattedResult});
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
if(index == allProperties.length - 1) {
|
|
868
|
+
resolve(resultArray);
|
|
869
|
+
|
|
870
|
+
// if(resultArray.length > 0) {
|
|
871
|
+
// resolve(resultArray);
|
|
872
|
+
// } else if(errorArray.length > 0){
|
|
873
|
+
// reject(errorArray);
|
|
874
|
+
// }
|
|
875
|
+
} else if( index < allProperties.length - 1) {
|
|
876
|
+
index++;
|
|
877
|
+
readIndividualProperties(index);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
);
|
|
881
|
+
};
|
|
882
|
+
});
|
|
799
883
|
};
|
|
800
884
|
|
|
801
885
|
_readObjectPropList(deviceAddress, type, instance) {
|
|
@@ -823,21 +907,15 @@ class BacnetClient extends EventEmitter {
|
|
|
823
907
|
doWrite(value, options){
|
|
824
908
|
let that = this;
|
|
825
909
|
let valuesArray = [];
|
|
826
|
-
|
|
827
910
|
options.pointsToWrite.forEach(function(point){
|
|
828
|
-
|
|
829
911
|
let deviceAddress = point.deviceAddress;
|
|
830
|
-
|
|
831
|
-
if(valuesArray[deviceAddress] == null || valuesArray[deviceAddress] == undefined){
|
|
832
|
-
valuesArray[deviceAddress] = [];
|
|
833
|
-
}
|
|
834
|
-
|
|
835
912
|
let writeObject = {
|
|
913
|
+
address: deviceAddress,
|
|
836
914
|
objectId: {
|
|
837
915
|
type: point.meta.objectId.type,
|
|
838
916
|
instance: point.meta.objectId.instance
|
|
839
917
|
},
|
|
840
|
-
values:
|
|
918
|
+
values: {
|
|
841
919
|
property: {
|
|
842
920
|
id: 85,
|
|
843
921
|
index: point.meta.arrayIndex
|
|
@@ -846,11 +924,17 @@ class BacnetClient extends EventEmitter {
|
|
|
846
924
|
type: options.appTag,
|
|
847
925
|
value: value
|
|
848
926
|
}],
|
|
927
|
+
|
|
928
|
+
},
|
|
929
|
+
options: {
|
|
930
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
931
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
932
|
+
arrayIndex: point.meta.arrayIndex,
|
|
849
933
|
priority: options.priority
|
|
850
|
-
}
|
|
934
|
+
}
|
|
851
935
|
};
|
|
852
936
|
|
|
853
|
-
valuesArray
|
|
937
|
+
valuesArray.push(writeObject);
|
|
854
938
|
});
|
|
855
939
|
|
|
856
940
|
return that._writePropertyMultiple(valuesArray);
|
|
@@ -858,24 +942,23 @@ class BacnetClient extends EventEmitter {
|
|
|
858
942
|
|
|
859
943
|
_writePropertyMultiple(values) {
|
|
860
944
|
let that = this;
|
|
861
|
-
let writePromises = [];
|
|
862
945
|
try {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
});
|
|
946
|
+
values.forEach(function(point) {
|
|
947
|
+
|
|
948
|
+
that.client.writeProperty(
|
|
949
|
+
point.address,
|
|
950
|
+
point.objectId,
|
|
951
|
+
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
952
|
+
point.values.value,
|
|
953
|
+
point.options,
|
|
954
|
+
(err, value) => {
|
|
955
|
+
if(err) {
|
|
956
|
+
that.logOut(err);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
);
|
|
878
960
|
});
|
|
961
|
+
|
|
879
962
|
} catch (error) {
|
|
880
963
|
that.logOut(error);
|
|
881
964
|
}
|
|
@@ -895,7 +978,11 @@ class BacnetClient extends EventEmitter {
|
|
|
895
978
|
scanDevice(device) {
|
|
896
979
|
let that = this;
|
|
897
980
|
return new Promise((resolve, reject) => {
|
|
898
|
-
|
|
981
|
+
const readOptions = {
|
|
982
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
983
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu
|
|
984
|
+
};
|
|
985
|
+
this._readObjectList(device.getAddress(), device.getDeviceId(), readOptions, (err, result) => {
|
|
899
986
|
if (!err) {
|
|
900
987
|
try {
|
|
901
988
|
resolve(result.values);
|
|
@@ -920,17 +1007,6 @@ class BacnetClient extends EventEmitter {
|
|
|
920
1007
|
|
|
921
1008
|
globalWhoIs() {
|
|
922
1009
|
let that = this;
|
|
923
|
-
let options = {
|
|
924
|
-
lowLimit: 0,
|
|
925
|
-
highLimit: bacnetIdMax,
|
|
926
|
-
'net': 65535
|
|
927
|
-
};
|
|
928
|
-
|
|
929
|
-
if(that.device_id_range_enabled == true) {
|
|
930
|
-
options.lowLimit = that.device_id_range_start;
|
|
931
|
-
options.highLimit = that.device_id_range_end;
|
|
932
|
-
}
|
|
933
|
-
|
|
934
1010
|
if(that.client) {
|
|
935
1011
|
that.client.whoIs({'net': 65535});
|
|
936
1012
|
} else {
|
|
@@ -944,7 +1020,11 @@ class BacnetClient extends EventEmitter {
|
|
|
944
1020
|
let that = this;
|
|
945
1021
|
return new Promise(async function(resolve, reject) {
|
|
946
1022
|
try {
|
|
947
|
-
|
|
1023
|
+
const reducedDeviceList = JSON.parse(JSON.stringify(that.deviceList));
|
|
1024
|
+
reducedDeviceList.forEach((device) => {
|
|
1025
|
+
delete device["pointsList"];
|
|
1026
|
+
});
|
|
1027
|
+
resolve({renderList: that.renderList, deviceList: reducedDeviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule, renderListCount: that.renderListCount});
|
|
948
1028
|
} catch(e){
|
|
949
1029
|
reject(e);
|
|
950
1030
|
}
|
|
@@ -970,7 +1050,7 @@ class BacnetClient extends EventEmitter {
|
|
|
970
1050
|
deviceL.forEach(function(device) {
|
|
971
1051
|
let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
|
|
972
1052
|
if(foundIndex == -1) {
|
|
973
|
-
let newBacnetDevice = new BacnetDevice(
|
|
1053
|
+
let newBacnetDevice = new BacnetDevice(true, device);
|
|
974
1054
|
newBacnetDevice.setLastSeen(Date.now());
|
|
975
1055
|
that.deviceList.push(newBacnetDevice);
|
|
976
1056
|
|
|
@@ -1049,7 +1129,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1049
1129
|
that.buildTreeMutex = new Mutex();
|
|
1050
1130
|
let displayNameCharThreshold = 40;
|
|
1051
1131
|
|
|
1052
|
-
Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
|
|
1132
|
+
Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, renderListCount: that.renderListCount}));
|
|
1053
1133
|
|
|
1054
1134
|
return new Promise(async function(resolve, reject) {
|
|
1055
1135
|
if(!that.renderList) that.renderList = [];
|
|
@@ -1074,6 +1154,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1074
1154
|
for(const pointName in deviceObject) {
|
|
1075
1155
|
let pointProperties = [];
|
|
1076
1156
|
let values = deviceObject[pointName];
|
|
1157
|
+
|
|
1077
1158
|
let displayName = pointName;
|
|
1078
1159
|
if(pointName.length > displayNameCharThreshold) {
|
|
1079
1160
|
displayName = "";
|
|
@@ -1087,45 +1168,150 @@ class BacnetClient extends EventEmitter {
|
|
|
1087
1168
|
}
|
|
1088
1169
|
|
|
1089
1170
|
if(values.objectName){
|
|
1090
|
-
pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-
|
|
1171
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-cog", "children": null});
|
|
1091
1172
|
}
|
|
1092
|
-
if(values.objectType){
|
|
1093
|
-
pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-
|
|
1173
|
+
if(values.objectType && values.objectID.type !== 8){
|
|
1174
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-cog", "children": null});
|
|
1094
1175
|
}
|
|
1095
1176
|
if(values.objectID && values.objectID.instance) {
|
|
1096
|
-
pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-
|
|
1177
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-cog", "children": null});
|
|
1097
1178
|
}
|
|
1098
1179
|
if(values.description){
|
|
1099
|
-
pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-
|
|
1180
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-cog", "children": null});
|
|
1100
1181
|
}
|
|
1101
1182
|
if(values.units){
|
|
1102
|
-
pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-
|
|
1183
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-cog", "children": null});
|
|
1103
1184
|
}
|
|
1104
1185
|
if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
|
|
1105
|
-
pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-
|
|
1186
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-cog", "children": null});
|
|
1106
1187
|
}
|
|
1107
1188
|
if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
|
|
1108
|
-
pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-
|
|
1189
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-cog", "children": null});
|
|
1109
1190
|
}
|
|
1110
1191
|
if(values.modificationDate && !values.modificationDate.errorClass) {
|
|
1111
|
-
pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-
|
|
1192
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-cog", "children": null});
|
|
1112
1193
|
}
|
|
1113
1194
|
if(values.programState){
|
|
1114
|
-
pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-
|
|
1195
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-cog", "children": null});
|
|
1115
1196
|
}
|
|
1116
1197
|
if(values.recordCount && !values.recordCount.errorClass){
|
|
1117
|
-
pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-
|
|
1198
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-cog", "children": null});
|
|
1199
|
+
}
|
|
1200
|
+
if(values.objectID && values.objectID.type == 8) {
|
|
1201
|
+
//device point, add segmentation supported, and apdu size
|
|
1202
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-10`, "label": `Segmentation Supported: ${deviceInfo.getSegmentation()}`, "data": `${deviceInfo.getSegmentation()}`, "icon": "pi pi-cog", "children": null});
|
|
1203
|
+
pointProperties.push({"key": `${index}-0-${pointIndex}-11`, "label": `APDU Size: ${deviceInfo.getMaxApdu()}`, "data": `${deviceInfo.getMaxApdu()}`, "icon": "pi pi-cog", "children": null});
|
|
1118
1204
|
}
|
|
1119
1205
|
|
|
1120
|
-
children.push({"key": `${index}-${pointIndex}`, "label": displayName, "data": displayName, "pointName": pointName, "icon": that.getPointIcon(values.meta.objectId.type), "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
|
|
1206
|
+
children.push({"key": `${index}-0-${pointIndex}`, "label": displayName, "data": displayName, "pointName": pointName, "icon": that.getPointIcon(values.meta.objectId.type), "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
|
|
1121
1207
|
pointIndex++;
|
|
1122
1208
|
}
|
|
1123
1209
|
let foundIndex = that.renderList.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1124
1210
|
if(foundIndex !== -1) {
|
|
1125
|
-
|
|
1211
|
+
let folderJson = [];
|
|
1212
|
+
if(deviceInfo.hasChildDevices()) {
|
|
1213
|
+
folderJson = [
|
|
1214
|
+
{
|
|
1215
|
+
key: `${index}-0`,
|
|
1216
|
+
label: "Points",
|
|
1217
|
+
data: "Points Folder",
|
|
1218
|
+
icon: "pi pi-circle-fill",
|
|
1219
|
+
type: "pointFolder",
|
|
1220
|
+
children: children.sort(that.sortPoints)
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
key: `${index}-1`,
|
|
1224
|
+
label: "MSTP Network",
|
|
1225
|
+
data: "Devices Folder",
|
|
1226
|
+
icon: "pi pi-database",
|
|
1227
|
+
type: "deviceFolder",
|
|
1228
|
+
children: []
|
|
1229
|
+
}
|
|
1230
|
+
];
|
|
1231
|
+
} else {
|
|
1232
|
+
folderJson = [
|
|
1233
|
+
{
|
|
1234
|
+
key: `${index}-0`,
|
|
1235
|
+
label: "Points",
|
|
1236
|
+
data: "Points Folder",
|
|
1237
|
+
icon: "pi pi-circle-fill",
|
|
1238
|
+
type: "pointFolder",
|
|
1239
|
+
children: children.sort(that.sortPoints)
|
|
1240
|
+
}
|
|
1241
|
+
];
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
if(!isMstpDevice) {
|
|
1245
|
+
that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": that.renderList[foundIndex].children, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1246
|
+
} else if(isMstpDevice) {
|
|
1247
|
+
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1248
|
+
let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
|
|
1249
|
+
|
|
1250
|
+
if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children[1].children) {
|
|
1251
|
+
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1252
|
+
if(mstpDeviceIndex == -1) {
|
|
1253
|
+
//that.renderListCount++;
|
|
1254
|
+
that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1255
|
+
} else {
|
|
1256
|
+
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1126
1261
|
} else if(foundIndex == -1) {
|
|
1127
|
-
|
|
1262
|
+
let folderJson = [];
|
|
1263
|
+
if(deviceInfo.hasChildDevices()) {
|
|
1264
|
+
folderJson = [
|
|
1265
|
+
{
|
|
1266
|
+
key: `${index}-0`,
|
|
1267
|
+
label: "Points",
|
|
1268
|
+
data: "Points Folder",
|
|
1269
|
+
icon: "pi pi-circle-fill",
|
|
1270
|
+
type: "pointFolder",
|
|
1271
|
+
children: children.sort(that.sortPoints)
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
key: `${index}-1`,
|
|
1275
|
+
label: "MSTP Network",
|
|
1276
|
+
data: "Devices Folder",
|
|
1277
|
+
icon: "pi pi-database",
|
|
1278
|
+
type: "deviceFolder",
|
|
1279
|
+
children: []
|
|
1280
|
+
}
|
|
1281
|
+
];
|
|
1282
|
+
} else {
|
|
1283
|
+
folderJson = [
|
|
1284
|
+
{
|
|
1285
|
+
key: `${index}-0`,
|
|
1286
|
+
label: "Points",
|
|
1287
|
+
data: "Points Folder",
|
|
1288
|
+
icon: "pi pi-circle-fill",
|
|
1289
|
+
type: "pointFolder",
|
|
1290
|
+
children: children.sort(that.sortPoints)
|
|
1291
|
+
}
|
|
1292
|
+
];
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
if(!isMstpDevice) {
|
|
1296
|
+
//that.renderListCount++;
|
|
1297
|
+
that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1298
|
+
} else if(isMstpDevice) {
|
|
1299
|
+
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1300
|
+
let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
|
|
1301
|
+
|
|
1302
|
+
if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children && that.renderList[parentDeviceIndex].children[1].children) {
|
|
1303
|
+
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1304
|
+
|
|
1305
|
+
if(mstpDeviceIndex == -1) {
|
|
1306
|
+
// that.renderListCount++;
|
|
1307
|
+
that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1308
|
+
} else {
|
|
1309
|
+
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1128
1313
|
}
|
|
1314
|
+
|
|
1129
1315
|
if(index == that.deviceList.length - 1) {
|
|
1130
1316
|
that.renderList.sort(that.sortDevices);
|
|
1131
1317
|
resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
@@ -1139,12 +1325,33 @@ class BacnetClient extends EventEmitter {
|
|
|
1139
1325
|
|
|
1140
1326
|
release();
|
|
1141
1327
|
});
|
|
1142
|
-
|
|
1143
1328
|
});
|
|
1144
1329
|
}
|
|
1145
1330
|
});
|
|
1146
1331
|
}
|
|
1147
1332
|
|
|
1333
|
+
countDevices() {
|
|
1334
|
+
let that = this;
|
|
1335
|
+
|
|
1336
|
+
let deviceCount = 0;
|
|
1337
|
+
|
|
1338
|
+
that.renderList.forEach(function(device, index) {
|
|
1339
|
+
if(device) {
|
|
1340
|
+
if(device.children[1] && device.children[1].label == 'MSTP Network' && device.children[1].children && device.children[1].children.length > 0) {
|
|
1341
|
+
//increment for parent device / mstp router
|
|
1342
|
+
deviceCount++;
|
|
1343
|
+
//increment for mstp device list
|
|
1344
|
+
deviceCount += device.children[1].children.length;
|
|
1345
|
+
} else {
|
|
1346
|
+
deviceCount++;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if(index == that.renderList.length -1) {
|
|
1350
|
+
that.renderListCount = deviceCount;
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1148
1355
|
buildJsonObject(device, priorityQueue) {
|
|
1149
1356
|
let that = this;
|
|
1150
1357
|
let address = device.address;
|
|
@@ -1158,10 +1365,14 @@ class BacnetClient extends EventEmitter {
|
|
|
1158
1365
|
requestMutex
|
|
1159
1366
|
.acquire()
|
|
1160
1367
|
.then(function(release) {
|
|
1161
|
-
that._readObjectFull(address, point.value.type, point.value.instance).then(function(result) {
|
|
1368
|
+
that._readObjectFull(device, address, point.value.type, point.value.instance).then(function(result) {
|
|
1162
1369
|
|
|
1163
1370
|
if(!result.error) {
|
|
1164
|
-
|
|
1371
|
+
if(result.length > 0 && Array.isArray(result)) {
|
|
1372
|
+
promiseArray = result;
|
|
1373
|
+
} else {
|
|
1374
|
+
promiseArray.push(result);
|
|
1375
|
+
}
|
|
1165
1376
|
}
|
|
1166
1377
|
|
|
1167
1378
|
release();
|
|
@@ -1210,6 +1421,11 @@ class BacnetClient extends EventEmitter {
|
|
|
1210
1421
|
let successfulResult = !obj.error ? obj.value : null;
|
|
1211
1422
|
if(successfulResult) {
|
|
1212
1423
|
successfulResult.values.forEach(function(pointProperty, pointPropertyIndex) {
|
|
1424
|
+
|
|
1425
|
+
if(!pointProperty.objectId && successfulResult.objectId && !pointProperty.values && successfulResult.values) {
|
|
1426
|
+
pointProperty = successfulResult;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1213
1429
|
let currobjectId = pointProperty.objectId.type
|
|
1214
1430
|
let bac_obj = that.getObjectType(currobjectId);
|
|
1215
1431
|
let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
@@ -1365,34 +1581,34 @@ class BacnetClient extends EventEmitter {
|
|
|
1365
1581
|
switch(objectId) {
|
|
1366
1582
|
case 0:
|
|
1367
1583
|
//AI
|
|
1368
|
-
return "pi pi-
|
|
1584
|
+
return "pi pi-circle";
|
|
1369
1585
|
case 1:
|
|
1370
1586
|
//AO
|
|
1371
|
-
return "pi pi-
|
|
1587
|
+
return "pi pi-circle";
|
|
1372
1588
|
case 2:
|
|
1373
1589
|
//AV
|
|
1374
|
-
return "pi pi-
|
|
1590
|
+
return "pi pi-circle";
|
|
1375
1591
|
case 3:
|
|
1376
1592
|
//BI
|
|
1377
|
-
return "pi pi-
|
|
1593
|
+
return "pi pi-circle";
|
|
1378
1594
|
case 4:
|
|
1379
1595
|
//BO
|
|
1380
|
-
return "pi pi-
|
|
1596
|
+
return "pi pi-circle";
|
|
1381
1597
|
case 5:
|
|
1382
1598
|
//BV
|
|
1383
|
-
return "pi pi-
|
|
1599
|
+
return "pi pi-circle";
|
|
1384
1600
|
case 8:
|
|
1385
1601
|
//Device
|
|
1386
1602
|
return "pi pi-box";
|
|
1387
1603
|
case 13:
|
|
1388
1604
|
//MI
|
|
1389
|
-
return "pi pi-
|
|
1605
|
+
return "pi pi-circle";
|
|
1390
1606
|
case 14:
|
|
1391
1607
|
//MO
|
|
1392
|
-
return "pi pi-
|
|
1608
|
+
return "pi pi-circle";
|
|
1393
1609
|
case 19:
|
|
1394
1610
|
//MV
|
|
1395
|
-
return "pi pi-
|
|
1611
|
+
return "pi pi-circle";
|
|
1396
1612
|
case 10:
|
|
1397
1613
|
//File
|
|
1398
1614
|
return "pi pi-file";
|
|
@@ -1415,7 +1631,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1415
1631
|
return "pi pi-calendar";
|
|
1416
1632
|
default:
|
|
1417
1633
|
//Return circle for all other types
|
|
1418
|
-
return "pi pi-
|
|
1634
|
+
return "pi pi-circle";
|
|
1419
1635
|
}
|
|
1420
1636
|
}
|
|
1421
1637
|
|
|
@@ -1489,16 +1705,14 @@ class BacnetClient extends EventEmitter {
|
|
|
1489
1705
|
|
|
1490
1706
|
getDeviceIcon(isMstp, manualDiscoveryMode) {
|
|
1491
1707
|
if(manualDiscoveryMode == true) {
|
|
1492
|
-
|
|
1493
|
-
return "pi pi-exclamation-triangle"
|
|
1708
|
+
return "pi pi-question-circle"
|
|
1494
1709
|
} else if(manualDiscoveryMode == false) {
|
|
1495
1710
|
if(isMstp == true) {
|
|
1496
|
-
return "pi pi-
|
|
1711
|
+
return "pi pi-box"
|
|
1497
1712
|
} else if(isMstp == false) {
|
|
1498
1713
|
return "pi pi-server"
|
|
1499
1714
|
}
|
|
1500
1715
|
}
|
|
1501
|
-
|
|
1502
1716
|
return "pi pi-server";
|
|
1503
1717
|
};
|
|
1504
1718
|
}
|