@bitpoolos/edge-bacnet 1.2.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bacnet_client.js CHANGED
@@ -2,1719 +2,1809 @@
2
2
  MIT License Copyright 2021, 2024 - Bitpool Pty Ltd
3
3
  */
4
4
 
5
- const bacnet = require('./resources/node-bacstack-ts/dist/index.js');
5
+ const bacnet = require("./resources/node-bacstack-ts/dist/index.js");
6
6
  const baEnum = bacnet.enum;
7
7
  const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
8
- const { EventEmitter } = require('events');
9
- const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber } = require('./common');
10
- const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
11
- const { BacnetDevice } = require('./bacnet_device');
12
- const {Mutex} = require("async-mutex");
8
+ const { EventEmitter } = require("events");
9
+ const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber, decodeBitArray } = require("./common");
10
+ const { ToadScheduler, SimpleIntervalJob, Task } = require("toad-scheduler");
11
+ const { BacnetDevice } = require("./bacnet_device");
12
+ const { Mutex } = require("async-mutex");
13
+ const { treeBuilder } = require("./treeBuilder.js");
13
14
 
14
15
  class BacnetClient extends EventEmitter {
16
+ //client constructor
17
+ constructor(config) {
18
+ super();
19
+ let that = this;
20
+ that.config = config;
21
+ that.deviceList = [];
22
+ that.networkTree = {};
23
+ that.lastWhoIs = null;
24
+ that.client = null;
25
+ that.lastNetworkPoll = null;
26
+ that.scheduler = new ToadScheduler();
27
+ that.mutex = new Mutex();
28
+ that.manualMutex = new Mutex();
29
+ that.pollInProgress = false;
30
+ that.scanMatrix = [];
31
+ that.renderListCount = 0;
32
+
33
+ try {
34
+ if (that.config.cacheFileEnabled) {
35
+ let cachedData = JSON.parse(Read_Config_Sync());
36
+ if (cachedData && typeof cachedData == "object") {
37
+ if (cachedData.renderList) that.renderList = cachedData.renderList;
38
+ if (cachedData.deviceList) {
39
+ cachedData.deviceList.forEach(function (device) {
40
+ let newBacnetDevice = new BacnetDevice(true, device);
41
+ that.deviceList.push(newBacnetDevice);
42
+ });
43
+ }
44
+ if (cachedData.pointList) that.networkTree = cachedData.pointList;
45
+ if (cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
46
+ }
47
+ }
48
+
49
+ that.roundDecimal = config.roundDecimal;
50
+ that.apduSize = config.apduSize;
51
+ that.maxSegments = config.maxSegments;
52
+ that.discover_polling_schedule = config.discover_polling_schedule;
53
+ that.deviceId = config.deviceId;
54
+ that.broadCastAddr = config.broadCastAddr;
55
+ that.device_read_schedule = config.device_read_schedule;
56
+ that.deviceRetryCount = parseInt(config.retries);
57
+ that.sanitise_device_schedule = config.sanitise_device_schedule;
58
+ that.buildTreeException = false;
59
+
60
+ that.readPropertyMultipleOptions = {
61
+ maxSegments: 112,
62
+ maxApdu: 5,
63
+ };
64
+
65
+ try {
66
+ that.client = new bacnet.Client({
67
+ apduTimeout: config.apduTimeout,
68
+ interface: config.localIpAdrress,
69
+ port: config.port,
70
+ broadcastAddress: config.broadCastAddr,
71
+ });
72
+ that.setMaxListeners(1);
15
73
 
16
- //client constructor
17
- constructor(config) {
18
- super();
19
- let that = this;
20
- that.deviceList = [];
21
- that.manualDiscoverQueue = [];
22
- that.networkTree = {};
23
- that.lastWhoIs = null;
24
- that.client = null;
25
- that.lastNetworkPoll = null;
26
- that.scheduler = new ToadScheduler();
27
- that.mutex = new Mutex();
28
- that.manualMutex = new Mutex();
29
- that.pollInProgress = false;
30
- that.scanMatrix = [];
31
- that.renderListCount = 0;
32
-
33
- try {
74
+ const task = new Task("simple task", () => {
75
+ that.globalWhoIs();
76
+ });
34
77
 
35
- if(config.cacheFileEnabled) {
36
- let cachedData = JSON.parse(Read_Config_Sync());
37
- if(cachedData && typeof cachedData == "object") {
38
- if(cachedData.renderList) that.renderList = cachedData.renderList;
39
- if(cachedData.deviceList) {
40
- cachedData.deviceList.forEach(function(device) {
41
- let newBacnetDevice = new BacnetDevice(true, device);
42
- that.deviceList.push(newBacnetDevice);
43
- });
44
- }
45
- if(cachedData.pointList) that.networkTree = cachedData.pointList;
46
- if(cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
47
- }
48
- }
78
+ const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule) }, task);
49
79
 
50
- that.config = config;
51
- that.roundDecimal = config.roundDecimal;
52
- that.apduSize = config.apduSize;
53
- that.maxSegments = config.maxSegments;
54
- that.discover_polling_schedule = config.discover_polling_schedule;
55
- that.deviceId = config.deviceId;
56
- that.broadCastAddr = config.broadCastAddr;
57
- that.manual_instance_range_enabled = config.manual_instance_range_enabled;
58
- that.manual_instance_range_start = config.manual_instance_range_start;
59
- that.manual_instance_range_end = config.manual_instance_range_end;
60
- that.device_read_schedule = config.device_read_schedule;
61
- that.deviceRetryCount = parseInt(config.retries);
62
-
63
- that.readPropertyMultipleOptions = {
64
- maxSegments: 112,
65
- maxApdu: 5
66
- };
80
+ that.scheduler.addSimpleIntervalJob(job);
67
81
 
68
- try {
69
-
70
- that.client = new bacnet.Client({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
71
- that.setMaxListeners(1);
82
+ //query device task
83
+ const queryDevices = new Task("simple task", () => {
84
+ if (!that.pollInProgress) that.queryDevices();
85
+ });
72
86
 
73
- const task = new Task('simple task', () => {
74
- that.globalWhoIs();
75
- });
87
+ const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule) }, queryDevices);
76
88
 
77
- const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, task)
78
-
79
- that.scheduler.addSimpleIntervalJob(job);
89
+ that.scheduler.addSimpleIntervalJob(queryJob);
80
90
 
81
- //query device task
82
- const queryDevices = new Task('simple task', () => {
83
- if(!that.pollInProgress) that.queryDevices();
84
- that.sanitizeDeviceList();
85
- });
91
+ //buildNetworkTreeData task
92
+ const buildNetworkTree = new Task("simple task", () => {
86
93
 
87
- const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule), }, queryDevices)
88
-
89
- that.scheduler.addSimpleIntervalJob(queryJob);
94
+ that.doTreeBuilder();
95
+ that.countDevices();
90
96
 
91
- //buildNetworkTreeData task
92
- const buildNetworkTree = new Task('simple task', () => {
93
- that.buildNetworkTreeData().then(function() {
94
- that.countDevices();
95
- });
96
- });
97
+ });
97
98
 
98
- const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
99
-
100
- that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
99
+ const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 5 }, buildNetworkTree);
100
+
101
+ that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
102
+
103
+ that.globalWhoIs();
104
+
105
+ setTimeout(() => {
106
+ that.queryDevices();
107
+ }, "5000");
108
+ } catch (e) {
109
+ that.logOut("Issue initializing client: ", e);
110
+ }
111
+
112
+ //who is callback
113
+ that.client.on("iAm", (device) => {
114
+ if (device.address !== that.config.localIpAdrress) {
115
+ if (that.scanMatrix.length > 0) {
116
+ let matrixMap = that.scanMatrix.filter((ele) => device.deviceId >= ele.start && device.deviceId <= ele.end);
117
+ if (matrixMap.length > 0) {
118
+ //only add unique device to array
119
+ let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
120
+ if (foundIndex == -1) {
121
+ let newBacnetDevice = new BacnetDevice(false, device);
122
+ newBacnetDevice.setLastSeen(Date.now());
123
+ if (newBacnetDevice.getIsMstpDevice()) {
124
+ that.addToParentMstpNetwork(newBacnetDevice);
125
+ }
126
+ that.deviceList.push(newBacnetDevice);
127
+ } else if (foundIndex !== -1) {
128
+ that.deviceList[foundIndex].updateDeviceConfig(device);
129
+ that.deviceList[foundIndex].setLastSeen(Date.now());
130
+ if (that.deviceList[foundIndex].getIsMstpDevice()) {
131
+ that.addToParentMstpNetwork(that.deviceList[foundIndex]);
132
+ }
133
+ }
101
134
 
102
- that.globalWhoIs();
135
+ //emit event for node-red to log
136
+ that.emit("deviceFound", device);
137
+ }
138
+ } else {
139
+ //only add unique device to array
140
+ let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
141
+ if (foundIndex == -1) {
142
+ let newBacnetDevice = new BacnetDevice(false, device);
143
+ newBacnetDevice.setLastSeen(Date.now());
144
+ if (newBacnetDevice.getIsMstpDevice()) {
145
+ that.addToParentMstpNetwork(newBacnetDevice);
146
+ }
147
+ that.deviceList.push(newBacnetDevice);
148
+ } else if (foundIndex !== -1) {
149
+ that.deviceList[foundIndex].updateDeviceConfig(device);
150
+ that.deviceList[foundIndex].setLastSeen(Date.now());
151
+ if (that.deviceList[foundIndex].getIsMstpDevice()) {
152
+ that.addToParentMstpNetwork(that.deviceList[foundIndex]);
153
+ }
154
+ }
103
155
 
104
- setTimeout(() => {
105
- that.queryDevices();
106
- that.sanitizeDeviceList();
107
- that.buildNetworkTreeData().then(function() {
108
- that.countDevices();
109
- });
110
- }, "5000")
156
+ //emit event for node-red to log
157
+ that.emit("deviceFound", device);
158
+ }
159
+ }
160
+ });
161
+ } catch (e) {
162
+ that.logOut("Issue with creating bacnet client, see error: ", e);
163
+ }
111
164
 
112
- } catch(e) {
113
- that.logOut("Issue initializing client: ", e)
114
- }
165
+ that.client.on("error", (err) => {
166
+ that.logOut("Error occurred: ", err);
167
+
168
+ if (err.errno == -4090) {
169
+ that.logOut("Invalid Client information or incorrect IP address provided");
170
+ } else if (err.errno == -49) {
171
+ that.logOut("Invalid IP address provided");
172
+ } else {
173
+ that.reinitializeClient(that.config);
174
+ }
175
+ });
176
+ }
177
+
178
+ testFunction(address, type, instance, property) {
179
+ let that = this;
180
+
181
+ console.log("test function ");
182
+
183
+ that.client.readProperty(
184
+ address,
185
+ { type: type, instance: instance },
186
+ property,
187
+ that.readPropertyMultipleOptions,
188
+ (err, value) => {
189
+ if (err) {
190
+ console.log("err: ", err);
191
+ }
115
192
 
116
- //who is callback
117
- that.client.on('iAm', (device) => {
118
- //console.log("found iAm device: ", device);
119
- if(device.address !== that.config.localIpAdrress) {
120
- if(that.scanMatrix.length > 0) {
121
- let matrixMap = that.scanMatrix.filter(ele => device.deviceId >= ele.start && device.deviceId <= ele.end);
122
- if(matrixMap.length > 0) {
123
- //only add unique device to array
124
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
125
- if(foundIndex == -1) {
126
- let newBacnetDevice = new BacnetDevice(false, device);
127
- newBacnetDevice.setLastSeen(Date.now());
128
- that.updateDeviceName(newBacnetDevice);
129
- if(newBacnetDevice.getIsMstpDevice()) {
130
- that.addToParentMstpNetwork(newBacnetDevice);
131
- }
132
- that.deviceList.push(newBacnetDevice);
133
-
134
- } else if(foundIndex !== -1) {
135
- that.deviceList[foundIndex].updateDeviceConfig(device);
136
- that.deviceList[foundIndex].setLastSeen(Date.now());
137
- that.updateDeviceName(that.deviceList[foundIndex]);
138
-
139
- if(that.deviceList[foundIndex].getIsMstpDevice()) {
140
- that.addToParentMstpNetwork(that.deviceList[foundIndex]);
141
- }
142
- }
143
-
144
- //emit event for node-red to log
145
- that.emit('deviceFound', device);
146
- }
147
- } else {
148
- //only add unique device to array
149
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
150
- if(foundIndex == -1) {
151
- let newBacnetDevice = new BacnetDevice(false, device);
152
- newBacnetDevice.setLastSeen(Date.now());
153
- that.updateDeviceName(newBacnetDevice);
154
- if(newBacnetDevice.getIsMstpDevice()) {
155
- that.addToParentMstpNetwork(newBacnetDevice);
156
- }
157
- that.deviceList.push(newBacnetDevice);
158
- } else if(foundIndex !== -1) {
159
- that.deviceList[foundIndex].updateDeviceConfig(device);
160
- that.deviceList[foundIndex].setLastSeen(Date.now());
161
- that.updateDeviceName(that.deviceList[foundIndex]);
162
-
163
- if(that.deviceList[foundIndex].getIsMstpDevice()) {
164
- that.addToParentMstpNetwork(that.deviceList[foundIndex]);
165
- }
193
+ if (value) {
194
+ console.log("value : ", value);
195
+ console.log("value1 : ", value.values[0].value);
196
+ }
197
+ }
198
+ );
199
+ }
200
+
201
+ getProtocolSupported(device) {
202
+ //return protocols support for device
203
+ let that = this;
204
+ return new Promise((resolve, reject) => {
205
+ that.client.readProperty(
206
+ device.getAddress(),
207
+ { type: baEnum.ObjectType.DEVICE, instance: device.getDeviceId() },
208
+ baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED,
209
+ that.readPropertyMultipleOptions,
210
+ (err, value) => {
211
+ if (err) {
212
+ reject(err);
213
+ }
214
+
215
+ if (value) {
216
+ resolve(value);
217
+ }
218
+ }
219
+ );
220
+ });
221
+
222
+ }
223
+
224
+ addToParentMstpNetwork(device) {
225
+ let that = this;
226
+ let address = device.getAddress().address;
227
+ let deviceId = device.getDeviceId();
228
+ let foundParentIndex = that.deviceList.findIndex((ele) => ele.getAddress() == address);
229
+ if (foundParentIndex !== -1) {
230
+ that.deviceList[foundParentIndex].addChildDevice(deviceId);
231
+ device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
232
+ }
233
+ }
166
234
 
167
- }
168
-
169
- //emit event for node-red to log
170
- that.emit('deviceFound', device);
171
- }
172
- }
173
- });
235
+ logOut(param1, param2) {
236
+ let that = this;
237
+ that.emit("bacnetErrorLog", param1, param2);
238
+ }
174
239
 
