@bitpoolos/edge-bacnet 1.2.6 → 1.2.8

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