@bitpoolos/edge-bacnet 1.2.8 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +20 -2
- package/bacnet_client.js +592 -760
- package/bacnet_device.js +122 -60
- package/bacnet_gateway.html +91 -75
- package/bacnet_gateway.js +161 -46
- package/bacnet_read.html +1025 -596
- package/bacnet_read.js +68 -84
- package/bacnet_server.js +187 -186
- package/bacnet_write.html +268 -24
- package/common.js +22 -4
- package/package.json +2 -2
- package/resources/bitArray.js +167 -0
- package/resources/node-bacstack-ts/dist/lib/asn1.js +16 -5
- package/resources/node-bacstack-ts/dist/lib/client.js +5 -6
- package/resources/style.css +321 -0
- package/treeBuilder.js +533 -0
package/bacnet_client.js
CHANGED
|
@@ -6,10 +6,11 @@ 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, isNumber } = require("./common");
|
|
9
|
+
const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber, decodeBitArray } = 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");
|
|
13
|
+
const { treeBuilder } = require("./treeBuilder.js");
|
|
13
14
|
|
|
14
15
|
class BacnetClient extends EventEmitter {
|
|
15
16
|
//client constructor
|
|
@@ -18,7 +19,6 @@ class BacnetClient extends EventEmitter {
|
|
|
18
19
|
let that = this;
|
|
19
20
|
that.config = config;
|
|
20
21
|
that.deviceList = [];
|
|
21
|
-
that.manualDiscoverQueue = [];
|
|
22
22
|
that.networkTree = {};
|
|
23
23
|
that.lastWhoIs = null;
|
|
24
24
|
that.client = null;
|
|
@@ -52,12 +52,10 @@ class BacnetClient extends EventEmitter {
|
|
|
52
52
|
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
53
53
|
that.deviceId = config.deviceId;
|
|
54
54
|
that.broadCastAddr = config.broadCastAddr;
|
|
55
|
-
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
56
|
-
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
57
|
-
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
58
55
|
that.device_read_schedule = config.device_read_schedule;
|
|
59
56
|
that.deviceRetryCount = parseInt(config.retries);
|
|
60
57
|
that.sanitise_device_schedule = config.sanitise_device_schedule;
|
|
58
|
+
that.buildTreeException = false;
|
|
61
59
|
|
|
62
60
|
that.readPropertyMultipleOptions = {
|
|
63
61
|
maxSegments: 112,
|
|
@@ -84,7 +82,6 @@ class BacnetClient extends EventEmitter {
|
|
|
84
82
|
//query device task
|
|
85
83
|
const queryDevices = new Task("simple task", () => {
|
|
86
84
|
if (!that.pollInProgress) that.queryDevices();
|
|
87
|
-
that.sanitizeDeviceList();
|
|
88
85
|
});
|
|
89
86
|
|
|
90
87
|
const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule) }, queryDevices);
|
|
@@ -93,12 +90,13 @@ class BacnetClient extends EventEmitter {
|
|
|
93
90
|
|
|
94
91
|
//buildNetworkTreeData task
|
|
95
92
|
const buildNetworkTree = new Task("simple task", () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
|
|
94
|
+
that.doTreeBuilder();
|
|
95
|
+
that.countDevices();
|
|
96
|
+
|
|
99
97
|
});
|
|
100
98
|
|
|
101
|
-
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds:
|
|
99
|
+
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 5 }, buildNetworkTree);
|
|
102
100
|
|
|
103
101
|
that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
|
|
104
102
|
|
|
@@ -106,10 +104,6 @@ class BacnetClient extends EventEmitter {
|
|
|
106
104
|
|
|
107
105
|
setTimeout(() => {
|
|
108
106
|
that.queryDevices();
|
|
109
|
-
that.sanitizeDeviceList();
|
|
110
|
-
that.buildNetworkTreeData().then(function () {
|
|
111
|
-
that.countDevices();
|
|
112
|
-
});
|
|
113
107
|
}, "5000");
|
|
114
108
|
} catch (e) {
|
|
115
109
|
that.logOut("Issue initializing client: ", e);
|
|
@@ -117,7 +111,6 @@ class BacnetClient extends EventEmitter {
|
|
|
117
111
|
|
|
118
112
|
//who is callback
|
|
119
113
|
that.client.on("iAm", (device) => {
|
|
120
|
-
//console.log("found iAm device: ", device);
|
|
121
114
|
if (device.address !== that.config.localIpAdrress) {
|
|
122
115
|
if (that.scanMatrix.length > 0) {
|
|
123
116
|
let matrixMap = that.scanMatrix.filter((ele) => device.deviceId >= ele.start && device.deviceId <= ele.end);
|
|
@@ -127,7 +120,6 @@ class BacnetClient extends EventEmitter {
|
|
|
127
120
|
if (foundIndex == -1) {
|
|
128
121
|
let newBacnetDevice = new BacnetDevice(false, device);
|
|
129
122
|
newBacnetDevice.setLastSeen(Date.now());
|
|
130
|
-
that.updateDeviceName(newBacnetDevice);
|
|
131
123
|
if (newBacnetDevice.getIsMstpDevice()) {
|
|
132
124
|
that.addToParentMstpNetwork(newBacnetDevice);
|
|
133
125
|
}
|
|
@@ -135,8 +127,6 @@ class BacnetClient extends EventEmitter {
|
|
|
135
127
|
} else if (foundIndex !== -1) {
|
|
136
128
|
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
137
129
|
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
138
|
-
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
139
|
-
|
|
140
130
|
if (that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
141
131
|
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
142
132
|
}
|
|
@@ -151,7 +141,6 @@ class BacnetClient extends EventEmitter {
|
|
|
151
141
|
if (foundIndex == -1) {
|
|
152
142
|
let newBacnetDevice = new BacnetDevice(false, device);
|
|
153
143
|
newBacnetDevice.setLastSeen(Date.now());
|
|
154
|
-
that.updateDeviceName(newBacnetDevice);
|
|
155
144
|
if (newBacnetDevice.getIsMstpDevice()) {
|
|
156
145
|
that.addToParentMstpNetwork(newBacnetDevice);
|
|
157
146
|
}
|
|
@@ -159,8 +148,6 @@ class BacnetClient extends EventEmitter {
|
|
|
159
148
|
} else if (foundIndex !== -1) {
|
|
160
149
|
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
161
150
|
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
162
|
-
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
163
|
-
|
|
164
151
|
if (that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
165
152
|
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
166
153
|
}
|
|
@@ -204,12 +191,36 @@ class BacnetClient extends EventEmitter {
|
|
|
204
191
|
}
|
|
205
192
|
|
|
206
193
|
if (value) {
|
|
207
|
-
console.log("value: ", value);
|
|
194
|
+
console.log("value : ", value);
|
|
195
|
+
console.log("value1 : ", value.values[0].value);
|
|
208
196
|
}
|
|
209
197
|
}
|
|
210
198
|
);
|
|
211
199
|
}
|
|
212
200
|
|
|
201
|
+
getProtocolSupported(device) {
|
|
202
|
+
//return protocols support for device
|
|
203
|
+
let that = this;
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
that.client.readProperty(
|
|
206
|
+
device.getAddress(),
|
|
207
|
+
{ type: baEnum.ObjectType.DEVICE, instance: device.getDeviceId() },
|
|
208
|
+
baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED,
|
|
209
|
+
that.readPropertyMultipleOptions,
|
|
210
|
+
(err, value) => {
|
|
211
|
+
if (err) {
|
|
212
|
+
reject(err);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (value) {
|
|
216
|
+
resolve(value);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
213
224
|
addToParentMstpNetwork(device) {
|
|
214
225
|
let that = this;
|
|
215
226
|
let address = device.getAddress().address;
|
|
@@ -243,223 +254,227 @@ class BacnetClient extends EventEmitter {
|
|
|
243
254
|
});
|
|
244
255
|
}
|
|
245
256
|
|
|
246
|
-
|
|
257
|
+
purgeDevice(device) {
|
|
247
258
|
let that = this;
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
try {
|
|
261
|
+
let renderListIndex = that.renderList.findIndex(
|
|
262
|
+
(ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address
|
|
263
|
+
);
|
|
264
|
+
let deviceListIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
265
|
+
let deviceKey = device.address + "-" + device.deviceId;
|
|
266
|
+
delete that.networkTree[deviceKey];
|
|
267
|
+
that.renderList.splice(renderListIndex, 1);
|
|
268
|
+
that.deviceList.splice(deviceListIndex, 1);
|
|
248
269
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
let index = 0;
|
|
252
|
-
|
|
253
|
-
query(index);
|
|
254
|
-
|
|
255
|
-
function query(index) {
|
|
256
|
-
that.queryPriorityDevices().then(function () {
|
|
257
|
-
let device = that.deviceList[index];
|
|
258
|
-
|
|
259
|
-
if (index < that.deviceList.length) {
|
|
260
|
-
index++;
|
|
270
|
+
that.countDevices();
|
|
261
271
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
.then(function () {
|
|
268
|
-
that.removeDeviceFromManualQueue(device);
|
|
269
|
-
that
|
|
270
|
-
.buildJsonObject(device, null)
|
|
271
|
-
.then(function () {
|
|
272
|
-
query(index);
|
|
273
|
-
})
|
|
274
|
-
.catch(function (e) {
|
|
275
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
276
|
-
query(index);
|
|
277
|
-
});
|
|
278
|
-
})
|
|
279
|
-
.catch(function (e) {
|
|
280
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
281
|
-
device.setManualDiscoveryMode(true);
|
|
282
|
-
that
|
|
283
|
-
.getDevicePointListWithoutObjectList(device)
|
|
284
|
-
.then(function () {
|
|
285
|
-
that
|
|
286
|
-
.buildJsonObject(device, null)
|
|
287
|
-
.then(function () {
|
|
288
|
-
query(index);
|
|
289
|
-
})
|
|
290
|
-
.catch(function (e) {
|
|
291
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
292
|
-
query(index);
|
|
293
|
-
});
|
|
294
|
-
})
|
|
295
|
-
.catch(function (e) {
|
|
296
|
-
query(index);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
} catch (e) {
|
|
300
|
-
that.logOut("Error while querying devices: ", e);
|
|
301
|
-
query(index);
|
|
302
|
-
}
|
|
303
|
-
} else {
|
|
304
|
-
query(index);
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
that.logOut("queryDevices: invalid device found: ", device);
|
|
308
|
-
query(index);
|
|
309
|
-
}
|
|
310
|
-
} else if (index == that.deviceList.length) {
|
|
311
|
-
if (that.manualDiscoverQueue.length > 0) {
|
|
312
|
-
that.queryDevicesManually();
|
|
313
|
-
} else {
|
|
314
|
-
that.pollInProgress = false;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
}
|
|
272
|
+
resolve(true);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
reject(e);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
319
277
|
}
|
|
320
278
|
|
|
321
|
-
|
|
279
|
+
updatePointsForDevice(deviceObject) {
|
|
322
280
|
let that = this;
|
|
323
|
-
|
|
324
|
-
|
|
281
|
+
return new Promise((resolve, reject) => {
|
|
282
|
+
try {
|
|
283
|
+
let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
|
|
284
|
+
that.updateDeviceName(device);
|
|
285
|
+
|
|
286
|
+
if (device.getIsProtocolServicesSet() == false) {
|
|
287
|
+
that.getProtocolSupported(device).then(function (result) {
|
|
288
|
+
let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
289
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
290
|
+
}).catch(function (error) {
|
|
291
|
+
that.logOut("getProtocolSupported error: ", error);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
325
294
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
295
|
+
that
|
|
296
|
+
.getDevicePointList(device)
|
|
297
|
+
.then(function () {
|
|
298
|
+
that
|
|
299
|
+
.buildJsonObject(device)
|
|
300
|
+
.then(function () {
|
|
301
|
+
// do nothing for now
|
|
302
|
+
resolve(true);
|
|
303
|
+
})
|
|
304
|
+
.catch(function (e) {
|
|
305
|
+
that.logOut(`Update points list error 1: ${device.getAddress()}`, e);
|
|
306
|
+
});
|
|
307
|
+
})
|
|
308
|
+
.catch(function (e) {
|
|
309
|
+
that.logOut(`Update points list error 2: ${device.getAddress()}`, e);
|
|
310
|
+
device.setManualDiscoveryMode(true);
|
|
311
|
+
that
|
|
312
|
+
.getDevicePointListWithoutObjectList(device)
|
|
313
|
+
.then(function () {
|
|
334
314
|
that
|
|
335
|
-
.
|
|
315
|
+
.buildJsonObject(device)
|
|
336
316
|
.then(function () {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
.then(function () {
|
|
340
|
-
query(index);
|
|
341
|
-
})
|
|
342
|
-
.catch(function (e) {
|
|
343
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
344
|
-
query(index);
|
|
345
|
-
});
|
|
317
|
+
// do nothing for now
|
|
318
|
+
resolve(true);
|
|
346
319
|
})
|
|
347
320
|
.catch(function (e) {
|
|
348
|
-
|
|
321
|
+
that.logOut(`Update points list error 3: ${device.getAddress()}`, e);
|
|
349
322
|
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
} else if (index == that.manualDiscoverQueue.length) {
|
|
361
|
-
that.pollInProgress = false;
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
}
|
|
323
|
+
})
|
|
324
|
+
.catch(function (e) {
|
|
325
|
+
that.logOut(`Update points list error 4: ${device.getAddress()}`, e);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
} catch (e) {
|
|
329
|
+
reject(e);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
365
332
|
}
|
|
366
333
|
|
|
367
|
-
|
|
334
|
+
setDeviceDisplayName(deviceObject, displayName) {
|
|
368
335
|
let that = this;
|
|
369
336
|
return new Promise((resolve, reject) => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (priorityDevices.length > 0) {
|
|
373
|
-
let index = 0;
|
|
337
|
+
try {
|
|
338
|
+
let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
|
|
374
339
|
|
|
375
|
-
|
|
340
|
+
device.setDisplayName(displayName);
|
|
376
341
|
|
|
377
|
-
|
|
378
|
-
let device = priorityDevices[index];
|
|
342
|
+
that.buildTreeException = true;
|
|
379
343
|
|
|
380
|
-
|
|
381
|
-
|
|
344
|
+
resolve(true);
|
|
345
|
+
} catch (e) {
|
|
346
|
+
that.logOut("setDeviceDisplayName error: ", e);
|
|
382
347
|
|
|
383
|
-
|
|
384
|
-
typeof device == "object" &&
|
|
385
|
-
(Date.now() - device.getLastPriorityQueueTS()) / 1000 > parseInt(that.device_read_schedule)
|
|
386
|
-
) {
|
|
387
|
-
try {
|
|
388
|
-
let points = device.getPriorityQueue();
|
|
389
|
-
that
|
|
390
|
-
.buildJsonObject(device, points)
|
|
391
|
-
.then(function () {
|
|
392
|
-
device.setLastPriorityQueueTS();
|
|
393
|
-
query(index);
|
|
394
|
-
})
|
|
395
|
-
.catch(function (e) {
|
|
396
|
-
that.logOut(`queryPriorityDevices error: ${device.getAddress()}`, e);
|
|
397
|
-
query(index);
|
|
398
|
-
});
|
|
399
|
-
} catch (e) {
|
|
400
|
-
that.logOut("Error while querying priority devices: ", e);
|
|
401
|
-
query(index);
|
|
402
|
-
}
|
|
403
|
-
} else {
|
|
404
|
-
query(index);
|
|
405
|
-
}
|
|
406
|
-
} else if (index == priorityDevices.length) {
|
|
407
|
-
resolve();
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
} else if (priorityDevices.length == 0) {
|
|
411
|
-
resolve();
|
|
348
|
+
reject(e);
|
|
412
349
|
}
|
|
413
350
|
});
|
|
414
351
|
}
|
|
415
352
|
|
|
416
|
-
|
|
353
|
+
setPointDisplayName(deviceKey, pointName, pointDisplayName) {
|
|
417
354
|
let that = this;
|
|
355
|
+
return new Promise((resolve, reject) => {
|
|
356
|
+
try {
|
|
357
|
+
if (that.networkTree[deviceKey][pointName]) {
|
|
358
|
+
that.networkTree[deviceKey][pointName].displayName = pointDisplayName;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
that.buildTreeException = true;
|
|
418
362
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
that.manualDiscoverQueue.push(device);
|
|
363
|
+
resolve(true);
|
|
364
|
+
} catch (e) {
|
|
365
|
+
that.logOut("setPointDisplayName error: ", e);
|
|
366
|
+
reject(e);
|
|
424
367
|
}
|
|
425
|
-
}
|
|
426
|
-
device.incrementPointListRetryCount();
|
|
427
|
-
}
|
|
368
|
+
});
|
|
428
369
|
}
|
|
429
370
|
|
|
430
|
-
|
|
371
|
+
importReadList(payload) {
|
|
431
372
|
let that = this;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
373
|
+
|
|
374
|
+
return new Promise((resolve, reject) => {
|
|
375
|
+
try {
|
|
376
|
+
that.buildTreeException = true;
|
|
377
|
+
|
|
378
|
+
for (let key in payload) {
|
|
379
|
+
let device = payload[key];
|
|
380
|
+
for (let pointName in device) {
|
|
381
|
+
let pointObject = device[pointName]
|
|
382
|
+
if (that.networkTree[key][pointName]) {
|
|
383
|
+
that.networkTree[key][pointName] = pointObject;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
resolve(true);
|
|
388
|
+
} catch (e) {
|
|
389
|
+
that.logOut("importReadList error: ", e);
|
|
390
|
+
reject(e);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
438
393
|
}
|
|
439
394
|
|
|
440
|
-
|
|
395
|
+
queryDevices() {
|
|
441
396
|
let that = this;
|
|
442
397
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
398
|
+
that.pollInProgress = true;
|
|
399
|
+
|
|
400
|
+
let index = 0;
|
|
401
|
+
|
|
402
|
+
query(index);
|
|
403
|
+
|
|
404
|
+
function query(index) {
|
|
405
|
+
let device = that.deviceList[index];
|
|
406
|
+
|
|
407
|
+
if (index < that.deviceList.length) {
|
|
408
|
+
index++;
|
|
409
|
+
|
|
410
|
+
if (typeof device == "object") {
|
|
411
|
+
if (device.getIsProtocolServicesSet() == false) {
|
|
412
|
+
that.getProtocolSupported(device).then(function (result) {
|
|
413
|
+
let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
414
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
415
|
+
}).catch(function (error) {
|
|
416
|
+
that.logOut("getProtocolSupported error: ", error);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (!device.getManualDiscoveryMode()) {
|
|
421
|
+
try {
|
|
422
|
+
that.updateDeviceName(device);
|
|
423
|
+
that
|
|
424
|
+
.getDevicePointList(device)
|
|
425
|
+
.then(function () {
|
|
426
|
+
that
|
|
427
|
+
.buildJsonObject(device)
|
|
428
|
+
.then(function () {
|
|
429
|
+
query(index);
|
|
430
|
+
})
|
|
431
|
+
.catch(function (e) {
|
|
432
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
433
|
+
query(index);
|
|
434
|
+
});
|
|
435
|
+
})
|
|
436
|
+
.catch(function (e) {
|
|
437
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
438
|
+
device.setManualDiscoveryMode(true);
|
|
439
|
+
that
|
|
440
|
+
.getDevicePointListWithoutObjectList(device)
|
|
441
|
+
.then(function () {
|
|
442
|
+
that
|
|
443
|
+
.buildJsonObject(device)
|
|
444
|
+
.then(function () {
|
|
445
|
+
query(index);
|
|
446
|
+
})
|
|
447
|
+
.catch(function (e) {
|
|
448
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
449
|
+
query(index);
|
|
450
|
+
});
|
|
451
|
+
})
|
|
452
|
+
.catch(function (e) {
|
|
453
|
+
query(index);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
} catch (e) {
|
|
457
|
+
that.logOut("Error while querying devices: ", e);
|
|
458
|
+
query(index);
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
query(index);
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
that.logOut("queryDevices: invalid device found: ", device);
|
|
465
|
+
query(index);
|
|
466
|
+
}
|
|
467
|
+
} else if (index == that.deviceList.length) {
|
|
468
|
+
that.pollInProgress = false;
|
|
454
469
|
}
|
|
455
|
-
}
|
|
470
|
+
}
|
|
456
471
|
}
|
|
457
472
|
|
|
458
473
|
updateDeviceName(device) {
|
|
459
474
|
let that = this;
|
|
460
475
|
that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function (deviceObject) {
|
|
461
476
|
if (typeof deviceObject.name == "string") {
|
|
462
|
-
device.setDeviceName(deviceObject.name);
|
|
477
|
+
device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
|
|
463
478
|
device.setPointsList(deviceObject.devicePointEntry);
|
|
464
479
|
}
|
|
465
480
|
});
|
|
@@ -475,9 +490,6 @@ class BacnetClient extends EventEmitter {
|
|
|
475
490
|
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
476
491
|
that.deviceId = config.deviceId;
|
|
477
492
|
that.broadCastAddr = config.broadCastAddr;
|
|
478
|
-
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
479
|
-
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
480
|
-
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
481
493
|
that.device_read_schedule = config.device_read_schedule;
|
|
482
494
|
|
|
483
495
|
if (that.scheduler !== null) {
|
|
@@ -505,7 +517,6 @@ class BacnetClient extends EventEmitter {
|
|
|
505
517
|
// //query device task
|
|
506
518
|
const queryDevices = new Task("simple task", () => {
|
|
507
519
|
if (!that.pollInProgress) that.queryDevices();
|
|
508
|
-
that.sanitizeDeviceList();
|
|
509
520
|
});
|
|
510
521
|
|
|
511
522
|
const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule) }, queryDevices);
|
|
@@ -514,7 +525,7 @@ class BacnetClient extends EventEmitter {
|
|
|
514
525
|
|
|
515
526
|
//buildNetworkTreeData task
|
|
516
527
|
const buildNetworkTree = new Task("simple task", () => {
|
|
517
|
-
that.
|
|
528
|
+
that.doTreeBuilder();
|
|
518
529
|
that.countDevices();
|
|
519
530
|
});
|
|
520
531
|
|
|
@@ -545,70 +556,196 @@ class BacnetClient extends EventEmitter {
|
|
|
545
556
|
return newProps;
|
|
546
557
|
}
|
|
547
558
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
559
|
+
findDeviceByKey(key, deviceList, that) {
|
|
560
|
+
return deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
getObjectId(pointName, pointConfig, that) {
|
|
564
|
+
// Retrieve the object type based on the point configuration
|
|
565
|
+
const bacObjType = that.getObjectType(pointConfig.meta.objectId.type);
|
|
566
|
+
// Construct the object ID string
|
|
567
|
+
return `${pointName}_${bacObjType}_${pointConfig.meta.objectId.instance}`;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
createDeviceKey(device) {
|
|
571
|
+
// Create a device key by combining the address and device ID
|
|
572
|
+
const address = device.getAddress();
|
|
573
|
+
const deviceId = device.getDeviceId();
|
|
574
|
+
if (typeof address === "object") {
|
|
575
|
+
return `${address.address}-${deviceId}`;
|
|
576
|
+
} else {
|
|
577
|
+
return `${address}-${deviceId}`;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
async doRead(readConfig, outputType, objectPropertyType, readNodeName) {
|
|
583
|
+
const that = this;
|
|
584
|
+
const roundDecimal = readConfig.precision;
|
|
585
|
+
const devicesToRead = Object.keys(readConfig.pointsToRead);
|
|
586
|
+
const bacnetResults = {};
|
|
587
|
+
let pendingRequests = 0;
|
|
588
|
+
|
|
552
589
|
try {
|
|
553
|
-
let bacnetResults = {};
|
|
554
|
-
devicesToRead.forEach(function (key, index) {
|
|
555
|
-
let device = that.deviceList.find((ele) => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
|
|
556
|
-
if (device) {
|
|
557
|
-
let deviceName = device.getDeviceName();
|
|
558
|
-
let deviceKey =
|
|
559
|
-
typeof device.getAddress() == "object"
|
|
560
|
-
? device.getAddress().address + "-" + device.getDeviceId()
|
|
561
|
-
: device.getAddress() + "-" + device.getDeviceId();
|
|
562
|
-
let deviceObject = that.networkTree[deviceKey];
|
|
563
|
-
if (!bacnetResults[deviceName]) bacnetResults[deviceName] = {};
|
|
564
|
-
if (deviceObject) {
|
|
565
|
-
for (const pointName in readConfig.pointsToRead[key]) {
|
|
566
|
-
let bac_obj = that.getObjectType(readConfig.pointsToRead[key][pointName].meta.objectId.type);
|
|
567
|
-
let objectId =
|
|
568
|
-
pointName + "_" + bac_obj + "_" + readConfig.pointsToRead[key][pointName].meta.objectId.instance;
|
|
569
|
-
let point = deviceObject[objectId];
|
|
570
590
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
591
|
+
// Process all devices in sequence
|
|
592
|
+
for (let deviceIndex = 0; deviceIndex < devicesToRead.length; deviceIndex++) {
|
|
593
|
+
const key = devicesToRead[deviceIndex];
|
|
594
|
+
const device = that.findDeviceByKey(key, that.deviceList, that);
|
|
595
|
+
if (!device) continue;
|
|
596
|
+
|
|
597
|
+
const deviceName = that.computeDeviceName(device);
|
|
598
|
+
const deviceKey = that.createDeviceKey(device);
|
|
599
|
+
const deviceObject = that.networkTree[deviceKey];
|
|
600
|
+
const maxObjectCount = that.estimateMaxObjectSize(device.getMaxApdu());
|
|
601
|
+
|
|
602
|
+
if (!bacnetResults[deviceName]) {
|
|
603
|
+
bacnetResults[deviceName] = {};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Process points for the current device
|
|
607
|
+
const pointsToRead = readConfig.pointsToRead[key];
|
|
608
|
+
const pointNames = Object.keys(pointsToRead);
|
|
609
|
+
const totalPoints = pointNames.length;
|
|
610
|
+
let requestArray = [];
|
|
611
|
+
let processedPoints = 0; // Counter for processed points
|
|
612
|
+
|
|
613
|
+
// Process each point for the device in batches
|
|
614
|
+
for (let i = 0; i < pointNames.length; i++) {
|
|
615
|
+
const pointName = pointNames[i];
|
|
616
|
+
if (pointName === "deviceName") continue;
|
|
617
|
+
|
|
618
|
+
const pointConfig = pointsToRead[pointName];
|
|
619
|
+
const objectId = that.getObjectId(pointName, pointConfig, that);
|
|
620
|
+
const point = deviceObject[objectId];
|
|
621
|
+
|
|
622
|
+
if (point) {
|
|
623
|
+
point.displayName = pointConfig.displayName;
|
|
624
|
+
|
|
625
|
+
// Prepare request array for batch processing
|
|
626
|
+
requestArray.push({
|
|
627
|
+
objectId: { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
|
|
628
|
+
properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }],
|
|
629
|
+
pointRef: point,
|
|
630
|
+
pointName: pointName
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Process the batch when the request array is full or the last point is reached
|
|
635
|
+
if (requestArray.length === maxObjectCount || i === pointNames.length - 1) {
|
|
636
|
+
if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
|
|
637
|
+
await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
638
|
+
} else {
|
|
639
|
+
await that.processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
584
640
|
}
|
|
641
|
+
|
|
642
|
+
requestArray = [];
|
|
643
|
+
// Increment the processed points counter
|
|
644
|
+
processedPoints += maxObjectCount;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Check if all points for the device have been processed
|
|
648
|
+
if (processedPoints >= totalPoints) {
|
|
649
|
+
pendingRequests++;
|
|
650
|
+
// Emit the `values` event for the current device
|
|
651
|
+
that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName, pendingRequests, devicesToRead.length);
|
|
652
|
+
delete bacnetResults[deviceName];
|
|
653
|
+
|
|
585
654
|
}
|
|
586
655
|
}
|
|
656
|
+
}
|
|
657
|
+
} catch (error) {
|
|
658
|
+
that.logOut("doRead error: ", error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
587
661
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
662
|
+
async processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
|
|
663
|
+
try {
|
|
664
|
+
const results = await that.updateManyPoints(device, requestArray);
|
|
665
|
+
if (results.error) {
|
|
666
|
+
throw results.error;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Process the results of the batch
|
|
670
|
+
results.value.values.forEach(pointResult => {
|
|
671
|
+
const cacheRef = requestArray.find(ele =>
|
|
672
|
+
ele.pointRef.meta.objectId.type === pointResult.objectId.type &&
|
|
673
|
+
ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
if (cacheRef) {
|
|
677
|
+
const pointRef = cacheRef.pointRef;
|
|
678
|
+
const pointNameRef = cacheRef.pointName;
|
|
679
|
+
const val = pointResult.values[0].value[0].value;
|
|
680
|
+
|
|
681
|
+
if (isNumber(val)) {
|
|
682
|
+
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
683
|
+
if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
|
|
684
|
+
if (val != 0) {
|
|
685
|
+
pointRef.presentValue = pointRef.stateTextArray[val - 1].value;
|
|
686
|
+
} else {
|
|
687
|
+
pointRef.presentValue = pointRef.stateTextArray[val].value;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} else {
|
|
691
|
+
if (typeof val !== "object") {
|
|
692
|
+
pointRef.presentValue = val;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Store the point data in results
|
|
697
|
+
bacnetResults[deviceName][pointNameRef] = pointRef;
|
|
698
|
+
}
|
|
592
699
|
});
|
|
593
|
-
} catch (
|
|
594
|
-
that.logOut("
|
|
700
|
+
} catch (err) {
|
|
701
|
+
that.logOut("Error processing batch:", err);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
|
|
706
|
+
for (const request of requestArray) {
|
|
707
|
+
const { objectId, pointRef, pointName } = request;
|
|
708
|
+
try {
|
|
709
|
+
const result = await that.updatePoint(device, pointRef);
|
|
710
|
+
const val = result.values[0].value;
|
|
711
|
+
|
|
712
|
+
if (isNumber(val)) {
|
|
713
|
+
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
714
|
+
} else {
|
|
715
|
+
pointRef.presentValue = val;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Store the point data in results
|
|
719
|
+
bacnetResults[deviceName][pointName] = pointRef;
|
|
720
|
+
} catch (err) {
|
|
721
|
+
that.logOut(`Error updating point ${pointName}:`, err);
|
|
722
|
+
}
|
|
595
723
|
}
|
|
596
724
|
}
|
|
597
725
|
|
|
726
|
+
updateManyPoints(device, points) {
|
|
727
|
+
let that = this;
|
|
728
|
+
return new Promise((resolve, reject) => {
|
|
729
|
+
that._readObjectWithRequestArray(device.getAddress(), points, that.readPropertyMultipleOptions).then(function (results) {
|
|
730
|
+
resolve(results);
|
|
731
|
+
}).catch(function (err) {
|
|
732
|
+
reject(err);
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
598
737
|
updatePoint(device, point) {
|
|
599
738
|
let that = this;
|
|
600
739
|
return new Promise((resolve, reject) => {
|
|
601
740
|
that.client.readProperty(
|
|
602
741
|
device.getAddress(),
|
|
603
|
-
{ type: point.
|
|
742
|
+
{ type: point.meta.objectId.type, instance: point.meta.objectId.instance },
|
|
604
743
|
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
605
|
-
|
|
744
|
+
that.readPropertyMultipleOptions,
|
|
606
745
|
(err, value) => {
|
|
607
746
|
if (err) {
|
|
608
|
-
//console.log("err ", err);
|
|
609
747
|
reject(err);
|
|
610
748
|
}
|
|
611
|
-
|
|
612
749
|
if (value) {
|
|
613
750
|
resolve(value);
|
|
614
751
|
}
|
|
@@ -617,6 +754,18 @@ class BacnetClient extends EventEmitter {
|
|
|
617
754
|
});
|
|
618
755
|
}
|
|
619
756
|
|
|
757
|
+
estimateMaxObjectSize(apduSize) {
|
|
758
|
+
if (apduSize < 500) {
|
|
759
|
+
return 20;
|
|
760
|
+
} else if (apduSize > 500 && apduSize < 1000) {
|
|
761
|
+
//return Math.round(((apduSize - 30) / 7));
|
|
762
|
+
return 50;
|
|
763
|
+
} else if (apduSize > 1000) {
|
|
764
|
+
//return Math.round(((apduSize - 30) / 7));
|
|
765
|
+
return 100;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
620
769
|
getDeviceAddress(device) {
|
|
621
770
|
switch (typeof device.getAddress()) {
|
|
622
771
|
case "object":
|
|
@@ -825,12 +974,13 @@ class BacnetClient extends EventEmitter {
|
|
|
825
974
|
}
|
|
826
975
|
|
|
827
976
|
_readObjectFull(device, deviceAddress, type, instance) {
|
|
828
|
-
|
|
977
|
+
const that = this;
|
|
829
978
|
const readOptions = {
|
|
830
979
|
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
831
980
|
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
832
981
|
};
|
|
833
982
|
|
|
983
|
+
// Define all properties to be read
|
|
834
984
|
const allProperties = [
|
|
835
985
|
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
836
986
|
{ id: baEnum.PropertyIdentifier.DESCRIPTION },
|
|
@@ -840,80 +990,77 @@ class BacnetClient extends EventEmitter {
|
|
|
840
990
|
{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
|
|
841
991
|
{ id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
|
|
842
992
|
{ id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
|
|
843
|
-
{ id: baEnum.PropertyIdentifier.
|
|
993
|
+
{ id: baEnum.PropertyIdentifier.STATE_TEXT },
|
|
844
994
|
{ id: baEnum.PropertyIdentifier.RECORD_COUNT },
|
|
845
995
|
{ id: baEnum.PropertyIdentifier.PRIORITY_ARRAY },
|
|
996
|
+
{ id: baEnum.PropertyIdentifier.VENDOR_NAME },
|
|
846
997
|
];
|
|
847
998
|
|
|
848
999
|
return new Promise((resolve, reject) => {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
.then(
|
|
1000
|
+
// Try to read all properties at once
|
|
1001
|
+
that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
|
|
1002
|
+
.then(result => {
|
|
852
1003
|
if (result.value) {
|
|
1004
|
+
// If the result has value, resolve the promise
|
|
853
1005
|
resolve(result);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
let i = 0;
|
|
858
|
-
readIndividualProperties(i);
|
|
1006
|
+
} else {
|
|
1007
|
+
// If not, proceed to read individual properties
|
|
1008
|
+
readPropertiesIndividually();
|
|
859
1009
|
}
|
|
860
1010
|
})
|
|
861
|
-
.catch(
|
|
862
|
-
|
|
863
|
-
|
|
1011
|
+
.catch(() => {
|
|
1012
|
+
// On error, proceed to read individual properties
|
|
1013
|
+
readPropertiesIndividually();
|
|
864
1014
|
});
|
|
865
1015
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
id: value.property.id,
|
|
885
|
-
index: value.property.index,
|
|
886
|
-
value: value.values,
|
|
887
|
-
};
|
|
888
|
-
|
|
889
|
-
resultArray.push(structuredResult);
|
|
1016
|
+
// Function to read properties individually
|
|
1017
|
+
const readPropertiesIndividually = () => {
|
|
1018
|
+
const promises = allProperties.map((property, index) => new Promise((propertyResolve) => {
|
|
1019
|
+
that.client.readProperty(
|
|
1020
|
+
deviceAddress,
|
|
1021
|
+
{ type: type, instance: instance },
|
|
1022
|
+
property.id,
|
|
1023
|
+
readOptions,
|
|
1024
|
+
(err, value) => {
|
|
1025
|
+
if (err) {
|
|
1026
|
+
propertyResolve(null);
|
|
1027
|
+
} else {
|
|
1028
|
+
propertyResolve({
|
|
1029
|
+
id: property.id,
|
|
1030
|
+
index: value.property.index,
|
|
1031
|
+
value: value.values,
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
890
1034
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1035
|
+
);
|
|
1036
|
+
}));
|
|
1037
|
+
|
|
1038
|
+
Promise.all(promises)
|
|
1039
|
+
.then(resultArray => {
|
|
1040
|
+
// Filter out null results
|
|
1041
|
+
const validResults = resultArray.filter(result => result !== null);
|
|
1042
|
+
|
|
1043
|
+
resolve({
|
|
1044
|
+
error: null,
|
|
1045
|
+
value: {
|
|
1046
|
+
values: [
|
|
1047
|
+
{
|
|
1048
|
+
objectId: {
|
|
1049
|
+
type: type,
|
|
1050
|
+
instance: instance,
|
|
903
1051
|
},
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
);
|
|
913
|
-
}
|
|
1052
|
+
values: validResults,
|
|
1053
|
+
},
|
|
1054
|
+
],
|
|
1055
|
+
},
|
|
1056
|
+
});
|
|
1057
|
+
})
|
|
1058
|
+
.catch(reject);
|
|
1059
|
+
};
|
|
914
1060
|
});
|
|
915
1061
|
}
|
|
916
1062
|
|
|
1063
|
+
|
|
917
1064
|
_readObjectPropList(deviceAddress, type, instance) {
|
|
918
1065
|
return this._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.PROPERTY_LIST }]);
|
|
919
1066
|
}
|
|
@@ -1048,6 +1195,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1048
1195
|
reducedDeviceList.forEach((device) => {
|
|
1049
1196
|
delete device["pointsList"];
|
|
1050
1197
|
});
|
|
1198
|
+
|
|
1051
1199
|
resolve({
|
|
1052
1200
|
renderList: that.renderList,
|
|
1053
1201
|
deviceList: reducedDeviceList,
|
|
@@ -1096,42 +1244,6 @@ class BacnetClient extends EventEmitter {
|
|
|
1096
1244
|
});
|
|
1097
1245
|
}
|
|
1098
1246
|
|
|
1099
|
-
updatePriorityQueue(priorityDevices) {
|
|
1100
|
-
let that = this;
|
|
1101
|
-
return new Promise(async function (resolve, reject) {
|
|
1102
|
-
try {
|
|
1103
|
-
let keys = Object.keys(priorityDevices);
|
|
1104
|
-
if (keys.length > 0) {
|
|
1105
|
-
keys.forEach(function (key) {
|
|
1106
|
-
let device = that.deviceList.find((ele) => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
|
|
1107
|
-
let points = priorityDevices[key];
|
|
1108
|
-
if (device) {
|
|
1109
|
-
device.setPriorityQueue(points);
|
|
1110
|
-
}
|
|
1111
|
-
});
|
|
1112
|
-
} else if (keys.length == 0) {
|
|
1113
|
-
that.clearPriorityQueues();
|
|
1114
|
-
}
|
|
1115
|
-
resolve(true);
|
|
1116
|
-
} catch (e) {
|
|
1117
|
-
reject(e);
|
|
1118
|
-
}
|
|
1119
|
-
});
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
clearPriorityQueues() {
|
|
1123
|
-
let that = this;
|
|
1124
|
-
that.deviceList.forEach(function (device) {
|
|
1125
|
-
device.clearPriorityQueue();
|
|
1126
|
-
});
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
getPriorityDevices() {
|
|
1130
|
-
let that = this;
|
|
1131
|
-
let priorityDevices = that.deviceList.filter((device) => device.getPriorityQueueIsActive() == true);
|
|
1132
|
-
return priorityDevices;
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
1247
|
sortDevices(a, b) {
|
|
1136
1248
|
if (a.deviceId < b.deviceId) {
|
|
1137
1249
|
return -1;
|
|
@@ -1153,443 +1265,128 @@ class BacnetClient extends EventEmitter {
|
|
|
1153
1265
|
return a.label.localeCompare(b.label);
|
|
1154
1266
|
}
|
|
1155
1267
|
|
|
1156
|
-
|
|
1268
|
+
computeDeviceName(device) {
|
|
1269
|
+
if (device.getDisplayName() !== null && device.getDisplayName() !== "" && device.getDisplayName() !== undefined) {
|
|
1270
|
+
return device.getDisplayName();
|
|
1271
|
+
}
|
|
1272
|
+
return device.getDeviceName();
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
checkInterruptFlag() {
|
|
1157
1276
|
let that = this;
|
|
1158
|
-
|
|
1159
|
-
let displayNameCharThreshold = 40;
|
|
1277
|
+
let BreakException = {};
|
|
1160
1278
|
|
|
1161
|
-
if (that.
|
|
1162
|
-
|
|
1163
|
-
JSON.stringify({
|
|
1164
|
-
renderList: that.renderList,
|
|
1165
|
-
deviceList: that.deviceList,
|
|
1166
|
-
pointList: that.networkTree,
|
|
1167
|
-
renderListCount: that.renderListCount,
|
|
1168
|
-
})
|
|
1169
|
-
);
|
|
1279
|
+
if (that.buildTreeException) {
|
|
1280
|
+
throw BreakException;
|
|
1170
1281
|
}
|
|
1282
|
+
}
|
|
1171
1283
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
|
|
1179
|
-
let deviceId = deviceInfo.getDeviceId();
|
|
1180
|
-
let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
|
|
1181
|
-
let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
|
|
1182
|
-
let deviceObject = that.networkTree[deviceKey];
|
|
1183
|
-
let isMstpDevice = deviceInfo.getIsMstpDevice();
|
|
1184
|
-
let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
|
|
1185
|
-
|
|
1186
|
-
if (deviceObject && typeof deviceName !== "object") {
|
|
1187
|
-
let children = [];
|
|
1188
|
-
let pointIndex = 0;
|
|
1189
|
-
|
|
1190
|
-
for (const pointName in deviceObject) {
|
|
1191
|
-
let pointProperties = [];
|
|
1192
|
-
let values = deviceObject[pointName];
|
|
1193
|
-
|
|
1194
|
-
let displayName = pointName;
|
|
1195
|
-
if (pointName.length > displayNameCharThreshold) {
|
|
1196
|
-
displayName = "";
|
|
1197
|
-
let charArray = pointName.split("");
|
|
1198
|
-
for (let i = 0; i < charArray.length; i++) {
|
|
1199
|
-
if (i < displayNameCharThreshold) {
|
|
1200
|
-
displayName += charArray[i];
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
displayName += "...";
|
|
1204
|
-
}
|
|
1284
|
+
getPointName(object, pointName) {
|
|
1285
|
+
if (object.displayName) {
|
|
1286
|
+
return object.displayName;
|
|
1287
|
+
}
|
|
1288
|
+
return pointName;
|
|
1289
|
+
}
|
|
1205
1290
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
children: null,
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
|
-
if (
|
|
1216
|
-
values.objectType &&
|
|
1217
|
-
values.hasOwnProperty("objectID") &&
|
|
1218
|
-
values.objectID.hasOwnProperty("type") &&
|
|
1219
|
-
values.objectID.type !== 8
|
|
1220
|
-
) {
|
|
1221
|
-
pointProperties.push({
|
|
1222
|
-
key: `${index}-0-${pointIndex}-1`,
|
|
1223
|
-
label: `Object Type: ${values.objectType}`,
|
|
1224
|
-
data: values.objectType,
|
|
1225
|
-
icon: "pi pi-cog",
|
|
1226
|
-
children: null,
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
if (values.objectID && values.objectID.instance) {
|
|
1230
|
-
pointProperties.push({
|
|
1231
|
-
key: `${index}-0-${pointIndex}-2`,
|
|
1232
|
-
label: `Object Instance: ${values.objectID.instance}`,
|
|
1233
|
-
data: values.objectID.instance,
|
|
1234
|
-
icon: "pi pi-cog",
|
|
1235
|
-
children: null,
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
if (values.description) {
|
|
1239
|
-
pointProperties.push({
|
|
1240
|
-
key: `${index}-0-${pointIndex}-3`,
|
|
1241
|
-
label: `Description: ${values.description}`,
|
|
1242
|
-
data: `${values.description}`,
|
|
1243
|
-
icon: "pi pi-cog",
|
|
1244
|
-
children: null,
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
if (values.units) {
|
|
1248
|
-
pointProperties.push({
|
|
1249
|
-
key: `${index}-0-${pointIndex}-4`,
|
|
1250
|
-
label: `Units: ${values.units}`,
|
|
1251
|
-
data: `${values.units}`,
|
|
1252
|
-
icon: "pi pi-cog",
|
|
1253
|
-
children: null,
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
if (
|
|
1257
|
-
values.presentValue !== "undefined" &&
|
|
1258
|
-
values.presentValue !== null &&
|
|
1259
|
-
typeof values.presentValue !== "undefined"
|
|
1260
|
-
) {
|
|
1261
|
-
pointProperties.push({
|
|
1262
|
-
key: `${index}-0-${pointIndex}-5`,
|
|
1263
|
-
label: `Present Value: ${values.presentValue}`,
|
|
1264
|
-
data: `${values.presentValue}`,
|
|
1265
|
-
icon: "pi pi-cog",
|
|
1266
|
-
children: null,
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
if (
|
|
1270
|
-
values.systemStatus !== null &&
|
|
1271
|
-
typeof values.systemStatus !== "undefined" &&
|
|
1272
|
-
values.systemStatus !== ""
|
|
1273
|
-
) {
|
|
1274
|
-
pointProperties.push({
|
|
1275
|
-
key: `${index}-0-${pointIndex}-6`,
|
|
1276
|
-
label: `System Status: ${values.systemStatus}`,
|
|
1277
|
-
data: `${values.systemStatus}`,
|
|
1278
|
-
icon: "pi pi-cog",
|
|
1279
|
-
children: null,
|
|
1280
|
-
});
|
|
1281
|
-
}
|
|
1282
|
-
if (values.modificationDate && !values.modificationDate.errorClass) {
|
|
1283
|
-
pointProperties.push({
|
|
1284
|
-
key: `${index}-0-${pointIndex}-7`,
|
|
1285
|
-
label: `Modification Date: ${values.modificationDate}`,
|
|
1286
|
-
data: `${values.modificationDate}`,
|
|
1287
|
-
icon: "pi pi-cog",
|
|
1288
|
-
children: null,
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
if (values.programState) {
|
|
1292
|
-
pointProperties.push({
|
|
1293
|
-
key: `${index}-0-${pointIndex}-8`,
|
|
1294
|
-
label: `Program State: ${values.programState}`,
|
|
1295
|
-
data: `${values.programState}`,
|
|
1296
|
-
icon: "pi pi-cog",
|
|
1297
|
-
children: null,
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
if (values.recordCount && !values.recordCount.errorClass) {
|
|
1301
|
-
pointProperties.push({
|
|
1302
|
-
key: `${index}-0-${pointIndex}-9`,
|
|
1303
|
-
label: `Record Count: ${values.recordCount}`,
|
|
1304
|
-
data: `${values.recordCount}`,
|
|
1305
|
-
icon: "pi pi-cog",
|
|
1306
|
-
children: null,
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
if (
|
|
1310
|
-
values.hasOwnProperty("objectID") &&
|
|
1311
|
-
values.objectID.hasOwnProperty("type") &&
|
|
1312
|
-
values.objectID.type == 8
|
|
1313
|
-
) {
|
|
1314
|
-
//device point, add segmentation supported, and apdu size
|
|
1315
|
-
pointProperties.push({
|
|
1316
|
-
key: `${index}-0-${pointIndex}-10`,
|
|
1317
|
-
label: `Segmentation Supported: ${deviceInfo.getSegmentation()}`,
|
|
1318
|
-
data: `${deviceInfo.getSegmentation()}`,
|
|
1319
|
-
icon: "pi pi-cog",
|
|
1320
|
-
children: null,
|
|
1321
|
-
});
|
|
1322
|
-
pointProperties.push({
|
|
1323
|
-
key: `${index}-0-${pointIndex}-11`,
|
|
1324
|
-
label: `APDU Size: ${deviceInfo.getMaxApdu()}`,
|
|
1325
|
-
data: `${deviceInfo.getMaxApdu()}`,
|
|
1326
|
-
icon: "pi pi-cog",
|
|
1327
|
-
children: null,
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1291
|
+
addUniqueToArray(device, array) {
|
|
1292
|
+
const foundIndex = array.findIndex(ele => ele.getDeviceId() === device.getDeviceId());
|
|
1293
|
+
if (foundIndex === -1) {
|
|
1294
|
+
array.push(device);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1330
1297
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1298
|
+
async getDevicesNotRenderedYet() {
|
|
1299
|
+
let that = this;
|
|
1300
|
+
let missingDevices = [];
|
|
1301
|
+
for (let i = 0; i < that.deviceList.length; i++) {
|
|
1302
|
+
const device = that.deviceList[i];
|
|
1303
|
+
if (!device.getIsMstpDevice()) {
|
|
1304
|
+
//ip device
|
|
1305
|
+
const foundIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1306
|
+
if (foundIndex == -1) {
|
|
1307
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1308
|
+
}
|
|
1309
|
+
} else {
|
|
1310
|
+
//mstp device
|
|
1311
|
+
const foundParentIndex = that.renderList.findIndex(ele => ele.deviceId == device.getParentDeviceId());
|
|
1312
|
+
if (foundParentIndex == -1) {
|
|
1313
|
+
//parent not existent in tree
|
|
1314
|
+
const parentDeviceIndex = that.deviceList.findIndex(ele => ele.getDeviceId() === device.getParentDeviceId());
|
|
1315
|
+
if (parentDeviceIndex !== -1) {
|
|
1316
|
+
that.addUniqueToArray(that.deviceList[parentDeviceIndex], missingDevices);
|
|
1317
|
+
}
|
|
1318
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1319
|
+
} else {
|
|
1320
|
+
const parentTreeDevice = that.renderList[foundParentIndex];
|
|
1321
|
+
let mstpIndex = -1;
|
|
1322
|
+
parentTreeDevice.children.forEach(child => {
|
|
1323
|
+
if (child.label.includes("MSTP")) {
|
|
1324
|
+
const tempIndex = child.children.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1325
|
+
if (tempIndex !== -1) {
|
|
1326
|
+
mstpIndex = tempIndex;
|
|
1344
1327
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
type: "pointFolder",
|
|
1356
|
-
children: children.sort(that.sortPoints),
|
|
1357
|
-
},
|
|
1358
|
-
{
|
|
1359
|
-
key: `${index}-1`,
|
|
1360
|
-
label: "MSTP Network",
|
|
1361
|
-
data: "Devices Folder",
|
|
1362
|
-
icon: "pi pi-database",
|
|
1363
|
-
type: "deviceFolder",
|
|
1364
|
-
children: [],
|
|
1365
|
-
},
|
|
1366
|
-
];
|
|
1367
|
-
} else {
|
|
1368
|
-
folderJson = [
|
|
1369
|
-
{
|
|
1370
|
-
key: `${index}-0`,
|
|
1371
|
-
label: "Points",
|
|
1372
|
-
data: "Points Folder",
|
|
1373
|
-
icon: "pi pi-circle-fill",
|
|
1374
|
-
type: "pointFolder",
|
|
1375
|
-
children: children.sort(that.sortPoints),
|
|
1376
|
-
},
|
|
1377
|
-
];
|
|
1378
|
-
}
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
if (mstpIndex == -1) {
|
|
1331
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return missingDevices;
|
|
1337
|
+
}
|
|
1379
1338
|
|
|
1380
|
-
|
|
1381
|
-
that.renderList[foundIndex] = {
|
|
1382
|
-
key: index,
|
|
1383
|
-
label: deviceName,
|
|
1384
|
-
data: deviceName,
|
|
1385
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1386
|
-
children: that.renderList[foundIndex].children,
|
|
1387
|
-
type: "device",
|
|
1388
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1389
|
-
showAdded: false,
|
|
1390
|
-
ipAddr: ipAddr,
|
|
1391
|
-
deviceId: deviceId,
|
|
1392
|
-
isMstpDevice: isMstpDevice,
|
|
1393
|
-
};
|
|
1394
|
-
} else if (isMstpDevice) {
|
|
1395
|
-
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1396
|
-
let parentDeviceIndex = that.renderList.findIndex(
|
|
1397
|
-
(ele) => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr
|
|
1398
|
-
);
|
|
1399
|
-
|
|
1400
|
-
if (parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children[1].children) {
|
|
1401
|
-
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(
|
|
1402
|
-
(ele) => ele.deviceId == deviceId && ele.ipAddr == ipAddr
|
|
1403
|
-
);
|
|
1404
|
-
if (mstpDeviceIndex == -1) {
|
|
1405
|
-
//that.renderListCount++;
|
|
1406
|
-
that.renderList[parentDeviceIndex].children[1].children.push({
|
|
1407
|
-
key: index,
|
|
1408
|
-
label: deviceName,
|
|
1409
|
-
data: deviceName,
|
|
1410
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1411
|
-
children: folderJson,
|
|
1412
|
-
type: "device",
|
|
1413
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1414
|
-
showAdded: false,
|
|
1415
|
-
ipAddr: ipAddr,
|
|
1416
|
-
deviceId: deviceId,
|
|
1417
|
-
isMstpDevice: isMstpDevice,
|
|
1418
|
-
});
|
|
1419
|
-
} else {
|
|
1420
|
-
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {
|
|
1421
|
-
key: index,
|
|
1422
|
-
label: deviceName,
|
|
1423
|
-
data: deviceName,
|
|
1424
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1425
|
-
children: folderJson,
|
|
1426
|
-
type: "device",
|
|
1427
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1428
|
-
showAdded: false,
|
|
1429
|
-
ipAddr: ipAddr,
|
|
1430
|
-
deviceId: deviceId,
|
|
1431
|
-
isMstpDevice: isMstpDevice,
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
} else if (foundIndex == -1) {
|
|
1437
|
-
let folderJson = [];
|
|
1438
|
-
if (deviceInfo.hasChildDevices()) {
|
|
1439
|
-
folderJson = [
|
|
1440
|
-
{
|
|
1441
|
-
key: `${index}-0`,
|
|
1442
|
-
label: "Points",
|
|
1443
|
-
data: "Points Folder",
|
|
1444
|
-
icon: "pi pi-circle-fill",
|
|
1445
|
-
type: "pointFolder",
|
|
1446
|
-
children: children.sort(that.sortPoints),
|
|
1447
|
-
},
|
|
1448
|
-
{
|
|
1449
|
-
key: `${index}-1`,
|
|
1450
|
-
label: "MSTP Network",
|
|
1451
|
-
data: "Devices Folder",
|
|
1452
|
-
icon: "pi pi-database",
|
|
1453
|
-
type: "deviceFolder",
|
|
1454
|
-
children: [],
|
|
1455
|
-
},
|
|
1456
|
-
];
|
|
1457
|
-
} else {
|
|
1458
|
-
folderJson = [
|
|
1459
|
-
{
|
|
1460
|
-
key: `${index}-0`,
|
|
1461
|
-
label: "Points",
|
|
1462
|
-
data: "Points Folder",
|
|
1463
|
-
icon: "pi pi-circle-fill",
|
|
1464
|
-
type: "pointFolder",
|
|
1465
|
-
children: children.sort(that.sortPoints),
|
|
1466
|
-
},
|
|
1467
|
-
];
|
|
1468
|
-
}
|
|
1339
|
+
initialTreeBuild = true;
|
|
1469
1340
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
that.renderList.push({
|
|
1473
|
-
key: index,
|
|
1474
|
-
label: deviceName,
|
|
1475
|
-
data: deviceName,
|
|
1476
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1477
|
-
children: folderJson,
|
|
1478
|
-
type: "device",
|
|
1479
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1480
|
-
showAdded: false,
|
|
1481
|
-
ipAddr: ipAddr,
|
|
1482
|
-
deviceId: deviceId,
|
|
1483
|
-
isMstpDevice: isMstpDevice,
|
|
1484
|
-
});
|
|
1485
|
-
} else if (isMstpDevice) {
|
|
1486
|
-
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1487
|
-
let parentDeviceIndex = that.renderList.findIndex(
|
|
1488
|
-
(ele) => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr
|
|
1489
|
-
);
|
|
1341
|
+
async doTreeBuilder() {
|
|
1342
|
+
let that = this;
|
|
1490
1343
|
|
|
1491
|
-
|
|
1492
|
-
parentDeviceIndex !== -1 &&
|
|
1493
|
-
that.renderList[parentDeviceIndex].children &&
|
|
1494
|
-
that.renderList[parentDeviceIndex].children[1].children
|
|
1495
|
-
) {
|
|
1496
|
-
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(
|
|
1497
|
-
(ele) => ele.deviceId == deviceId && ele.ipAddr == ipAddr
|
|
1498
|
-
);
|
|
1499
|
-
|
|
1500
|
-
if (mstpDeviceIndex == -1) {
|
|
1501
|
-
// that.renderListCount++;
|
|
1502
|
-
that.renderList[parentDeviceIndex].children[1].children.push({
|
|
1503
|
-
key: index,
|
|
1504
|
-
label: deviceName,
|
|
1505
|
-
data: deviceName,
|
|
1506
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1507
|
-
children: folderJson,
|
|
1508
|
-
type: "device",
|
|
1509
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1510
|
-
showAdded: false,
|
|
1511
|
-
ipAddr: ipAddr,
|
|
1512
|
-
deviceId: deviceId,
|
|
1513
|
-
isMstpDevice: isMstpDevice,
|
|
1514
|
-
});
|
|
1515
|
-
} else {
|
|
1516
|
-
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {
|
|
1517
|
-
key: index,
|
|
1518
|
-
label: deviceName,
|
|
1519
|
-
data: deviceName,
|
|
1520
|
-
icon: that.getDeviceIcon(isMstpDevice, manualDiscoveryMode),
|
|
1521
|
-
children: folderJson,
|
|
1522
|
-
type: "device",
|
|
1523
|
-
lastSeen: deviceInfo.getLastSeen(),
|
|
1524
|
-
showAdded: false,
|
|
1525
|
-
ipAddr: ipAddr,
|
|
1526
|
-
deviceId: deviceId,
|
|
1527
|
-
isMstpDevice: isMstpDevice,
|
|
1528
|
-
};
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1344
|
+
const treeWorker = new treeBuilder(that.deviceList, that.networkTree, that.renderList, that.renderListCount, that.initialTreeBuild);
|
|
1533
1345
|
|
|
1534
|
-
|
|
1535
|
-
that.renderList.sort(that.sortDevices);
|
|
1536
|
-
resolve({
|
|
1537
|
-
renderList: that.renderList,
|
|
1538
|
-
deviceList: that.deviceList,
|
|
1539
|
-
pointList: that.networkTree,
|
|
1540
|
-
pollFrequency: that.discover_polling_schedule,
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
} else {
|
|
1544
|
-
if (index == that.deviceList.length - 1) {
|
|
1545
|
-
that.renderList.sort(that.sortDevices);
|
|
1546
|
-
resolve({
|
|
1547
|
-
renderList: that.renderList,
|
|
1548
|
-
deviceList: that.deviceList,
|
|
1549
|
-
pointList: that.networkTree,
|
|
1550
|
-
pollFrequency: that.discover_polling_schedule,
|
|
1551
|
-
});
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1346
|
+
treeWorker.cacheData();
|
|
1554
1347
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1348
|
+
//const missingDevices = await that.getDevicesNotRenderedYet();
|
|
1349
|
+
|
|
1350
|
+
for (let i = 0; i < that.deviceList.length; i++) {
|
|
1351
|
+
let device = that.deviceList[i];
|
|
1352
|
+
await treeWorker.processDevice(device, i);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
that.deviceList = treeWorker.deviceList;
|
|
1356
|
+
that.networkTree = treeWorker.networkTree;
|
|
1357
|
+
that.renderList = treeWorker.renderList;
|
|
1358
|
+
|
|
1359
|
+
that.initialTreeBuild = false;
|
|
1560
1360
|
}
|
|
1561
1361
|
|
|
1562
1362
|
countDevices() {
|
|
1563
1363
|
let that = this;
|
|
1564
|
-
|
|
1565
1364
|
let deviceCount = 0;
|
|
1566
1365
|
|
|
1567
|
-
that.renderList.
|
|
1568
|
-
|
|
1569
|
-
if (
|
|
1570
|
-
device.children
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
} else {
|
|
1580
|
-
deviceCount++;
|
|
1366
|
+
if (that.renderList && that.renderList.length > 0) {
|
|
1367
|
+
that.renderList.forEach(function (device, index) {
|
|
1368
|
+
if (device && device.children.length > 0) {
|
|
1369
|
+
device.children.forEach(function (folder) {
|
|
1370
|
+
if (folder.label == "Points") {
|
|
1371
|
+
//increment for parent device / mstp router
|
|
1372
|
+
deviceCount++;
|
|
1373
|
+
} else if (folder.label.includes("MSTP")) {
|
|
1374
|
+
//increment for mstp device list
|
|
1375
|
+
deviceCount += folder.children.length;
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1581
1378
|
}
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1379
|
+
if (index == that.renderList.length - 1) {
|
|
1380
|
+
that.renderListCount = deviceCount;
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1587
1384
|
}
|
|
1588
1385
|
|
|
1589
|
-
buildJsonObject(device
|
|
1386
|
+
buildJsonObject(device) {
|
|
1590
1387
|
let that = this;
|
|
1591
1388
|
let address = device.address;
|
|
1592
|
-
let pointList =
|
|
1389
|
+
let pointList = device.getPointsList();
|
|
1593
1390
|
let requestMutex = new Mutex();
|
|
1594
1391
|
|
|
1595
1392
|
return new Promise(function (resolve, reject) {
|
|
@@ -1651,7 +1448,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1651
1448
|
// Builds response object for a fully qualified
|
|
1652
1449
|
buildResponse(fullObjects, device) {
|
|
1653
1450
|
let that = this;
|
|
1654
|
-
|
|
1451
|
+
const reg = /[$#\/\\+]/gi;
|
|
1655
1452
|
return new Promise(function (resolve, reject) {
|
|
1656
1453
|
let deviceKey =
|
|
1657
1454
|
typeof device.getAddress() == "object"
|
|
@@ -1673,6 +1470,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1673
1470
|
let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
|
|
1674
1471
|
let objectId;
|
|
1675
1472
|
if (objectName !== null && typeof objectName == "string") {
|
|
1473
|
+
objectName = objectName.replace(reg, '');
|
|
1676
1474
|
objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
|
|
1677
1475
|
|
|
1678
1476
|
try {
|
|
@@ -1697,6 +1495,15 @@ class BacnetClient extends EventEmitter {
|
|
|
1697
1495
|
} else if (objectType == 40) {
|
|
1698
1496
|
//character string
|
|
1699
1497
|
values[objectId].presentValue = object.value[0].value;
|
|
1498
|
+
} else if (objectType == 13 || objectType == 14 || objectType == 19) {
|
|
1499
|
+
//check for MSV MSI MSO - for enum state text
|
|
1500
|
+
if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
|
|
1501
|
+
if (object.value[0].value == 0) {
|
|
1502
|
+
values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value].value;
|
|
1503
|
+
} else if (object.value[0].value !== 0) {
|
|
1504
|
+
values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value - 1].value;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1700
1507
|
} else {
|
|
1701
1508
|
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
1702
1509
|
}
|
|
@@ -1711,7 +1518,12 @@ class BacnetClient extends EventEmitter {
|
|
|
1711
1518
|
values[objectId].units = getUnit(object.value[0].value);
|
|
1712
1519
|
break;
|
|
1713
1520
|
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
1714
|
-
if (object.value[0] && object.value[0].value)
|
|
1521
|
+
if (object.value[0] && object.value[0].value) {
|
|
1522
|
+
values[objectId].objectName = object.value[0].value.replace(reg, '');
|
|
1523
|
+
if (!values[objectId].displayName) {
|
|
1524
|
+
values[objectId].displayName = object.value[0].value.replace(reg, '');
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1715
1527
|
break;
|
|
1716
1528
|
case baEnum.PropertyIdentifier.OBJECT_TYPE:
|
|
1717
1529
|
if (object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
|
|
@@ -1722,13 +1534,11 @@ class BacnetClient extends EventEmitter {
|
|
|
1722
1534
|
case baEnum.PropertyIdentifier.PROPERTY_LIST:
|
|
1723
1535
|
if (object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
|
|
1724
1536
|
break;
|
|
1725
|
-
|
|
1726
1537
|
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
1727
1538
|
if (object.value[0]) {
|
|
1728
1539
|
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
1729
1540
|
}
|
|
1730
1541
|
break;
|
|
1731
|
-
|
|
1732
1542
|
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
1733
1543
|
if (object.value[0]) {
|
|
1734
1544
|
values[objectId].modificationDate = object.value[0].value;
|
|
@@ -1751,6 +1561,28 @@ class BacnetClient extends EventEmitter {
|
|
|
1751
1561
|
values[objectId].hasPriorityArray = true;
|
|
1752
1562
|
}
|
|
1753
1563
|
break;
|
|
1564
|
+
case baEnum.PropertyIdentifier.STATE_TEXT:
|
|
1565
|
+
if (object.value) {
|
|
1566
|
+
values[objectId].stateTextArray = object.value;
|
|
1567
|
+
if (typeof values[objectId].presentValue == "number" &&
|
|
1568
|
+
values[objectId].presentValue !== null &&
|
|
1569
|
+
values[objectId].presentValue !== undefined) {
|
|
1570
|
+
const tempIndex = values[objectId].presentValue;
|
|
1571
|
+
if (tempIndex == 0) {
|
|
1572
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
|
|
1573
|
+
} else if (tempIndex !== 0) {
|
|
1574
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
break;
|
|
1579
|
+
case baEnum.PropertyIdentifier.VENDOR_NAME:
|
|
1580
|
+
if (object.value) {
|
|
1581
|
+
if (object.value[0].value && typeof object.value[0].value == "string") {
|
|
1582
|
+
values[objectId].vendorName = object.value[0].value;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
break;
|
|
1754
1586
|
}
|
|
1755
1587
|
}
|
|
1756
1588
|
if (
|