175
- } catch(e) {
176
- that.logOut("Issue with creating bacnet client, see error: ", e);
240
+ rebuildDataModel() {
241
+ let that = this;
242
+ return new Promise((resolve, reject) => {
243
+ try {
244
+ that.deviceList = [];
245
+ that.renderList = [];
246
+ that.networkTree = {};
247
+ that.pollInProgress = false;
248
+ that.renderListCount = 0;
249
+ resolve(true);
250
+ } catch (e) {
251
+ that.logOut("Error clearing BACnet data model: ", e);
252
+ reject(e);
253
+ }
254
+ });
255
+ }
256
+
257
+ purgeDevice(device) {
258
+ let that = this;
259
+ return new Promise((resolve, reject) => {
260
+ try {
261
+ let renderListIndex = that.renderList.findIndex(
262
+ (ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address
263
+ );
264
+ let deviceListIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
265
+ let deviceKey = device.address + "-" + device.deviceId;
266
+ delete that.networkTree[deviceKey];
267
+ that.renderList.splice(renderListIndex, 1);
268
+ that.deviceList.splice(deviceListIndex, 1);
269
+
270
+ that.countDevices();
271
+
272
+ resolve(true);
273
+ } catch (e) {
274
+ reject(e);
275
+ }
276
+ });
277
+ }
278
+
279
+ updatePointsForDevice(deviceObject) {
280
+ let that = this;
281
+ return new Promise((resolve, reject) => {
282
+ try {
283
+ let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
284
+ that.updateDeviceName(device);
285
+
286
+ if (device.getIsProtocolServicesSet() == false) {
287
+ that.getProtocolSupported(device).then(function (result) {
288
+ let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
289
+ device.setProtocolServicesSupported(decodedValues);
290
+ }).catch(function (error) {
291
+ that.logOut("getProtocolSupported error: ", error);
292
+ });
177
293
  }
178
294
 
179
- that.client.on('error', (err) => {
180
- that.logOut('Error occurred: ', err);
295
+ that
296
+ .getDevicePointList(device)
297
+ .then(function () {
298
+ that
299
+ .buildJsonObject(device)
300
+ .then(function () {
301
+ // do nothing for now
302
+ resolve(true);
303
+ })
304
+ .catch(function (e) {
305
+ that.logOut(`Update points list error 1: ${device.getAddress()}`, e);
306
+ });
307
+ })
308
+ .catch(function (e) {
309
+ that.logOut(`Update points list error 2: ${device.getAddress()}`, e);
310
+ device.setManualDiscoveryMode(true);
311
+ that
312
+ .getDevicePointListWithoutObjectList(device)
313
+ .then(function () {
314
+ that
315
+ .buildJsonObject(device)
316
+ .then(function () {
317
+ // do nothing for now
318
+ resolve(true);
319
+ })
320
+ .catch(function (e) {
321
+ that.logOut(`Update points list error 3: ${device.getAddress()}`, e);
322
+ });
323
+ })
324
+ .catch(function (e) {
325
+ that.logOut(`Update points list error 4: ${device.getAddress()}`, e);
326
+ });
327
+ });
328
+ } catch (e) {
329
+ reject(e);
330
+ }
331
+ });
332
+ }
333
+
334
+ setDeviceDisplayName(deviceObject, displayName) {
335
+ let that = this;
336
+ return new Promise((resolve, reject) => {
337
+ try {
338
+ let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
339
+
340
+ device.setDisplayName(displayName);
341
+
342
+ that.buildTreeException = true;
343
+
344
+ resolve(true);
345
+ } catch (e) {
346
+ that.logOut("setDeviceDisplayName error: ", e);
347
+
348
+ reject(e);
349
+ }
350
+ });
351
+ }
352
+
353
+ setPointDisplayName(deviceKey, pointName, pointDisplayName) {
354
+ let that = this;
355
+ return new Promise((resolve, reject) => {
356
+ try {
357
+ if (that.networkTree[deviceKey][pointName]) {
358
+ that.networkTree[deviceKey][pointName].displayName = pointDisplayName;
359
+ }
181
360
 
182
- if(err.errno == -4090){
183
- that.logOut("Invalid Client information or incorrect IP address provided");
184
- } else if(err.errno == -49) {
185
- that.logOut("Invalid IP address provided");
186
- } else {
187
- that.reinitializeClient(that.config);
361
+ that.buildTreeException = true;
362
+
363
+ resolve(true);
364
+ } catch (e) {
365
+ that.logOut("setPointDisplayName error: ", e);
366
+ reject(e);
367
+ }
368
+ });
369
+ }
370
+
371
+ importReadList(payload) {
372
+ let that = this;
373
+
374
+ return new Promise((resolve, reject) => {
375
+ try {
376
+ that.buildTreeException = true;
377
+
378
+ for (let key in payload) {
379
+ let device = payload[key];
380
+ for (let pointName in device) {
381
+ let pointObject = device[pointName]
382
+ if (that.networkTree[key][pointName]) {
383
+ that.networkTree[key][pointName] = pointObject;
188
384
  }
189
- });
190
- }
385
+ }
386
+ }
387
+ resolve(true);
388
+ } catch (e) {
389
+ that.logOut("importReadList error: ", e);
390
+ reject(e);
391
+ }
392
+ });
393
+ }
191
394
 
192
- testFunction() {
193
- console.log("test function ");
395
+ queryDevices() {
396
+ let that = this;
194
397
 
398
+ that.pollInProgress = true;
195
399
 
400
+ let index = 0;
196
401
 
197
- }
402
+ query(index);
198
403
 
199
- addToParentMstpNetwork(device) {
200
- let that = this;
201
- let address = device.getAddress().address;
202
- let deviceId = device.getDeviceId();
203
- let foundParentIndex = that.deviceList.findIndex(ele => ele.getAddress() == address);
204
- if(foundParentIndex !== -1) {
205
- that.deviceList[foundParentIndex].addChildDevice(deviceId);
206
- device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
207
- }
208
- }
404
+ function query(index) {
405
+ let device = that.deviceList[index];
209
406
 
210
- logOut(param1, param2) {
211
- let that = this;
212
- that.emit('bacnetErrorLog', param1, param2);
213
- }
407
+ if (index < that.deviceList.length) {
408
+ index++;
214
409
 
215
- rebuildDataModel() {
216
- let that = this;
217
- return new Promise((resolve, reject) => {
410
+ if (typeof device == "object") {
411
+ if (device.getIsProtocolServicesSet() == false) {
412
+ that.getProtocolSupported(device).then(function (result) {
413
+ let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
414
+ device.setProtocolServicesSupported(decodedValues);
415
+ }).catch(function (error) {
416
+ that.logOut("getProtocolSupported error: ", error);
417
+ });
418
+ }
419
+
420
+ if (!device.getManualDiscoveryMode()) {
218
421
  try {
219
- that.deviceList = [];
220
- that.renderList = [];
221
- that.networkTree = {};
222
- that.pollInProgress = false;
223
- that.renderListCount = 0;
224
- resolve(true);
225
- } catch(e) {
226
- that.logOut("Error clearing BACnet data model: ", e);
227
- reject(e);
422
+ that.updateDeviceName(device);
423
+ that
424
+ .getDevicePointList(device)
425
+ .then(function () {
426
+ that
427
+ .buildJsonObject(device)
428
+ .then(function () {
429
+ query(index);
430
+ })
431
+ .catch(function (e) {
432
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
433
+ query(index);
434
+ });
435
+ })
436
+ .catch(function (e) {
437
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
438
+ device.setManualDiscoveryMode(true);
439
+ that
440
+ .getDevicePointListWithoutObjectList(device)
441
+ .then(function () {
442
+ that
443
+ .buildJsonObject(device)
444
+ .then(function () {
445
+ query(index);
446
+ })
447
+ .catch(function (e) {
448
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
449
+ query(index);
450
+ });
451
+ })
452
+ .catch(function (e) {
453
+ query(index);
454
+ });
455
+ });
456
+ } catch (e) {
457
+ that.logOut("Error while querying devices: ", e);
458
+ query(index);
228
459
  }
229
- });
230
- }
231
-
232
- queryDevices() {
233
- let that = this;
234
-
235
- that.pollInProgress = true;
236
-
237
- let index = 0;
238
-
239
- query(index);
240
-
241
- function query(index) {
242
-
243
- that.queryPriorityDevices().then(function() {
244
-
245
- let device = that.deviceList[index];
246
-
247
- if(index < that.deviceList.length) {
248
- index++;
249
-
250
- if(typeof device == "object") {
251
- if(!device.getManualDiscoveryMode()) {
252
- try {
253
- that.getDevicePointList(device).then(function() {
254
- that.removeDeviceFromManualQueue(device);
255
- that.buildJsonObject(device, null).then(function() {
256
- query(index);
257
- }).catch(function(e) {
258
- that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
259
- query(index);
260
- });
261
- }).catch(function(e) {
262
- that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
263
- device.setManualDiscoveryMode(true);
264
- that.getDevicePointListWithoutObjectList(device).then(function() {
265
- that.buildJsonObject(device, null).then(function() {
266
- query(index);
267
- }).catch(function(e) {
268
- that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
269
- query(index);
270
- });
271
- }).catch(function(e){
272
- query(index);
273
- });
274
- });
275
- } catch(e) {
276
- that.logOut("Error while querying devices: ", e);
277
- query(index);
278
- }
279
- } else {
280
- query(index);
281
- }
282
- } else {
283
- that.logOut("queryDevices: invalid device found: ", device);
284
- query(index);
285
- }
286
- } else if(index == that.deviceList.length) {
287
-
288
- if(that.manualDiscoverQueue.length > 0) {
289
- that.queryDevicesManually();
290
- } else {
291
- that.pollInProgress = false;
292
- }
293
- }
294
- });
460
+ } else {
461
+ query(index);
462
+ }
463
+ } else {
464
+ that.logOut("queryDevices: invalid device found: ", device);
465
+ query(index);
295
466
  }
296
-
467
+ } else if (index == that.deviceList.length) {
468
+ that.pollInProgress = false;
469
+ }
297
470
  }
298
-
299
- queryDevicesManually() {
300
- let that = this;
301
- let index = 0;
302
- query(index);
303
-
304
- function query(index) {
305
- that.queryPriorityDevices().then(function() {
306
- let device = that.manualDiscoverQueue[index];
307
- if(index < that.manualDiscoverQueue.length) {
308
- index++;
309
- if(typeof device == "object") {
310
- try {
311
- if(device.shouldBeInManualMode()) {
312
- that.getDevicePointListWithoutObjectList(device).then(function() {
313
- that.buildJsonObject(device, null).then(function() {
314
- query(index);
315
- }).catch(function(e) {
316
- that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
317
- query(index);
318
- });
319
- }).catch(function(e){
320
- query(index);
321
- });
322
- } else {
323
- that.removeDeviceFromManualQueue(device);
324
- query(index);
325
- }
326
- } catch(e) {
327
- query(index);
328
- }
329
- } else {
330
- query(index);
331
- }
332
- } else if(index == that.manualDiscoverQueue.length) {
333
- that.pollInProgress = false;
334
- }
335
- });
336
- }
471
+ }
472
+
473
+ updateDeviceName(device) {
474
+ let that = this;
475
+ that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function (deviceObject) {
476
+ if (typeof deviceObject.name == "string") {
477
+ device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
478
+ device.setPointsList(deviceObject.devicePointEntry);
479
+ }
480
+ });
481
+ }
482
+
483
+ reinitializeClient(config) {
484
+ let that = this;
485
+
486
+ that.config = config;
487
+ that.roundDecimal = config.roundDecimal;
488
+ that.apduSize = config.apduSize;
489
+ that.maxSegments = config.maxSegments;
490
+ that.discover_polling_schedule = config.discover_polling_schedule;
491
+ that.deviceId = config.deviceId;
492
+ that.broadCastAddr = config.broadCastAddr;
493
+ that.device_read_schedule = config.device_read_schedule;
494
+
495
+ if (that.scheduler !== null) {
496
+ that.scheduler.stop();
337
497
  }
338
498
 
339
- queryPriorityDevices() {
340
- let that = this;
341
- return new Promise((resolve, reject) => {
342
- let priorityDevices = that.getPriorityDevices();
343
-
344
- if(priorityDevices.length > 0) {
345
- let index = 0;
346
-
347
- query(index);
348
-
349
- function query(index) {
350
- let device = priorityDevices[index];
351
-
352
- if(index < priorityDevices.length) {
353
- index++;
354
-
355
- if(typeof device == "object" && ((Date.now() - device.getLastPriorityQueueTS()) / 1000) > parseInt(that.device_read_schedule) ) {
356
-
357
- try {
358
- let points = device.getPriorityQueue();
359
- that.buildJsonObject(device, points).then(function() {
360
- device.setLastPriorityQueueTS();
361
- query(index);
362
- }).catch(function(e) {
363
- that.logOut(`queryPriorityDevices error: ${device.getAddress()}`, e);
364
- query(index);
365
- });
366
-
367
- } catch(e) {
368
- that.logOut("Error while querying priority devices: ", e);
369
- query(index);
370
- }
371
-
372
- } else {
373
- query(index);
374
- }
375
- } else if(index == priorityDevices.length) {
376
- resolve()
377
- }
378
- }
379
- } else if(priorityDevices.length == 0) {
380
- resolve()
381
- }
382
- });
383
- }
499
+ try {
500
+ that.client._settings.apduTimeout = config.apduTimeout;
501
+ that.client._settings.interface = config.localIpAdrress;
502
+ that.client._settings.port = config.port;
503
+ that.client._settings.broadcastAddress = config.broadCastAddr;
384
504
 
385
- addDeviceToManualQueue(device) {
386
- let that = this;
505
+ that.client._transport.interface = config.localIpAdrress;
506
+ that.client._transport.port = config.port;
507
+ that.client._transport.broadcastAddress = config.broadCastAddr;
387
508
 
388
- if(device.getPointListRetryCount() > that.deviceRetryCount) {
389
- device.setManualDiscoveryMode(true);
390
- let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
391
- if(index == -1) {
392
- that.manualDiscoverQueue.push(device);
393
- }
394
- } else {
395
- device.incrementPointListRetryCount();
396
- }
397
- }
509
+ const task = new Task("simple task", () => {
510
+ that.globalWhoIs();
511
+ });
398
512
 
399
- removeDeviceFromManualQueue(device) {
400
- let that = this;
401
- device.setManualDiscoveryMode(false);
402
- device.clearPointListRetryCount()
403
- let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
404
- if(index !== -1) {
405
- that.manualDiscoverQueue.splice(index, 1);
406
- }
407
- }
513
+ const job = new SimpleIntervalJob({ seconds: parseInt(config.discover_polling_schedule) }, task);
408
514
 
409
- sanitizeDeviceList() {
410
- let that = this;
411
-
412
- //Discover frequencey x 2
413
- let timeoutThreshold = parseInt(that.discover_polling_schedule) * 2;
515
+ that.scheduler.addSimpleIntervalJob(job);
414
516
 
415
- that.deviceList.forEach(function(device, index) {
416
- if(((Date.now() - device.getLastSeen()) / 1000) > timeoutThreshold && device.getPriorityQueueIsActive() == false) {
417
- //render device hasnt responded to whoIs for disover frequency x 2
517
+ // //query device task
518
+ const queryDevices = new Task("simple task", () => {
519
+ if (!that.pollInProgress) that.queryDevices();
520
+ });
418
521
 
419
- let renderListIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
522
+ const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule) }, queryDevices);
420
523
 
421
- let ipAddr = typeof device.getAddress() == "object" ? device.getAddress().address : device.getAddress();
422
- let deviceKey = ipAddr + "-" + device.getDeviceId();
524
+ that.scheduler.addSimpleIntervalJob(queryJob);
423
525
 
424
- delete that.networkTree[deviceKey];
526
+ //buildNetworkTreeData task
527
+ const buildNetworkTree = new Task("simple task", () => {
528
+ that.doTreeBuilder();
529
+ that.countDevices();
530
+ });
425
531
 
426
- that.renderList.splice(renderListIndex, 1);
532
+ const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10 }, buildNetworkTree);
427
533
 
428
- that.deviceList.splice(index, 1);
429
- }
430
- });
431
-
534
+ that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
535
+ } catch (e) {
536
+ that.logOut("Error reinitializing bacnet client: ", e);
537
+ }
538
+ }
539
+
540
+ getValidPointProperties(point, requestedProps) {
541
+ let that = this;
542
+ let availableProps = point.propertyList;
543
+ let newProps = [];
544
+
545
+ try {
546
+ requestedProps.forEach(function (prop) {
547
+ let foundInAvailable = availableProps.find((ele) => ele === prop.id);
548
+ if (foundInAvailable) newProps.push(prop);
549
+ });
550
+ //add object name for use in formatting
551
+ newProps.push({ id: baEnum.PropertyIdentifier.OBJECT_NAME });
552
+ } catch (e) {
553
+ that.logOut("Issue finding valid object properties, see error: ", e);
432
554
  }
433
555
 
434
- updateDeviceName(device) {
435
- let that = this;
436
- that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceObject) {
437
- if(typeof deviceObject.name == "string") {
438
- device.setDeviceName(deviceObject.name);
439
- device.setPointsList(deviceObject.devicePointEntry);
440
- }
441
- });
556
+ return newProps;
557
+ }
558
+
559
+ findDeviceByKey(key, deviceList, that) {
560
+ return deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
561
+ }
562
+
563
+ getObjectId(pointName, pointConfig, that) {
564
+ // Retrieve the object type based on the point configuration
565
+ const bacObjType = that.getObjectType(pointConfig.meta.objectId.type);
566
+ // Construct the object ID string
567
+ return `${pointName}_${bacObjType}_${pointConfig.meta.objectId.instance}`;
568
+ }
569
+
570
+ createDeviceKey(device) {
571
+ // Create a device key by combining the address and device ID
572
+ const address = device.getAddress();
573
+ const deviceId = device.getDeviceId();
574
+ if (typeof address === "object") {
575
+ return `${address.address}-${deviceId}`;
576
+ } else {
577
+ return `${address}-${deviceId}`;
442
578
  }
579
+ }
443
580
 
