@bitpoolos/edge-bacnet 1.2.5 → 1.2.7

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