@bitpoolos/edge-bacnet 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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,31 @@ 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 {
328
-
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);
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
+ bacnetResults[deviceName] = readConfig.pointsToRead[key];
327
+ if(index == devicesToRead.length - 1) that.emit('values', bacnetResults, outputType, objectPropertyType);
359
328
  });
360
-
361
- } catch(e){
362
- console.log("Issue doing read, see error: ", e);
329
+ } catch(e) {
330
+ that.logOut("Issue doing read, see error: ", e);
363
331
  }
332
+ }
364
333
 
334
+ getDeviceAddress(device){
335
+ switch(typeof device.getAddress()) {
336
+ case "object":
337
+ return device.getAddress().address;
338
+ case "string":
339
+ return device.getAddress();
340
+ default:
341
+ return device.getAddress();
342
+ }
365
343
  }
366
344
 
367
345
  readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId) {
@@ -390,15 +368,6 @@ class BacnetClient extends EventEmitter {
390
368
  let bac_obj = that.getObjectType(currobjectId);
391
369
  let objectId;
392
370
  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
371
 
403
372
  //init json object
404
373
  if(!values[objectId]) values[objectId] = {};
@@ -408,7 +377,14 @@ class BacnetClient extends EventEmitter {
408
377
  if(object.value[0] &&
409
378
  object.value[0].value !== "undefined" &&
410
379
  object.value[0].value !== null &&
411
- typeof object.value[0].value == "number") values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
380
+ typeof object.value[0].value == "number") {
381
+ values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
382
+ } else if(object.value[0] &&
383
+ object.value[0].value !== "undefined" &&
384
+ object.value[0].value !== null &&
385
+ typeof object.value[0].value == "string") {
386
+ values[objectId].presentValue = object.value[0].value;
387
+ }
412
388
  break;
413
389
  case baEnum.PropertyIdentifier.DESCRIPTION:
414
390
  if(object.value[0]) values[objectId].description = object.value[0].value;
@@ -455,7 +431,7 @@ class BacnetClient extends EventEmitter {
455
431
  bacnetResults[deviceName] = values;
456
432
 
457
433
  } catch(e) {
458
- console.log("issue resolving bacnet payload, see error: ", e);
434
+ that.logOut("issue resolving bacnet payload, see error: ", e);
459
435
  }
460
436
  });
461
437
  if(Object.keys(bacnetResults[deviceName]).length !== 0) {
@@ -467,7 +443,7 @@ class BacnetClient extends EventEmitter {
467
443
  });
468
444
 
469
445
  } catch(e){
470
- console.log("Issue reading from device, see error: ", e);
446
+ that.logOut("Issue reading from device, see error: ", e);
471
447
  }
472
448
  }
473
449
 
@@ -481,10 +457,10 @@ class BacnetClient extends EventEmitter {
481
457
  if(object.value[0]) {
482
458
  resolve(object.value[0].value);
483
459
  } else {
484
- console.log("Issue with deviceName payload, see object: ", object);
460
+ that.logOut("Issue with deviceName payload, see object: ", object);
485
461
  }
486
462
  } catch(e){
487
- console.log("Unable to get device name: ", e);
463
+ that.logOut("Unable to get device name: ", e);
488
464
  }
489
465
  });
490
466
  }
@@ -493,9 +469,10 @@ class BacnetClient extends EventEmitter {
493
469
  }
494
470
 