444
- reinitializeClient(config) {
445
- let that = this;
446
-
447
- that.config = config;
448
- that.roundDecimal = config.roundDecimal;
449
- that.apduSize = config.apduSize;
450
- that.maxSegments = config.maxSegments;
451
- that.discover_polling_schedule = config.discover_polling_schedule;
452
- that.deviceId = config.deviceId;
453
- that.broadCastAddr = config.broadCastAddr;
454
- that.manual_instance_range_enabled = config.manual_instance_range_enabled;
455
- that.manual_instance_range_start = config.manual_instance_range_start;
456
- that.manual_instance_range_end = config.manual_instance_range_end;
457
- that.device_read_schedule = config.device_read_schedule;
458
-
459
- if(that.scheduler !== null) {
460
- that.scheduler.stop();
461
- }
462
581
 
463
- try {
464
- that.client._settings.apduTimeout = config.apduTimeout;
465
- that.client._settings.interface = config.localIpAdrress;
466
- that.client._settings.port = config.port;
467
- that.client._settings.broadcastAddress = config.broadCastAddr;
582
+ async doRead(readConfig, outputType, objectPropertyType, readNodeName) {
583
+ const that = this;
584
+ const roundDecimal = readConfig.precision;
585
+ const devicesToRead = Object.keys(readConfig.pointsToRead);
586
+ const bacnetResults = {};
587
+ let pendingRequests = 0;
468
588
 
469
- that.client._transport.interface = config.localIpAdrress;
470
- that.client._transport.port = config.port;
471
- that.client._transport.broadcastAddress = config.broadCastAddr;
589
+ try {
472
590
 
473
- const task = new Task('simple task', () => {
474
- that.globalWhoIs();
475
- });
591
+ // Process all devices in sequence
592
+ for (let deviceIndex = 0; deviceIndex < devicesToRead.length; deviceIndex++) {
593
+ const key = devicesToRead[deviceIndex];
594
+ const device = that.findDeviceByKey(key, that.deviceList, that);
595
+ if (!device) continue;
476
596
 
477
- const job = new SimpleIntervalJob({ seconds: parseInt(config.discover_polling_schedule), }, task)
478
-
479
- that.scheduler.addSimpleIntervalJob(job);
597
+ const deviceName = that.computeDeviceName(device);
598
+ const deviceKey = that.createDeviceKey(device);
599
+ const deviceObject = that.networkTree[deviceKey];
600
+ const maxObjectCount = that.estimateMaxObjectSize(device.getMaxApdu());
480
601
 
602
+ if (!bacnetResults[deviceName]) {
603
+ bacnetResults[deviceName] = {};
604
+ }
481
605
 
482
- // //query device task
483
- const queryDevices = new Task('simple task', () => {
484
- if(!that.pollInProgress) that.queryDevices();
485
- that.sanitizeDeviceList();
606
+ // Process points for the current device
607
+ const pointsToRead = readConfig.pointsToRead[key];
608
+ const pointNames = Object.keys(pointsToRead);
609
+ const totalPoints = pointNames.length;
610
+ let requestArray = [];
611
+ let processedPoints = 0; // Counter for processed points
612
+
613
+ // Process each point for the device in batches
614
+ for (let i = 0; i < pointNames.length; i++) {
615
+ const pointName = pointNames[i];
616
+ if (pointName === "deviceName") continue;
617
+
618
+ const pointConfig = pointsToRead[pointName];
619
+ const objectId = that.getObjectId(pointName, pointConfig, that);
620
+ const point = deviceObject[objectId];
621
+
622
+ if (point) {
623
+ point.displayName = pointConfig.displayName;
624
+
625
+ // Prepare request array for batch processing
626
+ requestArray.push({
627
+ objectId: { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
628
+ properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }],
629
+ pointRef: point,
630
+ pointName: pointName
486
631
  });
632
+ }
487
633
 
488
- const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule), }, queryDevices)
489
-
490
- that.scheduler.addSimpleIntervalJob(queryJob);
634
+ // Process the batch when the request array is full or the last point is reached
635
+ if (requestArray.length === maxObjectCount || i === pointNames.length - 1) {
636
+ if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
637
+ await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
638
+ } else {
639
+ await that.processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
640
+ }
491
641
 
492
- //buildNetworkTreeData task
493
- const buildNetworkTree = new Task('simple task', () => {
494
- that.buildNetworkTreeData();
495
- that.countDevices();
496
- });
642
+ requestArray = [];
643
+ // Increment the processed points counter
644
+ processedPoints += maxObjectCount;
645
+ }
497
646
 
498
- const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
499
-
500
- that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
647
+ // Check if all points for the device have been processed
648
+ if (processedPoints >= totalPoints) {
649
+ pendingRequests++;
650
+ // Emit the `values` event for the current device
651
+ that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName, pendingRequests, devicesToRead.length);
652
+ delete bacnetResults[deviceName];
501
653
 
502
- } catch(e){
503
- that.logOut("Error reinitializing bacnet client: ", e)
654
+ }
504
655
  }
505
- };
506
-
507
- getValidPointProperties(point, requestedProps) {
508
- let that = this;
509
- let availableProps = point.propertyList;
510
- let newProps = [];
656
+ }
657
+ } catch (error) {
658
+ that.logOut("doRead error: ", error);
659
+ }
660
+ }
661
+
662
+ async processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
663
+ try {
664
+ const results = await that.updateManyPoints(device, requestArray);
665
+ if (results.error) {
666
+ throw results.error;
667
+ }
668
+
669
+ // Process the results of the batch
670
+ results.value.values.forEach(pointResult => {
671
+ const cacheRef = requestArray.find(ele =>
672
+ ele.pointRef.meta.objectId.type === pointResult.objectId.type &&
673
+ ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
674
+ );
675
+
676
+ if (cacheRef) {
677
+ const pointRef = cacheRef.pointRef;
678
+ const pointNameRef = cacheRef.pointName;
679
+ const val = pointResult.values[0].value[0].value;
680
+
681
+ if (isNumber(val)) {
682
+ pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
683
+ if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
684
+ if (val != 0) {
685
+ pointRef.presentValue = pointRef.stateTextArray[val - 1].value;
686
+ } else {
687
+ pointRef.presentValue = pointRef.stateTextArray[val].value;
688
+ }
689
+ }
690
+ } else {
691
+ if (typeof val !== "object") {
692
+ pointRef.presentValue = val;
693
+ }
694
+ }
511
695
 
512
- try{
513
- requestedProps.forEach(function(prop) {
514
- let foundInAvailable = availableProps.find(ele => ele === prop.id);
515
- if(foundInAvailable) newProps.push(prop);
516
- });
517
- //add object name for use in formatting
518
- newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
519
- } catch(e){
520
- that.logOut("Issue finding valid object properties, see error: ", e);
696
+ // Store the point data in results
697
+ bacnetResults[deviceName][pointNameRef] = pointRef;
521
698
  }
522
-
523
- return newProps;
699
+ });
700
+ } catch (err) {
701
+ that.logOut("Error processing batch:", err);
524
702
  }
703
+ }
525
704
 
