@bitpoolos/edge-bacnet 1.0.9 → 1.1.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
@@ -2,19 +2,24 @@
2
2
  MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
3
3
  */
4
4
  const bacnet = require('./resources/node-bacnet/index.js');
5
+ const { BacnetServer } = require("./bacnet_server.js");
5
6
  const baEnum = bacnet.enum;
6
7
  const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
7
8
  const { EventEmitter, captureRejectionSymbol } = require('events');
8
- const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces } = require('./common');
9
- const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
9
+ const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync } = require('./common');
10
+ const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
10
11
  const { BacnetDevice } = require('./bacnet_device');
11
12
  const {Mutex, Semaphore, withTimeout} = require("async-mutex");
13
+
12
14
  class BacnetClient extends EventEmitter {
13
15
 
14
16
  //client constructor
15
17
  constructor(config) {
16
18
  super();
17
19
  let that = this;
20
+
21
+ let cachedData = JSON.parse(Read_Config_Sync());
22
+
18
23
  that.deviceList = [];
19
24
  that.networkTree = {};
20
25
  that.lastWhoIs = null;
@@ -23,6 +28,17 @@ class BacnetClient extends EventEmitter {
23
28
  that.scheduler = new ToadScheduler();
24
29
  that.mutex = new Mutex();
25
30
 
31
+ if(typeof cachedData == "object") {
32
+ if(cachedData.renderList) that.renderList = cachedData.renderList;
33
+ if(cachedData.deviceList) {
34
+ cachedData.deviceList.forEach(function(device) {
35
+ let newBacnetDevice = new BacnetDevice(true, device);
36
+ that.deviceList.push(newBacnetDevice);
37
+ });
38
+ }
39
+ if(cachedData.pointList) that.networkTree = cachedData.pointList;
40
+ }
41
+
26
42
  try {
27
43
  that.config = config;
28
44
  that.roundDecimal = config.roundDecimal;
@@ -37,31 +53,13 @@ class BacnetClient extends EventEmitter {
37
53
  that.manual_instance_range_enabled = config.manual_instance_range_enabled;
38
54
  that.manual_instance_range_start = config.manual_instance_range_start;
39
55
  that.manual_instance_range_end = config.manual_instance_range_end;
56
+ that.bacnetServerEnabled = config.bacnetServerEnabled;
40
57
 
41
58
  that.readPropertyMultipleOptions = {
42
59
  maxSegments: that.maxSegments,
43
60
  maxApdu: that.apduSize
44
61
  };
45
62
 
46
- that.selfObjectList = [
47
- {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
48
- ];
49
-
50
- that.selfData = {
51
- 8: {
52
- [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}], // OBJECT_IDENTIFIER
53
- [baEnum.PropertyIdentifier.OBJECT_LIST]: that.selfObjectList, // OBJECT_IDENTIFIER
54
- [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: 'Bitpool Edge BACnet Gateway', type: 7}], // OBJECT_NAME
55
- [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: 8, type: 9}], // OBJECT_TYPE
56
- [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: 'Bitpool Edge BACnet gateway', type: 7}], // DESCRIPTION
57
- [baEnum.PropertyIdentifier.SYSTEM_STATUS]: [{value: 0, type: 9}], // SYSTEM_STATUS
58
- [baEnum.PropertyIdentifier.VENDOR_NAME]: [{value: "Bitpool", type: 7}], //VENDOR_NAME
59
- [baEnum.PropertyIdentifier.VENDOR_IDENTIFIER]: [{value: 9999, type: 7}], //VENDOR_IDENTIFIER
60
- [baEnum.PropertyIdentifier.MODEL_NAME]: [{value: "bitpool-edge", type: 7}], //MODEL_NAME
61
- [baEnum.PropertyIdentifier.FIRMWARE_REVISION]: [{value: "Node-Red v3.0.2", type: 7}], //FIRMWARE_REVISION
62
- }
63
- };
64
-
65
63
  try {
66
64
 
67
65
  that.client = new bacnet({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
@@ -73,21 +71,20 @@ class BacnetClient extends EventEmitter {
73
71
 
74
72
  const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, task)
75
73
 
76
- that.scheduler.addSimpleIntervalJob(job)
74
+ that.scheduler.addSimpleIntervalJob(job);
77
75
 
78
76
  //query device task
79
- const queryDevices = new Task('simple task', () => {
77
+ const queryDevices = new Task('simple task', () => {
80
78
  that.queryDevices();
79
+ that.sanitizeDeviceList();
81
80
  });
82
81
 
83
82
  const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, queryDevices)
84
- //const queryJob = new SimpleIntervalJob({ seconds: 10, }, queryDevices)
85
-
86
83
 
87
84
  that.scheduler.addSimpleIntervalJob(queryJob);
88
85
 
89
86
  //buildNetworkTreeData task
90
- const buildNetworkTree = new Task('simple task', () => {
87
+ const buildNetworkTree = new Task('simple task', () => {
91
88
  that.buildNetworkTreeData();
92
89
  });
93
90
 
@@ -102,99 +99,72 @@ class BacnetClient extends EventEmitter {
102
99
  }, "5000")
103
100
 
104
101
  } catch(e) {
105
- console.log("Issue initializing client: ", e)
102
+ that.logOut("Issue initializing client: ", e)
106
103
  }
107
104
 
108
105
  //who is callback
109
106
  that.client.on('iAm', (device) => {
110
107
  if(device.header.sender.address !== that.config.localIpAdrress) {
111
- //only add unique device to array
112
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
113
- if(foundIndex == -1) {
114
- let newBacnetDevice = new BacnetDevice(device);
115
- newBacnetDevice.setLastSeen(Date.now());
116
- that.updateDeviceName(newBacnetDevice);
117
- that.deviceList.push(newBacnetDevice);
118
-
119
- } else if(foundIndex !== -1) {
120
- that.deviceList[foundIndex].updateDeviceConfig(device);
121
- that.deviceList[foundIndex].setLastSeen(Date.now());
122
- that.updateDeviceName(that.deviceList[foundIndex]);
123
- }
124
-
125
- //emit event for node-red to log
126
- that.emit('deviceFound', device);
127
- }
128
- });
129
-
130
- that.client.on('whoIs', (device) => {
131
- that.client.iAmResponse(that.broadCastAddr, that.deviceId, baEnum.Segmentation.SEGMENTED_BOTH, 27823);
132
- });
133
-
134
- that.client.on('readPropertyMultiple', (data) => {
135
- try {
136
- if(data.payload.properties[0]){
137
- let objectId = data.payload.properties[0].objectId.type;
138
- let objectInstance = data.payload.properties[0].objectId.instance;
139
- let propId = data.payload.properties[0].properties[0].id.toString();
140
- let responseObj = that.selfData[objectId][propId];
141
-
142
- if(responseObj !== null && responseObj !== "undefined") {
143
- that.client.readPropertyMultipleResponse(data.address, data.invokeId, responseObj);
144
- } else {
145
- this.client.errorResponse(
146
- data.address,
147
- baEnum.ConfirmedServices.SERVICE_CONFIRMED_READ_PROPERTY,
148
- data.invokeId,
149
- baEnum.ErrorClasses.ERROR_CLASS_PROPERTY,
150
- baEnum.ErrorCodes.ERROR_CODE_UNKNOWN_PROPERTY
151
- );
108
+ if(that.device_id_range_enabled) {
109
+ if(device.payload.deviceId >= that.device_id_range_start && device.payload.deviceId <= that.device_id_range_end) {
110
+ //only add unique device to array
111
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
112
+ if(foundIndex == -1) {
113
+ let newBacnetDevice = new BacnetDevice(false, device);
114
+ newBacnetDevice.setLastSeen(Date.now());
115
+ that.updateDeviceName(newBacnetDevice);
116
+ that.deviceList.push(newBacnetDevice);
117
+
118
+ } else if(foundIndex !== -1) {
119
+ that.deviceList[foundIndex].updateDeviceConfig(device);
120
+ that.deviceList[foundIndex].setLastSeen(Date.now());
121
+ that.updateDeviceName(that.deviceList[foundIndex]);
122
+ }
123
+
124
+ //emit event for node-red to log
125
+ that.emit('deviceFound', device);
152
126
  }
153
- }
154
-
155
- } catch(e) {
156
- //console.log("Local BACnet device readPropertyMultiple error: ");
157
- }
158
- });
159
-
160
- that.client.on('readProperty', (data) => {
161
- try {
162
- let objectId = data.payload.objectId.type;
163
- let propId = data.payload.property.id.toString();
164
- let responseObj = that.selfData[objectId][propId];
165
- if(responseObj !== null && responseObj !== undefined && typeof responseObj !== "undefined") {
166
- that.client.readPropertyResponse(data.header.sender.address, data.invokeId, objectId, data.payload.property, responseObj);
167
127
  } else {
168
- this.client.errorResponse(
169
- data.address,
170
- baEnum.ConfirmedServiceChoice.READ_PROPERTY,
171
- data.invokeId,
172
- baEnum.ErrorClass.PROPERTY,
173
- baEnum.ErrorCode.UNKNOWN_PROPERTY
174
- );
128
+ //only add unique device to array
129
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
130
+ if(foundIndex == -1) {
131
+ let newBacnetDevice = new BacnetDevice(false, device);
132
+ newBacnetDevice.setLastSeen(Date.now());
133
+ that.updateDeviceName(newBacnetDevice);
134
+ that.deviceList.push(newBacnetDevice);
135
+
136
+ } else if(foundIndex !== -1) {
137
+ that.deviceList[foundIndex].updateDeviceConfig(device);
138
+ that.deviceList[foundIndex].setLastSeen(Date.now());
139
+ that.updateDeviceName(that.deviceList[foundIndex]);
140
+ }
141
+
142
+ //emit event for node-red to log
143
+ that.emit('deviceFound', device);
175
144
  }
176
- } catch(e){
177
- console.log("Local BACnet device readProperty error: ", e);
178
145
  }
179
-
180
146
  });
181
147
 
182
148
  } catch(e) {
183
- console.log("Issue with creating bacnet client, see error: ", e);
149
+ that.logOut("Issue with creating bacnet client, see error: ", e);
184
150
  }
185
151
 
186
152
  that.client.on('error', (err) => {
187
- console.log('Error occurred: ', err);
153
+ that.logOut('Error occurred: ', err);
188
154
 
189
155
  if(err.errno == -4090){
190
- console.log("Invalid Client information or incorrect IP address provided");
156
+ that.logOut("Invalid Client information or incorrect IP address provided");
191
157
  } else if(err.errno == -49) {
192
- console.log("Invalid IP address provided");
158
+ that.logOut("Invalid IP address provided");
193
159
  } else {
194
160
  that.reinitializeClient(that.config);
195
161
  }
196
162
  });
163
+ }
197
164
 
165
+ logOut(param1, param2) {
166
+ let that = this;
167
+ that.emit('bacnetErrorLog', param1, param2);
198
168
  }
199
169
 
200
170
  rebuildDataModel() {
@@ -206,7 +176,7 @@ class BacnetClient extends EventEmitter {
206
176
  that.networkTree = {};
207
177
  resolve(true);
208
178
  } catch(e) {
209
- console.log("Error clearing BACnet data model: ", e);
179
+ that.logOut("Error clearing BACnet data model: ", e);
210
180
  reject(e);
211
181
  }
212
182
  });
@@ -220,16 +190,6 @@ class BacnetClient extends EventEmitter {
220
190
  .then(function(release) {
221
191
  try {
222
192
 
223
- // that.getDevicePointListWithoutObjectList(device).then(function() {
224
- // that.buildJsonObject(device).then(function() {
225
- // release();
226
- // }).catch(function(e) {
227
- // release();
228
- // });
229
- // }).catch(function(e) {
230
- // release();
231
- // });
232
-
233
193
  that.getDevicePointList(device).then(function() {
234
194
  that.buildJsonObject(device).then(function() {
235
195
  release();
@@ -249,13 +209,35 @@ class BacnetClient extends EventEmitter {
249
209
  release();
250
210
  });
251
211
 
252
-
253
212
  } catch(e) {
254
- console.log("Error while querying devices: ", e);
213
+ that.logOut("Error while querying devices: ", e);
255
214
  release();
256
215
  }
257
216
  });
258
217
  });
218
+ Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
219
+ }
220
+
221
+ sanitizeDeviceList() {
222
+ let that = this;
223
+
224
+ that.deviceList.forEach(function(device, index) {
225
+ if(((Date.now() - device.getLastSeen()) / 1000) > 3600) {
226
+ //device hasnt responded to whoIs for over an hour
227
+
228
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
229
+ delete that.networkTree[deviceKey];
230
+
231
+ if(that.renderList){
232
+ let foundIndex = that.renderList.findIndex(ele => ele.ipAddr == device.getAddress() && ele.deviceId == device.getDeviceId());
233
+ if(foundIndex !== -1) {
234
+ that.renderList.splice(foundIndex, 1);
235
+ }
236
+ }
237
+
238
+ that.deviceList.splice(index, 1);
239
+ }
240
+ });
259
241
  }
260
242
 
261
243
  updateDeviceName(device) {
@@ -268,21 +250,34 @@ class BacnetClient extends EventEmitter {
268
250
  reinitializeClient(config) {
269
251
  let that = this;
270
252
 
253
+ that.config = config;
254
+ that.roundDecimal = config.roundDecimal;
255
+ that.apduSize = config.apduSize;
256
+ that.maxSegments = config.maxSegments;
257
+ that.discover_polling_schedule = config.discover_polling_schedule;
271
258
  that.device_id_range_enabled = config.device_id_range_enabled;
272
259
  that.device_id_range_start = config.device_id_range_start;
273
260
  that.device_id_range_end = config.device_id_range_end;
274
-
275
- if(that.client !== null) {
276
- that.client.close();
277
- that.client = null;
278
- }
261
+ that.deviceId = config.deviceId;
262
+ that.broadCastAddr = config.broadCastAddr;
263
+ that.manual_instance_range_enabled = config.manual_instance_range_enabled;
264
+ that.manual_instance_range_start = config.manual_instance_range_start;
265
+ that.manual_instance_range_end = config.manual_instance_range_end;
266
+ that.bacnetServerEnabled = config.bacnetServerEnabled;
279
267
 
280
268
  if(that.scheduler !== null) {
281
269
  that.scheduler.stop();
282
270
  }
283
271
 
284
- try{
285
- that.client = new bacnet({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
272
+ try {
273
+ that.client._settings.apduTimeout = config.apduTimeout;
274
+ that.client._settings.interface = config.localIpAdrress;
275
+ that.client._settings.port = config.port;
276
+ that.client._settings.broadcastAddress = config.broadCastAddr;
277
+
278
+ that.client._transport.interface = config.localIpAdrress;
279
+ that.client._transport.port = config.port;
280
+ that.client._transport.broadcastAddress = config.broadCastAddr;
286
281
 
287
282
  const task = new Task('simple task', () => {
288
283
  that.globalWhoIs();
@@ -295,11 +290,12 @@ class BacnetClient extends EventEmitter {
295
290
  that.globalWhoIs();
296
291
 
297
292
  } catch(e){
298
- console.log("Error reinitializing bacnet client: ", e)
293
+ that.logOut("Error reinitializing bacnet client: ", e)
299
294
  }
300
295
  };
301
296
 
302
- getValidPointProperties(point, requestedProps){
297
+ getValidPointProperties(point, requestedProps) {
298
+ let that = this;
303
299
  let availableProps = point.propertyList;
304
300
  let newProps = [];
305
301
 
@@ -311,7 +307,7 @@ class BacnetClient extends EventEmitter {
311
307
  //add object name for use in formatting
312
308
  newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
313
309
  } catch(e){
314
- console.log("Issue finding valid object properties, see error: ", e);
310
+ that.logOut("Issue finding valid object properties, see error: ", e);
315
311
  }
316
312
 
317
313
  return newProps;
@@ -319,49 +315,42 @@ class BacnetClient extends EventEmitter {
319
315
 
320
316
  doRead(readConfig, outputType, objectPropertyType, msgId) {
321
317
  let that = this;
322
-
323
318
  that.roundDecimal = readConfig.precision;
324
319
  let devicesToRead = Object.keys(readConfig.pointsToRead);
325
- let propertiesToRead = readConfig.objectProperties;
326
320
 
327
321
  try {
322
+ let bacnetResults = {};
323
+ devicesToRead.forEach(function(key, index) {
324
+ let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
325
+ let deviceName = device.getDeviceName();
326
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
327
+ let deviceObject = that.networkTree[deviceKey];
328
+ if(!bacnetResults[deviceName]) bacnetResults[deviceName] = {};
329
+ if(deviceObject) {
330
+ for(const pointName in readConfig.pointsToRead[key]) {
331
+ let bac_obj = that.getObjectType(readConfig.pointsToRead[key][pointName].objectID.type);
332
+ let objectId = pointName + "_" + bac_obj + '_' + readConfig.pointsToRead[key][pointName].objectID.instance;
333
+ let point = deviceObject[objectId];
334
+ bacnetResults[deviceName][pointName] = point;
335
+ }
336
+ }
328
337
 
329
- // const requestArray1 = [{
330
- // objectId: { type: baEnum.ObjectType.OBJECT_TRENDLOG, instance: 300002 },
331
- // properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
332
- // { id: baEnum.PropertyIdentifier.LOG_BUFFER }]
333
- // }];
334
-
335
- // this.client.readPropertyMultiple("10.0.8.202", requestArray1, that.readPropertyMultipleOptions, (error, value) => {
336
- // console.log("error: ", error);
337
- // console.log("value: ", value.values[0].values[0]);
338
- // console.log("value: ", value.values[0].values[1]);
339
- // //console.log(JSON.stringify(value));
340
- // });
341
-
342
- // that.client.readRange("10.0.8.202", 300002, 1, 5, {}, (error, value) => {
343
- // console.log("that.client.readRange: ");
344
- // console.log("error: ", error);
345
- // console.log("value: ", value);
346
- // });
347
-
348
-
349
-
350
- devicesToRead.forEach(function(deviceId) {
351
- let readPromiseArray = [];
352
- let pointsToReadNames = Object.keys(readConfig.pointsToRead[deviceId]);
353
- let device = that.deviceList.find(ele => ele.getDeviceId() == deviceId);
354
- pointsToReadNames.forEach(function(pointName, index) {
355
- let point = readConfig.pointsToRead[deviceId][pointName];
356
- readPromiseArray.push(that._readObjectFull(device.getAddress(), point.meta.objectId.type, point.meta.objectId.instance));
357
- });
358
- that.readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId);
338
+ if(index == devicesToRead.length - 1) that.emit('values', bacnetResults, outputType, objectPropertyType);
359
339
  });
360
-
361
- } catch(e){
362
- console.log("Issue doing read, see error: ", e);
340
+ } catch(e) {
341
+ that.logOut("Issue doing read, see error: ", e);
363
342
  }
343
+ }
364
344
 
345
+ getDeviceAddress(device) {
346
+ switch(typeof device.getAddress()) {
347
+ case "object":
348
+ return device.getAddress().address;
349
+ case "string":
350
+ return device.getAddress();
351
+ default:
352
+ return device.getAddress();
353
+ }
365
354
  }
366
355
 
367
356
  readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId) {
@@ -390,15 +379,6 @@ class BacnetClient extends EventEmitter {
390
379
  let bac_obj = that.getObjectType(currobjectId);
391
380
  let objectId;
392
381
  objectId = objectName;
393
-
394
- /*
395
- if(objectName !== null) {
396
- objectName = objectName.split(" ").join("_");
397
- objectId = objectName + "_" + bac_obj + '_' + point.objectId.instance;
398
- } else {
399
- objectId = bac_obj + '_' + point.objectId.instance;
400
- }
401
- */
402
382
 
403
383
  //init json object
404
384
  if(!values[objectId]) values[objectId] = {};
@@ -408,7 +388,14 @@ class BacnetClient extends EventEmitter {
408
388
  if(object.value[0] &&
409
389
  object.value[0].value !== "undefined" &&
410
390
  object.value[0].value !== null &&
411
- typeof object.value[0].value == "number") values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
391
+ typeof object.value[0].value == "number") {
392
+ values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
393
+ } else if(object.value[0] &&
394
+ object.value[0].value !== "undefined" &&
395
+ object.value[0].value !== null &&
396
+ typeof object.value[0].value == "string") {
397
+ values[objectId].presentValue = object.value[0].value;
398
+ }
412
399
  break;
413
400
  case baEnum.PropertyIdentifier.DESCRIPTION:
414
401
  if(object.value[0]) values[objectId].description = object.value[0].value;
@@ -455,7 +442,7 @@ class BacnetClient extends EventEmitter {
455
442
  bacnetResults[deviceName] = values;
456
443
 
457
444
  } catch(e) {
458
- console.log("issue resolving bacnet payload, see error: ", e);
445
+ that.logOut("issue resolving bacnet payload, see error: ", e);
459
446
  }
460
447
  });
461
448
  if(Object.keys(bacnetResults[deviceName]).length !== 0) {
@@ -467,7 +454,7 @@ class BacnetClient extends EventEmitter {
467
454
  });
468
455
 
469
456
  } catch(e){
470
- console.log("Issue reading from device, see error: ", e);
457
+ that.logOut("Issue reading from device, see error: ", e);
471
458
  }
472
459
  }
473
460
 
@@ -481,10 +468,10 @@ class BacnetClient extends EventEmitter {
481
468
  if(object.value[0]) {
482
469
  resolve(object.value[0].value);
483
470
  } else {
484
- console.log("Issue with deviceName payload, see object: ", object);
471
+ that.logOut("Issue with deviceName payload, see object: ", object);
485
472
  }
486
473
  } catch(e){
487
- console.log("Unable to get device name: ", e);
474
+ that.logOut("Unable to get device name: ", e);
488
475
  }
489
476
  });
490
477
  }
@@ -493,9 +480,10 @@ class BacnetClient extends EventEmitter {
493
480
  }
494
481
 
495
482
  getPropertiesForType(props, type) {
483
+ let that = this;
496
484
  let newProps = [];
497
485
  props.forEach(function(prop) {
498
- //console.log(prop);
486
+ //that.logOut(prop);
499
487
  switch(type){
500
488
  case 0: //analog-input
501
489
  newProps.push(prop);
@@ -533,11 +521,12 @@ class BacnetClient extends EventEmitter {
533
521
  let that = this;
534
522
  return new Promise(async function(resolve, reject) {
535
523
  try {
536
- let result = await that.scanDevice(device);
524
+ device.setManualDiscoveryMode(false);
525
+ let result = await that.scanDevice(device);
537
526
  device.setPointsList(result);
538
527
  resolve(result);
539
528
  } catch(e) {
540
- console.log(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
529
+ that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
541
530
  reject(e);
542
531
  }
543
532
  });
@@ -547,6 +536,7 @@ class BacnetClient extends EventEmitter {
547
536
  let that = this;
548
537
  return new Promise(function(resolve, reject) {
549
538
  try {
539
+ device.setManualDiscoveryMode(true);
550
540
  that.scanDeviceManually(device).then(function(result) {
551
541
  device.setPointsList(result);
552
542
  resolve(result);
@@ -556,7 +546,7 @@ class BacnetClient extends EventEmitter {
556
546
 
557
547
 
558
548
  } catch(e) {
559
- console.log("Error getting point list: ", e);
549
+ that.logOut("Error getting point list: ", e);
560
550
  reject(e);
561
551
  }
562
552
 
@@ -565,12 +555,9 @@ class BacnetClient extends EventEmitter {
565
555
 
566
556
  scanDeviceManually(device) {
567
557
  let that = this;
568
- // console.log("scanning device: ", device.getAddress());
569
558
  return new Promise(function(resolve, reject) {
570
559
  let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
571
560
  let address = device.getAddress();
572
- //let deviceInstance = device.deviceId();
573
- //let objectTypeList = [0, 1, 2, 3, 4, 5, 8, 13, 14, 19];
574
561
  let objectTypeList = [0, 1, 2, 3];
575
562
  let instanceRange = {start: 0, end: 100};
576
563
  let requestArray = [];
@@ -579,8 +566,6 @@ class BacnetClient extends EventEmitter {
579
566
  let requestBuffer = [];
580
567
  let sendBuffer = [];
581
568
 
582
- //requestBuffer.push(that._readObjectFull(address, 8, deviceInstance));
583
-
584
569
  if(that.manual_instance_range_enabled == true) {
585
570
  instanceRange.start = that.manual_instance_range_start;
586
571
  maxRequestThreshold = that.manual_instance_range_end;
@@ -616,8 +601,7 @@ class BacnetClient extends EventEmitter {
616
601
  instanceRange.end = 100;
617
602
  };
618
603
 
619
- function send() {
620
- //console.log("request buffer size: ", requestBuffer.length);
604
+ function send() {
621
605
 
622
606
  for(let index = 0; index < requestBuffer.length; index++) {
623
607
  let promise = requestBuffer[index];
@@ -630,7 +614,6 @@ class BacnetClient extends EventEmitter {
630
614
  let ele = value.values[x];
631
615
  let valueRoot = ele.values[0].value[0];
632
616
  if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
633
- // console.log("pushing to send buffer");
634
617
  sendBuffer.push({"value": ele.objectId, "type": 12});
635
618
  }
636
619
  }
@@ -638,14 +621,12 @@ class BacnetClient extends EventEmitter {
638
621
  }
639
622
 
640
623
  if(index == requestBuffer.length - 1) {
641
- // console.log("resolving send buffer");
642
624
  resolve(sendBuffer);
643
625
  }
644
626
 
645
627
  }).catch(function(error) {
646
628
  reject(error);
647
629
  });
648
-
649
630
  } catch(e) {
650
631
  reject(e)
651
632
  }
@@ -656,7 +637,6 @@ class BacnetClient extends EventEmitter {
656
637
 
657
638
  _readObjectWithRequestArray(deviceAddress, requestArray) {
658
639
  let that = this;
659
-
660
640
  return new Promise((resolve, reject) => {
661
641
  this.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, (error, value) => {
662
642
  resolve({
@@ -706,30 +686,16 @@ class BacnetClient extends EventEmitter {
706
686
  try {
707
687
  that.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
708
688
  } catch(e) {
709
- console.log("Error reading object list: ", e);
689
+ that.logOut("Error reading object list: ", e);
710
690
  }
711
691
  }
712
692
 
713
693
  _readObjectFull(deviceAddress, type, instance) {
714
694
 
715
695
  return this._readObject(deviceAddress, type, instance, [
716
- { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
717
- { id: baEnum.PropertyIdentifier.OBJECT_NAME },
718
- { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
719
- { id: baEnum.PropertyIdentifier.DESCRIPTION },
720
- { id: baEnum.PropertyIdentifier.UNITS },
721
- { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
722
- { id: baEnum.PropertyIdentifier.PROPERTY_LIST },
723
- { id: baEnum.PropertyIdentifier.STATUS_FLAGS },
724
- { id: baEnum.PropertyIdentifier.RELIABILITY },
725
- { id: baEnum.PropertyIdentifier.OUT_OF_SERVICE },
726
-
727
- { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
728
- { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
729
- { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
730
- { id: baEnum.PropertyIdentifier.RECORD_COUNT }
731
-
696
+ { id: baEnum.PropertyIdentifier.ALL }
732
697
  ]);
698
+
733
699
  };
734
700
 
735
701
  _readObjectPropList(deviceAddress, type, instance) {
@@ -761,7 +727,7 @@ class BacnetClient extends EventEmitter {
761
727
  options.pointsToWrite.forEach(function(point){
762
728
 
763
729
  let deviceAddress = point.deviceAddress;
764
-
730
+
765
731
  if(valuesArray[deviceAddress] == null || valuesArray[deviceAddress] == undefined){
766
732
  valuesArray[deviceAddress] = [];
767
733
  }
@@ -807,11 +773,11 @@ class BacnetClient extends EventEmitter {
807
773
  Promise.all(writePromises).then(function(result) {
808
774
  resolve(result);
809
775
  }).catch(function(e) {
810
- console.log("Error writing: ", e);
776
+ that.logOut("Error writing: ", e);
811
777
  });
812
778
  });
813
779
  } catch (error) {
814
- console.log(error);
780
+ that.logOut(error);
815
781
  }
816
782
  }
817
783
 
@@ -873,16 +839,17 @@ class BacnetClient extends EventEmitter {
873
839
  }
874
840
 
875
841
  scanDevice(device) {
842
+ let that = this;
876
843
  return new Promise((resolve, reject) => {
877
844
  this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
878
845
  if (!err) {
879
846
  try {
880
847
  resolve(result.values[0].values[0].value);
881
848
  } catch(e) {
882
- console.log("Issue with getting device point list, see error: ", e);
849
+ that.logOut("Issue with getting device point list, see error: ", e);
883
850
  }
884
851
  } else {
885
- logger.log('error', `Error while fetching objects: ${err}`);
852
+ that.logOut(`Error while fetching objects: ${err}`);
886
853
  reject(err);
887
854
  }
888
855
  });
@@ -893,7 +860,7 @@ class BacnetClient extends EventEmitter {
893
860
  shutDownClient() {
894
861
  let that = this;
895
862
  if(that.client) that.client.close((err, result) => {
896
- console.log(err, result);
863
+ that.logOut(err, result);
897
864
  });
898
865
  };
899
866
 
@@ -912,24 +879,6 @@ class BacnetClient extends EventEmitter {
912
879
 
913
880
  if(that.client) {
914
881
  that.client.whoIs({'net': 65535});
915
-
916
- //that.client.whoIs(options);
917
- //that.client.whoIs({'net':3});
918
-
919
- // that.client.whoIs({'net':3001});
920
-
921
- // read a point through a router to an MSTP device
922
- // that.client.readProperty({address: '10.0.8.212',net:3001,adr:[20]} , {type: 8, instance: 2002}, 77, (err, value) => {
923
- // console.log('value: ', value);
924
- // console.log('err: ', err);
925
- // });
926
-
927
- // that.client.readProperty({address: '10.0.8.212',net:3001,adr:[20]} , {type: 8, instance: 2002}, 77, (err, value) => {
928
- // console.log('value: ', value);
929
- // console.log('err: ', err);
930
- // });
931
-
932
-
933
882
  } else {
934
883
  that.reinitializeClient(that.config);
935
884
  }
@@ -962,83 +911,94 @@ class BacnetClient extends EventEmitter {
962
911
 
963
912
  buildNetworkTreeData() {
964
913
  let that = this;
914
+ that.buildTreeMutex = new Mutex();
965
915
  let displayNameCharThreshold = 40;
966
916
  return new Promise(async function(resolve, reject) {
967
917
  if(!that.renderList) that.renderList = [];
968
918
  if(that.deviceList && that.networkTree) {
969
919
  that.deviceList.forEach(function(deviceInfo, index) {
970
- let ipAddr = deviceInfo.getAddress();
971
- let deviceId = deviceInfo.getDeviceId();
972
- let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
973
- let deviceObject = that.networkTree[deviceId];
974
- let isMstpDevice = deviceInfo.getIsMstpDevice();
975
-
976
- if(deviceObject) {
977
- let children = [];
978
- let pointIndex = 0;
979
-
980
- for(const pointName in deviceObject) {
981
- //console.log("buidling tree obj for: ", pointName);
982
- let pointProperties = [];
983
- let values = deviceObject[pointName];
984
- let displayName = pointName;
985
- if(pointName.length > displayNameCharThreshold) {
986
- displayName = "";
987
- let charArray = pointName.split("");
988
- for(let i = 0; i < charArray.length; i++){
989
- if(i < displayNameCharThreshold){
990
- displayName += charArray[i];
920
+ that.buildTreeMutex
921
+ .acquire()
922
+ .then(function(release) {
923
+
924
+ let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
925
+ let deviceId = deviceInfo.getDeviceId();
926
+ let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
927
+ let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
928
+ let deviceObject = that.networkTree[deviceKey];
929
+ let isMstpDevice = deviceInfo.getIsMstpDevice();
930
+ let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
931
+
932
+ if(deviceObject) {
933
+ let children = [];
934
+ let pointIndex = 0;
935
+
936
+ for(const pointName in deviceObject) {
937
+ let pointProperties = [];
938
+ let values = deviceObject[pointName];
939
+ let displayName = pointName;
940
+ if(pointName.length > displayNameCharThreshold) {
941
+ displayName = "";
942
+ let charArray = pointName.split("");
943
+ for(let i = 0; i < charArray.length; i++) {
944
+ if(i < displayNameCharThreshold){
945
+ displayName += charArray[i];
946
+ }
991
947
  }
948
+ displayName += "...";
992
949
  }
993
- displayName += "...";
994
- }
995
950
 
996
- if(values.objectName){
997
- pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
998
- }
999
- if(values.objectType){
1000
- pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
1001
- }
1002
- if(values.objectID && values.objectID.instance) {
1003
- pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
1004
- }
1005
- if(values.description){
1006
- pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
1007
- }
1008
- if(values.units){
1009
- pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
1010
- }
1011
- if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
1012
- pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
1013
- }
1014
- if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
1015
- pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
951
+ if(values.objectName){
952
+ pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
953
+ }
954
+ if(values.objectType){
955
+ pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
956
+ }
957
+ if(values.objectID && values.objectID.instance) {
958
+ pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
959
+ }
960
+ if(values.description){
961
+ pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
962
+ }
963
+ if(values.units){
964
+ pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
965
+ }
966
+ if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
967
+ pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
968
+ }
969
+ if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
970
+ pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
971
+ }
972
+ if(values.modificationDate && !values.modificationDate.errorClass) {
973
+ pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
974
+ }
975
+ if(values.programState){
976
+ pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
977
+ }
978
+ if(values.recordCount && !values.recordCount.errorClass){
979
+ pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
980
+ }
981
+
982
+ 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})
983
+ pointIndex++;
1016
984
  }
1017
- if(values.modificationDate && !values.modificationDate.errorClass) {
1018
- pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
985
+ let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
986
+ if(foundIndex !== -1) {
987
+ 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};
988
+ } else if(foundIndex == -1) {
989
+ 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});
1019
990
  }
1020
- if(values.programState){
1021
- pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
991
+ if(index == that.deviceList.length - 1) {
992
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1022
993
  }
1023
- if(values.recordCount && !values.recordCount.errorClass){
1024
- pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
994
+ } else {
995
+ if(index == that.deviceList.length - 1) {
996
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1025
997
  }
1026
-
1027
- 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})
1028
- pointIndex++;
1029
998
  }
1030
- let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
1031
- if(foundIndex !== -1) {
1032
- that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
1033
- } else if(foundIndex == -1) {
1034
- that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
1035
- }
1036
- if(index == that.deviceList.length - 1) {
1037
- resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1038
- }
1039
- } else {
1040
- if(index == that.deviceList.length - 1) resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1041
- }
999
+
1000
+ release();
1001
+ });
1042
1002
  });
1043
1003
  }
1044
1004
  });
@@ -1048,26 +1008,49 @@ class BacnetClient extends EventEmitter {
1048
1008
  let that = this;
1049
1009
  let address = device.address;
1050
1010
  let pointList = device.getPointsList();
1011
+ let requestMutex = new Mutex();
1051
1012
 
1052
1013
  return new Promise(function(resolve, reject) {
1053
1014
  let promiseArray = [];
1054
1015
  if(typeof pointList !== "undefined" && pointList.length > 0) {
1055
1016
  pointList.forEach(function(point, pointListIndex) {
1056
- promiseArray.push(that._readObjectFull(address, point.value.type, point.value.instance));
1057
- if(pointListIndex == pointList.length - 1) {
1058
- Promise.all(promiseArray).then(function(objectList){
1059
- that.buildResponse(objectList, device).then(function() {
1060
- that.lastNetworkPoll = Date.now();
1061
- resolve({deviceList: that.deviceList, pointList: that.networkTree});
1062
- }).catch(function(e){
1063
- console.log("Error while building json object: ", e);
1064
- reject(e);
1065
- });
1017
+ requestMutex
1018
+ .acquire()
1019
+ .then(function(release) {
1020
+ that._readObjectFull(address, point.value.type, point.value.instance).then(function(result) {
1021
+
1022
+ if(!result.error) {
1023
+ promiseArray.push(result);
1024
+ }
1025
+
1026
+ release();
1027
+
1028
+ if(pointListIndex == pointList.length - 1) {
1029
+ that.buildResponse(promiseArray, device).then(function() {
1030
+ that.lastNetworkPoll = Date.now();
1031
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1032
+ }).catch(function(e){
1033
+ that.logOut("Error while building json object: ", e);
1034
+ reject(e);
1035
+ });
1036
+ }
1037
+
1066
1038
  }).catch(function(e) {
1067
- console.log("Error while building json object: ", e);
1068
- reject(e);
1039
+ release();
1040
+ that.logOut("_readObjectFull error: ", e);
1041
+
1042
+ if(pointListIndex == pointList.length - 1) {
1043
+ that.buildResponse(promiseArray, device).then(function() {
1044
+ that.lastNetworkPoll = Date.now();
1045
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1046
+ }).catch(function(e){
1047
+ that.logOut("Error while building json object: ", e);
1048
+ reject(e);
1049
+ });
1050
+ }
1051
+
1069
1052
  });
1070
- }
1053
+ });
1071
1054
  });
1072
1055
  } else {
1073
1056
  reject("Unable to build network tree, empty point list");
@@ -1079,7 +1062,8 @@ class BacnetClient extends EventEmitter {
1079
1062
  buildResponse(fullObjects, device) {
1080
1063
  let that = this;
1081
1064
  return new Promise(function(resolve, reject) {
1082
- let values = that.networkTree[device.getDeviceId()] ? that.networkTree[device.getDeviceId()] : {};
1065
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
1066
+ let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
1083
1067
  for(let i = 0; i < fullObjects.length; i++) {
1084
1068
  let obj = fullObjects[i];
1085
1069
  let successfulResult = !obj.error ? obj.value : null;
@@ -1091,7 +1075,6 @@ class BacnetClient extends EventEmitter {
1091
1075
  let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
1092
1076
  let objectId;
1093
1077
  if(objectName !== null) {
1094
- //objectName = objectName.split(" ").join("_");
1095
1078
  objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
1096
1079
  } else {
1097
1080
  objectId = bac_obj + '_' + pointProperty.objectId.instance;
@@ -1099,7 +1082,9 @@ class BacnetClient extends EventEmitter {
1099
1082
  try {
1100
1083
  pointProperty.values.forEach(function(object, objectIndex) {
1101
1084
  //checks for error code json structure, returned for invalid bacnet requests
1102
- if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1085
+ //if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1086
+ if(object && object.value && !object.value.errorClass) {
1087
+
1103
1088
 
1104
1089
  if(!values[objectId]) values[objectId] = {};
1105
1090
  values[objectId].meta = {
@@ -1116,6 +1101,9 @@ class BacnetClient extends EventEmitter {
1116
1101
  } else if(object.value[0].value == 1) {
1117
1102
  values[objectId].presentValue = true;
1118
1103
  }
1104
+ } else if(objectType == 40) {
1105
+ //character string
1106
+ values[objectId].presentValue = object.value[0].value;
1119
1107
  } else {
1120
1108
  values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
1121
1109
  }
@@ -1163,23 +1151,23 @@ class BacnetClient extends EventEmitter {
1163
1151
  if(object.value[0] ) {
1164
1152
  values[objectId].recordCount = object.value[0].value;
1165
1153
  }
1166
- break;
1154
+ break;
1167
1155
  }
1168
1156
  }
1169
1157
  if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
1170
- that.networkTree[device.getDeviceId()] = values;
1158
+ that.networkTree[deviceKey] = values;
1171
1159
  resolve(that.networkTree);
1172
1160
  }
1173
1161
  });
1174
1162
  } catch(e) {
1175
- console.log("issue resolving bacnet payload, see error: ", e);
1163
+ that.logOut("issue resolving bacnet payload, see error: ", e);
1176
1164
  reject(e);
1177
1165
  }
1178
1166
  });
1179
1167
  } else {
1180
1168
  //error found in point property
1181
1169
  if(i == fullObjects.length - 1) {
1182
- that.networkTree[device.getDeviceId()] = values;
1170
+ that.networkTree[deviceKey] = values;
1183
1171
  resolve(that.networkTree);
1184
1172
  }
1185
1173
  }
@@ -1316,6 +1304,8 @@ class BacnetClient extends EventEmitter {
1316
1304
  return "MO";
1317
1305
  case 19:
1318
1306
  return "MV";
1307
+ case 40:
1308
+ return "CS";
1319
1309
  default:
1320
1310
  return "";
1321
1311
  }
@@ -1360,14 +1350,19 @@ class BacnetClient extends EventEmitter {
1360
1350
  return flags.value[0].value;
1361
1351
  }
1362
1352
 
1363
- getDeviceIcon(isMstp){
1364
- if(isMstp == true) {
1365
- return "pi pi-share-alt"
1366
- } else if(isMstp == false) {
1367
- return "pi pi-server"
1353
+ getDeviceIcon(isMstp, manualDiscoveryMode) {
1354
+ if(manualDiscoveryMode == true) {
1355
+ return "pi pi-exclamation-triangle"
1356
+ } else if(manualDiscoveryMode == false) {
1357
+ if(isMstp == true) {
1358
+ return "pi pi-share-alt"
1359
+ } else if(isMstp == false) {
1360
+ return "pi pi-server"
1361
+ }
1368
1362
  }
1363
+
1369
1364
  return "pi pi-server";
1370
- }
1365
+ };
1371
1366
  }
1372
1367
 
1373
1368
  module.exports = { BacnetClient };