@bitpoolos/edge-bacnet 1.4.4 → 1.4.6
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/CHANGELOG.md +30 -0
- package/bacnet_client.js +463 -495
- package/bacnet_device.js +10 -0
- package/bacnet_gateway.html +141 -135
- package/bacnet_read.html +73 -47
- package/bacnet_write.html +7 -5
- package/bitpool_inject.html +49 -136
- package/package.json +1 -1
- package/resources/node-bacstack-ts/dist/lib/client.js +3 -0
- package/resources/node-bacstack-ts/dist/lib/transport.js +12 -7
- package/resources/style.css +612 -203
- package/treeBuilder.js +41 -5
package/bacnet_client.js
CHANGED
|
@@ -27,6 +27,7 @@ class BacnetClient extends EventEmitter {
|
|
|
27
27
|
that.mutex = new Mutex();
|
|
28
28
|
that.manualMutex = new Mutex();
|
|
29
29
|
that.pollInProgress = false;
|
|
30
|
+
that.buildJsonInProgress = false;
|
|
30
31
|
that.scanMatrix = [];
|
|
31
32
|
that.renderListCount = 0;
|
|
32
33
|
|
|
@@ -63,6 +64,7 @@ class BacnetClient extends EventEmitter {
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
try {
|
|
67
|
+
|
|
66
68
|
that.client = new bacnet.Client({
|
|
67
69
|
apduTimeout: config.apduTimeout,
|
|
68
70
|
interface: config.localIpAdrress,
|
|
@@ -81,7 +83,13 @@ class BacnetClient extends EventEmitter {
|
|
|
81
83
|
|
|
82
84
|
//query device task
|
|
83
85
|
const queryDevices = new Task("simple task", () => {
|
|
84
|
-
if (!that.pollInProgress)
|
|
86
|
+
if (!that.pollInProgress) {
|
|
87
|
+
that.queryDevices();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!that.buildJsonInProgress) {
|
|
91
|
+
that.buildJsonTree();
|
|
92
|
+
}
|
|
85
93
|
});
|
|
86
94
|
|
|
87
95
|
const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule) }, queryDevices);
|
|
@@ -90,10 +98,8 @@ class BacnetClient extends EventEmitter {
|
|
|
90
98
|
|
|
91
99
|
//buildNetworkTreeData task
|
|
92
100
|
const buildNetworkTree = new Task("simple task", () => {
|
|
93
|
-
|
|
94
101
|
that.doTreeBuilder();
|
|
95
102
|
that.countDevices();
|
|
96
|
-
|
|
97
103
|
});
|
|
98
104
|
|
|
99
105
|
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 5 }, buildNetworkTree);
|
|
@@ -104,6 +110,7 @@ class BacnetClient extends EventEmitter {
|
|
|
104
110
|
|
|
105
111
|
setTimeout(() => {
|
|
106
112
|
that.queryDevices();
|
|
113
|
+
that.buildJsonTree();
|
|
107
114
|
}, "5000");
|
|
108
115
|
} catch (e) {
|
|
109
116
|
that.logOut("Issue initializing client: ", e);
|
|
@@ -213,28 +220,30 @@ class BacnetClient extends EventEmitter {
|
|
|
213
220
|
if (lastIndex) {
|
|
214
221
|
let formattedName = deviceName.substring(0, lastIndex);
|
|
215
222
|
formattedName = `${formattedName.trim()}_Device_${deviceId}`;
|
|
216
|
-
if (
|
|
217
|
-
|
|
223
|
+
if (
|
|
224
|
+
that.networkTree[deviceKey][formattedName] &&
|
|
225
|
+
Object.keys(that.networkTree[deviceKey][formattedName]).length > 0
|
|
226
|
+
) {
|
|
218
227
|
delete that.networkTree[deviceKey]["device"];
|
|
219
228
|
}
|
|
220
229
|
}
|
|
221
230
|
}
|
|
222
231
|
} else {
|
|
223
232
|
const json = {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
233
|
+
objectId: {
|
|
234
|
+
type: 8,
|
|
235
|
+
instance: device.getDeviceId(),
|
|
236
|
+
},
|
|
228
237
|
};
|
|
229
238
|
|
|
230
239
|
if (that.networkTree[deviceKey] && that.networkTree[deviceKey]["device"]) {
|
|
231
240
|
that.networkTree[deviceKey]["device"]["meta"] = json;
|
|
232
241
|
} else {
|
|
233
242
|
that.networkTree[deviceKey] = {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
}
|
|
243
|
+
device: {
|
|
244
|
+
meta: json,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
249
|
} catch (e) {
|
|
@@ -262,7 +271,6 @@ class BacnetClient extends EventEmitter {
|
|
|
262
271
|
}
|
|
263
272
|
);
|
|
264
273
|
});
|
|
265
|
-
|
|
266
274
|
}
|
|
267
275
|
|
|
268
276
|
addToParentMstpNetwork(device) {
|
|
@@ -289,6 +297,7 @@ class BacnetClient extends EventEmitter {
|
|
|
289
297
|
that.renderList = [];
|
|
290
298
|
that.networkTree = {};
|
|
291
299
|
that.pollInProgress = false;
|
|
300
|
+
that.buildJsonInProgress = false;
|
|
292
301
|
that.renderListCount = 0;
|
|
293
302
|
resolve(true);
|
|
294
303
|
} catch (e) {
|
|
@@ -302,9 +311,7 @@ class BacnetClient extends EventEmitter {
|
|
|
302
311
|
let that = this;
|
|
303
312
|
return new Promise((resolve, reject) => {
|
|
304
313
|
try {
|
|
305
|
-
let renderListIndex = that.renderList.findIndex(
|
|
306
|
-
(ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address
|
|
307
|
-
);
|
|
314
|
+
let renderListIndex = that.renderList.findIndex((ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address);
|
|
308
315
|
let deviceListIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
309
316
|
let deviceKey = device.address + "-" + device.deviceId;
|
|
310
317
|
delete that.networkTree[deviceKey];
|
|
@@ -320,59 +327,46 @@ class BacnetClient extends EventEmitter {
|
|
|
320
327
|
});
|
|
321
328
|
}
|
|
322
329
|
|
|
323
|
-
updatePointsForDevice(deviceObject) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
330
|
+
async updatePointsForDevice(deviceObject) {
|
|
331
|
+
try {
|
|
332
|
+
let device = this.deviceList.find((ele) => ele.getDeviceId() === deviceObject.deviceId);
|
|
333
|
+
|
|
334
|
+
if (!device) {
|
|
335
|
+
throw new Error(`Device with ID ${deviceObject.deviceId} not found`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
await this.updateDeviceName(device);
|
|
339
|
+
|
|
340
|
+
if (!device.getIsProtocolServicesSet()) {
|
|
341
|
+
try {
|
|
342
|
+
const result = await this.getProtocolSupported(device);
|
|
343
|
+
const decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
344
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
this.logOut("getProtocolSupported error: ", error);
|
|
337
347
|
}
|
|
348
|
+
}
|
|
338
349
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
that
|
|
343
|
-
.buildJsonObject(device)
|
|
344
|
-
.then(function () {
|
|
345
|
-
// do nothing for now
|
|
346
|
-
resolve(true);
|
|
347
|
-
})
|
|
348
|
-
.catch(function (e) {
|
|
349
|
-
that.logOut(`Update points list error 1: ${that.getDeviceAddress(device)}`, e);
|
|
350
|
-
});
|
|
351
|
-
})
|
|
352
|
-
.catch(function (e) {
|
|
353
|
-
that.logOut(`Update points list error 2: ${that.getDeviceAddress(device)}`, e);
|
|
354
|
-
device.setManualDiscoveryMode(true);
|
|
355
|
-
that
|
|
356
|
-
.getDevicePointListWithoutObjectList(device)
|
|
357
|
-
.then(function () {
|
|
358
|
-
that
|
|
359
|
-
.buildJsonObject(device)
|
|
360
|
-
.then(function () {
|
|
361
|
-
// do nothing for now
|
|
362
|
-
resolve(true);
|
|
363
|
-
})
|
|
364
|
-
.catch(function (e) {
|
|
365
|
-
that.logOut(`Update points list error 3: ${that.getDeviceAddress(device)}`, e);
|
|
366
|
-
});
|
|
367
|
-
})
|
|
368
|
-
.catch(function (e) {
|
|
369
|
-
that.logOut(`Update points list error 4: ${that.getDeviceAddress(device)}`, e);
|
|
370
|
-
});
|
|
371
|
-
});
|
|
350
|
+
try {
|
|
351
|
+
await this.getDevicePointList(device);
|
|
352
|
+
await this.buildJsonObject(device);
|
|
372
353
|
} catch (e) {
|
|
373
|
-
|
|
354
|
+
this.logOut(`Update points list error 2: ${this.getDeviceAddress(device)}`, e);
|
|
355
|
+
device.setManualDiscoveryMode(true);
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
await this.getDevicePointListWithoutObjectList(device);
|
|
359
|
+
await this.buildJsonObject(device);
|
|
360
|
+
} catch (e) {
|
|
361
|
+
this.logOut(`Update points list error 4: ${this.getDeviceAddress(device)}`, e);
|
|
362
|
+
}
|
|
374
363
|
}
|
|
375
|
-
|
|
364
|
+
|
|
365
|
+
return true;
|
|
366
|
+
} catch (e) {
|
|
367
|
+
this.logOut(`Error in updatePointsForDevice: ${e.message}`, e);
|
|
368
|
+
throw e; // Re-throw the error to be handled by the caller
|
|
369
|
+
}
|
|
376
370
|
}
|
|
377
371
|
|
|
378
372
|
applyDisplayNames(pointsToRead) {
|
|
@@ -405,13 +399,21 @@ class BacnetClient extends EventEmitter {
|
|
|
405
399
|
let that = this;
|
|
406
400
|
return new Promise((resolve, reject) => {
|
|
407
401
|
try {
|
|
408
|
-
let
|
|
402
|
+
let address = "";
|
|
403
|
+
if (typeof deviceObject.address == "string") {
|
|
404
|
+
address = deviceObject.address;
|
|
405
|
+
} else if (typeof deviceObject.address == "object") {
|
|
406
|
+
address = deviceObject.address.address;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
let device = that.deviceList.find(
|
|
410
|
+
(ele) => that.getDeviceAddress(ele) == address && ele.getDeviceId() == deviceObject.deviceId
|
|
411
|
+
);
|
|
409
412
|
device.setDisplayName(displayName);
|
|
410
413
|
that.buildTreeException = true;
|
|
411
414
|
resolve(true);
|
|
412
415
|
} catch (e) {
|
|
413
416
|
that.logOut("setDeviceDisplayName error: ", e);
|
|
414
|
-
|
|
415
417
|
reject(e);
|
|
416
418
|
}
|
|
417
419
|
});
|
|
@@ -441,7 +443,7 @@ class BacnetClient extends EventEmitter {
|
|
|
441
443
|
for (let key in payload) {
|
|
442
444
|
let device = payload[key];
|
|
443
445
|
for (let pointName in device) {
|
|
444
|
-
let pointObject = device[pointName]
|
|
446
|
+
let pointObject = device[pointName];
|
|
445
447
|
if (that.networkTree[key][pointName]) {
|
|
446
448
|
that.networkTree[key][pointName] = pointObject;
|
|
447
449
|
}
|
|
@@ -455,108 +457,89 @@ class BacnetClient extends EventEmitter {
|
|
|
455
457
|
});
|
|
456
458
|
}
|
|
457
459
|
|
|
458
|
-
|
|
460
|
+
//test re write
|
|
461
|
+
async queryDevices() {
|
|
459
462
|
let that = this;
|
|
463
|
+
try {
|
|
464
|
+
that.pollInProgress = true;
|
|
465
|
+
let index = 0;
|
|
466
|
+
await query(index);
|
|
467
|
+
|
|
468
|
+
async function query(index) {
|
|
469
|
+
if (index < that.deviceList.length) {
|
|
470
|
+
let device = that.deviceList[index];
|
|
471
|
+
if (typeof device == "object" && (device.getIsDumbMstpRouter() == false || device.getIsDumbMstpRouter() == undefined)) {
|
|
472
|
+
if (device.getIsProtocolServicesSet() == false) {
|
|
473
|
+
try {
|
|
474
|
+
let result = await that.getProtocolSupported(device);
|
|
475
|
+
let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
476
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
477
|
+
} catch (error) {
|
|
478
|
+
that.logOut("getProtocolSupported error: ", error);
|
|
479
|
+
index++;
|
|
480
|
+
await query(index);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
await that.updateDeviceName(device);
|
|
485
|
+
if (device.getSegmentation() !== 3) {
|
|
486
|
+
try {
|
|
487
|
+
await that.getDevicePointList(device);
|
|
488
|
+
|
|
489
|
+
index++;
|
|
490
|
+
await query(index);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
460
493
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
index++;
|
|
494
|
+
index++;
|
|
495
|
+
await query(index);
|
|
496
|
+
}
|
|
497
|
+
} else if (device.getSegmentation() == 3) {
|
|
498
|
+
try {
|
|
499
|
+
await that.getDevicePointListWithoutObjectList(device);
|
|
500
|
+
index++;
|
|
501
|
+
await query(index);
|
|
502
|
+
} catch (e) {
|
|
503
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
472
504
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
that.logOut("getProtocolSupported error: ", error);
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
try {
|
|
505
|
+
index++;
|
|
506
|
+
await query(index);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
} catch (e) {
|
|
510
|
+
that.logOut("Error while querying devices: ", e);
|
|
483
511
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
that
|
|
487
|
-
.getDevicePointList(device)
|
|
488
|
-
.then(function () {
|
|
489
|
-
that
|
|
490
|
-
.buildJsonObject(device)
|
|
491
|
-
.then(function () {
|
|
492
|
-
query(index);
|
|
493
|
-
})
|
|
494
|
-
.catch(function (e) {
|
|
495
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
496
|
-
query(index);
|
|
497
|
-
});
|
|
498
|
-
})
|
|
499
|
-
.catch(function (e) {
|
|
500
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
501
|
-
that
|
|
502
|
-
.getDevicePointListWithoutObjectList(device)
|
|
503
|
-
.then(function () {
|
|
504
|
-
that
|
|
505
|
-
.buildJsonObject(device)
|
|
506
|
-
.then(function () {
|
|
507
|
-
query(index);
|
|
508
|
-
})
|
|
509
|
-
.catch(function (e) {
|
|
510
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
511
|
-
query(index);
|
|
512
|
-
});
|
|
513
|
-
})
|
|
514
|
-
.catch(function (e) {
|
|
515
|
-
query(index);
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
} else if (device.getSegmentation() == 3) {
|
|
520
|
-
|
|
521
|
-
that.updateDeviceName(device);
|
|
522
|
-
that
|
|
523
|
-
.getDevicePointListWithoutObjectList(device)
|
|
524
|
-
.then(function () {
|
|
525
|
-
that
|
|
526
|
-
.buildJsonObject(device)
|
|
527
|
-
.then(function () {
|
|
528
|
-
query(index);
|
|
529
|
-
})
|
|
530
|
-
.catch(function (e) {
|
|
531
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
532
|
-
query(index);
|
|
533
|
-
});
|
|
534
|
-
})
|
|
535
|
-
.catch(function (e) {
|
|
536
|
-
query(index);
|
|
537
|
-
});
|
|
512
|
+
index++;
|
|
513
|
+
await query(index);
|
|
538
514
|
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
query(index);
|
|
515
|
+
} else {
|
|
516
|
+
index++;
|
|
517
|
+
await query(index);
|
|
542
518
|
}
|
|
543
|
-
} else {
|
|
544
|
-
that.
|
|
545
|
-
query(index);
|
|
519
|
+
} else if (index == that.deviceList.length) {
|
|
520
|
+
that.pollInProgress = false;
|
|
546
521
|
}
|
|
547
|
-
} else if (index == that.deviceList.length) {
|
|
548
|
-
that.pollInProgress = false;
|
|
549
522
|
}
|
|
523
|
+
} catch (e) {
|
|
524
|
+
that.logOut("Error while querying devices: ", e);
|
|
550
525
|
}
|
|
551
526
|
}
|
|
552
527
|
|
|
553
528
|
updateDeviceName(device) {
|
|
554
529
|
let that = this;
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
device.
|
|
558
|
-
|
|
559
|
-
|
|
530
|
+
return new Promise((resolve, reject) => {
|
|
531
|
+
that
|
|
532
|
+
._getDeviceName(device.getAddress(), device.getDeviceId())
|
|
533
|
+
.then(function (deviceObject) {
|
|
534
|
+
if (typeof deviceObject.name == "string") {
|
|
535
|
+
device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
|
|
536
|
+
device.setPointsList(deviceObject.devicePointEntry);
|
|
537
|
+
}
|
|
538
|
+
resolve();
|
|
539
|
+
})
|
|
540
|
+
.catch(function (e) {
|
|
541
|
+
reject(e);
|
|
542
|
+
});
|
|
560
543
|
});
|
|
561
544
|
}
|
|
562
545
|
|
|
@@ -596,7 +579,13 @@ class BacnetClient extends EventEmitter {
|
|
|
596
579
|
|
|
597
580
|
// //query device task
|
|
598
581
|
const queryDevices = new Task("simple task", () => {
|
|
599
|
-
if (!that.pollInProgress)
|
|
582
|
+
if (!that.pollInProgress) {
|
|
583
|
+
that.queryDevices();
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (!that.buildJsonInProgress) {
|
|
587
|
+
that.buildJsonTree();
|
|
588
|
+
}
|
|
600
589
|
});
|
|
601
590
|
|
|
602
591
|
const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule) }, queryDevices);
|
|
@@ -638,7 +627,7 @@ class BacnetClient extends EventEmitter {
|
|
|
638
627
|
|
|
639
628
|
findDeviceByKey(key) {
|
|
640
629
|
let that = this;
|
|
641
|
-
return that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
|
|
630
|
+
return that.deviceList.find((ele) => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
|
|
642
631
|
}
|
|
643
632
|
|
|
644
633
|
getObjectId(pointName, pointConfig, that) {
|
|
@@ -659,7 +648,6 @@ class BacnetClient extends EventEmitter {
|
|
|
659
648
|
}
|
|
660
649
|
}
|
|
661
650
|
|
|
662
|
-
|
|
663
651
|
async doRead(readConfig, outputType, objectPropertyType, readNodeName) {
|
|
664
652
|
const that = this;
|
|
665
653
|
const roundDecimal = readConfig.precision;
|
|
@@ -668,7 +656,6 @@ class BacnetClient extends EventEmitter {
|
|
|
668
656
|
let pendingRequests = 0;
|
|
669
657
|
|
|
670
658
|
try {
|
|
671
|
-
|
|
672
659
|
// Process all devices in sequence
|
|
673
660
|
for (let deviceIndex = 0; deviceIndex < devicesToRead.length; deviceIndex++) {
|
|
674
661
|
const key = devicesToRead[deviceIndex];
|
|
@@ -711,7 +698,7 @@ class BacnetClient extends EventEmitter {
|
|
|
711
698
|
objectId: { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
|
|
712
699
|
properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }],
|
|
713
700
|
pointRef: point,
|
|
714
|
-
pointName: pointName
|
|
701
|
+
pointName: pointName,
|
|
715
702
|
});
|
|
716
703
|
}
|
|
717
704
|
|
|
@@ -732,9 +719,16 @@ class BacnetClient extends EventEmitter {
|
|
|
732
719
|
if (processedPoints >= totalPoints) {
|
|
733
720
|
pendingRequests++;
|
|
734
721
|
// Emit the `values` event for the current device
|
|
735
|
-
that.emit(
|
|
722
|
+
that.emit(
|
|
723
|
+
"values",
|
|
724
|
+
bacnetResults,
|
|
725
|
+
outputType,
|
|
726
|
+
objectPropertyType,
|
|
727
|
+
readNodeName,
|
|
728
|
+
pendingRequests,
|
|
729
|
+
devicesToRead.length
|
|
730
|
+
);
|
|
736
731
|
delete bacnetResults[deviceName];
|
|
737
|
-
|
|
738
732
|
}
|
|
739
733
|
}
|
|
740
734
|
}
|
|
@@ -751,18 +745,19 @@ class BacnetClient extends EventEmitter {
|
|
|
751
745
|
}
|
|
752
746
|
|
|
753
747
|
let deviceMetaInfo = {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
748
|
+
address: device.getAddress(),
|
|
749
|
+
isMstp: device.getIsMstpDevice(),
|
|
750
|
+
deviceId: device.getDeviceId(),
|
|
751
|
+
vendorId: device.getVendorId(),
|
|
752
|
+
deviceName: deviceName,
|
|
759
753
|
};
|
|
760
754
|
|
|
761
755
|
// Process the results of the batch
|
|
762
|
-
results.value.values.forEach(pointResult => {
|
|
763
|
-
const cacheRef = requestArray.find(
|
|
764
|
-
ele
|
|
765
|
-
|
|
756
|
+
results.value.values.forEach((pointResult) => {
|
|
757
|
+
const cacheRef = requestArray.find(
|
|
758
|
+
(ele) =>
|
|
759
|
+
ele.pointRef.meta.objectId.type === pointResult.objectId.type &&
|
|
760
|
+
ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
|
|
766
761
|
);
|
|
767
762
|
|
|
768
763
|
if (cacheRef) {
|
|
@@ -799,31 +794,31 @@ class BacnetClient extends EventEmitter {
|
|
|
799
794
|
that.logOut("Error processing batch:", err);
|
|
800
795
|
|
|
801
796
|
let deviceMetaInfo = {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
797
|
+
address: device.getAddress(),
|
|
798
|
+
isMstp: device.getIsMstpDevice(),
|
|
799
|
+
deviceId: device.getDeviceId(),
|
|
800
|
+
vendorId: device.getVendorId(),
|
|
801
|
+
deviceName: deviceName,
|
|
807
802
|
};
|
|
808
803
|
|
|
809
|
-
requestArray.forEach(request => {
|
|
804
|
+
requestArray.forEach((request) => {
|
|
810
805
|
let pointRef = request.pointRef;
|
|
811
806
|
pointRef.status = "offline";
|
|
807
|
+
pointRef.timestamp = Date.now();
|
|
812
808
|
pointRef.meta["device"] = deviceMetaInfo;
|
|
813
809
|
|
|
814
810
|
bacnetResults[deviceName][request.pointName] = pointRef;
|
|
815
811
|
});
|
|
816
|
-
|
|
817
812
|
}
|
|
818
813
|
}
|
|
819
814
|
|
|
820
815
|
async processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
|
|
821
816
|
let deviceMetaInfo = {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
817
|
+
address: device.getAddress(),
|
|
818
|
+
isMstp: device.getIsMstpDevice(),
|
|
819
|
+
deviceId: device.getDeviceId(),
|
|
820
|
+
vendorId: device.getVendorId(),
|
|
821
|
+
deviceName: deviceName,
|
|
827
822
|
};
|
|
828
823
|
|
|
829
824
|
for (const request of requestArray) {
|
|
@@ -839,6 +834,8 @@ class BacnetClient extends EventEmitter {
|
|
|
839
834
|
}
|
|
840
835
|
|
|
841
836
|
pointRef.meta["device"] = deviceMetaInfo;
|
|
837
|
+
pointRef.timestamp = Date.now();
|
|
838
|
+
pointRef.status = "online";
|
|
842
839
|
|
|
843
840
|
// Store the point data in results
|
|
844
841
|
bacnetResults[deviceName][pointName] = pointRef;
|
|
@@ -846,7 +843,7 @@ class BacnetClient extends EventEmitter {
|
|
|
846
843
|
that.logOut(`Error updating point ${pointName}:`, err);
|
|
847
844
|
|
|
848
845
|
pointRef.meta["device"] = deviceMetaInfo;
|
|
849
|
-
|
|
846
|
+
pointRef.timestamp = Date.now();
|
|
850
847
|
pointRef.status = "offline";
|
|
851
848
|
bacnetResults[deviceName][pointName] = pointRef;
|
|
852
849
|
}
|
|
@@ -856,11 +853,14 @@ class BacnetClient extends EventEmitter {
|
|
|
856
853
|
updateManyPoints(device, points) {
|
|
857
854
|
let that = this;
|
|
858
855
|
return new Promise((resolve, reject) => {
|
|
859
|
-
that
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
856
|
+
that
|
|
857
|
+
._readObjectWithRequestArray(device.getAddress(), points, that.readPropertyMultipleOptions)
|
|
858
|
+
.then(function (results) {
|
|
859
|
+
resolve(results);
|
|
860
|
+
})
|
|
861
|
+
.catch(function (err) {
|
|
862
|
+
reject(err);
|
|
863
|
+
});
|
|
864
864
|
});
|
|
865
865
|
}
|
|
866
866
|
|
|
@@ -924,8 +924,12 @@ class BacnetClient extends EventEmitter {
|
|
|
924
924
|
}
|
|
925
925
|
} catch (e) {
|
|
926
926
|
that.logOut("Unable to get device name: ", e);
|
|
927
|
+
reject(e);
|
|
927
928
|
}
|
|
928
929
|
}
|
|
930
|
+
if (err) {
|
|
931
|
+
reject(err);
|
|
932
|
+
}
|
|
929
933
|
});
|
|
930
934
|
});
|
|
931
935
|
}
|
|
@@ -978,6 +982,7 @@ class BacnetClient extends EventEmitter {
|
|
|
978
982
|
device.setManualDiscoveryMode(false);
|
|
979
983
|
let result = await that.scanDevice(device);
|
|
980
984
|
device.setPointsList(result);
|
|
985
|
+
device.setLastSeen(Date.now());
|
|
981
986
|
resolve(result);
|
|
982
987
|
} catch (e) {
|
|
983
988
|
that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
|
|
@@ -994,6 +999,7 @@ class BacnetClient extends EventEmitter {
|
|
|
994
999
|
.scanDeviceManually(device)
|
|
995
1000
|
.then(function (result) {
|
|
996
1001
|
device.setPointsList(result);
|
|
1002
|
+
device.setLastSeen(Date.now());
|
|
997
1003
|
resolve(result);
|
|
998
1004
|
})
|
|
999
1005
|
.catch(function (error) {
|
|
@@ -1128,8 +1134,9 @@ class BacnetClient extends EventEmitter {
|
|
|
1128
1134
|
|
|
1129
1135
|
return new Promise((resolve, reject) => {
|
|
1130
1136
|
// Try to read all properties at once
|
|
1131
|
-
that
|
|
1132
|
-
.
|
|
1137
|
+
that
|
|
1138
|
+
._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
|
|
1139
|
+
.then((result) => {
|
|
1133
1140
|
if (result.value) {
|
|
1134
1141
|
// If the result has value, resolve the promise
|
|
1135
1142
|
resolve(result);
|
|
@@ -1145,30 +1152,33 @@ class BacnetClient extends EventEmitter {
|
|
|
1145
1152
|
|
|
1146
1153
|
// Function to read properties individually
|
|
1147
1154
|
const readPropertiesIndividually = () => {
|
|
1148
|
-
const promises = allProperties.map(
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1155
|
+
const promises = allProperties.map(
|
|
1156
|
+
(property, index) =>
|
|
1157
|
+
new Promise((propertyResolve) => {
|
|
1158
|
+
that.client.readProperty(
|
|
1159
|
+
deviceAddress,
|
|
1160
|
+
{ type: type, instance: instance },
|
|
1161
|
+
property.id,
|
|
1162
|
+
readOptions,
|
|
1163
|
+
(err, value) => {
|
|
1164
|
+
if (err) {
|
|
1165
|
+
propertyResolve(null);
|
|
1166
|
+
} else {
|
|
1167
|
+
propertyResolve({
|
|
1168
|
+
id: property.id,
|
|
1169
|
+
index: value.property.index,
|
|
1170
|
+
value: value.values,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
);
|
|
1175
|
+
})
|
|
1176
|
+
);
|
|
1167
1177
|
|
|
1168
1178
|
Promise.all(promises)
|
|
1169
|
-
.then(resultArray => {
|
|
1179
|
+
.then((resultArray) => {
|
|
1170
1180
|
// Filter out null results
|
|
1171
|
-
const validResults = resultArray.filter(result => result !== null);
|
|
1181
|
+
const validResults = resultArray.filter((result) => result !== null);
|
|
1172
1182
|
|
|
1173
1183
|
resolve({
|
|
1174
1184
|
error: null,
|
|
@@ -1190,7 +1200,6 @@ class BacnetClient extends EventEmitter {
|
|
|
1190
1200
|
});
|
|
1191
1201
|
}
|
|
1192
1202
|
|
|
1193
|
-
|
|
1194
1203
|
_readObjectLite(device, deviceAddress, type, instance) {
|
|
1195
1204
|
const that = this;
|
|
1196
1205
|
const readOptions = {
|
|
@@ -1199,15 +1208,13 @@ class BacnetClient extends EventEmitter {
|
|
|
1199
1208
|
};
|
|
1200
1209
|
|
|
1201
1210
|
// Define all properties to be read
|
|
1202
|
-
const allProperties = [
|
|
1203
|
-
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
1204
|
-
{ id: baEnum.PropertyIdentifier.OBJECT_NAME },
|
|
1205
|
-
];
|
|
1211
|
+
const allProperties = [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }, { id: baEnum.PropertyIdentifier.OBJECT_NAME }];
|
|
1206
1212
|
|
|
1207
1213
|
return new Promise((resolve, reject) => {
|
|
1208
1214
|
// Try to read all properties at once
|
|
1209
|
-
that
|
|
1210
|
-
.
|
|
1215
|
+
that
|
|
1216
|
+
._readObject(deviceAddress, type, instance, allProperties, readOptions)
|
|
1217
|
+
.then((result) => {
|
|
1211
1218
|
if (result.value) {
|
|
1212
1219
|
// If the result has value, resolve the promise
|
|
1213
1220
|
resolve(result);
|
|
@@ -1223,30 +1230,33 @@ class BacnetClient extends EventEmitter {
|
|
|
1223
1230
|
|
|
1224
1231
|
// Function to read properties individually
|
|
1225
1232
|
const readPropertiesIndividually = () => {
|
|
1226
|
-
const promises = allProperties.map(
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1233
|
+
const promises = allProperties.map(
|
|
1234
|
+
(property, index) =>
|
|
1235
|
+
new Promise((propertyResolve) => {
|
|
1236
|
+
that.client.readProperty(
|
|
1237
|
+
deviceAddress,
|
|
1238
|
+
{ type: type, instance: instance },
|
|
1239
|
+
property.id,
|
|
1240
|
+
readOptions,
|
|
1241
|
+
(err, value) => {
|
|
1242
|
+
if (err) {
|
|
1243
|
+
propertyResolve(null);
|
|
1244
|
+
} else {
|
|
1245
|
+
propertyResolve({
|
|
1246
|
+
id: property.id,
|
|
1247
|
+
index: value.property.index,
|
|
1248
|
+
value: value.values,
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
);
|
|
1253
|
+
})
|
|
1254
|
+
);
|
|
1245
1255
|
|
|
1246
1256
|
Promise.all(promises)
|
|
1247
|
-
.then(resultArray => {
|
|
1257
|
+
.then((resultArray) => {
|
|
1248
1258
|
// Filter out null results
|
|
1249
|
-
const validResults = resultArray.filter(result => result !== null);
|
|
1259
|
+
const validResults = resultArray.filter((result) => result !== null);
|
|
1250
1260
|
|
|
1251
1261
|
resolve({
|
|
1252
1262
|
error: null,
|
|
@@ -1496,7 +1506,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1496
1506
|
}
|
|
1497
1507
|
|
|
1498
1508
|
addUniqueToArray(device, array) {
|
|
1499
|
-
const foundIndex = array.findIndex(ele => ele.getDeviceId() === device.getDeviceId());
|
|
1509
|
+
const foundIndex = array.findIndex((ele) => ele.getDeviceId() === device.getDeviceId());
|
|
1500
1510
|
if (foundIndex === -1) {
|
|
1501
1511
|
array.push(device);
|
|
1502
1512
|
}
|
|
@@ -1509,16 +1519,16 @@ class BacnetClient extends EventEmitter {
|
|
|
1509
1519
|
const device = that.deviceList[i];
|
|
1510
1520
|
if (!device.getIsMstpDevice()) {
|
|
1511
1521
|
//ip device
|
|
1512
|
-
const foundIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1522
|
+
const foundIndex = that.renderList.findIndex((ele) => ele.deviceId == device.getDeviceId());
|
|
1513
1523
|
if (foundIndex == -1) {
|
|
1514
1524
|
that.addUniqueToArray(device, missingDevices);
|
|
1515
1525
|
}
|
|
1516
1526
|
} else {
|
|
1517
1527
|
//mstp device
|
|
1518
|
-
const foundParentIndex = that.renderList.findIndex(ele => ele.deviceId == device.getParentDeviceId());
|
|
1528
|
+
const foundParentIndex = that.renderList.findIndex((ele) => ele.deviceId == device.getParentDeviceId());
|
|
1519
1529
|
if (foundParentIndex == -1) {
|
|
1520
1530
|
//parent not existent in tree
|
|
1521
|
-
const parentDeviceIndex = that.deviceList.findIndex(ele => ele.getDeviceId() === device.getParentDeviceId());
|
|
1531
|
+
const parentDeviceIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() === device.getParentDeviceId());
|
|
1522
1532
|
if (parentDeviceIndex !== -1) {
|
|
1523
1533
|
that.addUniqueToArray(that.deviceList[parentDeviceIndex], missingDevices);
|
|
1524
1534
|
}
|
|
@@ -1526,9 +1536,9 @@ class BacnetClient extends EventEmitter {
|
|
|
1526
1536
|
} else {
|
|
1527
1537
|
const parentTreeDevice = that.renderList[foundParentIndex];
|
|
1528
1538
|
let mstpIndex = -1;
|
|
1529
|
-
parentTreeDevice.children.forEach(child => {
|
|
1539
|
+
parentTreeDevice.children.forEach((child) => {
|
|
1530
1540
|
if (child.label.includes("MSTP")) {
|
|
1531
|
-
const tempIndex = child.children.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1541
|
+
const tempIndex = child.children.findIndex((ele) => ele.deviceId == device.getDeviceId());
|
|
1532
1542
|
if (tempIndex !== -1) {
|
|
1533
1543
|
mstpIndex = tempIndex;
|
|
1534
1544
|
}
|
|
@@ -1548,7 +1558,13 @@ class BacnetClient extends EventEmitter {
|
|
|
1548
1558
|
async doTreeBuilder() {
|
|
1549
1559
|
let that = this;
|
|
1550
1560
|
|
|
1551
|
-
const treeWorker = new treeBuilder(
|
|
1561
|
+
const treeWorker = new treeBuilder(
|
|
1562
|
+
that.deviceList,
|
|
1563
|
+
that.networkTree,
|
|
1564
|
+
that.renderList,
|
|
1565
|
+
that.renderListCount,
|
|
1566
|
+
that.initialTreeBuild
|
|
1567
|
+
);
|
|
1552
1568
|
|
|
1553
1569
|
treeWorker.cacheData();
|
|
1554
1570
|
|
|
@@ -1588,280 +1604,232 @@ class BacnetClient extends EventEmitter {
|
|
|
1588
1604
|
}
|
|
1589
1605
|
}
|
|
1590
1606
|
|
|
1591
|
-
|
|
1607
|
+
async buildJsonTree() {
|
|
1592
1608
|
let that = this;
|
|
1593
|
-
|
|
1594
|
-
let
|
|
1595
|
-
|
|
1609
|
+
that.buildJsonInProgress = true;
|
|
1610
|
+
for (let i = 0; i < that.deviceList.length; i++) {
|
|
1611
|
+
try {
|
|
1612
|
+
let device = that.deviceList[i];
|
|
1613
|
+
await that.buildJsonObject(device);
|
|
1614
|
+
} catch (e) {
|
|
1615
|
+
that.logOut("buildJsonTree error: ", e);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1596
1618
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
if (typeof pointList !== "undefined" && pointList.length > 0) {
|
|
1600
|
-
pointList.forEach(function (point, pointListIndex) {
|
|
1601
|
-
requestMutex.acquire().then(function (release) {
|
|
1602
|
-
if (device.getIsInitialQuery()) {
|
|
1603
|
-
that
|
|
1604
|
-
._readObjectLite(device, address, point.value.type, point.value.instance)
|
|
1605
|
-
.then(function (result) {
|
|
1606
|
-
if (!result.error) {
|
|
1607
|
-
if (result.length > 0 && Array.isArray(result)) {
|
|
1608
|
-
promiseArray = result;
|
|
1609
|
-
} else {
|
|
1610
|
-
promiseArray.push(result);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1619
|
+
that.buildJsonInProgress = false;
|
|
1620
|
+
}
|
|
1613
1621
|
|
|
1614
|
-
release();
|
|
1615
|
-
|
|
1616
|
-
if (pointListIndex == pointList.length - 1) {
|
|
1617
|
-
device.setIsInitialQuery(false);
|
|
1618
|
-
that
|
|
1619
|
-
.buildResponse(promiseArray, device)
|
|
1620
|
-
.then(function () {
|
|
1621
|
-
that.lastNetworkPoll = Date.now();
|
|
1622
|
-
resolve({ deviceList: that.deviceList, pointList: that.networkTree });
|
|
1623
|
-
})
|
|
1624
|
-
.catch(function (e) {
|
|
1625
|
-
that.logOut("Error while building json object: ", e);
|
|
1626
|
-
reject(e);
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
})
|
|
1630
|
-
.catch(function (e) {
|
|
1631
|
-
release();
|
|
1632
|
-
that.logOut("_readObjectLite error: ", e);
|
|
1633
|
-
|
|
1634
|
-
if (pointListIndex == pointList.length - 1) {
|
|
1635
|
-
device.setIsInitialQuery(false);
|
|
1636
|
-
that
|
|
1637
|
-
.buildResponse(promiseArray, device)
|
|
1638
|
-
.then(function () {
|
|
1639
|
-
that.lastNetworkPoll = Date.now();
|
|
1640
|
-
resolve({ deviceList: that.deviceList, pointList: that.networkTree });
|
|
1641
|
-
})
|
|
1642
|
-
.catch(function (e) {
|
|
1643
|
-
that.logOut("Error while building json object: ", e);
|
|
1644
|
-
reject(e);
|
|
1645
|
-
});
|
|
1646
|
-
}
|
|
1647
|
-
});
|
|
1648
1622
|
|
|
1623
|
+
async buildJsonObject(device) {
|
|
1624
|
+
try {
|
|
1625
|
+
const address = device.address;
|
|
1626
|
+
const pointList = device.getPointsList();
|
|
1627
|
+
const requestMutex = new Mutex();
|
|
1628
|
+
const promiseArray = [];
|
|
1649
1629
|
|
|
1630
|
+
if (typeof pointList === "undefined" || pointList.length === 0) {
|
|
1631
|
+
throw new Error("Unable to build network tree, empty point list");
|
|
1632
|
+
}
|
|
1650
1633
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
._readObjectFull(device, address, point.value.type, point.value.instance)
|
|
1654
|
-
.then(function (result) {
|
|
1655
|
-
if (!result.error) {
|
|
1656
|
-
if (result.length > 0 && Array.isArray(result)) {
|
|
1657
|
-
promiseArray = result;
|
|
1658
|
-
} else {
|
|
1659
|
-
promiseArray.push(result);
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1634
|
+
for (const point of pointList) {
|
|
1635
|
+
await requestMutex.acquire();
|
|
1662
1636
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
that.logOut("_readObjectFull error: ", e);
|
|
1681
|
-
|
|
1682
|
-
if (pointListIndex == pointList.length - 1) {
|
|
1683
|
-
that
|
|
1684
|
-
.buildResponse(promiseArray, device)
|
|
1685
|
-
.then(function () {
|
|
1686
|
-
that.lastNetworkPoll = Date.now();
|
|
1687
|
-
resolve({ deviceList: that.deviceList, pointList: that.networkTree });
|
|
1688
|
-
})
|
|
1689
|
-
.catch(function (e) {
|
|
1690
|
-
that.logOut("Error while building json object: ", e);
|
|
1691
|
-
reject(e);
|
|
1692
|
-
});
|
|
1693
|
-
}
|
|
1694
|
-
});
|
|
1695
|
-
}
|
|
1696
|
-
});
|
|
1697
|
-
});
|
|
1698
|
-
} else {
|
|
1699
|
-
reject("Unable to build network tree, empty point list");
|
|
1637
|
+
let result;
|
|
1638
|
+
if (device.getIsInitialQuery()) {
|
|
1639
|
+
result = await this._readObjectLite(device, address, point.value.type, point.value.instance);
|
|
1640
|
+
} else {
|
|
1641
|
+
result = await this._readObjectFull(device, address, point.value.type, point.value.instance);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
if (!result.error) {
|
|
1645
|
+
device.setLastSeen(Date.now());
|
|
1646
|
+
if (result.length > 0 && Array.isArray(result)) {
|
|
1647
|
+
promiseArray.push(...result);
|
|
1648
|
+
} else {
|
|
1649
|
+
promiseArray.push(result);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
requestMutex.release();
|
|
1700
1654
|
}
|
|
1701
|
-
|
|
1655
|
+
|
|
1656
|
+
await this.buildResponse(promiseArray, device);
|
|
1657
|
+
this.lastNetworkPoll = Date.now();
|
|
1658
|
+
|
|
1659
|
+
return { deviceList: this.deviceList, pointList: this.networkTree };
|
|
1660
|
+
} catch (error) {
|
|
1661
|
+
this.logOut("Error while building json object: ", error);
|
|
1662
|
+
throw error;
|
|
1663
|
+
}
|
|
1702
1664
|
}
|
|
1703
1665
|
|
|
1704
1666
|
// Builds response object for a fully qualified
|
|
1705
1667
|
buildResponse(fullObjects, device) {
|
|
1706
1668
|
let that = this;
|
|
1707
|
-
const reg = /[
|
|
1669
|
+
const reg = /[$#\/\\+,]/gi;
|
|
1708
1670
|
return new Promise(function (resolve, reject) {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
let
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
pointProperty
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
let currobjectId = pointProperty.objectId.type;
|
|
1724
|
-
let bac_obj = that.getObjectType(currobjectId);
|
|
1725
|
-
let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
1726
|
-
let objectType = pointProperty.objectId.type;
|
|
1727
|
-
|
|
1728
|
-
let objectId;
|
|
1729
|
-
if (objectName !== null && typeof objectName == "string") {
|
|
1730
|
-
objectName = objectName.replace(reg, '');
|
|
1731
|
-
objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
|
|
1671
|
+
try {
|
|
1672
|
+
let deviceKey =
|
|
1673
|
+
typeof device.getAddress() == "object"
|
|
1674
|
+
? device.getAddress().address + "-" + device.getDeviceId()
|
|
1675
|
+
: device.getAddress() + "-" + device.getDeviceId();
|
|
1676
|
+
let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
|
|
1677
|
+
for (let i = 0; i < fullObjects.length; i++) {
|
|
1678
|
+
let obj = fullObjects[i];
|
|
1679
|
+
let successfulResult = !obj.error ? obj.value : null;
|
|
1680
|
+
if (successfulResult) {
|
|
1681
|
+
successfulResult.values.forEach(function (pointProperty, pointPropertyIndex) {
|
|
1682
|
+
if (!pointProperty.objectId && successfulResult.objectId && !pointProperty.values && successfulResult.values) {
|
|
1683
|
+
pointProperty = successfulResult;
|
|
1684
|
+
}
|
|
1732
1685
|
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
|
|
1686
|
+
let currobjectId = pointProperty.objectId.type;
|
|
1687
|
+
let bac_obj = that.getObjectType(currobjectId);
|
|
1688
|
+
let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
1689
|
+
let objectType = pointProperty.objectId.type;
|
|
1690
|
+
|
|
1691
|
+
let objectId;
|
|
1692
|
+
if (objectName !== null && typeof objectName == "string") {
|
|
1693
|
+
objectName = objectName.replace(reg, "");
|
|
1694
|
+
objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
|
|
1695
|
+
|
|
1696
|
+
try {
|
|
1697
|
+
pointProperty.values.forEach(function (object, objectIndex) {
|
|
1698
|
+
//checks for error code json structure, returned for invalid bacnet requests
|
|
1699
|
+
if (object && object.value && !object.value.errorClass) {
|
|
1700
|
+
if (!values[objectId]) values[objectId] = {};
|
|
1701
|
+
values[objectId].meta = {
|
|
1702
|
+
objectId: pointProperty.objectId,
|
|
1703
|
+
};
|
|
1704
|
+
|
|
1705
|
+
switch (object.id) {
|
|
1706
|
+
case baEnum.PropertyIdentifier.PRESENT_VALUE:
|
|
1707
|
+
if (object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
|
|
1708
|
+
//check for binary object type
|
|
1709
|
+
if (objectType == 3 || objectType == 4 || objectType == 5) {
|
|
1758
1710
|
if (object.value[0].value == 0) {
|
|
1759
|
-
values[objectId].presentValue =
|
|
1760
|
-
} else if (object.value[0].value
|
|
1761
|
-
values[objectId].presentValue =
|
|
1711
|
+
values[objectId].presentValue = false;
|
|
1712
|
+
} else if (object.value[0].value == 1) {
|
|
1713
|
+
values[objectId].presentValue = true;
|
|
1762
1714
|
}
|
|
1715
|
+
} else if (objectType == 40) {
|
|
1716
|
+
//character string
|
|
1717
|
+
values[objectId].presentValue = object.value[0].value;
|
|
1718
|
+
} else if (objectType == 13 || objectType == 14 || objectType == 19) {
|
|
1719
|
+
//check for MSV MSI MSO - for enum state text
|
|
1720
|
+
if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
|
|
1721
|
+
if (object.value[0].value == 0) {
|
|
1722
|
+
values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value].value;
|
|
1723
|
+
} else if (object.value[0].value !== 0) {
|
|
1724
|
+
values[objectId].presentValue =
|
|
1725
|
+
values[objectId].stateTextArray[object.value[0].value - 1].value;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
} else if (objectType !== 8) {
|
|
1729
|
+
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
values[objectId].meta.arrayIndex = object.index;
|
|
1733
|
+
break;
|
|
1734
|
+
case baEnum.PropertyIdentifier.DESCRIPTION:
|
|
1735
|
+
if (object.value[0]) values[objectId].description = object.value[0].value;
|
|
1736
|
+
break;
|
|
1737
|
+
case baEnum.PropertyIdentifier.UNITS:
|
|
1738
|
+
if (object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
|
|
1739
|
+
break;
|
|
1740
|
+
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
1741
|
+
if (object.value[0] && object.value[0].value) {
|
|
1742
|
+
values[objectId].objectName = object.value[0].value.replace(reg, "");
|
|
1743
|
+
if (!values[objectId].displayName) {
|
|
1744
|
+
values[objectId].displayName = object.value[0].value.replace(reg, "");
|
|
1763
1745
|
}
|
|
1764
|
-
} else if (objectType !== 8) {
|
|
1765
|
-
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
1766
1746
|
}
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
if (
|
|
1781
|
-
values[objectId].
|
|
1747
|
+
break;
|
|
1748
|
+
case baEnum.PropertyIdentifier.OBJECT_TYPE:
|
|
1749
|
+
if (object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
|
|
1750
|
+
break;
|
|
1751
|
+
case baEnum.PropertyIdentifier.PROPERTY_LIST:
|
|
1752
|
+
if (object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
|
|
1753
|
+
break;
|
|
1754
|
+
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
1755
|
+
if (object.value[0]) {
|
|
1756
|
+
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
1757
|
+
}
|
|
1758
|
+
break;
|
|
1759
|
+
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
1760
|
+
if (object.value[0]) {
|
|
1761
|
+
values[objectId].modificationDate = object.value[0].value;
|
|
1762
|
+
}
|
|
1763
|
+
break;
|
|
1764
|
+
case baEnum.PropertyIdentifier.PROGRAM_STATE:
|
|
1765
|
+
if (object.value[0]) {
|
|
1766
|
+
values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
|
|
1782
1767
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
values[objectId].recordCount = object.value[0].value;
|
|
1809
|
-
}
|
|
1810
|
-
break;
|
|
1811
|
-
case baEnum.PropertyIdentifier.PRIORITY_ARRAY:
|
|
1812
|
-
if (object.value.length > 0) {
|
|
1813
|
-
values[objectId].hasPriorityArray = true;
|
|
1814
|
-
}
|
|
1815
|
-
break;
|
|
1816
|
-
case baEnum.PropertyIdentifier.STATE_TEXT:
|
|
1817
|
-
if (object.value) {
|
|
1818
|
-
values[objectId].stateTextArray = object.value;
|
|
1819
|
-
if (typeof values[objectId].presentValue == "number" &&
|
|
1820
|
-
values[objectId].presentValue !== null &&
|
|
1821
|
-
values[objectId].presentValue !== undefined) {
|
|
1822
|
-
const tempIndex = values[objectId].presentValue;
|
|
1823
|
-
if (tempIndex == 0) {
|
|
1824
|
-
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
|
|
1825
|
-
} else if (tempIndex !== 0) {
|
|
1826
|
-
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
|
|
1768
|
+
break;
|
|
1769
|
+
case baEnum.PropertyIdentifier.RECORD_COUNT:
|
|
1770
|
+
if (object.value[0]) {
|
|
1771
|
+
values[objectId].recordCount = object.value[0].value;
|
|
1772
|
+
}
|
|
1773
|
+
break;
|
|
1774
|
+
case baEnum.PropertyIdentifier.PRIORITY_ARRAY:
|
|
1775
|
+
if (object.value.length > 0) {
|
|
1776
|
+
values[objectId].hasPriorityArray = true;
|
|
1777
|
+
}
|
|
1778
|
+
break;
|
|
1779
|
+
case baEnum.PropertyIdentifier.STATE_TEXT:
|
|
1780
|
+
if (object.value) {
|
|
1781
|
+
values[objectId].stateTextArray = object.value;
|
|
1782
|
+
if (
|
|
1783
|
+
typeof values[objectId].presentValue == "number" &&
|
|
1784
|
+
values[objectId].presentValue !== null &&
|
|
1785
|
+
values[objectId].presentValue !== undefined
|
|
1786
|
+
) {
|
|
1787
|
+
const tempIndex = values[objectId].presentValue;
|
|
1788
|
+
if (tempIndex == 0) {
|
|
1789
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
|
|
1790
|
+
} else if (tempIndex !== 0) {
|
|
1791
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
|
|
1792
|
+
}
|
|
1827
1793
|
}
|
|
1828
1794
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1795
|
+
break;
|
|
1796
|
+
case baEnum.PropertyIdentifier.VENDOR_NAME:
|
|
1797
|
+
if (object.value) {
|
|
1798
|
+
if (object.value[0].value && typeof object.value[0].value == "string") {
|
|
1799
|
+
values[objectId].vendorName = object.value[0].value;
|
|
1800
|
+
}
|
|
1835
1801
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1802
|
+
break;
|
|
1803
|
+
}
|
|
1838
1804
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
}
|
|
1848
|
-
})
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1805
|
+
if (
|
|
1806
|
+
pointPropertyIndex == successfulResult.values.length - 1 &&
|
|
1807
|
+
objectIndex == pointProperty.values.length - 1 &&
|
|
1808
|
+
i == fullObjects.length - 1
|
|
1809
|
+
) {
|
|
1810
|
+
that.networkTree[deviceKey] = values;
|
|
1811
|
+
resolve(that.networkTree);
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
} catch (e) {
|
|
1815
|
+
that.logOut("issue resolving bacnet payload, see error: ", e);
|
|
1816
|
+
reject(e);
|
|
1817
|
+
}
|
|
1852
1818
|
}
|
|
1819
|
+
});
|
|
1820
|
+
} else {
|
|
1821
|
+
//error found in point property
|
|
1822
|
+
if (i == fullObjects.length - 1) {
|
|
1823
|
+
that.networkTree[deviceKey] = values;
|
|
1824
|
+
resolve(that.networkTree);
|
|
1853
1825
|
}
|
|
1854
|
-
});
|
|
1855
|
-
} else {
|
|
1856
|
-
//error found in point property
|
|
1857
|
-
if (i == fullObjects.length - 1) {
|
|
1858
|
-
that.networkTree[deviceKey] = values;
|
|
1859
|
-
resolve(that.networkTree);
|
|
1860
1826
|
}
|
|
1861
1827
|
}
|
|
1828
|
+
that.networkTree[deviceKey] = values;
|
|
1829
|
+
resolve(that.networkTree);
|
|
1830
|
+
} catch (e) {
|
|
1831
|
+
reject(e);
|
|
1862
1832
|
}
|
|
1863
|
-
that.networkTree[deviceKey] = values;
|
|
1864
|
-
resolve(that.networkTree);
|
|
1865
1833
|
});
|
|
1866
1834
|
}
|
|
1867
1835
|
|