526
- doRead(readConfig, outputType, objectPropertyType, readNodeName) {
527
- let that = this;
528
- that.roundDecimal = readConfig.precision;
529
- let devicesToRead = Object.keys(readConfig.pointsToRead);
530
- try {
531
- let bacnetResults = {};
532
- devicesToRead.forEach(function(key, index) {
533
- let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
534
- if(device) {
535
- let deviceName = device.getDeviceName();
536
- let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
537
- let deviceObject = that.networkTree[deviceKey];
538
- if(!bacnetResults[deviceName]) bacnetResults[deviceName] = {};
539
- if(deviceObject) {
540
- for(const pointName in readConfig.pointsToRead[key]) {
541
- let bac_obj = that.getObjectType(readConfig.pointsToRead[key][pointName].meta.objectId.type);
542
- let objectId = pointName + "_" + bac_obj + '_' + readConfig.pointsToRead[key][pointName].meta.objectId.instance;
543
- let point = deviceObject[objectId];
544
-
545
- that.updatePoint(device, point).then(function(result) {
546
- if(isNumber(result.values[0].value)) {
547
- point.presentValue = roundDecimalPlaces(result.values[0].value, that.roundDecimal);
548
- } else {
549
- point.presentValue = result.values[0].value;
550
- }
551
- bacnetResults[deviceName][pointName] = point;
552
- }).catch(function(err) {
553
- //do nothing for now
554
- });
705
+ async processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
706
+ for (const request of requestArray) {
707
+ const { objectId, pointRef, pointName } = request;
708
+ try {
709
+ const result = await that.updatePoint(device, pointRef);
710
+ const val = result.values[0].value;
555
711
 
556
- }
557
- }
558
- }
559
-
560
- setTimeout(() => {
561
- if(index == devicesToRead.length - 1 && Object.keys(readConfig.pointsToRead).length > 0) that.emit('values', bacnetResults, outputType, objectPropertyType, readNodeName);
562
- }, 3000);
563
- });
564
- } catch(e) {
565
- that.logOut("Issue doing read, see error: ", e);
712
+ if (isNumber(val)) {
713
+ pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
714
+ } else {
715
+ pointRef.presentValue = val;
566
716
  }
567
- }
568
717
 
569
- updatePoint(device, point) {
570
- let that = this;
571
- return new Promise((resolve, reject) => {
572
-
573
- that.client.readProperty(
574
- device.getAddress(),
575
- {type: point.objectID.type, instance: point.objectID.instance },
576
- baEnum.PropertyIdentifier.PRESENT_VALUE,
577
- {},
578
- (err, value) => {
579
- if(err) {
580
- //console.log("err ", err);
581
- reject(err);
582
- }
583
-
584
- if(value) {
585
- resolve(value);
586
- }
587
- }
588
- );
589
- });
718
+ // Store the point data in results
719
+ bacnetResults[deviceName][pointName] = pointRef;
720
+ } catch (err) {
721
+ that.logOut(`Error updating point ${pointName}:`, err);
722
+ }
590
723
  }
591
-
592
- getDeviceAddress(device) {
593
- switch(typeof device.getAddress()) {
594
- case "object":
595
- return device.getAddress().address;
596
- case "string":
597
- return device.getAddress();
598
- default:
599
- return device.getAddress();
724
+ }
725
+
726
+ updateManyPoints(device, points) {
727
+ let that = this;
728
+ return new Promise((resolve, reject) => {
729
+ that._readObjectWithRequestArray(device.getAddress(), points, that.readPropertyMultipleOptions).then(function (results) {
730
+ resolve(results);
731
+ }).catch(function (err) {
732
+ reject(err);
733
+ });
734
+ });
735
+ }
736
+
737
+ updatePoint(device, point) {
738
+ let that = this;
739
+ return new Promise((resolve, reject) => {
740
+ that.client.readProperty(
741
+ device.getAddress(),
742
+ { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
743
+ baEnum.PropertyIdentifier.PRESENT_VALUE,
744
+ that.readPropertyMultipleOptions,
745
+ (err, value) => {
746
+ if (err) {
747
+ reject(err);
748
+ }
749
+ if (value) {
750
+ resolve(value);
751
+ }
600
752
  }
753
+ );
754
+ });
755
+ }
756
+
757
+ estimateMaxObjectSize(apduSize) {
758
+ if (apduSize < 500) {
759
+ return 20;
760
+ } else if (apduSize > 500 && apduSize < 1000) {
761
+ //return Math.round(((apduSize - 30) / 7));
762
+ return 50;
763
+ } else if (apduSize > 1000) {
764
+ //return Math.round(((apduSize - 30) / 7));
765
+ return 100;
601
766
  }
602
-
603
- _getDeviceName(address, deviceId) {
604
- let that = this;
605
- return new Promise((resolve, reject) => {
606
- that._readDeviceName(address, deviceId, (err, result) => {
607
- if(result) {
608
- try {
609
- if(result.values[0].value) {
610
- const deviceObject = {
611
- name: result.values[0].value,
612
- devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }]
613
- };
614
- resolve(deviceObject);
615
- } else {
616
- that.logOut("Issue with deviceName payload, see object: ", object);
617
- }
618
- } catch(e){
619
- that.logOut("Unable to get device name: ", e);
620
- }
621
- }
622
- });
623
- });
767
+ }
768
+
769
+ getDeviceAddress(device) {
770
+ switch (typeof device.getAddress()) {
771
+ case "object":
772
+ return device.getAddress().address;
773
+ case "string":
774
+ return device.getAddress();
775
+ default:
776
+ return device.getAddress();
624
777
  }
625
-
626
- getPropertiesForType(props, type) {
627
- let that = this;
628
- let newProps = [];
629
- props.forEach(function(prop) {
630
- //that.logOut(prop);
631
- switch(type){
632
- case 0: //analog-input
633
- newProps.push(prop);
634
- break;
635
- case 1: //analog-output
636
- newProps.push(prop);
637
- break;
638
- case 2: //analog-value
639
- newProps.push(prop);
640
- break;
641
- case 3: //binary-input
642
- newProps.push(prop);
643
- break;
644
- case 4: //binary-output
645
- newProps.push(prop);
646
- break;
647
- case 5: //binary-value
648
- newProps.push(prop);
649
- break;
650
- case 13:
651
- if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
652
- break;
653
- case 14:
654
- if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
655
- break;
656
- case 19:
657
- if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
658
- break;
778
+ }
779
+
780
+ _getDeviceName(address, deviceId) {
781
+ let that = this;
782
+ return new Promise((resolve, reject) => {
783
+ that._readDeviceName(address, deviceId, (err, result) => {
784
+ if (result) {
785
+ try {
786
+ if (result.values[0].value) {
787
+ const deviceObject = {
788
+ name: result.values[0].value,
789
+ devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }],
790
+ };
791
+ resolve(deviceObject);
792
+ } else {
793
+ that.logOut("Issue with deviceName payload, see object: ", object);
659
794
  }
660
- });
661
- return newProps;
662
- }
795
+ } catch (e) {
796
+ that.logOut("Unable to get device name: ", e);
797
+ }
798
+ }
799
+ });
800
+ });
801
+ }
802
+
803
+ getPropertiesForType(props, type) {
804
+ let that = this;
805
+ let newProps = [];
806
+ props.forEach(function (prop) {
807
+ //that.logOut(prop);
808
+ switch (type) {
809
+ case 0: //analog-input
810
+ newProps.push(prop);
811
+ break;
812
+ case 1: //analog-output
813
+ newProps.push(prop);
814
+ break;
815
+ case 2: //analog-value
816
+ newProps.push(prop);
817
+ break;
818
+ case 3: //binary-input
819
+ newProps.push(prop);
820
+ break;
821
+ case 4: //binary-output
822
+ newProps.push(prop);
823
+ break;
824
+ case 5: //binary-value
825
+ newProps.push(prop);
826
+ break;
827
+ case 13:
828
+ if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
829
+ newProps.push(prop);
830
+ break;
831
+ case 14:
832
+ if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
833
+ newProps.push(prop);
834
+ break;
835
+ case 19:
836
+ if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
837
+ newProps.push(prop);
838
+ break;
839
+ }
840
+ });
841
+ return newProps;
842
+ }
843
+
844
+ getDevicePointList(device) {
845
+ let that = this;
846
+ return new Promise(async function (resolve, reject) {
847
+ try {
848
+ device.setManualDiscoveryMode(false);
849
+ let result = await that.scanDevice(device);
850
+ device.setPointsList(result);
851
+ resolve(result);
852
+ } catch (e) {
853
+ that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
854
+ reject(e);
855
+ }
856
+ });
857
+ }
858
+
859
+ getDevicePointListWithoutObjectList(device) {
860
+ let that = this;
861
+ return new Promise(function (resolve, reject) {
862
+ try {
863
+ that
864
+ .scanDeviceManually(device)
865
+ .then(function (result) {
866
+ device.setPointsList(result);
867
+ resolve(result);
868
+ })
869
+ .catch(function (error) {
870
+ reject(error);
871
+ });
872
+ } catch (e) {
873
+ that.logOut("Error getting point list: ", e);
874
+ reject(e);
875
+ }
876
+ });
877
+ }
878
+
879
+ scanDeviceManually(device) {
880
+ let that = this;
881
+
882
+ return new Promise(function (resolve, reject) {
883
+ let address = device.getAddress();
884
+ let deviceId = device.getDeviceId();
885
+ let discoveredPointList = [];
886
+
887
+ let index = 1;
888
+
889
+ send(index);
890
+
891
+ function send(index) {
892
+ let readOptions = {
893
+ maxSegments: that.readPropertyMultipleOptions.maxSegments,
894
+ maxApdu: that.readPropertyMultipleOptions.maxApdu,
895
+ arrayIndex: index,
896
+ };
663
897
 
664
- getDevicePointList(device) {
665
- let that = this;
666
- return new Promise(async function(resolve, reject) {
667
- try {
668
- device.setManualDiscoveryMode(false);
669
- let result = await that.scanDevice(device);
670
- device.setPointsList(result);
671
- resolve(result);
672
- } catch(e) {
673
- that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
674
- reject(e);
898
+ that.client.readProperty(
899
+ address,
900
+ { type: baEnum.ObjectType.DEVICE, instance: deviceId },
901
+ baEnum.PropertyIdentifier.OBJECT_LIST,
902
+ readOptions,
903
+ (err, value) => {
904
+ if (err) {
905
+ resolve(discoveredPointList);
675
906
  }
676
- });
677
- }
678
907
 
679
- getDevicePointListWithoutObjectList(device) {
680
- let that = this;
681
- return new Promise(function(resolve, reject) {
682
- try {
683
- that.scanDeviceManually(device).then(function(result) {
684
- device.setPointsList(result);
685
- resolve(result);
686
- }).catch(function(error) {
687
- reject(error);
688
- });
689
-
690
- } catch(e) {
691
- that.logOut("Error getting point list: ", e);
692
- reject(e);
908
+ if (value) {
909
+ discoveredPointList.push(value.values[0]);
910
+ index++;
911
+ send(index);
693
912
  }
694
-
913
+ }
914
+ );
915
+ }
916
+ });
917
+ }
918
+
919
+ _readObjectWithRequestArray(deviceAddress, requestArray, readOptions) {
920
+ let that = this;
921
+ return new Promise((resolve, reject) => {
922
+ this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
923
+ resolve({
924
+ error: error,
925
+ value: value,
695
926
  });
927
+ });
928
+ });
929
+ }
930
+
931
+ _readDeviceName(deviceAddress, deviceId, callback) {
932
+ let that = this;
933
+ that.client.readProperty(
934
+ deviceAddress,
935
+ { type: baEnum.ObjectType.DEVICE, instance: deviceId },
936
+ baEnum.PropertyIdentifier.OBJECT_NAME,
937
+ that.readPropertyMultipleOptions,
938
+ callback
939
+ );
940
+ }
941
+
942
+ _readObjectList(deviceAddress, deviceId, readOptions, callback) {
943
+ let that = this;
944
+
945
+ try {
946
+ that.client.readProperty(
947
+ deviceAddress,
948
+ { type: baEnum.ObjectType.DEVICE, instance: deviceId },
949
+ baEnum.PropertyIdentifier.OBJECT_LIST,
950
+ readOptions,
951
+ callback
952
+ );
953
+ } catch (e) {
954
+ that.logOut("Error reading object list: ", e);
696
955
  }
956
+ }
957
+
958
+ _readObject(deviceAddress, type, instance, properties, readOptions) {
959
+ let that = this;
960
+ return new Promise((resolve, reject) => {
961
+ const requestArray = [
962
+ {
963
+ objectId: { type: type, instance: instance },
964
+ properties: properties,
965
+ },
966
+ ];
967
+ this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
968
+ resolve({
969
+ error: error,
970
+ value: value,
971
+ });
972
+ });
973
+ });
974
+ }
975
+
976
+ _readObjectFull(device, deviceAddress, type, instance) {
977
+ const that = this;
978
+ const readOptions = {
979
+ maxSegments: that.readPropertyMultipleOptions.maxSegments,
980
+ maxApdu: that.readPropertyMultipleOptions.maxApdu,
981
+ };
697
982
 
698
- scanDeviceManually(device) {
699
- let that = this;
700
-
701
- return new Promise(function(resolve, reject) {
702
-
703
- let address = device.getAddress();
704
- let deviceId = device.getDeviceId();
705
- let discoveredPointList = [];
706
-
707
- let index = 1;
708
-
709
- send(index);
710
-
711
-
712
- function send(index) {
713
-
714
- let readOptions = {
715
- maxSegments: that.readPropertyMultipleOptions.maxSegments,
716
- maxApdu: that.readPropertyMultipleOptions.maxApdu,
717
- arrayIndex: index
718
- }
719
-
720
- that.client.readProperty(
721
- address,
722
- {type: baEnum.ObjectType.DEVICE, instance: deviceId },
723
- baEnum.PropertyIdentifier.OBJECT_LIST,
724
- readOptions,
725
- (err, value) => {
726
- if(err) {
727
- resolve(discoveredPointList);
728
- }
729
-
730
- if(value) {
731
- discoveredPointList.push(value.values[0]);
732
- index++;
733
- send(index);
734
- }
735
- }
736
- );
737
- }
983
+ // Define all properties to be read
984
+ const allProperties = [
985
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
986
+ { id: baEnum.PropertyIdentifier.DESCRIPTION },
987
+ { id: baEnum.PropertyIdentifier.UNITS },
988
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
989
+ { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
990
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
991
+ { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
992
+ { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
993
+ { id: baEnum.PropertyIdentifier.STATE_TEXT },
994
+ { id: baEnum.PropertyIdentifier.RECORD_COUNT },
995
+ { id: baEnum.PropertyIdentifier.PRIORITY_ARRAY },
996
+ { id: baEnum.PropertyIdentifier.VENDOR_NAME },
997
+ ];
998
+
999
+ return new Promise((resolve, reject) => {
1000
+ // Try to read all properties at once
1001
+ that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
1002
+ .then(result => {
1003
+ if (result.value) {
1004
+ // If the result has value, resolve the promise
1005
+ resolve(result);
1006
+ } else {
1007
+ // If not, proceed to read individual properties
1008
+ readPropertiesIndividually();
1009
+ }
1010
+ })
1011
+ .catch(() => {
1012
+ // On error, proceed to read individual properties
1013
+ readPropertiesIndividually();
738
1014
  });
739
- }
740
1015
 
741
- _readObjectWithRequestArray(deviceAddress, requestArray, readOptions) {
742
- let that = this;
743
- return new Promise((resolve, reject) => {
744
- this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
745
- resolve({
746
- error: error,
747
- value: value
1016
+ // Function to read properties individually
1017
+ const readPropertiesIndividually = () => {
1018
+ const promises = allProperties.map((property, index) => new Promise((propertyResolve) => {
1019
+ that.client.readProperty(
1020
+ deviceAddress,
1021
+ { type: type, instance: instance },
1022
+ property.id,
1023
+ readOptions,
1024
+ (err, value) => {
1025
+ if (err) {
1026
+ propertyResolve(null);
1027
+ } else {
1028
+ propertyResolve({
1029
+ id: property.id,
1030
+ index: value.property.index,
1031
+ value: value.values,
748
1032
  });
1033
+ }
1034
+ }
1035
+ );
1036
+ }));
1037
+
1038
+ Promise.all(promises)
1039
+ .then(resultArray => {
1040
+ // Filter out null results
1041
+ const validResults = resultArray.filter(result => result !== null);
1042
+
1043
+ resolve({
1044
+ error: null,
1045
+ value: {
1046
+ values: [
1047
+ {
1048
+ objectId: {
1049
+ type: type,
1050
+ instance: instance,
1051
+ },
1052
+ values: validResults,
1053
+ },
1054
+ ],
1055
+ },
749
1056
  });
750
- });
1057
+ })
1058
+ .catch(reject);
1059
+ };
1060
+ });
1061
+ }
1062
+
1063
+
1064
+ _readObjectPropList(deviceAddress, type, instance) {
1065
+ return this._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.PROPERTY_LIST }]);
1066
+ }
1067
+
1068
+ _readObjectId(deviceAddress, type, instance) {
1069
+ return this._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }]);
1070
+ }
1071
+
1072
+ _readObjectPresentValue(deviceAddress, type, instance) {
1073
+ return this._readObject(deviceAddress, type, instance, [
1074
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
1075
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
1076
+ ]);
1077
+ }
1078
+
1079
+ doWrite(value, options) {
1080
+ let that = this;
1081
+ let valuesArray = [];
1082
+ options.pointsToWrite.forEach(function (point) {
1083
+ let deviceAddress = point.deviceAddress;
1084
+ let writeObject = {
1085
+ address: deviceAddress,
1086
+ objectId: {
1087
+ type: point.meta.objectId.type,
1088
+ instance: point.meta.objectId.instance,
1089
+ },
1090
+ values: {
1091
+ property: {
1092
+ id: 85,
1093
+ index: point.meta.arrayIndex,
1094
+ },
1095
+ value: [
1096
+ {
1097
+ type: options.appTag,
1098
+ value: value,
1099
+ },
1100
+ ],
1101
+ },
1102
+ options: {
1103
+ maxSegments: that.readPropertyMultipleOptions.maxSegments,
1104
+ maxApdu: that.readPropertyMultipleOptions.maxApdu,
1105
+ arrayIndex: point.meta.arrayIndex,
1106
+ priority: options.priority,
1107
+ },
1108
+ };
1109
+
1110
+ valuesArray.push(writeObject);
1111
+ });
1112
+
1113
+ return that._writePropertyMultiple(valuesArray);
1114
+ }
1115
+
1116
+ _writePropertyMultiple(values) {
1117
+ let that = this;
1118
+ try {
1119
+ values.forEach(function (point) {
1120
+ that.client.writeProperty(
1121
+ point.address,
1122
+ point.objectId,
1123
+ baEnum.PropertyIdentifier.PRESENT_VALUE,
1124
+ point.values.value,
1125
+ point.options,
1126
+ (err, value) => {
1127
+ if (err) {
1128
+ that.logOut(err);
1129
+ }
1130
+ }
1131
+ );
1132
+ });
1133
+ } catch (error) {
1134
+ that.logOut(error);
751
1135
  }
752
-
753
- _readDeviceName(deviceAddress, deviceId, callback) {
754
- let that = this;
755
- that.client.readProperty(
756
- deviceAddress,
757
- {type: baEnum.ObjectType.DEVICE, instance: deviceId },
758
- baEnum.PropertyIdentifier.OBJECT_NAME,
759
- that.readPropertyMultipleOptions,
760
- callback
761
- );
1136
+ }
1137
+
1138
+ _findValueById(properties, id) {
1139
+ const property = properties.find(function (element) {
1140
+ return element.id === id;
1141
+ });
1142
+ if (property && property.value && property.value.length > 0) {
1143
+ return property.value[0].value;
1144
+ } else {
1145
+ return null;
762
1146
  }
763
-
764
- _readObjectList(deviceAddress, deviceId, readOptions, callback) {
765
- let that = this;
766
-
767
- try {
768
- that.client.readProperty(
769
- deviceAddress,
770
- {type: baEnum.ObjectType.DEVICE, instance: deviceId },
771
- baEnum.PropertyIdentifier.OBJECT_LIST,
772
- readOptions,
773
- callback
774
- );
775
-
776
- } catch(e) {
777
- that.logOut("Error reading object list: ", e);
1147
+ }
1148
+
1149
+ scanDevice(device) {
1150
+ let that = this;
1151
+ return new Promise((resolve, reject) => {
1152
+ const readOptions = {
1153
+ maxSegments: that.readPropertyMultipleOptions.maxSegments,
1154
+ maxApdu: that.readPropertyMultipleOptions.maxApdu,
1155
+ };
1156
+ this._readObjectList(device.getAddress(), device.getDeviceId(), readOptions, (err, result) => {
1157
+ if (!err) {
1158
+ try {
1159
+ resolve(result.values);
1160
+ } catch (e) {
1161
+ that.logOut("Issue with getting device point list, see error: ", e);
1162
+ }
1163
+ } else {
1164
+ that.logOut(`Error while fetching objects: ${err}`);
1165
+ reject(err);
778
1166
  }
1167
+ });
1168
+ });
1169
+ }
1170
+
1171
+ //closes bacnet client
1172
+ shutDownClient() {
1173
+ let that = this;
1174
+ if (that.client)
1175
+ that.client.close((err, result) => {
1176
+ that.logOut(err, result);
1177
+ });
1178
+ }
1179
+
1180
+ globalWhoIs() {
1181
+ let that = this;
1182
+ if (that.client) {
1183
+ that.client.whoIs({ net: 65535 });
1184
+ } else {
1185
+ that.reinitializeClient(that.config);
779
1186
  }
780
-
781
- _readObject(deviceAddress, type, instance, properties, readOptions) {
782
- let that = this;
783
- return new Promise((resolve, reject) => {
784
- const requestArray = [{
785
- objectId: { type: type, instance: instance },
786
- properties: properties
787
- }];
788
- this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
789
- resolve({
790
- error: error,
791
- value: value
792
- });
793
- });
1187
+ that.lastWhoIs = Date.now();
1188
+ }
1189
+
1190
+ getNetworkTreeData() {
1191
+ let that = this;
1192
+ return new Promise(async function (resolve, reject) {
1193
+ try {
1194
+ const reducedDeviceList = JSON.parse(JSON.stringify(that.deviceList));
1195
+ reducedDeviceList.forEach((device) => {
1196
+ delete device["pointsList"];
794
1197
  });
795
- }
796
-
797
- _readObjectFull(device, deviceAddress, type, instance) {
798
- let that = this;
799
- const readOptions = {
800
- maxSegments: that.readPropertyMultipleOptions.maxSegments,
801
- maxApdu: that.readPropertyMultipleOptions.maxApdu
802
- };
803
-
804
- const allProperties = [
805
- { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
806
- { id: baEnum.PropertyIdentifier.DESCRIPTION },
807
- { id: baEnum.PropertyIdentifier.UNITS },
808
- { id: baEnum.PropertyIdentifier.OBJECT_NAME },
809
- { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
810
- { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
811
- { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
812
- { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
813
- { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
814
- { id: baEnum.PropertyIdentifier.RECORD_COUNT }
815
- ];
816
-
817
- return new Promise((resolve, reject) => {
818
- that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions).then(function(result) {
819
-
820
- if(result.value) {
821
- resolve(result);
822
- }
823
-
824
- if(result.error) {
825
- let i = 0;
826
- readIndividualProperties(i);
827
- }
828
-
829
- }).catch(function(error) {
830
- let i = 0;
831
- readIndividualProperties(i);
832
- });
833
1198
 
834
- let resultArray = [];
835
- let errorArray = [];
836
-
837
- function readIndividualProperties(index) {
838
-
839
- const property = allProperties[index];
840
-
841
- that.client.readProperty(
842
- deviceAddress,
843
- {type: type, instance: instance },
844
- property.id,
845
- readOptions,
846
- (err, value) => {
847
- if(err) {
848
- errorArray.push(err);
849
- }
850
-
851
- if(value) {
852
- let formattedResult = {
853
- len: value.len,
854
- objectId: value.objectId,
855
- values: [
856
- {
857
- id: value.property.id,
858
- index: value.property.index,
859
- value: value.values
860
- }
861
- ]
862
- };
863
-
864
- resultArray.push({error: null, value: formattedResult});
865
- }
866
-
867
- if(index == allProperties.length - 1) {
868
- resolve(resultArray);
869
-
870
- // if(resultArray.length > 0) {
871
- // resolve(resultArray);
872
- // } else if(errorArray.length > 0){
873
- // reject(errorArray);
874
- // }
875
- } else if( index < allProperties.length - 1) {
876
- index++;
877
- readIndividualProperties(index);
878
- }
879
- }
880
- );
881
- };
1199
+ resolve({
1200
+ renderList: that.renderList,
1201
+ deviceList: reducedDeviceList,
1202
+ pointList: that.networkTree,
1203
+ pollFrequency: that.discover_polling_schedule,
1204
+ renderListCount: that.renderListCount,
1205
+ });
1206
+ } catch (e) {
1207
+ reject(e);
1208
+ }
1209
+ });
1210
+ }
1211
+
1212
+ getDeviceList() {
1213
+ let that = this;
1214
+ return new Promise(async function (resolve, reject) {
1215
+ try {
1216
+ resolve({ deviceList: that.deviceList });
1217
+ } catch (e) {
1218
+ reject(e);
1219
+ }
1220
+ });
1221
+ }
1222
+
1223
+ updateDeviceList(json) {
1224
+ let that = this;
1225
+ return new Promise(async function (resolve, reject) {
1226
+ try {
1227
+ let deviceL = json.body.deviceList;
1228
+ deviceL.forEach(function (device) {
1229
+ let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
1230
+ if (foundIndex == -1) {
1231
+ let newBacnetDevice = new BacnetDevice(true, device);
1232
+ newBacnetDevice.setLastSeen(Date.now());
1233
+ that.deviceList.push(newBacnetDevice);
1234
+ } else if (foundIndex !== -1) {
1235
+ that.deviceList[foundIndex].updateDeviceConfig(device);
1236
+ that.deviceList[foundIndex].setLastSeen(Date.now());
1237
+ }
882
1238
  });
883
- };
884
-
885
- _readObjectPropList(deviceAddress, type, instance) {
886
-
887
- return this._readObject(deviceAddress, type, instance, [
888
- { id: baEnum.PropertyIdentifier.PROPERTY_LIST }
889
- ]);
890
- };
891
-
892
- _readObjectId(deviceAddress, type, instance) {
893
1239
 
894
- return this._readObject(deviceAddress, type, instance, [
895
- { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }
896
- ]);
1240
+ resolve(true);
1241
+ } catch (e) {
1242
+ reject(e);
1243
+ }
1244
+ });
1245
+ }
1246
+
1247
+ sortDevices(a, b) {
1248
+ if (a.deviceId < b.deviceId) {
1249
+ return -1;
1250
+ } else if (a.deviceId > b.deviceId) {
1251
+ return 1;
897
1252
  }
898
-
899
- _readObjectPresentValue(deviceAddress, type, instance) {
900
-
901
- return this._readObject(deviceAddress, type, instance, [
902
- { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
903
- { id: baEnum.PropertyIdentifier.OBJECT_NAME}
904
- ]);
1253
+ return 0; // deviceIds are equal
1254
+ }
1255
+
1256
+ sortPoints(a, b) {
1257
+ if (a.bacnetType > b.bacnetType) {
1258
+ return 1;
1259
+ } else if (a.bacnetType < b.bacnetType) {
1260
+ return -1;
1261
+ } else if (a.bacnetType == b.bacnetType) {
1262
+ return 0;
905
1263
  }
906
1264
 
907
- doWrite(value, options){
908
- let that = this;
909
- let valuesArray = [];
910
- options.pointsToWrite.forEach(function(point){
911
- let deviceAddress = point.deviceAddress;
912
- let writeObject = {
913
- address: deviceAddress,
914
- objectId: {
915
- type: point.meta.objectId.type,
916
- instance: point.meta.objectId.instance
917
- },
918
- values: {
919
- property: {
920
- id: 85,
921
- index: point.meta.arrayIndex
922
- },
923
- value: [{
924
- type: options.appTag,
925
- value: value
926
- }],
927
-
928
- },
929
- options: {
930
- maxSegments: that.readPropertyMultipleOptions.maxSegments,
931
- maxApdu: that.readPropertyMultipleOptions.maxApdu,
932
- arrayIndex: point.meta.arrayIndex,
933
- priority: options.priority
934
- }
935
- };
936
-
937
- valuesArray.push(writeObject);
938
- });
1265
+ return a.label.localeCompare(b.label);
1266
+ }
939
1267
 
940
- return that._writePropertyMultiple(valuesArray);
1268
+ computeDeviceName(device) {
1269
+ if (device.getDisplayName() !== null && device.getDisplayName() !== "" && device.getDisplayName() !== undefined) {
1270
+ return device.getDisplayName();
941
1271
  }
1272
+ return device.getDeviceName();
1273
+ }
942
1274
 
943
- _writePropertyMultiple(values) {
944
- let that = this;
945
- try {
946
- values.forEach(function(point) {
947
-
948
- that.client.writeProperty(
949
- point.address,
950
- point.objectId,
951
- baEnum.PropertyIdentifier.PRESENT_VALUE,
952
- point.values.value,
953
- point.options,
954
- (err, value) => {
955
- if(err) {
956
- that.logOut(err);
957
- }
958
- }
959
- );
960
- });
1275
+ checkInterruptFlag() {
1276
+ let that = this;
1277
+ let BreakException = {};
961
1278
 
962
- } catch (error) {
963
- that.logOut(error);
964
- }
1279
+ if (that.buildTreeException) {
1280
+ throw BreakException;
965
1281
  }
1282
+ }
966
1283
 
967
- _findValueById(properties, id) {
968
- const property = properties.find(function (element) {
969
- return element.id === id;
970
- });
971
- if (property && property.value && property.value.length > 0) {
972
- return property.value[0].value;
973
- } else {
974
- return null;
975
- }
976
- };
977
-
978
- scanDevice(device) {
979
- let that = this;
980
- return new Promise((resolve, reject) => {
981
- const readOptions = {
982
- maxSegments: that.readPropertyMultipleOptions.maxSegments,
983
- maxApdu: that.readPropertyMultipleOptions.maxApdu
984
- };
985
- this._readObjectList(device.getAddress(), device.getDeviceId(), readOptions, (err, result) => {
986
- if (!err) {
987
- try {
988
- resolve(result.values);
989
- } catch(e) {
990
- that.logOut("Issue with getting device point list, see error: ", e);
991
- }
992
- } else {
993
- that.logOut(`Error while fetching objects: ${err}`);
994
- reject(err);
995
- }
996
- });
997
- });
1284
+ getPointName(object, pointName) {
1285
+ if (object.displayName) {
1286
+ return object.displayName;
998
1287
  }
1288
+ return pointName;
1289
+ }
999
1290
 
1000
- //closes bacnet client
1001
- shutDownClient() {
1002
- let that = this;
1003
- if(that.client) that.client.close((err, result) => {
1004
- that.logOut(err, result);
1005
- });
1006
- };
1007
-
1008
- globalWhoIs() {
1009
- let that = this;
1010
- if(that.client) {
1011
- that.client.whoIs({'net': 65535});
1012
- } else {
1013
- that.reinitializeClient(that.config);
1014
- }
1015
- that.lastWhoIs = Date.now();
1291
+ addUniqueToArray(device, array) {
1292
+ const foundIndex = array.findIndex(ele => ele.getDeviceId() === device.getDeviceId());
1293
+ if (foundIndex === -1) {
1294
+ array.push(device);
1016
1295
  }
1017
-
1018
-
1019
- getNetworkTreeData() {
1020
- let that = this;
1021
- return new Promise(async function(resolve, reject) {
1022
- try {
1023
- const reducedDeviceList = JSON.parse(JSON.stringify(that.deviceList));
1024
- reducedDeviceList.forEach((device) => {
1025
- delete device["pointsList"];
1026
- });
1027
- resolve({renderList: that.renderList, deviceList: reducedDeviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule, renderListCount: that.renderListCount});
1028
- } catch(e){
1029
- reject(e);
1296
+ }
1297
+
1298
+ async getDevicesNotRenderedYet() {
1299
+ let that = this;
1300
+ let missingDevices = [];
1301
+ for (let i = 0; i < that.deviceList.length; i++) {
1302
+ const device = that.deviceList[i];
1303
+ if (!device.getIsMstpDevice()) {
1304
+ //ip device
1305
+ const foundIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
1306
+ if (foundIndex == -1) {
1307
+ that.addUniqueToArray(device, missingDevices);
1308
+ }
1309
+ } else {
1310
+ //mstp device
1311
+ const foundParentIndex = that.renderList.findIndex(ele => ele.deviceId == device.getParentDeviceId());
1312
+ if (foundParentIndex == -1) {
1313
+ //parent not existent in tree
1314
+ const parentDeviceIndex = that.deviceList.findIndex(ele => ele.getDeviceId() === device.getParentDeviceId());
1315
+ if (parentDeviceIndex !== -1) {
1316
+ that.addUniqueToArray(that.deviceList[parentDeviceIndex], missingDevices);
1317
+ }
1318
+ that.addUniqueToArray(device, missingDevices);
1319
+ } else {
1320
+ const parentTreeDevice = that.renderList[foundParentIndex];
1321
+ let mstpIndex = -1;
1322
+ parentTreeDevice.children.forEach(child => {
1323
+ if (child.label.includes("MSTP")) {
1324
+ const tempIndex = child.children.findIndex(ele => ele.deviceId == device.getDeviceId());
1325
+ if (tempIndex !== -1) {
1326
+ mstpIndex = tempIndex;
1327
+ }
1030
1328
  }
1031
- });
1329
+ });
1330
+ if (mstpIndex == -1) {
1331
+ that.addUniqueToArray(device, missingDevices);
1332
+ }
1333
+ }
1334
+ }
1032
1335
  }
1336
+ return missingDevices;
1337
+ }
1033
1338
 
1034
- getDeviceList() {
1035
- let that = this;
1036
- return new Promise(async function(resolve, reject) {
1037
- try {
1038
- resolve({"deviceList": that.deviceList});
1039
- } catch(e){
1040
- reject(e);
1041
- }
1042
- });
1043
- }
1339
+ initialTreeBuild = true;
1044
1340
 
1045
- updateDeviceList(json) {
1046
- let that = this;
1047
- return new Promise(async function(resolve, reject) {
1048
- try {
1049
- let deviceL = json.body.deviceList;
1050
- deviceL.forEach(function(device) {
1051
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
1052
- if(foundIndex == -1) {
1053
- let newBacnetDevice = new BacnetDevice(true, device);
1054
- newBacnetDevice.setLastSeen(Date.now());
1055
- that.deviceList.push(newBacnetDevice);
1056
-
1057
- } else if(foundIndex !== -1) {
1058
- that.deviceList[foundIndex].updateDeviceConfig(device);
1059
- that.deviceList[foundIndex].setLastSeen(Date.now());
1060
- }
1061
- });
1341
+ async doTreeBuilder() {
1342
+ let that = this;
1062
1343
 
1063
- resolve(true);
1064
- } catch(e) {
1065
- reject(e);
1066
- }
1067
- });
1068
- }
1344
+ const treeWorker = new treeBuilder(that.deviceList, that.networkTree, that.renderList, that.renderListCount, that.initialTreeBuild);
1069
1345
 
1070
- updatePriorityQueue(priorityDevices) {
1071
- let that = this;
1072
- return new Promise(async function(resolve, reject) {
1073
- try {
1074
- let keys = Object.keys(priorityDevices);
1075
- if(keys.length > 0) {
1076
- keys.forEach(function(key) {
1077
- let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
1078
- let points = priorityDevices[key];
1079
- if(device) {
1080
- device.setPriorityQueue(points);
1081
- }
1082
- });
1083
- } else if(keys.length == 0) {
1084
- that.clearPriorityQueues();
1085
- }
1086
- resolve(true);
1087
- } catch(e){
1088
- reject(e);
1089
- }
1090
- });
1091
- }
1346
+ treeWorker.cacheData();
1092
1347
 
1093
- clearPriorityQueues() {
1094
- let that = this;
1095
- that.deviceList.forEach(function(device) {
1096
- device.clearPriorityQueue();
1097
- });
1098
- }
1348
+ //const missingDevices = await that.getDevicesNotRenderedYet();
1099
1349
 
1100
- getPriorityDevices() {
1101
- let that = this;
1102
- let priorityDevices = that.deviceList.filter(device => device.getPriorityQueueIsActive() == true);
1103
- return priorityDevices;
1350
+ for (let i = 0; i < that.deviceList.length; i++) {
1351
+ let device = that.deviceList[i];
1352
+ await treeWorker.processDevice(device, i);
1104
1353
  }
1105
1354
 
1106
- sortDevices(a, b) {
1107
- if (a.deviceId < b.deviceId) {
1108
- return -1;
1109
- } else if (a.deviceId > b.deviceId) {
1110
- return 1;
1355
+ that.deviceList = treeWorker.deviceList;
1356
+ that.networkTree = treeWorker.networkTree;
1357
+ that.renderList = treeWorker.renderList;
1358
+
1359
+ that.initialTreeBuild = false;
1360
+ }
1361
+
1362
+ countDevices() {
1363
+ let that = this;
1364
+ let deviceCount = 0;
1365
+
1366
+ if (that.renderList && that.renderList.length > 0) {
1367
+ that.renderList.forEach(function (device, index) {
1368
+ if (device && device.children.length > 0) {
1369
+ device.children.forEach(function (folder) {
1370
+ if (folder.label == "Points") {
1371
+ //increment for parent device / mstp router
1372
+ deviceCount++;
1373
+ } else if (folder.label.includes("MSTP")) {
1374
+ //increment for mstp device list
1375
+ deviceCount += folder.children.length;
1376
+ }
1377
+ });
1111
1378
  }
1112
- return 0; // deviceIds are equal
1113
- }
1114
-
1115
- sortPoints(a, b) {
1116
- if(a.bacnetType > b.bacnetType) {
1117
- return 1;
1118
- } else if(a.bacnetType < b.bacnetType) {
1119
- return -1;
1120
- } else if(a.bacnetType == b.bacnetType) {
1121
- return 0;
1379
+ if (index == that.renderList.length - 1) {
1380
+ that.renderListCount = deviceCount;
1122
1381
  }
1123
-
1124
- return a.label.localeCompare(b.label)
1382
+ });
1125
1383
  }
1384
+ }
1385
+
1386
+ buildJsonObject(device) {
1387
+ let that = this;
1388
+ let address = device.address;
1389
+ let pointList = device.getPointsList();
1390
+ let requestMutex = new Mutex();
1391
+
1392
+ return new Promise(function (resolve, reject) {
1393
+ let promiseArray = [];
1394
+ if (typeof pointList !== "undefined" && pointList.length > 0) {
1395
+ pointList.forEach(function (point, pointListIndex) {
1396
+ requestMutex.acquire().then(function (release) {
1397
+ that
1398
+ ._readObjectFull(device, address, point.value.type, point.value.instance)
1399
+ .then(function (result) {
1400
+ if (!result.error) {
1401
+ if (result.length > 0 && Array.isArray(result)) {
1402
+ promiseArray = result;
1403
+ } else {
1404
+ promiseArray.push(result);
1405
+ }
1406
+ }
1126
1407
 
1127
- buildNetworkTreeData() {
1128
- let that = this;
1129
- that.buildTreeMutex = new Mutex();
1130
- let displayNameCharThreshold = 40;
1131
-
1132
- Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, renderListCount: that.renderListCount}));
1133
-
1134
- return new Promise(async function(resolve, reject) {
1135
- if(!that.renderList) that.renderList = [];
1136
- if(that.deviceList && that.networkTree) {
1137
- that.deviceList.forEach(function(deviceInfo, index) {
1138
- that.buildTreeMutex
1139
- .acquire()
1140
- .then(function(release) {
1141
-
1142
- let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
1143
- let deviceId = deviceInfo.getDeviceId();
1144
- let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
1145
- let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
1146
- let deviceObject = that.networkTree[deviceKey];
1147
- let isMstpDevice = deviceInfo.getIsMstpDevice();
1148
- let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
1149
-
1150
- if(deviceObject && typeof deviceName !== "object") {
1151
- let children = [];
1152
- let pointIndex = 0;
1153
-
1154
- for(const pointName in deviceObject) {
1155
- let pointProperties = [];
1156
- let values = deviceObject[pointName];
1157
-
1158
- let displayName = pointName;
1159
- if(pointName.length > displayNameCharThreshold) {
1160
- displayName = "";
1161
- let charArray = pointName.split("");
1162
- for(let i = 0; i < charArray.length; i++) {
1163
- if(i < displayNameCharThreshold){
1164
- displayName += charArray[i];
1165
- }
1166
- }
1167
- displayName += "...";
1168
- }
1169
-
1170
- if(values.objectName){
1171
- pointProperties.push({"key": `${index}-0-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-cog", "children": null});
1172
- }
1173
- if(values.objectType && values.objectID.type !== 8){
1174
- pointProperties.push({"key": `${index}-0-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-cog", "children": null});
1175
- }
1176
- if(values.objectID && values.objectID.instance) {
1177
- pointProperties.push({"key": `${index}-0-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-cog", "children": null});
1178
- }
1179
- if(values.description){
1180
- pointProperties.push({"key": `${index}-0-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-cog", "children": null});
1181
- }
1182
- if(values.units){
1183
- pointProperties.push({"key": `${index}-0-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-cog", "children": null});
1184
- }
1185
- if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
1186
- pointProperties.push({"key": `${index}-0-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-cog", "children": null});
1187
- }
1188
- if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
1189
- pointProperties.push({"key": `${index}-0-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-cog", "children": null});
1190
- }
1191
- if(values.modificationDate && !values.modificationDate.errorClass) {
1192
- pointProperties.push({"key": `${index}-0-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-cog", "children": null});
1193
- }
1194
- if(values.programState){
1195
- pointProperties.push({"key": `${index}-0-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-cog", "children": null});
1196
- }
1197
- if(values.recordCount && !values.recordCount.errorClass){
1198
- pointProperties.push({"key": `${index}-0-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-cog", "children": null});
1199
- }
1200
- if(values.objectID && values.objectID.type == 8) {
1201
- //device point, add segmentation supported, and apdu size
1202
- pointProperties.push({"key": `${index}-0-${pointIndex}-10`, "label": `Segmentation Supported: ${deviceInfo.getSegmentation()}`, "data": `${deviceInfo.getSegmentation()}`, "icon": "pi pi-cog", "children": null});
1203
- pointProperties.push({"key": `${index}-0-${pointIndex}-11`, "label": `APDU Size: ${deviceInfo.getMaxApdu()}`, "data": `${deviceInfo.getMaxApdu()}`, "icon": "pi pi-cog", "children": null});
1204
- }
1205
-
1206
- children.push({"key": `${index}-0-${pointIndex}`, "label": displayName, "data": displayName, "pointName": pointName, "icon": that.getPointIcon(values.meta.objectId.type), "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
1207
- pointIndex++;
1208
- }
1209
- let foundIndex = that.renderList.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
1210
- if(foundIndex !== -1) {
1211
- let folderJson = [];
1212
- if(deviceInfo.hasChildDevices()) {
1213
- folderJson = [
1214
- {
1215
- key: `${index}-0`,
1216
- label: "Points",
1217
- data: "Points Folder",
1218
- icon: "pi pi-circle-fill",
1219
- type: "pointFolder",
1220
- children: children.sort(that.sortPoints)
1221
- },
1222
- {
1223
- key: `${index}-1`,
1224
- label: "MSTP Network",
1225
- data: "Devices Folder",
1226
- icon: "pi pi-database",
1227
- type: "deviceFolder",
1228
- children: []
1229
- }
1230
- ];
1231
- } else {
1232
- folderJson = [
1233
- {
1234
- key: `${index}-0`,
1235
- label: "Points",
1236
- data: "Points Folder",
1237
- icon: "pi pi-circle-fill",
1238
- type: "pointFolder",
1239
- children: children.sort(that.sortPoints)
1240
- }
1241
- ];
1242
- }
1243
-
1244
- if(!isMstpDevice) {
1245
- that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": that.renderList[foundIndex].children, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
1246
- } else if(isMstpDevice) {
1247
- let parentDeviceId = deviceInfo.getParentDeviceId();
1248
- let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
1249
-
1250
- if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children[1].children) {
1251
- let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
1252
- if(mstpDeviceIndex == -1) {
1253
- //that.renderListCount++;
1254
- that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
1255
- } else {
1256
- that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
1257
- }
1258
- }
1259
- }
1260
-
1261
- } else if(foundIndex == -1) {
1262
- let folderJson = [];
1263
- if(deviceInfo.hasChildDevices()) {
1264
- folderJson = [
1265
- {
1266
- key: `${index}-0`,
1267
- label: "Points",
1268
- data: "Points Folder",
1269
- icon: "pi pi-circle-fill",
1270
- type: "pointFolder",
1271
- children: children.sort(that.sortPoints)
1272
- },
1273
- {
1274
- key: `${index}-1`,
1275
- label: "MSTP Network",
1276
- data: "Devices Folder",
1277
- icon: "pi pi-database",
1278
- type: "deviceFolder",
1279
- children: []
1280
- }
1281
- ];
1282
- } else {
1283
- folderJson = [
1284
- {
1285
- key: `${index}-0`,
1286
- label: "Points",
1287
- data: "Points Folder",
1288
- icon: "pi pi-circle-fill",
1289
- type: "pointFolder",
1290
- children: children.sort(that.sortPoints)
1291
- }
1292
- ];
1293
- }
1294
-
1295
- if(!isMstpDevice) {
1296
- //that.renderListCount++;
1297
- that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
1298
- } else if(isMstpDevice) {
1299
- let parentDeviceId = deviceInfo.getParentDeviceId();
1300
- let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
1301
-
1302
- if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children && that.renderList[parentDeviceIndex].children[1].children) {
1303
- let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
1304
-
1305
- if(mstpDeviceIndex == -1) {
1306
- // that.renderListCount++;
1307
- that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
1308
- } else {
1309
- that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
1310
- }
1311
- }
1312
- }
1313
- }
1314
-
1315
- if(index == that.deviceList.length - 1) {
1316
- that.renderList.sort(that.sortDevices);
1317
- resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1318
- }
1319
- } else {
1320
- if(index == that.deviceList.length - 1) {
1321
- that.renderList.sort(that.sortDevices);
1322
- resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
1323
- }
1324
- }
1325
-
1326
- release();
1408
+ release();
1409
+
1410
+ if (pointListIndex == pointList.length - 1) {
1411
+ that
1412
+ .buildResponse(promiseArray, device)
1413
+ .then(function () {
1414
+ that.lastNetworkPoll = Date.now();
1415
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1416
+ })
1417
+ .catch(function (e) {
1418
+ that.logOut("Error while building json object: ", e);
1419
+ reject(e);
1327
1420
  });
1328
- });
1329
- }
1330
- });
1331
- }
1332
-
1333
- countDevices() {
1334
- let that = this;
1335
-
1336
- let deviceCount = 0;
1337
-
1338
- that.renderList.forEach(function(device, index) {
1339
- if(device) {
1340
- if(device.children[1] && device.children[1].label == 'MSTP Network' && device.children[1].children && device.children[1].children.length > 0) {
1341
- //increment for parent device / mstp router
1342
- deviceCount++;
1343
- //increment for mstp device list
1344
- deviceCount += device.children[1].children.length;
1345
- } else {
1346
- deviceCount++;
1347
1421
  }
1348
- }
1349
- if(index == that.renderList.length -1) {
1350
- that.renderListCount = deviceCount;
1351
- }
1422
+ })
1423
+ .catch(function (e) {
1424
+ release();
1425
+ that.logOut("_readObjectFull error: ", e);
1426
+
1427
+ if (pointListIndex == pointList.length - 1) {
1428
+ that
1429
+ .buildResponse(promiseArray, device)
1430
+ .then(function () {
1431
+ that.lastNetworkPoll = Date.now();
1432
+ resolve({ deviceList: that.deviceList, pointList: that.networkTree });
1433
+ })
1434
+ .catch(function (e) {
1435
+ that.logOut("Error while building json object: ", e);
1436
+ reject(e);
1437
+ });
1438
+ }
1439
+ });
1440
+ });
1352
1441
  });
1353
- }
1354
-
1355
- buildJsonObject(device, priorityQueue) {
1356
- let that = this;
1357
- let address = device.address;
1358
- let pointList = priorityQueue !== null ? priorityQueue : device.getPointsList();
1359
- let requestMutex = new Mutex();
1360
-
1361
- return new Promise(function(resolve, reject) {
1362
- let promiseArray = [];
1363
- if(typeof pointList !== "undefined" && pointList.length > 0) {
1364
- pointList.forEach(function(point, pointListIndex) {
1365
- requestMutex
1366
- .acquire()
1367
- .then(function(release) {
1368
- that._readObjectFull(device, address, point.value.type, point.value.instance).then(function(result) {
1369
-
1370
- if(!result.error) {
1371
- if(result.length > 0 && Array.isArray(result)) {
1372
- promiseArray = result;
1373
- } else {
1374
- promiseArray.push(result);
1375
- }
1376
- }
1377
-
1378
- release();
1442
+ } else {
1443
+ reject("Unable to build network tree, empty point list");
1444
+ }
1445
+ });
1446
+ }
1447
+
1448
+ // Builds response object for a fully qualified
1449
+ buildResponse(fullObjects, device) {
1450
+ let that = this;
1451
+ const reg = /[$#\/\\+]/gi;
1452
+ return new Promise(function (resolve, reject) {
1453
+ let deviceKey =
1454
+ typeof device.getAddress() == "object"
1455
+ ? device.getAddress().address + "-" + device.getDeviceId()
1456
+ : device.getAddress() + "-" + device.getDeviceId();
1457
+ let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
1458
+ for (let i = 0; i < fullObjects.length; i++) {
1459
+ let obj = fullObjects[i];
1460
+ let successfulResult = !obj.error ? obj.value : null;
1461
+ if (successfulResult) {
1462
+ successfulResult.values.forEach(function (pointProperty, pointPropertyIndex) {
1463
+ if (!pointProperty.objectId && successfulResult.objectId && !pointProperty.values && successfulResult.values) {
1464
+ pointProperty = successfulResult;
1465
+ }
1379
1466
 
1380
- if(pointListIndex == pointList.length - 1) {
1381
- that.buildResponse(promiseArray, device).then(function() {
1382
- that.lastNetworkPoll = Date.now();
1383
- resolve({deviceList: that.deviceList, pointList: that.networkTree});
1384
- }).catch(function(e){
1385
- that.logOut("Error while building json object: ", e);
1386
- reject(e);
1387
- });
1467
+ let currobjectId = pointProperty.objectId.type;
1468
+ let bac_obj = that.getObjectType(currobjectId);
1469
+ let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
1470
+ let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
1471
+ let objectId;
1472
+ if (objectName !== null && typeof objectName == "string") {
1473
+ objectName = objectName.replace(reg, '');
1474
+ objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
1475
+
1476
+ try {
1477
+ pointProperty.values.forEach(function (object, objectIndex) {
1478
+ //checks for error code json structure, returned for invalid bacnet requests
1479
+ if (object && object.value && !object.value.errorClass) {
1480
+ if (!values[objectId]) values[objectId] = {};
1481
+ values[objectId].meta = {
1482
+ objectId: pointProperty.objectId,
1483
+ };
1484
+
1485
+ switch (object.id) {
1486
+ case baEnum.PropertyIdentifier.PRESENT_VALUE:
1487
+ if (object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
1488
+ //check for binary object type
1489
+ if (objectType == 3 || objectType == 4 || objectType == 5) {
1490
+ if (object.value[0].value == 0) {
1491
+ values[objectId].presentValue = false;
1492
+ } else if (object.value[0].value == 1) {
1493
+ values[objectId].presentValue = true;
1388
1494
  }
1389
-
1390
- }).catch(function(e) {
1391
- release();
1392
- that.logOut("_readObjectFull error: ", e);
1393
-
1394
- if(pointListIndex == pointList.length - 1) {
1395
- that.buildResponse(promiseArray, device).then(function() {
1396
- that.lastNetworkPoll = Date.now();
1397
- resolve({deviceList: that.deviceList, pointList: that.networkTree});
1398
- }).catch(function(e){
1399
- that.logOut("Error while building json object: ", e);
1400
- reject(e);
1401
- });
1495
+ } else if (objectType == 40) {
1496
+ //character string
1497
+ values[objectId].presentValue = object.value[0].value;
1498
+ } else if (objectType == 13 || objectType == 14 || objectType == 19) {
1499
+ //check for MSV MSI MSO - for enum state text
1500
+ if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
1501
+ if (object.value[0].value == 0) {
1502
+ values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value].value;
1503
+ } else if (object.value[0].value !== 0) {
1504
+ values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value - 1].value;
1505
+ }
1402
1506
  }
1403
- });
1404
- });
1405
- });
1406
- } else {
1407
- reject("Unable to build network tree, empty point list");
1408
- }
1409
- });
1410
- }
1507
+ } else {
1508
+ values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
1509
+ }
1510
+ }
1511
+ values[objectId].meta.arrayIndex = object.index;
1512
+ break;
1513
+ case baEnum.PropertyIdentifier.DESCRIPTION:
1514
+ if (object.value[0]) values[objectId].description = object.value[0].value;
1515
+ break;
1516
+ case baEnum.PropertyIdentifier.UNITS:
1517
+ if (object.value[0] && object.value[0].value)
1518
+ values[objectId].units = getUnit(object.value[0].value);
1519
+ break;
1520
+ case baEnum.PropertyIdentifier.OBJECT_NAME:
1521
+ if (object.value[0] && object.value[0].value) {
1522
+ values[objectId].objectName = object.value[0].value.replace(reg, '');
1523
+ if (!values[objectId].displayName) {
1524
+ values[objectId].displayName = object.value[0].value.replace(reg, '');
1525
+ }
1526
+ }
1527
+ break;
1528
+ case baEnum.PropertyIdentifier.OBJECT_TYPE:
1529
+ if (object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
1530
+ break;
1531
+ case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
1532
+ if (object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
1533
+ break;
1534
+ case baEnum.PropertyIdentifier.PROPERTY_LIST:
1535
+ if (object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
1536
+ break;
1537
+ case baEnum.PropertyIdentifier.SYSTEM_STATUS:
1538
+ if (object.value[0]) {
1539
+ values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
1540
+ }
1541
+ break;
1542
+ case baEnum.PropertyIdentifier.MODIFICATION_DATE:
1543
+ if (object.value[0]) {
1544
+ values[objectId].modificationDate = object.value[0].value;
1545
+ }
1546
+ break;
1547
+
1548
+ case baEnum.PropertyIdentifier.PROGRAM_STATE:
1549
+ if (object.value[0]) {
1550
+ values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
1551
+ }
1552
+ break;
1411
1553
 
1412
- // Builds response object for a fully qualified
1413
- buildResponse(fullObjects, device) {
1414
- let that = this;
1415
-
1416
- return new Promise(function(resolve, reject) {
1417
- let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
1418
- let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
1419
- for(let i = 0; i < fullObjects.length; i++) {
1420
- let obj = fullObjects[i];
1421
- let successfulResult = !obj.error ? obj.value : null;
1422
- if(successfulResult) {
1423
- successfulResult.values.forEach(function(pointProperty, pointPropertyIndex) {
1424
-
1425
- if(!pointProperty.objectId && successfulResult.objectId && !pointProperty.values && successfulResult.values) {
1426
- pointProperty = successfulResult;
1427
- }
1428
-
1429
- let currobjectId = pointProperty.objectId.type
1430
- let bac_obj = that.getObjectType(currobjectId);
1431
- let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
1432
- let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
1433
- let objectId;
1434
- if(objectName !== null && typeof objectName == "string") {
1435
- objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
1436
-
1437
- try {
1438
- pointProperty.values.forEach(function(object, objectIndex) {
1439
- //checks for error code json structure, returned for invalid bacnet requests
1440
- if(object && object.value && !object.value.errorClass) {
1441
-
1442
- if(!values[objectId]) values[objectId] = {};
1443
- values[objectId].meta = {
1444
- objectId: pointProperty.objectId
1445
- };
1446
-
1447
- switch(object.id) {
1448
- case baEnum.PropertyIdentifier.PRESENT_VALUE:
1449
- if(object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
1450
- //check for binary object type
1451
- if(objectType == 3 || objectType == 4 || objectType == 5) {
1452
- if(object.value[0].value == 0) {
1453
- values[objectId].presentValue = false;
1454
- } else if(object.value[0].value == 1) {
1455
- values[objectId].presentValue = true;
1456
- }
1457
- } else if(objectType == 40) {
1458
- //character string
1459
- values[objectId].presentValue = object.value[0].value;
1460
- } else {
1461
- values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
1462
- }
1463
- }
1464
- values[objectId].meta.arrayIndex = object.index;
1465
- break;
1466
- case baEnum.PropertyIdentifier.DESCRIPTION:
1467
- if(object.value[0]) values[objectId].description = object.value[0].value;
1468
- break;
1469
- case baEnum.PropertyIdentifier.UNITS:
1470
- if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
1471
- break;
1472
- case baEnum.PropertyIdentifier.OBJECT_NAME:
1473
- if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
1474
- break;
1475
- case baEnum.PropertyIdentifier.OBJECT_TYPE:
1476
- if(object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
1477
- break;
1478
- case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
1479
- if(object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
1480
- break;
1481
- case baEnum.PropertyIdentifier.PROPERTY_LIST:
1482
- if(object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
1483
- break;
1484
-
1485
- case baEnum.PropertyIdentifier.SYSTEM_STATUS:
1486
- if(object.value[0]){
1487
- values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
1488
- }
1489
- break;
1490
-
1491
- case baEnum.PropertyIdentifier.MODIFICATION_DATE:
1492
- if(object.value[0]) {
1493
- values[objectId].modificationDate = object.value[0].value;
1494
- }
1495
- break;
1496
-
1497
- case baEnum.PropertyIdentifier.PROGRAM_STATE:
1498
- if(object.value[0]){
1499
- values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
1500
- }
1501
- break;
1502
-
1503
- case baEnum.PropertyIdentifier.RECORD_COUNT:
1504
- if(object.value[0] ) {
1505
- values[objectId].recordCount = object.value[0].value;
1506
- }
1507
- break;
1508
- }
1509
- }
1510
- if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
1511
- that.networkTree[deviceKey] = values;
1512
- resolve(that.networkTree);
1513
- }
1514
- });
1515
- } catch(e) {
1516
- that.logOut("issue resolving bacnet payload, see error: ", e);
1517
- reject(e);
1554
+ case baEnum.PropertyIdentifier.RECORD_COUNT:
1555
+ if (object.value[0]) {
1556
+ values[objectId].recordCount = object.value[0].value;
1557
+ }
1558
+ break;
1559
+ case baEnum.PropertyIdentifier.PRIORITY_ARRAY:
1560
+ if (object.value.length > 0) {
1561
+ values[objectId].hasPriorityArray = true;
1562
+ }
1563
+ break;
1564
+ case baEnum.PropertyIdentifier.STATE_TEXT:
1565
+ if (object.value) {
1566
+ values[objectId].stateTextArray = object.value;
1567
+ if (typeof values[objectId].presentValue == "number" &&
1568
+ values[objectId].presentValue !== null &&
1569
+ values[objectId].presentValue !== undefined) {
1570
+ const tempIndex = values[objectId].presentValue;
1571
+ if (tempIndex == 0) {
1572
+ values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
1573
+ } else if (tempIndex !== 0) {
1574
+ values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
1518
1575
  }
1576
+ }
1519
1577
  }
1520
- });
1521
- } else {
1522
- //error found in point property
1523
- if(i == fullObjects.length - 1) {
1524
- that.networkTree[deviceKey] = values;
1525
- resolve(that.networkTree);
1578
+ break;
1579
+ case baEnum.PropertyIdentifier.VENDOR_NAME:
1580
+ if (object.value) {
1581
+ if (object.value[0].value && typeof object.value[0].value == "string") {
1582
+ values[objectId].vendorName = object.value[0].value;
1583
+ }
1584
+ }
1585
+ break;
1526
1586
  }
1527
- }
1587
+ }
1588
+ if (
1589
+ pointPropertyIndex == successfulResult.values.length - 1 &&
1590
+ objectIndex == pointProperty.values.length - 1 &&
1591
+ i == fullObjects.length - 1
1592
+ ) {
1593
+ that.networkTree[deviceKey] = values;
1594
+ resolve(that.networkTree);
1595
+ }
1596
+ });
1597
+ } catch (e) {
1598
+ that.logOut("issue resolving bacnet payload, see error: ", e);
1599
+ reject(e);
1600
+ }
1528
1601
  }
1602
+ });
1603
+ } else {
1604
+ //error found in point property
1605
+ if (i == fullObjects.length - 1) {
1529
1606
  that.networkTree[deviceKey] = values;
1530
1607
  resolve(that.networkTree);
1531
- });
1532
- }
1533
-
1534
- mapPropsToArray(propertyList) {
1535
- let uniquePropArray = [];
1536
- for(let i = 0; i < propertyList.length; i++) {
1537
- if(uniquePropArray.indexOf(propertyList[i].value) === -1) uniquePropArray.push(propertyList[i].value);
1608
+ }
1538
1609
  }
1539
- return uniquePropArray;
1610
+ }
1611
+ that.networkTree[deviceKey] = values;
1612
+ resolve(that.networkTree);
1613
+ });
1614
+ }
1615
+
1616
+ mapPropsToArray(propertyList) {
1617
+ let uniquePropArray = [];
1618
+ for (let i = 0; i < propertyList.length; i++) {
1619
+ if (uniquePropArray.indexOf(propertyList[i].value) === -1) uniquePropArray.push(propertyList[i].value);
1540
1620
  }
1541
-
1542
- getPROP_PROGRAM_STATE(value) {
1543
- switch(value) {
1544
- case 0:
1545
- return "0 - Idle";
1546
- case 1:
1547
- return "1 - Loading";
1548
- case 2:
1549
- return "2 - Running";
1550
- case 3:
1551
- return "3 - Waiting";
1552
- case 4:
1553
- return "4 - Halted";
1554
- case 5:
1555
- return "5 - Unloading";
1556
- default:
1557
- return "";
1558
- }
1621
+ return uniquePropArray;
1622
+ }
1623
+
1624
+ getPROP_PROGRAM_STATE(value) {
1625
+ switch (value) {
1626
+ case 0:
1627
+ return "0 - Idle";
1628
+ case 1:
1629
+ return "1 - Loading";
1630
+ case 2:
1631
+ return "2 - Running";
1632
+ case 3:
1633
+ return "3 - Waiting";
1634
+ case 4:
1635
+ return "4 - Halted";
1636
+ case 5:
1637
+ return "5 - Unloading";
1638
+ default:
1639
+ return "";
1559
1640
  }
1560
-
1561
- getPROP_SYSTEM_STATUS(value) {
1562
- switch(value) {
1563
- case 0:
1564
- return "0 - Operational";
1565
- case 1:
1566
- return "1 - Operational Readonly";
1567
- case 2:
1568
- return "2 - Download Required";
1569
- case 3:
1570
- return "3 - Download In Progress";
1571
- case 4:
1572
- return "4 - Non Operational";
1573
- case 5:
1574
- return "5 - Backup In Progress";
1575
- default:
1576
- return "";
1577
- }
1641
+ }
1642
+
1643
+ getPROP_SYSTEM_STATUS(value) {
1644
+ switch (value) {
1645
+ case 0:
1646
+ return "0 - Operational";
1647
+ case 1:
1648
+ return "1 - Operational Readonly";
1649
+ case 2:
1650
+ return "2 - Download Required";
1651
+ case 3:
1652
+ return "3 - Download In Progress";
1653
+ case 4:
1654
+ return "4 - Non Operational";
1655
+ case 5:
1656
+ return "5 - Backup In Progress";
1657
+ default:
1658
+ return "";
1578
1659
  }
1579
-
1580
- getPointIcon(objectId) {
1581
- switch(objectId) {
1582
- case 0:
1583
- //AI
1584
- return "pi pi-circle";
1585
- case 1:
1586
- //AO
1587
- return "pi pi-circle";
1588
- case 2:
1589
- //AV
1590
- return "pi pi-circle";
1591
- case 3:
1592
- //BI
1593
- return "pi pi-circle";
1594
- case 4:
1595
- //BO
1596
- return "pi pi-circle";
1597
- case 5:
1598
- //BV
1599
- return "pi pi-circle";
1600
- case 8:
1601
- //Device
1602
- return "pi pi-box";
1603
- case 13:
1604
- //MI
1605
- return "pi pi-circle";
1606
- case 14:
1607
- //MO
1608
- return "pi pi-circle";
1609
- case 19:
1610
- //MV
1611
- return "pi pi-circle";
1612
- case 10:
1613
- //File
1614
- return "pi pi-file";
1615
- case 16:
1616
- //Program
1617
- return "pi pi-database";
1618
- case 20:
1619
- //Trendlog
1620
- return "pi pi-chart-line";
1621
- case 15:
1622
- //Notification Class
1623
- return "pi pi-bell";
1624
- case 56:
1625
- return "pi pi-sitemap";
1626
- case 178:
1627
- return "pi pi-lock";
1628
- case 17:
1629
- return "pi pi-calendar";
1630
- case 6:
1631
- return "pi pi-calendar";
1632
- default:
1633
- //Return circle for all other types
1634
- return "pi pi-circle";
1635
- }
1660
+ }
1661
+
1662
+ getPointIcon(values) {
1663
+ const objectId = values.meta.objectId.type;
1664
+ const hasPriorityArray =
1665
+ values.hasPriorityArray && values.hasOwnProperty("hasPriorityArray") ? values.hasPriorityArray : false;
1666
+
1667
+ if (hasPriorityArray) {
1668
+ return "pi writePointIcon";
1669
+ } else {
1670
+ switch (objectId) {
1671
+ case 0:
1672
+ //AI
1673
+ return "pi readPointIcon";
1674
+ case 1:
1675
+ //AO
1676
+ return "pi readPointIcon";
1677
+ case 2:
1678
+ //AV
1679
+ return "pi readPointIcon";
1680
+ case 3:
1681
+ //BI
1682
+ return "pi readPointIcon";
1683
+ case 4:
1684
+ //BO
1685
+ return "pi readPointIcon";
1686
+ case 5:
1687
+ //BV
1688
+ return "pi readPointIcon";
1689
+ case 8:
1690
+ //Device
1691
+ return "pi pi-box";
1692
+ case 13:
1693
+ //MI
1694
+ return "pi readPointIcon";
1695
+ case 14:
1696
+ //MO
1697
+ return "pi readPointIcon";
1698
+ case 19:
1699
+ //MV
1700
+ return "pi readPointIcon";
1701
+ case 10:
1702
+ //File
1703
+ return "pi pi-file";
1704
+ case 16:
1705
+ //Program
1706
+ return "pi pi-database";
1707
+ case 20:
1708
+ //Trendlog
1709
+ return "pi pi-chart-line";
1710
+ case 15:
1711
+ //Notification Class
1712
+ return "pi pi-bell";
1713
+ case 56:
1714
+ return "pi pi-sitemap";
1715
+ case 178:
1716
+ return "pi pi-lock";
1717
+ case 17:
1718
+ return "pi pi-calendar";
1719
+ case 6:
1720
+ return "pi pi-calendar";
1721
+ default:
1722
+ //Return circle for all other types
1723
+ return "pi readPointIcon";
1724
+ }
1636
1725
  }
1637
-
1638
- getObjectType(objectId) {
1639
- switch(objectId) {
1640
- case 0:
1641
- return "AI";
1642
- case 1:
1643
- return "AO";
1644
- case 2:
1645
- return "AV";
1646
- case 3:
1647
- return "BI";
1648
- case 4:
1649
- return "BO";
1650
- case 5:
1651
- return "BV";
1652
- case 8:
1653
- return "Device";
1654
- case 13:
1655
- return "MI";
1656
- case 14:
1657
- return "MO";
1658
- case 19:
1659
- return "MV";
1660
- case 40:
1661
- return "CS";
1662
- default:
1663
- return "";
1664
- }
1726
+ }
1727
+
1728
+ getObjectType(objectId) {
1729
+ switch (objectId) {
1730
+ case 0:
1731
+ return "AI";
1732
+ case 1:
1733
+ return "AO";
1734
+ case 2:
1735
+ return "AV";
1736
+ case 3:
1737
+ return "BI";
1738
+ case 4:
1739
+ return "BO";
1740
+ case 5:
1741
+ return "BV";
1742
+ case 8:
1743
+ return "Device";
1744
+ case 13:
1745
+ return "MI";
1746
+ case 14:
1747
+ return "MO";
1748
+ case 19:
1749
+ return "MV";
1750
+ case 40:
1751
+ return "CS";
1752
+ default:
1753
+ return "";
1665
1754
  }
1666
-
1667
- getPROP_RELIABILITY(value) {
1668
- switch(value) {
1669
- case 0:
1670
- return "No Fault Detected";
1671
- case 1:
1672
- return "No Sensor";
1673
- case 2:
1674
- return "Over Range";
1675
- case 3:
1676
- return "Under Range";
1677
- case 4:
1678
- return "Open Loop";
1679
- case 5:
1680
- return "Shorted Loop";
1681
- case 6:
1682
- return "No Output";
1683
- case 7:
1684
- return "Unreliable Other";
1685
- case 8:
1686
- return "Process Error";
1687
- case 9:
1688
- return "Multi State Fault";
1689
- case 10:
1690
- return "Configuration Error";
1691
- case 11:
1692
- return "Member Fault";
1693
- case 12:
1694
- return "Communication Failure";
1695
- case 13:
1696
- return "Tripped";
1697
- default:
1698
- return "";
1699
- }
1755
+ }
1756
+
1757
+ getPROP_RELIABILITY(value) {
1758
+ switch (value) {
1759
+ case 0:
1760
+ return "No Fault Detected";
1761
+ case 1:
1762
+ return "No Sensor";
1763
+ case 2:
1764
+ return "Over Range";
1765
+ case 3:
1766
+ return "Under Range";
1767
+ case 4:
1768
+ return "Open Loop";
1769
+ case 5:
1770
+ return "Shorted Loop";
1771
+ case 6:
1772
+ return "No Output";
1773
+ case 7:
1774
+ return "Unreliable Other";
1775
+ case 8:
1776
+ return "Process Error";
1777
+ case 9:
1778
+ return "Multi State Fault";
1779
+ case 10:
1780
+ return "Configuration Error";
1781
+ case 11:
1782
+ return "Member Fault";
1783
+ case 12:
1784
+ return "Communication Failure";
1785
+ case 13:
1786
+ return "Tripped";
1787
+ default:
1788
+ return "";
1700
1789
  }
1701
-
1702
- getStatusFlags(flags) {
1703
- return flags.value[0].value;
1704
- }
1705
-
1706
- getDeviceIcon(isMstp, manualDiscoveryMode) {
1707
- if(manualDiscoveryMode == true) {
1708
- return "pi pi-question-circle"
1709
- } else if(manualDiscoveryMode == false) {
1710
- if(isMstp == true) {
1711
- return "pi pi-box"
1712
- } else if(isMstp == false) {
1713
- return "pi pi-server"
1714
- }
1715
- }
1790
+ }
1791
+
1792
+ getStatusFlags(flags) {
1793
+ return flags.value[0].value;
1794
+ }
1795
+
1796
+ getDeviceIcon(isMstp, manualDiscoveryMode) {
1797
+ if (manualDiscoveryMode == true) {
1798
+ return "pi pi-question-circle";
1799
+ } else if (manualDiscoveryMode == false) {
1800
+ if (isMstp == true) {
1801
+ return "pi pi-box";
1802
+ } else if (isMstp == false) {
1716
1803
  return "pi pi-server";
1717
- };
1804
+ }
1805
+ }
1806
+ return "pi pi-server";
1807
+ }
1718
1808
  }
1719
1809
 
1720
1810
  module.exports = { BacnetClient };