@bitpoolos/edge-bacnet 1.2.8 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bacnet_client.js 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
- that.buildNetworkTreeData().then(function () {
97
- that.countDevices();
98
- });
93
+
94
+ that.doTreeBuilder();
95
+ that.countDevices();
96
+
99
97
  });
100
98
 
101
- const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10 }, buildNetworkTree);
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,21 +120,19 @@ 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
  }
134
126
  that.deviceList.push(newBacnetDevice);
127
+ that.addToNetworkTree(newBacnetDevice);
135
128
  } else if (foundIndex !== -1) {
136
129
  that.deviceList[foundIndex].updateDeviceConfig(device);
137
130
  that.deviceList[foundIndex].setLastSeen(Date.now());
138
- that.updateDeviceName(that.deviceList[foundIndex]);
139
-
140
131
  if (that.deviceList[foundIndex].getIsMstpDevice()) {
141
132
  that.addToParentMstpNetwork(that.deviceList[foundIndex]);
142
133
  }
134
+ that.addToNetworkTree(that.deviceList[foundIndex]);
143
135
  }
144
-
145
136
  //emit event for node-red to log
146
137
  that.emit("deviceFound", device);
147
138
  }
@@ -151,19 +142,18 @@ class BacnetClient extends EventEmitter {
151
142
  if (foundIndex == -1) {
152
143
  let newBacnetDevice = new BacnetDevice(false, device);
153
144
  newBacnetDevice.setLastSeen(Date.now());
154
- that.updateDeviceName(newBacnetDevice);
155
145
  if (newBacnetDevice.getIsMstpDevice()) {
156
146
  that.addToParentMstpNetwork(newBacnetDevice);
157
147
  }
158
148
  that.deviceList.push(newBacnetDevice);
149
+ that.addToNetworkTree(newBacnetDevice);
159
150
  } else if (foundIndex !== -1) {
160
151
  that.deviceList[foundIndex].updateDeviceConfig(device);
161
152
  that.deviceList[foundIndex].setLastSeen(Date.now());
162
- that.updateDeviceName(that.deviceList[foundIndex]);
163
-
164
153
  if (that.deviceList[foundIndex].getIsMstpDevice()) {
165
154
  that.addToParentMstpNetwork(that.deviceList[foundIndex]);
166
155
  }
156
+ that.addToNetworkTree(that.deviceList[foundIndex]);
167
157
  }
168
158
 
169
159
  //emit event for node-red to log
@@ -190,26 +180,91 @@ class BacnetClient extends EventEmitter {
190
180
 
191
181
  testFunction(address, type, instance, property) {
192
182
  let that = this;
193
-
194
183
  console.log("test function ");
195
-
196
184
  that.client.readProperty(
197
185
  address,
198
186
  { type: type, instance: instance },
199
187
  property,
200
188
  that.readPropertyMultipleOptions,
201
189
  (err, value) => {
202
- if (err) {
203
- console.log("err: ", err);
204
- }
205
-
190
+ console.log(value);
206
191
  if (value) {
207
- console.log("value: ", value);
192
+ // If the result has value, resolve the promise
193
+ console.log(value.values[0]);
194
+ value.values[0].values.forEach(function (value) {
195
+ console.log("value: ", value.value);
196
+ });
197
+ } else {
198
+ console.log(err);
208
199
  }
209
200
  }
210
201
  );
211
202
  }
212
203
 
204
+ addToNetworkTree(device) {
205
+ let that = this;
206
+ try {
207
+ const deviceKey = that.createDeviceKey(device);
208
+ let deviceName = device.getDeviceName();
209
+ if (deviceName !== null) {
210
+ const deviceId = device.getDeviceId();
211
+ if (deviceId !== null) {
212
+ let lastIndex = deviceName.lastIndexOf(deviceId);
213
+ if (lastIndex) {
214
+ let formattedName = deviceName.substring(0, lastIndex);
215
+ formattedName = `${formattedName.trim()}_Device_${deviceId}`;
216
+ if (that.networkTree[deviceKey][formattedName] &&
217
+ Object.keys(that.networkTree[deviceKey][formattedName]).length > 0) {
218
+ delete that.networkTree[deviceKey]["device"];
219
+ }
220
+ }
221
+ }
222
+ } else {
223
+ const json = {
224
+ "objectId": {
225
+ "type": 8,
226
+ "instance": device.getDeviceId()
227
+ }
228
+ };
229
+
230
+ if (that.networkTree[deviceKey] && that.networkTree[deviceKey]["device"]) {
231
+ that.networkTree[deviceKey]["device"]["meta"] = json;
232
+ } else {
233
+ that.networkTree[deviceKey] = {
234
+ "device": {
235
+ "meta": json
236
+ }
237
+ }
238
+ }
239
+ }
240
+ } catch (e) {
241
+ that.logOut("addToNetworkTree error: ", e);
242
+ }
243
+ }
244
+
245
+ getProtocolSupported(device) {
246
+ //return protocols support for device
247
+ let that = this;
248
+ return new Promise((resolve, reject) => {
249
+ that.client.readProperty(
250
+ device.getAddress(),
251
+ { type: baEnum.ObjectType.DEVICE, instance: device.getDeviceId() },
252
+ baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED,
253
+ that.readPropertyMultipleOptions,
254
+ (err, value) => {
255
+ if (err) {
256
+ reject(err);
257
+ }
258
+
259
+ if (value) {
260
+ resolve(value);
261
+ }
262
+ }
263
+ );
264
+ });
265
+
266
+ }
267
+
213
268
  addToParentMstpNetwork(device) {
214
269
  let that = this;
215
270
  let address = device.getAddress().address;
@@ -243,223 +298,262 @@ class BacnetClient extends EventEmitter {
243
298
  });
244
299
  }
245
300
 
246
- queryDevices() {
301
+ purgeDevice(device) {
247
302
  let that = this;
303
+ return new Promise((resolve, reject) => {
304
+ try {
305
+ let renderListIndex = that.renderList.findIndex(
306
+ (ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address
307
+ );
308
+ let deviceListIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
309
+ let deviceKey = device.address + "-" + device.deviceId;
310
+ delete that.networkTree[deviceKey];
311
+ that.renderList.splice(renderListIndex, 1);
312
+ that.deviceList.splice(deviceListIndex, 1);
248
313
 
249
- that.pollInProgress = true;
314
+ that.countDevices();
250
315
 
251
- let index = 0;
316
+ resolve(true);
317
+ } catch (e) {
318
+ reject(e);
319
+ }
320
+ });
321
+ }
252
322
 
253
- query(index);
323
+ updatePointsForDevice(deviceObject) {
324
+ let that = this;
325
+ return new Promise((resolve, reject) => {
326
+ try {
327
+ let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
328
+ that.updateDeviceName(device);
254
329
 
255
- function query(index) {
256
- that.queryPriorityDevices().then(function () {
257
- let device = that.deviceList[index];
258
330
 
259
- if (index < that.deviceList.length) {
260
- index++;
331
+ //test
261
332
 
262
- if (typeof device == "object") {
263
- if (!device.getManualDiscoveryMode()) {
264
- try {
265
- that
266
- .getDevicePointList(device)
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
- }
319
- }
333
+ that.getProtocolSupported(device).then(function (result) {
334
+ console.log("updatePointsForDevice getProtocolSupported ", result.values[0].originalBitString);
335
+ console.log(result.values[0]);
336
+ console.log(result);
337
+ console.log(result.values[0]);
338
+ let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
339
+ device.setProtocolServicesSupported(decodedValues);
340
+ }).catch(function (error) {
341
+ that.logOut("getProtocolSupported error: ", error);
342
+ });
320
343
 
321
- queryDevicesManually() {
322
- let that = this;
323
- let index = 0;
324
- query(index);
344
+ //test
325
345
 
326
- function query(index) {
327
- that.queryPriorityDevices().then(function () {
328
- let device = that.manualDiscoverQueue[index];
329
- if (index < that.manualDiscoverQueue.length) {
330
- index++;
331
- if (typeof device == "object") {
332
- try {
333
- if (device.shouldBeInManualMode()) {
346
+
347
+ if (device.getIsProtocolServicesSet() == false) {
348
+ that.getProtocolSupported(device).then(function (result) {
349
+ console.log("updatePointsForDevice getProtocolSupported ", result.values[0].originalBitString);
350
+ let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
351
+ device.setProtocolServicesSupported(decodedValues);
352
+ }).catch(function (error) {
353
+ that.logOut("getProtocolSupported error: ", error);
354
+ });
355
+ }
356
+
357
+ that
358
+ .getDevicePointList(device)
359
+ .then(function () {
360
+ that
361
+ .buildJsonObject(device)
362
+ .then(function () {
363
+ // do nothing for now
364
+ resolve(true);
365
+ })
366
+ .catch(function (e) {
367
+ that.logOut(`Update points list error 1: ${that.getDeviceAddress(device)}`, e);
368
+ });
369
+ })
370
+ .catch(function (e) {
371
+ that.logOut(`Update points list error 2: ${that.getDeviceAddress(device)}`, e);
372
+ device.setManualDiscoveryMode(true);
373
+ that
374
+ .getDevicePointListWithoutObjectList(device)
375
+ .then(function () {
334
376
  that
335
- .getDevicePointListWithoutObjectList(device)
377
+ .buildJsonObject(device)
336
378
  .then(function () {
337
- that
338
- .buildJsonObject(device, null)
339
- .then(function () {
340
- query(index);
341
- })
342
- .catch(function (e) {
343
- that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
344
- query(index);
345
- });
379
+ // do nothing for now
380
+ resolve(true);
346
381
  })
347
382
  .catch(function (e) {
348
- query(index);
383
+ that.logOut(`Update points list error 3: ${that.getDeviceAddress(device)}`, e);
349
384
  });
350
- } else {
351
- that.removeDeviceFromManualQueue(device);
352
- query(index);
353
- }
354
- } catch (e) {
355
- query(index);
356
- }
357
- } else {
358
- query(index);
359
- }
360
- } else if (index == that.manualDiscoverQueue.length) {
361
- that.pollInProgress = false;
362
- }
363
- });
364
- }
385
+ })
386
+ .catch(function (e) {
387
+ that.logOut(`Update points list error 4: ${that.getDeviceAddress(device)}`, e);
388
+ });
389
+ });
390
+ } catch (e) {
391
+ reject(e);
392
+ }
393
+ });
365
394
  }
366
395
 
367
- queryPriorityDevices() {
396
+ setDeviceDisplayName(deviceObject, displayName) {
368
397
  let that = this;
369
398
  return new Promise((resolve, reject) => {
370
- let priorityDevices = that.getPriorityDevices();
371
-
372
- if (priorityDevices.length > 0) {
373
- let index = 0;
399
+ try {
400
+ let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
374
401
 
375
- query(index);
402
+ device.setDisplayName(displayName);
376
403
 
377
- function query(index) {
378
- let device = priorityDevices[index];
404
+ that.buildTreeException = true;
379
405
 
380
- if (index < priorityDevices.length) {
381
- index++;
406
+ resolve(true);
407
+ } catch (e) {
408
+ that.logOut("setDeviceDisplayName error: ", e);
382
409
 
383
- if (
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();
410
+ reject(e);
412
411
  }
413
412
  });
414
413
  }
415
414
 
416
- addDeviceToManualQueue(device) {
415
+ setPointDisplayName(deviceKey, pointName, pointDisplayName) {
417
416
  let that = this;
417
+ return new Promise((resolve, reject) => {
418
+ try {
419
+ if (that.networkTree[deviceKey][pointName]) {
420
+ that.networkTree[deviceKey][pointName].displayName = pointDisplayName;
421
+ }
422
+
423
+ that.buildTreeException = true;
418
424
 
419
- if (device.getPointListRetryCount() > that.deviceRetryCount) {
420
- device.setManualDiscoveryMode(true);
421
- let index = that.manualDiscoverQueue.findIndex((ele) => ele.getDeviceId() == device.getDeviceId());
422
- if (index == -1) {
423
- that.manualDiscoverQueue.push(device);
425
+ resolve(true);
426
+ } catch (e) {
427
+ that.logOut("setPointDisplayName error: ", e);
428
+ reject(e);
424
429
  }
425
- } else {
426
- device.incrementPointListRetryCount();
427
- }
430
+ });
428
431
  }
429
432
 
430
- removeDeviceFromManualQueue(device) {
433
+ importReadList(payload) {
431
434
  let that = this;
432
- device.setManualDiscoveryMode(false);
433
- device.clearPointListRetryCount();
434
- let index = that.manualDiscoverQueue.findIndex((ele) => ele.getDeviceId() == device.getDeviceId());
435
- if (index !== -1) {
436
- that.manualDiscoverQueue.splice(index, 1);
437
- }
435
+
436
+ return new Promise((resolve, reject) => {
437
+ try {
438
+ that.buildTreeException = true;
439
+
440
+ for (let key in payload) {
441
+ let device = payload[key];
442
+ for (let pointName in device) {
443
+ let pointObject = device[pointName]
444
+ if (that.networkTree[key][pointName]) {
445
+ that.networkTree[key][pointName] = pointObject;
446
+ }
447
+ }
448
+ }
449
+ resolve(true);
450
+ } catch (e) {
451
+ that.logOut("importReadList error: ", e);
452
+ reject(e);
453
+ }
454
+ });
438
455
  }
439
456
 
440
- sanitizeDeviceList() {
457
+ queryDevices() {
441
458
  let that = this;
442
459
 
443
- //that.sanitise_device_schedule - from gateway node
444
- let timeoutThreshold = parseInt(that.sanitise_device_schedule);
445
- that.deviceList.forEach(function (device, index) {
446
- if ((Date.now() - device.getLastSeen()) / 1000 > timeoutThreshold && device.getPriorityQueueIsActive() == false) {
447
- //render device hasnt responded to whoIs for sanitise_device_schedule
448
- let renderListIndex = that.renderList.findIndex((ele) => ele.deviceId == device.getDeviceId());
449
- let ipAddr = typeof device.getAddress() == "object" ? device.getAddress().address : device.getAddress();
450
- let deviceKey = ipAddr + "-" + device.getDeviceId();
451
- delete that.networkTree[deviceKey];
452
- that.renderList.splice(renderListIndex, 1);
453
- that.deviceList.splice(index, 1);
460
+ that.pollInProgress = true;
461
+
462
+ let index = 0;
463
+
464
+ query(index);
465
+
466
+ function query(index) {
467
+ let device = that.deviceList[index];
468
+
469
+ if (index < that.deviceList.length) {
470
+ index++;
471
+
472
+ if (typeof device == "object") {
473
+ if (device.getIsProtocolServicesSet() == false) {
474
+ that.getProtocolSupported(device).then(function (result) {
475
+ let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
476
+ device.setProtocolServicesSupported(decodedValues);
477
+ }).catch(function (error) {
478
+ that.logOut("getProtocolSupported error: ", error);
479
+ });
480
+ }
481
+ try {
482
+
483
+ if (device.getSegmentation() !== 3) {
484
+ that.updateDeviceName(device);
485
+ that
486
+ .getDevicePointList(device)
487
+ .then(function () {
488
+ that
489
+ .buildJsonObject(device)
490
+ .then(function () {
491
+ query(index);
492
+ })
493
+ .catch(function (e) {
494
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
495
+ query(index);
496
+ });
497
+ })
498
+ .catch(function (e) {
499
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
500
+ that
501
+ .getDevicePointListWithoutObjectList(device)
502
+ .then(function () {
503
+ that
504
+ .buildJsonObject(device)
505
+ .then(function () {
506
+ query(index);
507
+ })
508
+ .catch(function (e) {
509
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
510
+ query(index);
511
+ });
512
+ })
513
+ .catch(function (e) {
514
+ query(index);
515
+ });
516
+ });
517
+
518
+ } else if (device.getSegmentation() == 3) {
519
+
520
+ that.updateDeviceName(device);
521
+ that
522
+ .getDevicePointListWithoutObjectList(device)
523
+ .then(function () {
524
+ that
525
+ .buildJsonObject(device)
526
+ .then(function () {
527
+ query(index);
528
+ })
529
+ .catch(function (e) {
530
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
531
+ query(index);
532
+ });
533
+ })
534
+ .catch(function (e) {
535
+ query(index);
536
+ });
537
+ }
538
+ } catch (e) {
539
+ that.logOut("Error while querying devices: ", e);
540
+ query(index);
541
+ }
542
+ } else {
543
+ that.logOut("queryDevices: invalid device found: ", device);
544
+ query(index);
545
+ }
546
+ } else if (index == that.deviceList.length) {
547
+ that.pollInProgress = false;
454
548
  }
455
- });
549
+ }
456
550
  }
457
551
 
458
552
  updateDeviceName(device) {
459
553
  let that = this;
460
554
  that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function (deviceObject) {
461
555
  if (typeof deviceObject.name == "string") {
462
- device.setDeviceName(deviceObject.name);
556
+ device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
463
557
  device.setPointsList(deviceObject.devicePointEntry);
464
558
  }
465
559
  });
@@ -475,9 +569,6 @@ class BacnetClient extends EventEmitter {
475
569
  that.discover_polling_schedule = config.discover_polling_schedule;
476
570
  that.deviceId = config.deviceId;
477
571
  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
572
  that.device_read_schedule = config.device_read_schedule;
482
573
 
483
574
  if (that.scheduler !== null) {
@@ -505,7 +596,6 @@ class BacnetClient extends EventEmitter {
505
596
  // //query device task
506
597
  const queryDevices = new Task("simple task", () => {
507
598
  if (!that.pollInProgress) that.queryDevices();
508
- that.sanitizeDeviceList();
509
599
  });
510
600
 
511
601
  const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule) }, queryDevices);
@@ -514,7 +604,7 @@ class BacnetClient extends EventEmitter {
514
604
 
515
605
  //buildNetworkTreeData task
516
606
  const buildNetworkTree = new Task("simple task", () => {
517
- that.buildNetworkTreeData();
607
+ that.doTreeBuilder();
518
608
  that.countDevices();
519
609
  });
520
610
 
@@ -545,54 +635,182 @@ class BacnetClient extends EventEmitter {
545
635
  return newProps;
546
636
  }
547
637
 
548
- doRead(readConfig, outputType, objectPropertyType, readNodeName) {
549
- let that = this;
550
- that.roundDecimal = readConfig.precision;
551
- let devicesToRead = Object.keys(readConfig.pointsToRead);
638
+ findDeviceByKey(key, deviceList, that) {
639
+ return deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
640
+ }
641
+
642
+ getObjectId(pointName, pointConfig, that) {
643
+ // Retrieve the object type based on the point configuration
644
+ const bacObjType = that.getObjectType(pointConfig.meta.objectId.type);
645
+ // Construct the object ID string
646
+ return `${pointName}_${bacObjType}_${pointConfig.meta.objectId.instance}`;
647
+ }
648
+
649
+ createDeviceKey(device) {
650
+ // Create a device key by combining the address and device ID
651
+ const address = device.getAddress();
652
+ const deviceId = device.getDeviceId();
653
+ if (typeof address === "object") {
654
+ return `${address.address}-${deviceId}`;
655
+ } else {
656
+ return `${address}-${deviceId}`;
657
+ }
658
+ }
659
+
660
+
661
+ async doRead(readConfig, outputType, objectPropertyType, readNodeName) {
662
+ const that = this;
663
+ const roundDecimal = readConfig.precision;
664
+ const devicesToRead = Object.keys(readConfig.pointsToRead);
665
+ const bacnetResults = {};
666
+ let pendingRequests = 0;
667
+
552
668
  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
669
 
571
- that
572
- .updatePoint(device, point)
573
- .then(function (result) {
574
- if (isNumber(result.values[0].value)) {
575
- point.presentValue = roundDecimalPlaces(result.values[0].value, that.roundDecimal);
576
- } else {
577
- point.presentValue = result.values[0].value;
578
- }
579
- bacnetResults[deviceName][pointName] = point;
580
- })
581
- .catch(function (err) {
582
- //do nothing for now
583
- });
670
+ // Process all devices in sequence
671
+ for (let deviceIndex = 0; deviceIndex < devicesToRead.length; deviceIndex++) {
672
+ const key = devicesToRead[deviceIndex];
673
+ const device = that.findDeviceByKey(key, that.deviceList, that);
674
+ if (!device) continue;
675
+
676
+ const deviceName = that.computeDeviceName(device);
677
+ const deviceKey = that.createDeviceKey(device);
678
+ const deviceObject = that.networkTree[deviceKey];
679
+ const maxObjectCount = that.estimateMaxObjectSize(device.getMaxApdu());
680
+
681
+ if (!bacnetResults[deviceName]) {
682
+ bacnetResults[deviceName] = {};
683
+ }
684
+
685
+ // Process points for the current device
686
+ const pointsToRead = readConfig.pointsToRead[key];
687
+ const pointNames = Object.keys(pointsToRead);
688
+ const totalPoints = pointNames.length;
689
+ let requestArray = [];
690
+ let processedPoints = 0; // Counter for processed points
691
+
692
+ // Process each point for the device in batches
693
+ for (let i = 0; i < pointNames.length; i++) {
694
+ const pointName = pointNames[i];
695
+ if (pointName === "deviceName") continue;
696
+
697
+ const pointConfig = pointsToRead[pointName];
698
+ const objectId = that.getObjectId(pointName, pointConfig, that);
699
+ const point = deviceObject[objectId];
700
+
701
+ if (point) {
702
+ point.displayName = pointConfig.displayName;
703
+
704
+ // Prepare request array for batch processing
705
+ requestArray.push({
706
+ objectId: { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
707
+ properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }],
708
+ pointRef: point,
709
+ pointName: pointName
710
+ });
711
+ }
712
+
713
+ // Process the batch when the request array is full or the last point is reached
714
+ if (requestArray.length === maxObjectCount || i === pointNames.length - 1) {
715
+ if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
716
+ await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
717
+ } else {
718
+ await that.processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
719
+ }
720
+
721
+ requestArray = [];
722
+ // Increment the processed points counter
723
+ processedPoints += maxObjectCount;
724
+ }
725
+
726
+ // Check if all points for the device have been processed
727
+ if (processedPoints >= totalPoints) {
728
+ pendingRequests++;
729
+ // Emit the `values` event for the current device
730
+ that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName, pendingRequests, devicesToRead.length);
731
+ delete bacnetResults[deviceName];
732
+
733
+ }
734
+ }
735
+ }
736
+ } catch (error) {
737
+ that.logOut("doRead error: ", error);
738
+ }
739
+ }
740
+
741
+ async processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
742
+ try {
743
+ const results = await that.updateManyPoints(device, requestArray);
744
+ if (results.error) {
745
+ throw results.error;
746
+ }
747
+
748
+ // Process the results of the batch
749
+ results.value.values.forEach(pointResult => {
750
+ const cacheRef = requestArray.find(ele =>
751
+ ele.pointRef.meta.objectId.type === pointResult.objectId.type &&
752
+ ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
753
+ );
754
+
755
+ if (cacheRef) {
756
+ const pointRef = cacheRef.pointRef;
757
+ const pointNameRef = cacheRef.pointName;
758
+ const val = pointResult.values[0].value[0].value;
759
+
760
+ if (isNumber(val)) {
761
+ pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
762
+ if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
763
+ if (val != 0) {
764
+ pointRef.presentValue = pointRef.stateTextArray[val - 1].value;
765
+ } else {
766
+ pointRef.presentValue = pointRef.stateTextArray[val].value;
767
+ }
768
+ }
769
+ } else {
770
+ if (typeof val !== "object") {
771
+ pointRef.presentValue = val;
584
772
  }
585
773
  }
774
+
775
+ // Store the point data in results
776
+ bacnetResults[deviceName][pointNameRef] = pointRef;
586
777
  }
778
+ });
779
+ } catch (err) {
780
+ that.logOut("Error processing batch:", err);
781
+ }
782
+ }
587
783
 
588
- setTimeout(() => {
589
- if (index == devicesToRead.length - 1 && Object.keys(readConfig.pointsToRead).length > 0)
590
- that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName);
591
- }, 3000);
784
+ async processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
785
+ for (const request of requestArray) {
786
+ const { objectId, pointRef, pointName } = request;
787
+ try {
788
+ const result = await that.updatePoint(device, pointRef);
789
+ const val = result.values[0].value;
790
+
791
+ if (isNumber(val)) {
792
+ pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
793
+ } else {
794
+ pointRef.presentValue = val;
795
+ }
796
+
797
+ // Store the point data in results
798
+ bacnetResults[deviceName][pointName] = pointRef;
799
+ } catch (err) {
800
+ that.logOut(`Error updating point ${pointName}:`, err);
801
+ }
802
+ }
803
+ }
804
+
805
+ updateManyPoints(device, points) {
806
+ let that = this;
807
+ return new Promise((resolve, reject) => {
808
+ that._readObjectWithRequestArray(device.getAddress(), points, that.readPropertyMultipleOptions).then(function (results) {
809
+ resolve(results);
810
+ }).catch(function (err) {
811
+ reject(err);
592
812
  });
593
- } catch (e) {
594
- that.logOut("Issue doing read, see error: ", e);
595
- }
813
+ });
596
814
  }
597
815
 
598
816
  updatePoint(device, point) {
@@ -600,15 +818,13 @@ class BacnetClient extends EventEmitter {
600
818
  return new Promise((resolve, reject) => {
601
819
  that.client.readProperty(
602
820
  device.getAddress(),
603
- { type: point.objectID.type, instance: point.objectID.instance },
821
+ { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
604
822
  baEnum.PropertyIdentifier.PRESENT_VALUE,
605
- {},
823
+ that.readPropertyMultipleOptions,
606
824
  (err, value) => {
607
825
  if (err) {
608
- //console.log("err ", err);
609
826
  reject(err);
610
827
  }
611
-
612
828
  if (value) {
613
829
  resolve(value);
614
830
  }
@@ -617,6 +833,18 @@ class BacnetClient extends EventEmitter {
617
833
  });
618
834
  }
619
835
 
836
+ estimateMaxObjectSize(apduSize) {
837
+ if (apduSize < 500) {
838
+ return 20;
839
+ } else if (apduSize > 500 && apduSize < 1000) {
840
+ //return Math.round(((apduSize - 30) / 7));
841
+ return 50;
842
+ } else if (apduSize > 1000) {
843
+ //return Math.round(((apduSize - 30) / 7));
844
+ return 100;
845
+ }
846
+ }
847
+
620
848
  getDeviceAddress(device) {
621
849
  switch (typeof device.getAddress()) {
622
850
  case "object":
@@ -825,12 +1053,13 @@ class BacnetClient extends EventEmitter {
825
1053
  }
826
1054
 
827
1055
  _readObjectFull(device, deviceAddress, type, instance) {
828
- let that = this;
1056
+ const that = this;
829
1057
  const readOptions = {
830
1058
  maxSegments: that.readPropertyMultipleOptions.maxSegments,
831
1059
  maxApdu: that.readPropertyMultipleOptions.maxApdu,
832
1060
  };
833
1061
 
1062
+ // Define all properties to be read
834
1063
  const allProperties = [
835
1064
  { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
836
1065
  { id: baEnum.PropertyIdentifier.DESCRIPTION },
@@ -840,77 +1069,151 @@ class BacnetClient extends EventEmitter {
840
1069
  { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
841
1070
  { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
842
1071
  { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
843
- { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
1072
+ { id: baEnum.PropertyIdentifier.STATE_TEXT },
844
1073
  { id: baEnum.PropertyIdentifier.RECORD_COUNT },
845
1074
  { id: baEnum.PropertyIdentifier.PRIORITY_ARRAY },
1075
+ { id: baEnum.PropertyIdentifier.VENDOR_NAME },
846
1076
  ];
847
1077
 
848
1078
  return new Promise((resolve, reject) => {
849
- that
850
- ._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
851
- .then(function (result) {
1079
+ // Try to read all properties at once
1080
+ that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
1081
+ .then(result => {
852
1082
  if (result.value) {
1083
+ // If the result has value, resolve the promise
853
1084
  resolve(result);
854
- }
855
-
856
- if (result.error) {
857
- let i = 0;
858
- readIndividualProperties(i);
1085
+ } else {
1086
+ // If not, proceed to read individual properties
1087
+ readPropertiesIndividually();
859
1088
  }
860
1089
  })
861
- .catch(function (error) {
862
- let i = 0;
863
- readIndividualProperties(i);
1090
+ .catch(() => {
1091
+ // On error, proceed to read individual properties
1092
+ readPropertiesIndividually();
864
1093
  });
865
1094
 
866
- let resultArray = [];
867
- let errorArray = [];
1095
+ // Function to read properties individually
1096
+ const readPropertiesIndividually = () => {
1097
+ const promises = allProperties.map((property, index) => new Promise((propertyResolve) => {
1098
+ that.client.readProperty(
1099
+ deviceAddress,
1100
+ { type: type, instance: instance },
1101
+ property.id,
1102
+ readOptions,
1103
+ (err, value) => {
1104
+ if (err) {
1105
+ propertyResolve(null);
1106
+ } else {
1107
+ propertyResolve({
1108
+ id: property.id,
1109
+ index: value.property.index,
1110
+ value: value.values,
1111
+ });
1112
+ }
1113
+ }
1114
+ );
1115
+ }));
1116
+
1117
+ Promise.all(promises)
1118
+ .then(resultArray => {
1119
+ // Filter out null results
1120
+ const validResults = resultArray.filter(result => result !== null);
1121
+
1122
+ resolve({
1123
+ error: null,
1124
+ value: {
1125
+ values: [
1126
+ {
1127
+ objectId: {
1128
+ type: type,
1129
+ instance: instance,
1130
+ },
1131
+ values: validResults,
1132
+ },
1133
+ ],
1134
+ },
1135
+ });
1136
+ })
1137
+ .catch(reject);
1138
+ };
1139
+ });
1140
+ }
868
1141
 
869
- function readIndividualProperties(index) {
870
- const property = allProperties[index];
871
1142
 
872
- that.client.readProperty(
873
- deviceAddress,
874
- { type: type, instance: instance },
875
- property.id,
876
- readOptions,
877
- (err, value) => {
878
- if (err) {
879
- errorArray.push(err);
880
- }
1143
+ _readObjectLite(device, deviceAddress, type, instance) {
1144
+ const that = this;
1145
+ const readOptions = {
1146
+ maxSegments: that.readPropertyMultipleOptions.maxSegments,
1147
+ maxApdu: that.readPropertyMultipleOptions.maxApdu,
1148
+ };
881
1149
 
882
- if (value) {
883
- const structuredResult = {
884
- id: value.property.id,
885
- index: value.property.index,
886
- value: value.values,
887
- };
1150
+ // Define all properties to be read
1151
+ const allProperties = [
1152
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
1153
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
1154
+ ];
888
1155
 
889
- resultArray.push(structuredResult);
890
- }
1156
+ return new Promise((resolve, reject) => {
1157
+ // Try to read all properties at once
1158
+ that._readObject(deviceAddress, type, instance, allProperties, readOptions)
1159
+ .then(result => {
1160
+ if (result.value) {
1161
+ // If the result has value, resolve the promise
1162
+ resolve(result);
1163
+ } else {
1164
+ // If not, proceed to read individual properties
1165
+ readPropertiesIndividually();
1166
+ }
1167
+ })
1168
+ .catch(() => {
1169
+ // On error, proceed to read individual properties
1170
+ readPropertiesIndividually();
1171
+ });
891
1172
 
892
- if (index == allProperties.length - 1) {
893
- resolve({
894
- error: null,
895
- value: {
896
- values: [
897
- {
898
- objectId: {
899
- type: type,
900
- instance: instance,
901
- },
902
- values: resultArray,
903
- },
904
- ],
905
- },
906
- });
907
- } else if (index < allProperties.length - 1) {
908
- index++;
909
- readIndividualProperties(index);
1173
+ // Function to read properties individually
1174
+ const readPropertiesIndividually = () => {
1175
+ const promises = allProperties.map((property, index) => new Promise((propertyResolve) => {
1176
+ that.client.readProperty(
1177
+ deviceAddress,
1178
+ { type: type, instance: instance },
1179
+ property.id,
1180
+ readOptions,
1181
+ (err, value) => {
1182
+ if (err) {
1183
+ propertyResolve(null);
1184
+ } else {
1185
+ propertyResolve({
1186
+ id: property.id,
1187
+ index: value.property.index,
1188
+ value: value.values,
1189
+ });
1190
+ }
910
1191
  }
911
- }
912
- );
913
- }
1192
+ );
1193
+ }));
1194
+
1195
+ Promise.all(promises)
1196
+ .then(resultArray => {
1197
+ // Filter out null results
1198
+ const validResults = resultArray.filter(result => result !== null);
1199
+
1200
+ resolve({
1201
+ error: null,
1202
+ value: {
1203
+ values: [
1204
+ {
1205
+ objectId: {
1206
+ type: type,
1207
+ instance: instance,
1208
+ },
1209
+ values: validResults,
1210
+ },
1211
+ ],
1212
+ },
1213
+ });
1214
+ })
1215
+ .catch(reject);
1216
+ };
914
1217
  });
915
1218
  }
916
1219
 
@@ -1048,6 +1351,7 @@ class BacnetClient extends EventEmitter {
1048
1351
  reducedDeviceList.forEach((device) => {
1049
1352
  delete device["pointsList"];
1050
1353
  });
1354
+
1051
1355
  resolve({
1052
1356
  renderList: that.renderList,
1053
1357
  deviceList: reducedDeviceList,
@@ -1096,42 +1400,6 @@ class BacnetClient extends EventEmitter {
1096
1400
  });
1097
1401
  }
1098
1402
 
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
1403
  sortDevices(a, b) {
1136
1404
  if (a.deviceId < b.deviceId) {
1137
1405
  return -1;
@@ -1153,443 +1421,128 @@ class BacnetClient extends EventEmitter {
1153
1421
  return a.label.localeCompare(b.label);
1154
1422
  }
1155
1423
 
1156
- buildNetworkTreeData() {
1424
+ computeDeviceName(device) {
1425
+ if (device.getDisplayName() !== null && device.getDisplayName() !== "" && device.getDisplayName() !== undefined) {
1426
+ return device.getDisplayName();
1427
+ }
1428
+ return device.getDeviceName();
1429
+ }
1430
+
1431
+ checkInterruptFlag() {
1157
1432
  let that = this;
1158
- that.buildTreeMutex = new Mutex();
1159
- let displayNameCharThreshold = 40;
1433
+ let BreakException = {};
1160
1434
 
1161
- if (that.config.cacheFileEnabled) {
1162
- Store_Config(
1163
- JSON.stringify({
1164
- renderList: that.renderList,
1165
- deviceList: that.deviceList,
1166
- pointList: that.networkTree,
1167
- renderListCount: that.renderListCount,
1168
- })
1169
- );
1435
+ if (that.buildTreeException) {
1436
+ throw BreakException;
1170
1437
  }
1438
+ }
1171
1439
 
1172
- return new Promise(async function (resolve, reject) {
1173
- if (!that.renderList) that.renderList = [];
1174
- if (that.deviceList && that.networkTree) {
1175
- that.deviceList.forEach(function (deviceInfo, index) {
1176
- that.buildTreeMutex.acquire().then(function (release) {
1177
- let ipAddr =
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
- }
1440
+ getPointName(object, pointName) {
1441
+ if (object.displayName) {
1442
+ return object.displayName;
1443
+ }
1444
+ return pointName;
1445
+ }
1205
1446
 
1206
- if (values.objectName) {
1207
- pointProperties.push({
1208
- key: `${index}-0-${pointIndex}-0`,
1209
- label: `Name: ${values.objectName}`,
1210
- data: values.objectName,
1211
- icon: "pi pi-cog",
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
- }
1447
+ addUniqueToArray(device, array) {
1448
+ const foundIndex = array.findIndex(ele => ele.getDeviceId() === device.getDeviceId());
1449
+ if (foundIndex === -1) {
1450
+ array.push(device);
1451
+ }
1452
+ }
1330
1453
 
1331
- children.push({
1332
- key: `${index}-0-${pointIndex}`,
1333
- label: displayName,
1334
- data: displayName,
1335
- pointName: pointName,
1336
- icon: that.getPointIcon(values),
1337
- children: pointProperties,
1338
- type: "point",
1339
- parentDevice: deviceName,
1340
- showAdded: false,
1341
- bacnetType: values.meta.objectId.type,
1342
- });
1343
- pointIndex++;
1454
+ async getDevicesNotRenderedYet() {
1455
+ let that = this;
1456
+ let missingDevices = [];
1457
+ for (let i = 0; i < that.deviceList.length; i++) {
1458
+ const device = that.deviceList[i];
1459
+ if (!device.getIsMstpDevice()) {
1460
+ //ip device
1461
+ const foundIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
1462
+ if (foundIndex == -1) {
1463
+ that.addUniqueToArray(device, missingDevices);
1464
+ }
1465
+ } else {
1466
+ //mstp device
1467
+ const foundParentIndex = that.renderList.findIndex(ele => ele.deviceId == device.getParentDeviceId());
1468
+ if (foundParentIndex == -1) {
1469
+ //parent not existent in tree
1470
+ const parentDeviceIndex = that.deviceList.findIndex(ele => ele.getDeviceId() === device.getParentDeviceId());
1471
+ if (parentDeviceIndex !== -1) {
1472
+ that.addUniqueToArray(that.deviceList[parentDeviceIndex], missingDevices);
1473
+ }
1474
+ that.addUniqueToArray(device, missingDevices);
1475
+ } else {
1476
+ const parentTreeDevice = that.renderList[foundParentIndex];
1477
+ let mstpIndex = -1;
1478
+ parentTreeDevice.children.forEach(child => {
1479
+ if (child.label.includes("MSTP")) {
1480
+ const tempIndex = child.children.findIndex(ele => ele.deviceId == device.getDeviceId());
1481
+ if (tempIndex !== -1) {
1482
+ mstpIndex = tempIndex;
1344
1483
  }
1345
- let foundIndex = that.renderList.findIndex((ele) => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
1346
- if (foundIndex !== -1) {
1347
- let folderJson = [];
1348
- if (deviceInfo.hasChildDevices()) {
1349
- folderJson = [
1350
- {
1351
- key: `${index}-0`,
1352
- label: "Points",
1353
- data: "Points Folder",
1354
- icon: "pi pi-circle-fill",
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
- }
1484
+ }
1485
+ });
1486
+ if (mstpIndex == -1) {
1487
+ that.addUniqueToArray(device, missingDevices);
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+ return missingDevices;
1493
+ }
1379
1494
 
1380
- if (!isMstpDevice) {
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
- }
1495
+ initialTreeBuild = true;
1469
1496
 
1470
- if (!isMstpDevice) {
1471
- //that.renderListCount++;
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
- );
1497
+ async doTreeBuilder() {
1498
+ let that = this;
1490
1499
 
1491
- if (
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
- }
1500
+ const treeWorker = new treeBuilder(that.deviceList, that.networkTree, that.renderList, that.renderListCount, that.initialTreeBuild);
1533
1501
 
1534
- if (index == that.deviceList.length - 1) {
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
- }
1502
+ treeWorker.cacheData();
1554
1503
 
1555
- release();
1556
- });
1557
- });
1558
- }
1559
- });
1504
+ //const missingDevices = await that.getDevicesNotRenderedYet();
1505
+
1506
+ for (let i = 0; i < that.deviceList.length; i++) {
1507
+ let device = that.deviceList[i];
1508
+ await treeWorker.processDevice(device, i);
1509
+ }
1510
+
1511
+ that.deviceList = treeWorker.deviceList;
1512
+ that.networkTree = treeWorker.networkTree;
1513
+ that.renderList = treeWorker.renderList;
1514
+
1515
+ that.initialTreeBuild = false;
1560
1516
  }
1561
1517
 
1562
1518
  countDevices() {
1563
1519
  let that = this;
1564
-
1565
1520
  let deviceCount = 0;
1566
1521
 
1567
- that.renderList.forEach(function (device, index) {
1568
- if (device) {
1569
- if (
1570
- device.children[1] &&
1571
- device.children[1].label == "MSTP Network" &&
1572
- device.children[1].children &&
1573
- device.children[1].children.length > 0
1574
- ) {
1575
- //increment for parent device / mstp router
1576
- deviceCount++;
1577
- //increment for mstp device list
1578
- deviceCount += device.children[1].children.length;
1579
- } else {
1580
- deviceCount++;
1522
+ if (that.renderList && that.renderList.length > 0) {
1523
+ that.renderList.forEach(function (device, index) {
1524
+ if (device && device.children.length > 0) {
1525
+ device.children.forEach(function (folder) {
1526
+ if (folder.label == "Points") {
1527
+ //increment for parent device / mstp router
1528
+ deviceCount++;
1529
+ } else if (folder.label.includes("MSTP")) {
1530
+ //increment for mstp device list
1531
+ deviceCount += folder.children.length;
1532
+ }
1533
+ });
1581
1534
  }
1582
- }
1583
- if (index == that.renderList.length - 1) {
1584
- that.renderListCount = deviceCount;
1585
- }
1586
- });
1535
+ if (index == that.renderList.length - 1) {
1536
+ that.renderListCount = deviceCount;
1537
+ }
1538
+ });
1539
+ }
1587
1540
  }
1588
1541
 
1589
- buildJsonObject(device, priorityQueue) {
1542
+ buildJsonObject(device) {
1590
1543
  let that = this;
1591
1544
  let address = device.address;
1592
- let pointList = priorityQueue !== null ? priorityQueue : device.getPointsList();
1545
+ let pointList = device.getPointsList();
1593
1546
  let requestMutex = new Mutex();
1594
1547
 
1595
1548
  return new Promise(function (resolve, reject) {
@@ -1597,49 +1550,100 @@ class BacnetClient extends EventEmitter {
1597
1550
  if (typeof pointList !== "undefined" && pointList.length > 0) {
1598
1551
  pointList.forEach(function (point, pointListIndex) {
1599
1552
  requestMutex.acquire().then(function (release) {
1600
- that
1601
- ._readObjectFull(device, address, point.value.type, point.value.instance)
1602
- .then(function (result) {
1603
- if (!result.error) {
1604
- if (result.length > 0 && Array.isArray(result)) {
1605
- promiseArray = result;
1606
- } else {
1607
- promiseArray.push(result);
1553
+ if (device.getIsInitialQuery()) {
1554
+ that
1555
+ ._readObjectLite(device, address, point.value.type, point.value.instance)
1556
+ .then(function (result) {
1557
+ if (!result.error) {
1558
+ if (result.length > 0 && Array.isArray(result)) {
1559
+ promiseArray = result;
1560
+ } else {
1561
+ promiseArray.push(result);
1562
+ }
1608
1563
  }
1609
- }
1610
1564
 
1611
- release();
1565
+ release();
1612
1566
 
1613
- if (pointListIndex == pointList.length - 1) {
1614
- that
1615
- .buildResponse(promiseArray, device)
1616
- .then(function () {
1617
- that.lastNetworkPoll = Date.now();
1618
- resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1619
- })
1620
- .catch(function (e) {
1621
- that.logOut("Error while building json object: ", e);
1622
- reject(e);
1623
- });
1624
- }
1625
- })
1626
- .catch(function (e) {
1627
- release();
1628
- that.logOut("_readObjectFull error: ", e);
1567
+ if (pointListIndex == pointList.length - 1) {
1568
+ device.setIsInitialQuery(false);
1569
+ that
1570
+ .buildResponse(promiseArray, device)
1571
+ .then(function () {
1572
+ that.lastNetworkPoll = Date.now();
1573
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1574
+ })
1575
+ .catch(function (e) {
1576
+ that.logOut("Error while building json object: ", e);
1577
+ reject(e);
1578
+ });
1579
+ }
1580
+ })
1581
+ .catch(function (e) {
1582
+ release();
1583
+ that.logOut("_readObjectLite error: ", e);
1629
1584
 
1630
- if (pointListIndex == pointList.length - 1) {
1631
- that
1632
- .buildResponse(promiseArray, device)
1633
- .then(function () {
1634
- that.lastNetworkPoll = Date.now();
1635
- resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1636
- })
1637
- .catch(function (e) {
1638
- that.logOut("Error while building json object: ", e);
1639
- reject(e);
1640
- });
1641
- }
1642
- });
1585
+ if (pointListIndex == pointList.length - 1) {
1586
+ device.setIsInitialQuery(false);
1587
+ that
1588
+ .buildResponse(promiseArray, device)
1589
+ .then(function () {
1590
+ that.lastNetworkPoll = Date.now();
1591
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1592
+ })
1593
+ .catch(function (e) {
1594
+ that.logOut("Error while building json object: ", e);
1595
+ reject(e);
1596
+ });
1597
+ }
1598
+ });
1599
+
1600
+
1601
+
1602
+ } else {
1603
+ that
1604
+ ._readObjectFull(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
+ }
1613
+
1614
+ release();
1615
+
1616
+ if (pointListIndex == pointList.length - 1) {
1617
+ that
1618
+ .buildResponse(promiseArray, device)
1619
+ .then(function () {
1620
+ that.lastNetworkPoll = Date.now();
1621
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1622
+ })
1623
+ .catch(function (e) {
1624
+ that.logOut("Error while building json object: ", e);
1625
+ reject(e);
1626
+ });
1627
+ }
1628
+ })
1629
+ .catch(function (e) {
1630
+ release();
1631
+ that.logOut("_readObjectFull error: ", e);
1632
+
1633
+ if (pointListIndex == pointList.length - 1) {
1634
+ that
1635
+ .buildResponse(promiseArray, device)
1636
+ .then(function () {
1637
+ that.lastNetworkPoll = Date.now();
1638
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1639
+ })
1640
+ .catch(function (e) {
1641
+ that.logOut("Error while building json object: ", e);
1642
+ reject(e);
1643
+ });
1644
+ }
1645
+ });
1646
+ }
1643
1647
  });
1644
1648
  });
1645
1649
  } else {
@@ -1651,7 +1655,7 @@ class BacnetClient extends EventEmitter {
1651
1655
  // Builds response object for a fully qualified
1652
1656
  buildResponse(fullObjects, device) {
1653
1657
  let that = this;
1654
-
1658
+ const reg = /[$#\/\\+]/gi;
1655
1659
  return new Promise(function (resolve, reject) {
1656
1660
  let deviceKey =
1657
1661
  typeof device.getAddress() == "object"
@@ -1670,9 +1674,11 @@ class BacnetClient extends EventEmitter {
1670
1674
  let currobjectId = pointProperty.objectId.type;
1671
1675
  let bac_obj = that.getObjectType(currobjectId);
1672
1676
  let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
1673
- let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
1677
+ let objectType = pointProperty.objectId.type;
1678
+
1674
1679
  let objectId;
1675
1680
  if (objectName !== null && typeof objectName == "string") {
1681
+ objectName = objectName.replace(reg, '');
1676
1682
  objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
1677
1683
 
1678
1684
  try {
@@ -1697,7 +1703,16 @@ class BacnetClient extends EventEmitter {
1697
1703
  } else if (objectType == 40) {
1698
1704
  //character string
1699
1705
  values[objectId].presentValue = object.value[0].value;
1700
- } else {
1706
+ } else if (objectType == 13 || objectType == 14 || objectType == 19) {
1707
+ //check for MSV MSI MSO - for enum state text
1708
+ if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
1709
+ if (object.value[0].value == 0) {
1710
+ values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value].value;
1711
+ } else if (object.value[0].value !== 0) {
1712
+ values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value - 1].value;
1713
+ }
1714
+ }
1715
+ } else if (objectType !== 8) {
1701
1716
  values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
1702
1717
  }
1703
1718
  }
@@ -1711,7 +1726,12 @@ class BacnetClient extends EventEmitter {
1711
1726
  values[objectId].units = getUnit(object.value[0].value);
1712
1727
  break;
1713
1728
  case baEnum.PropertyIdentifier.OBJECT_NAME:
1714
- if (object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
1729
+ if (object.value[0] && object.value[0].value) {
1730
+ values[objectId].objectName = object.value[0].value.replace(reg, '');
1731
+ if (!values[objectId].displayName) {
1732
+ values[objectId].displayName = object.value[0].value.replace(reg, '');
1733
+ }
1734
+ }
1715
1735
  break;
1716
1736
  case baEnum.PropertyIdentifier.OBJECT_TYPE:
1717
1737
  if (object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
@@ -1722,13 +1742,11 @@ class BacnetClient extends EventEmitter {
1722
1742
  case baEnum.PropertyIdentifier.PROPERTY_LIST:
1723
1743
  if (object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
1724
1744
  break;
1725
-
1726
1745
  case baEnum.PropertyIdentifier.SYSTEM_STATUS:
1727
1746
  if (object.value[0]) {
1728
1747
  values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
1729
1748
  }
1730
1749
  break;
1731
-
1732
1750
  case baEnum.PropertyIdentifier.MODIFICATION_DATE:
1733
1751
  if (object.value[0]) {
1734
1752
  values[objectId].modificationDate = object.value[0].value;
@@ -1751,6 +1769,28 @@ class BacnetClient extends EventEmitter {
1751
1769
  values[objectId].hasPriorityArray = true;
1752
1770
  }
1753
1771
  break;
1772
+ case baEnum.PropertyIdentifier.STATE_TEXT:
1773
+ if (object.value) {
1774
+ values[objectId].stateTextArray = object.value;
1775
+ if (typeof values[objectId].presentValue == "number" &&
1776
+ values[objectId].presentValue !== null &&
1777
+ values[objectId].presentValue !== undefined) {
1778
+ const tempIndex = values[objectId].presentValue;
1779
+ if (tempIndex == 0) {
1780
+ values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
1781
+ } else if (tempIndex !== 0) {
1782
+ values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
1783
+ }
1784
+ }
1785
+ }
1786
+ break;
1787
+ case baEnum.PropertyIdentifier.VENDOR_NAME:
1788
+ if (object.value) {
1789
+ if (object.value[0].value && typeof object.value[0].value == "string") {
1790
+ values[objectId].vendorName = object.value[0].value;
1791
+ }
1792
+ }
1793
+ break;
1754
1794
  }
1755
1795
  }
1756
1796
  if (