495
471
  getPropertiesForType(props, type) {
472
+ let that = this;
496
473
  let newProps = [];
497
474
  props.forEach(function(prop) {
498
- //console.log(prop);
475
+ //that.logOut(prop);
499
476
  switch(type){
500
477
  case 0: //analog-input
501
478
  newProps.push(prop);
@@ -533,11 +510,12 @@ class BacnetClient extends EventEmitter {
533
510
  let that = this;
534
511
  return new Promise(async function(resolve, reject) {
535
512
  try {
536
- let result = await that.scanDevice(device);
513
+ device.setManualDiscoveryMode(false);
514
+ let result = await that.scanDevice(device);
537
515
  device.setPointsList(result);
538
516
  resolve(result);
539
517
  } catch(e) {
540
- console.log(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
518
+ that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
541
519
  reject(e);
542
520
  }
543
521
  });
@@ -547,6 +525,7 @@ class BacnetClient extends EventEmitter {
547
525
  let that = this;
548
526
  return new Promise(function(resolve, reject) {
549
527
  try {
528
+ device.setManualDiscoveryMode(true);
550
529
  that.scanDeviceManually(device).then(function(result) {
551
530
  device.setPointsList(result);
552
531
  resolve(result);
@@ -556,7 +535,7 @@ class BacnetClient extends EventEmitter {
556
535
 
557
536
 
558
537
  } catch(e) {
559
- console.log("Error getting point list: ", e);
538
+ that.logOut("Error getting point list: ", e);
560
539
  reject(e);
561
540
  }
562
541
 
@@ -565,12 +544,9 @@ class BacnetClient extends EventEmitter {
565
544
 
566
545
  scanDeviceManually(device) {
567
546
  let that = this;
568
- // console.log("scanning device: ", device.getAddress());
569
547
  return new Promise(function(resolve, reject) {
570
548
  let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
571
549
  let address = device.getAddress();
572
- //let deviceInstance = device.deviceId();
573
- //let objectTypeList = [0, 1, 2, 3, 4, 5, 8, 13, 14, 19];
574
550
  let objectTypeList = [0, 1, 2, 3];
575
551
  let instanceRange = {start: 0, end: 100};
576
552
  let requestArray = [];
@@ -579,8 +555,6 @@ class BacnetClient extends EventEmitter {
579
555
  let requestBuffer = [];
580
556
  let sendBuffer = [];
581
557
 
582
- //requestBuffer.push(that._readObjectFull(address, 8, deviceInstance));
583
-
584
558
  if(that.manual_instance_range_enabled == true) {
585
559
  instanceRange.start = that.manual_instance_range_start;
586
560
  maxRequestThreshold = that.manual_instance_range_end;
@@ -616,8 +590,7 @@ class BacnetClient extends EventEmitter {
616
590
  instanceRange.end = 100;
617
591
  };
618
592
 
619
- function send() {
620
- //console.log("request buffer size: ", requestBuffer.length);
593
+ function send() {
621
594
 
622
595
  for(let index = 0; index < requestBuffer.length; index++) {
623
596
  let promise = requestBuffer[index];
@@ -630,7 +603,6 @@ class BacnetClient extends EventEmitter {
630
603
  let ele = value.values[x];
631
604
  let valueRoot = ele.values[0].value[0];
632
605
  if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
633
- // console.log("pushing to send buffer");
634
606
  sendBuffer.push({"value": ele.objectId, "type": 12});
635
607
  }
636
608
  }
@@ -638,14 +610,12 @@ class BacnetClient extends EventEmitter {
638
610
  }
639
611
 
640
612
  if(index == requestBuffer.length - 1) {
641
- // console.log("resolving send buffer");
642
613
  resolve(sendBuffer);
643
614
  }
644
615
 
645
616
  }).catch(function(error) {
646
617
  reject(error);
647
618
  });
648
-
649
619
  } catch(e) {
650
620
  reject(e)
651
621
  }
@@ -656,7 +626,6 @@ class BacnetClient extends EventEmitter {
656
626
 
657
627
  _readObjectWithRequestArray(deviceAddress, requestArray) {
658
628
  let that = this;
659
-
660
629
  return new Promise((resolve, reject) => {
661
630
  this.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, (error, value) => {
662
631
  resolve({
@@ -706,30 +675,16 @@ class BacnetClient extends EventEmitter {
706
675
  try {
707
676
  that.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
708
677
  } catch(e) {
709
- console.log("Error reading object list: ", e);
678
+ that.logOut("Error reading object list: ", e);
710
679
  }
711
680
  }
712
681
 
713
682
  _readObjectFull(deviceAddress, type, instance) {
714
683
 
715
684
  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
-
685
+ { id: baEnum.PropertyIdentifier.ALL }
732
686
  ]);
687
+
733
688
  };
734
689
 
735
690
  _readObjectPropList(deviceAddress, type, instance) {
@@ -761,7 +716,7 @@ class BacnetClient extends EventEmitter {
761
716
  options.pointsToWrite.forEach(function(point){
762
717
 
763
718
  let deviceAddress = point.deviceAddress;
764
-
719
+
765
720
  if(valuesArray[deviceAddress] == null || valuesArray[deviceAddress] == undefined){
766
721
  valuesArray[deviceAddress] = [];
767
722
  }
@@ -807,11 +762,11 @@ class BacnetClient extends EventEmitter {
807
762
  Promise.all(writePromises).then(function(result) {
808
763
  resolve(result);
809
764
  }).catch(function(e) {
810
- console.log("Error writing: ", e);
765
+ that.logOut("Error writing: ", e);
811
766
  });
812
767
  });
813
768
  } catch (error) {
814
- console.log(error);
769
+ that.logOut(error);
815
770
  }
816
771
  }
817
772
 
@@ -873,16 +828,17 @@ class BacnetClient extends EventEmitter {
873
828
  }
874
829
 
875
830
  scanDevice(device) {
831
+ let that = this;
876
832
  return new Promise((resolve, reject) => {
877
833
  this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
878
834
  if (!err) {
879
835
  try {
880
836
  resolve(result.values[0].values[0].value);
881
837
  } catch(e) {
882
- console.log("Issue with getting device point list, see error: ", e);
838
+ that.logOut("Issue with getting device point list, see error: ", e);
883
839
  }
884
840
  } else {
885
- logger.log('error', `Error while fetching objects: ${err}`);
841
+ that.logOut(`Error while fetching objects: ${err}`);
886
842
  reject(err);
887
843
  }
888
844
  });
@@ -893,7 +849,7 @@ class BacnetClient extends EventEmitter {
893
849
  shutDownClient() {
894
850
  let that = this;
895
851
  if(that.client) that.client.close((err, result) => {
896
- console.log(err, result);
852
+ that.logOut(err, result);
897
853
  });
898
854
  };
899
855
 
@@ -912,24 +868,6 @@ class BacnetClient extends EventEmitter {
912
868
 
913
869
  if(that.client) {
914
870
  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
871
  } else {
934
872
  that.reinitializeClient(that.config);
935
873
  }
@@ -962,83 +900,94 @@ class BacnetClient extends EventEmitter {
962
900
 
963
901
  buildNetworkTreeData() {
964
902
  let that = this;
903
+ that.buildTreeMutex = new Mutex();
965
904
  let displayNameCharThreshold = 40;
966
905
  return new Promise(async function(resolve, reject) {
967
906
  if(!that.renderList) that.renderList = [];
968
907
  if(that.deviceList && that.networkTree) {
969
908
  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];
909
+ that.buildTreeMutex
910
+ .acquire()
911
+ .then(function(release) {
912
+
913
+ let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
914
+ let deviceId = deviceInfo.getDeviceId();
915
+ let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
916
+ let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
917
+ let deviceObject = that.networkTree[deviceKey];
918
+ let isMstpDevice = deviceInfo.getIsMstpDevice();
919
+ let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
920
+
921
+ if(deviceObject) {
922
+ let children = [];
923
+ let pointIndex = 0;
924
+
925
+ for(const pointName in deviceObject) {
926
+ let pointProperties = [];
927
+ let values = deviceObject[pointName];
928
+ let displayName = pointName;
929
+ if(pointName.length > displayNameCharThreshold) {
930
+ displayName = "";
931
+ let charArray = pointName.split("");
932
+ for(let i = 0; i < charArray.length; i++) {
933
+ if(i < displayNameCharThreshold){
934
+ displayName += charArray[i];
935
+ }
991
936
  }
937
+ displayName += "...";
992
938
  }
993
- displayName += "...";
994
- }
995
939
 
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});
940
+ if(values.objectName){
941
+ pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
942
+ }
943
+ if(values.objectType){
944
+ pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
945
+ }
946
+ if(values.objectID && values.objectID.instance) {
947
+ pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
948
+ }
949
+ if(values.description){
950
+ pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
951
+ }
952
+ if(values.units){
953
+ pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
954
+ }
955
+ if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
956
+ pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
957
+ }
958
+ if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
959
+ pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
960
+ }
961
+ if(values.modificationDate && !values.modificationDate.errorClass) {
962
+ pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
963
+ }
964
+ if(values.programState){
965
+ pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
966
+ }
967
+ if(values.recordCount && !values.recordCount.errorClass){
968
+ pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
969
+ }
970
+
971
+ 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})
972
+ pointIndex++;
1016
973
  }
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});
974
+ let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
975
+ if(foundIndex !== -1) {
976
+ 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};
977
+ } else if(foundIndex == -1) {
978
+ 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
979
  }
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});
980
+ if(index == that.deviceList.length - 1) {
981
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1022
982
  }
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});
983
+ } else {
984
+ if(index == that.deviceList.length - 1) {
985
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1025
986
  }
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
987
  }
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
- }
988
+
989
+ release();
990
+ });
1042
991
  });
1043
992
  }
1044
993
  });
@@ -1048,26 +997,49 @@ class BacnetClient extends EventEmitter {
1048
997
  let that = this;
1049
998
  let address = device.address;
1050
999
  let pointList = device.getPointsList();
1000
+ let requestMutex = new Mutex();
1051
1001
 
1052
1002
  return new Promise(function(resolve, reject) {
1053
1003
  let promiseArray = [];
1054
1004
  if(typeof pointList !== "undefined" && pointList.length > 0) {
1055
1005
  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
- });
1006
+ requestMutex
1007
+ .acquire()
1008
+ .then(function(release) {
1009
+ that._readObjectFull(address, point.value.type, point.value.instance).then(function(result) {
1010
+
1011
+ if(!result.error) {
1012
+ promiseArray.push(result);
1013
+ }
1014
+
1015
+ release();
1016
+
1017
+ if(pointListIndex == pointList.length - 1) {
1018
+ that.buildResponse(promiseArray, device).then(function() {
1019
+ that.lastNetworkPoll = Date.now();
1020
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1021
+ }).catch(function(e){
1022
+ that.logOut("Error while building json object: ", e);
1023
+ reject(e);
1024
+ });
1025
+ }
1026
+
1066
1027
  }).catch(function(e) {
1067
- console.log("Error while building json object: ", e);
1068
- reject(e);
1028
+ release();
1029
+ that.logOut("_readObjectFull error: ", e);
1030
+
1031
+ if(pointListIndex == pointList.length - 1) {
1032
+ that.buildResponse(promiseArray, device).then(function() {
1033
+ that.lastNetworkPoll = Date.now();
1034
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1035
+ }).catch(function(e){
1036
+ that.logOut("Error while building json object: ", e);
1037
+ reject(e);
1038
+ });
1039
+ }
1040
+
1069
1041
  });
1070
- }
1042
+ });
1071
1043
  });
1072
1044
  } else {
1073
1045
  reject("Unable to build network tree, empty point list");
@@ -1079,7 +1051,8 @@ class BacnetClient extends EventEmitter {
1079
1051
  buildResponse(fullObjects, device) {
1080
1052
  let that = this;
1081
1053
  return new Promise(function(resolve, reject) {
1082
- let values = that.networkTree[device.getDeviceId()] ? that.networkTree[device.getDeviceId()] : {};
1054
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
1055
+ let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
1083
1056
  for(let i = 0; i < fullObjects.length; i++) {
1084
1057
  let obj = fullObjects[i];
1085
1058
  let successfulResult = !obj.error ? obj.value : null;
@@ -1091,7 +1064,6 @@ class BacnetClient extends EventEmitter {
1091
1064
  let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
1092
1065
  let objectId;
1093
1066
  if(objectName !== null) {
1094
- //objectName = objectName.split(" ").join("_");
1095
1067
  objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
1096
1068
  } else {
1097
1069
  objectId = bac_obj + '_' + pointProperty.objectId.instance;
@@ -1099,7 +1071,9 @@ class BacnetClient extends EventEmitter {
1099
1071
  try {
1100
1072
  pointProperty.values.forEach(function(object, objectIndex) {
1101
1073
  //checks for error code json structure, returned for invalid bacnet requests
1102
- if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1074
+ //if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1075
+ if(object && object.value && !object.value.errorClass) {
1076
+
1103
1077
 
1104
1078
  if(!values[objectId]) values[objectId] = {};
1105
1079
  values[objectId].meta = {
@@ -1116,6 +1090,9 @@ class BacnetClient extends EventEmitter {
1116
1090
  } else if(object.value[0].value == 1) {
1117
1091
  values[objectId].presentValue = true;
1118
1092
  }
1093
+ } else if(objectType == 40) {
1094
+ //character string
1095
+ values[objectId].presentValue = object.value[0].value;
1119
1096
  } else {
1120
1097
  values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
1121
1098
  }
@@ -1163,23 +1140,23 @@ class BacnetClient extends EventEmitter {
1163
1140
  if(object.value[0] ) {
1164
1141
  values[objectId].recordCount = object.value[0].value;
1165
1142
  }
1166
- break;
1143
+ break;
1167
1144
  }
1168
1145
  }
1169
1146
  if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
1170
- that.networkTree[device.getDeviceId()] = values;
1147
+ that.networkTree[deviceKey] = values;
1171
1148
  resolve(that.networkTree);
1172
1149
  }
1173
1150
  });
1174
1151
  } catch(e) {
1175
- console.log("issue resolving bacnet payload, see error: ", e);
1152
+ that.logOut("issue resolving bacnet payload, see error: ", e);
1176
1153
  reject(e);
1177
1154
  }
1178
1155
  });
1179
1156
  } else {
1180
1157
  //error found in point property
1181
1158
  if(i == fullObjects.length - 1) {
1182
- that.networkTree[device.getDeviceId()] = values;
1159
+ that.networkTree[deviceKey] = values;
1183
1160
  resolve(that.networkTree);
1184
1161
  }
1185
1162
  }
@@ -1316,6 +1293,8 @@ class BacnetClient extends EventEmitter {
1316
1293
  return "MO";
1317
1294
  case 19:
1318
1295
  return "MV";
1296
+ case 40:
1297
+ return "CS";
1319
1298
  default:
1320
1299
  return "";
1321
1300
  }
@@ -1360,14 +1339,19 @@ class BacnetClient extends EventEmitter {
1360
1339
  return flags.value[0].value;
1361
1340
  }
1362
1341
 
1363
- getDeviceIcon(isMstp){
1364
- if(isMstp == true) {
1365
- return "pi pi-share-alt"
1366
- } else if(isMstp == false) {
1367
- return "pi pi-server"
1342
+ getDeviceIcon(isMstp, manualDiscoveryMode) {
1343
+ if(manualDiscoveryMode == true) {
1344
+ return "pi pi-exclamation-triangle"
1345
+ } else if(manualDiscoveryMode == false) {
1346
+ if(isMstp == true) {
1347
+ return "pi pi-share-alt"
1348
+ } else if(isMstp == false) {
1349
+ return "pi pi-server"
1350
+ }
1368
1351
  }
1352
+
1369
1353
  return "pi pi-server";
1370
- }
1354
+ };
1371
1355
  }
1372
1356
 
1373
1357
  module.exports = { BacnetClient };