@bitpoolos/edge-bacnet 1.1.8 → 1.2.2

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.
Files changed (122) hide show
  1. package/bacnet_client.js +336 -168
  2. package/bacnet_device.js +50 -16
  3. package/bacnet_gateway.html +119 -15
  4. package/bacnet_gateway.js +388 -395
  5. package/bacnet_read.html +32 -11
  6. package/bacnet_read.js +1 -1
  7. package/bacnet_server.js +16 -12
  8. package/common.js +26 -19
  9. package/examples/1-Discover-Read.json +1 -1
  10. package/examples/2-Discover-Write.json +1 -1
  11. package/examples/3-Discover-Read-Write.json +1 -1
  12. package/package.json +3 -3
  13. package/resources/{node-bacnet/LICENSE.md → node-bacstack-ts/LICENSE} +3 -4
  14. package/resources/node-bacstack-ts/README.md +75 -0
  15. package/resources/{node-bacnet → node-bacstack-ts/dist}/index.js +0 -2
  16. package/resources/node-bacstack-ts/dist/lib/apdu.js +193 -0
  17. package/resources/node-bacstack-ts/dist/lib/asn1.js +1660 -0
  18. package/resources/node-bacstack-ts/dist/lib/bvlc.js +47 -0
  19. package/resources/node-bacstack-ts/dist/lib/client.js +1454 -0
  20. package/resources/node-bacstack-ts/dist/lib/enum.js +2114 -0
  21. package/resources/node-bacstack-ts/dist/lib/npdu.js +112 -0
  22. package/resources/node-bacstack-ts/dist/lib/services/add-list-element.js +58 -0
  23. package/resources/node-bacstack-ts/dist/lib/services/alarm-acknowledge.js +93 -0
  24. package/resources/node-bacstack-ts/dist/lib/services/alarm-summary.js +42 -0
  25. package/resources/node-bacstack-ts/dist/lib/services/atomic-read-file.js +157 -0
  26. package/resources/node-bacstack-ts/dist/lib/services/atomic-write-file.js +136 -0
  27. package/resources/node-bacstack-ts/dist/lib/services/cov-notify.js +119 -0
  28. package/resources/node-bacstack-ts/dist/lib/services/create-object.js +104 -0
  29. package/resources/node-bacstack-ts/dist/lib/services/delete-object.js +21 -0
  30. package/resources/node-bacstack-ts/dist/lib/services/device-communication-control.js +46 -0
  31. package/resources/node-bacstack-ts/dist/lib/services/error.js +27 -0
  32. package/resources/node-bacstack-ts/dist/lib/services/event-information.js +100 -0
  33. package/resources/node-bacstack-ts/dist/lib/services/event-notify-data.js +219 -0
  34. package/resources/node-bacstack-ts/dist/lib/services/get-enrollment-summary.js +172 -0
  35. package/resources/node-bacstack-ts/dist/lib/services/get-event-information.js +135 -0
  36. package/resources/node-bacstack-ts/dist/lib/services/i-am-broadcast.js +59 -0
  37. package/resources/node-bacstack-ts/dist/lib/services/i-have-broadcast.js +34 -0
  38. package/resources/node-bacstack-ts/dist/lib/services/index.js +32 -0
  39. package/resources/node-bacstack-ts/dist/lib/services/life-safety-operation.js +40 -0
  40. package/resources/node-bacstack-ts/dist/lib/services/private-transfer.js +43 -0
  41. package/resources/node-bacstack-ts/dist/lib/services/read-property-multiple.js +44 -0
  42. package/resources/node-bacstack-ts/dist/lib/services/read-property.js +122 -0
  43. package/resources/node-bacstack-ts/dist/lib/services/read-range.js +201 -0
  44. package/resources/node-bacstack-ts/dist/lib/services/reinitialize-device.js +35 -0
  45. package/resources/node-bacstack-ts/dist/lib/services/subscribe-cov.js +55 -0
  46. package/resources/node-bacstack-ts/dist/lib/services/subscribe-property.js +93 -0
  47. package/resources/node-bacstack-ts/dist/lib/services/time-sync.js +31 -0
  48. package/resources/node-bacstack-ts/dist/lib/services/who-has.js +56 -0
  49. package/resources/node-bacstack-ts/dist/lib/services/who-is.js +45 -0
  50. package/resources/node-bacstack-ts/dist/lib/services/write-property-multiple.js +105 -0
  51. package/resources/node-bacstack-ts/dist/lib/services/write-property.js +90 -0
  52. package/resources/node-bacstack-ts/dist/lib/transport.js +49 -0
  53. package/resources/node-bacstack-ts/dist/lib/types.js +2 -0
  54. package/resources/node-bacstack-ts/package.json +94 -0
  55. package/resources/node-bacnet/CHANGELOG.md +0 -481
  56. package/resources/node-bacnet/README.md +0 -91
  57. package/resources/node-bacnet/docs/Client.html +0 -4422
  58. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  59. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  60. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  61. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  62. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  63. package/resources/node-bacnet/docs/bacnet.html +0 -7032
  64. package/resources/node-bacnet/docs/client.js.html +0 -1759
  65. package/resources/node-bacnet/docs/enum.js.html +0 -2530
  66. package/resources/node-bacnet/docs/global.html +0 -2068
  67. package/resources/node-bacnet/docs/images/mocha-logo.svg +0 -65
  68. package/resources/node-bacnet/docs/index.html +0 -283
  69. package/resources/node-bacnet/docs/scripts/collapse.js +0 -11
  70. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +0 -4
  71. package/resources/node-bacnet/docs/scripts/linenumber.js +0 -26
  72. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  73. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +0 -2
  74. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +0 -28
  75. package/resources/node-bacnet/docs/scripts/search.js +0 -47
  76. package/resources/node-bacnet/docs/services_i-am.js.html +0 -157
  77. package/resources/node-bacnet/docs/services_time-sync.js.html +0 -118
  78. package/resources/node-bacnet/docs/services_who-is.js.html +0 -138
  79. package/resources/node-bacnet/docs/styles/jsdoc.css +0 -683
  80. package/resources/node-bacnet/docs/styles/prettify.css +0 -82
  81. package/resources/node-bacnet/examples/discover-devices.js +0 -66
  82. package/resources/node-bacnet/examples/read-device.js +0 -510
  83. package/resources/node-bacnet/examples/subscribe-cov.js +0 -75
  84. package/resources/node-bacnet/lib/apdu.js +0 -209
  85. package/resources/node-bacnet/lib/asn1.js +0 -1733
  86. package/resources/node-bacnet/lib/bvlc.js +0 -90
  87. package/resources/node-bacnet/lib/client.js +0 -1695
  88. package/resources/node-bacnet/lib/enum.js +0 -2463
  89. package/resources/node-bacnet/lib/npdu.js +0 -123
  90. package/resources/node-bacnet/lib/services/add-list-element.js +0 -64
  91. package/resources/node-bacnet/lib/services/alarm-acknowledge.js +0 -90
  92. package/resources/node-bacnet/lib/services/alarm-summary.js +0 -42
  93. package/resources/node-bacnet/lib/services/atomic-read-file.js +0 -162
  94. package/resources/node-bacnet/lib/services/atomic-write-file.js +0 -138
  95. package/resources/node-bacnet/lib/services/cov-notify.js +0 -126
  96. package/resources/node-bacnet/lib/services/create-object.js +0 -106
  97. package/resources/node-bacnet/lib/services/delete-object.js +0 -23
  98. package/resources/node-bacnet/lib/services/device-communication-control.js +0 -48
  99. package/resources/node-bacnet/lib/services/error.js +0 -33
  100. package/resources/node-bacnet/lib/services/event-information.js +0 -99
  101. package/resources/node-bacnet/lib/services/event-notify-data.js +0 -229
  102. package/resources/node-bacnet/lib/services/get-enrollment-summary.js +0 -178
  103. package/resources/node-bacnet/lib/services/get-event-information.js +0 -144
  104. package/resources/node-bacnet/lib/services/i-am.js +0 -90
  105. package/resources/node-bacnet/lib/services/i-have.js +0 -34
  106. package/resources/node-bacnet/lib/services/index.js +0 -34
  107. package/resources/node-bacnet/lib/services/life-safety-operation.js +0 -40
  108. package/resources/node-bacnet/lib/services/private-transfer.js +0 -43
  109. package/resources/node-bacnet/lib/services/read-property-multiple.js +0 -50
  110. package/resources/node-bacnet/lib/services/read-property.js +0 -130
  111. package/resources/node-bacnet/lib/services/read-range.js +0 -201
  112. package/resources/node-bacnet/lib/services/register-foreign-device.js +0 -18
  113. package/resources/node-bacnet/lib/services/reinitialize-device.js +0 -37
  114. package/resources/node-bacnet/lib/services/subscribe-cov.js +0 -57
  115. package/resources/node-bacnet/lib/services/subscribe-property.js +0 -97
  116. package/resources/node-bacnet/lib/services/time-sync.js +0 -51
  117. package/resources/node-bacnet/lib/services/who-has.js +0 -54
  118. package/resources/node-bacnet/lib/services/who-is.js +0 -71
  119. package/resources/node-bacnet/lib/services/write-property-multiple.js +0 -117
  120. package/resources/node-bacnet/lib/services/write-property.js +0 -94
  121. package/resources/node-bacnet/lib/transport.js +0 -82
  122. package/resources/node-bacnet/package.json +0 -92
package/bacnet_client.js CHANGED
@@ -1,15 +1,15 @@
1
1
  /*
2
2
  MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
3
3
  */
4
- const bacnet = require('./resources/node-bacnet/index.js');
5
- const { BacnetServer } = require("./bacnet_server.js");
4
+
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, captureRejectionSymbol } = require('events');
9
- const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync } = require('./common');
8
+ const { EventEmitter } = require('events');
9
+ const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync } = require('./common');
10
10
  const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
11
11
  const { BacnetDevice } = require('./bacnet_device');
12
- const {Mutex, Semaphore, withTimeout} = require("async-mutex");
12
+ const {Mutex} = require("async-mutex");
13
13
 
14
14
  class BacnetClient extends EventEmitter {
15
15
 
@@ -17,29 +17,31 @@ class BacnetClient extends EventEmitter {
17
17
  constructor(config) {
18
18
  super();
19
19
  let that = this;
20
-
21
- let cachedData = JSON.parse(Read_Config_Sync());
22
-
23
20
  that.deviceList = [];
21
+ that.manualDiscoverQueue = [];
24
22
  that.networkTree = {};
25
23
  that.lastWhoIs = null;
26
24
  that.client = null;
27
25
  that.lastNetworkPoll = null;
28
26
  that.scheduler = new ToadScheduler();
29
27
  that.mutex = new Mutex();
28
+ that.manualMutex = new Mutex();
29
+ that.pollInProgress = false;
30
30
 
31
- if(typeof cachedData == "object") {
32
- if(cachedData.renderList) that.renderList = cachedData.renderList;
33
- if(cachedData.deviceList) {
34
- cachedData.deviceList.forEach(function(device) {
35
- let newBacnetDevice = new BacnetDevice(true, device);
36
- that.deviceList.push(newBacnetDevice);
37
- });
31
+ try {
32
+
33
+ let cachedData = JSON.parse(Read_Config_Sync());
34
+ if(typeof cachedData == "object") {
35
+ if(cachedData.renderList) that.renderList = cachedData.renderList;
36
+ if(cachedData.deviceList) {
37
+ cachedData.deviceList.forEach(function(device) {
38
+ let newBacnetDevice = new BacnetDevice(true, device);
39
+ that.deviceList.push(newBacnetDevice);
40
+ });
41
+ }
42
+ if(cachedData.pointList) that.networkTree = cachedData.pointList;
38
43
  }
39
- if(cachedData.pointList) that.networkTree = cachedData.pointList;
40
- }
41
44
 
42
- try {
43
45
  that.config = config;
44
46
  that.roundDecimal = config.roundDecimal;
45
47
  that.apduSize = config.apduSize;
@@ -53,7 +55,8 @@ class BacnetClient extends EventEmitter {
53
55
  that.manual_instance_range_enabled = config.manual_instance_range_enabled;
54
56
  that.manual_instance_range_start = config.manual_instance_range_start;
55
57
  that.manual_instance_range_end = config.manual_instance_range_end;
56
- that.bacnetServerEnabled = config.bacnetServerEnabled;
58
+ that.device_read_schedule = config.device_read_schedule;
59
+ that.deviceRetryCount = parseInt(config.retries);
57
60
 
58
61
  that.readPropertyMultipleOptions = {
59
62
  maxSegments: that.maxSegments,
@@ -62,10 +65,10 @@ class BacnetClient extends EventEmitter {
62
65
 
63
66
  try {
64
67
 
65
- that.client = new bacnet({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
68
+ that.client = new bacnet.Client({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
66
69
  that.setMaxListeners(1);
67
70
 
68
- const task = new Task('simple task', () => {
71
+ const task = new Task('simple task', () => {
69
72
  that.globalWhoIs();
70
73
  });
71
74
 
@@ -75,11 +78,12 @@ class BacnetClient extends EventEmitter {
75
78
 
76
79
  //query device task
77
80
  const queryDevices = new Task('simple task', () => {
78
- that.queryDevices();
81
+ if(!that.pollInProgress) that.queryDevices();
79
82
  that.sanitizeDeviceList();
83
+ //that.queryDevicesManually();
80
84
  });
81
85
 
82
- const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, queryDevices)
86
+ const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule), }, queryDevices)
83
87
 
84
88
  that.scheduler.addSimpleIntervalJob(queryJob);
85
89
 
@@ -88,7 +92,7 @@ class BacnetClient extends EventEmitter {
88
92
  that.buildNetworkTreeData();
89
93
  });
90
94
 
91
- const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 5, }, buildNetworkTree)
95
+ const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
92
96
 
93
97
  that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
94
98
 
@@ -97,19 +101,21 @@ class BacnetClient extends EventEmitter {
97
101
  setTimeout(() => {
98
102
  that.queryDevices();
99
103
  that.sanitizeDeviceList();
104
+ that.buildNetworkTreeData();
100
105
  }, "5000")
101
106
 
102
107
  } catch(e) {
108
+ console.log("Issue initializing client: ", e)
103
109
  that.logOut("Issue initializing client: ", e)
104
110
  }
105
111
 
106
112
  //who is callback
107
113
  that.client.on('iAm', (device) => {
108
- if(device.header.sender.address !== that.config.localIpAdrress) {
114
+ if(device.address !== that.config.localIpAdrress) {
109
115
  if(that.device_id_range_enabled) {
110
- if(device.payload.deviceId >= that.device_id_range_start && device.payload.deviceId <= that.device_id_range_end) {
116
+ if(device.deviceId >= that.device_id_range_start && device.deviceId <= that.device_id_range_end) {
111
117
  //only add unique device to array
112
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
118
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
113
119
  if(foundIndex == -1) {
114
120
  let newBacnetDevice = new BacnetDevice(false, device);
115
121
  newBacnetDevice.setLastSeen(Date.now());
@@ -127,7 +133,7 @@ class BacnetClient extends EventEmitter {
127
133
  }
128
134
  } else {
129
135
  //only add unique device to array
130
- let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
136
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
131
137
  if(foundIndex == -1) {
132
138
  let newBacnetDevice = new BacnetDevice(false, device);
133
139
  newBacnetDevice.setLastSeen(Date.now());
@@ -174,6 +180,7 @@ class BacnetClient extends EventEmitter {
174
180
  that.deviceList = [];
175
181
  that.renderList = [];
176
182
  that.networkTree = {};
183
+ that.pollInProgress = false;
177
184
  resolve(true);
178
185
  } catch(e) {
179
186
  that.logOut("Error clearing BACnet data model: ", e);
@@ -184,50 +191,135 @@ class BacnetClient extends EventEmitter {
184
191
 
185
192
  queryDevices() {
186
193
  let that = this;
187
- that.deviceList.forEach(function(device, index){
188
- that.mutex
189
- .acquire()
190
- .then(function(release) {
191
- try {
192
- that.getDevicePointList(device).then(function() {
193
- that.buildJsonObject(device).then(function() {
194
- release();
195
- }).catch(function(e) {
196
- release();
197
- });
198
- }).catch(function(e) {
199
- that.getDevicePointListWithoutObjectList(device).then(function() {
200
- that.buildJsonObject(device).then(function() {
201
- release();
194
+
195
+ that.pollInProgress = true;
196
+
197
+ let index = 0;
198
+
199
+ query(index);
200
+
201
+ function query(index) {
202
+ let device = that.deviceList[index];
203
+
204
+ if(index < that.deviceList.length) {
205
+ index++;
206
+
207
+ if(typeof device == "object") {
208
+ if(!device.getManualDiscoveryMode()) {
209
+ try {
210
+ that.getDevicePointList(device).then(function() {
211
+ that.removeDeviceFromManualQueue(device);
212
+ that.buildJsonObject(device).then(function() {
213
+ query(index);
214
+ }).catch(function(e) {
215
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
216
+ query(index);
217
+ });
202
218
  }).catch(function(e) {
203
- release();
219
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
220
+ that.addDeviceToManualQueue(device);
221
+ query(index);
204
222
  });
205
- }).catch(function(e) {
206
- release();
207
- });
208
- release();
209
- });
210
- } catch(e) {
211
- that.logOut("Error while querying devices: ", e);
212
- release();
223
+ } catch(e) {
224
+ that.logOut("Error while querying devices: ", e);
225
+ query(index);
226
+ }
227
+ } else {
228
+ query(index);
229
+ }
230
+ } else {
231
+ that.logOut("queryDevices: invalid device found: ", device);
232
+ query(index);
213
233
  }
214
- });
215
- });
216
- Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
234
+ } else if(index == that.deviceList.length) {
235
+
236
+ if(that.manualDiscoverQueue.length > 0) {
237
+ that.queryDevicesManually();
238
+ } else {
239
+ that.pollInProgress = false;
240
+ }
241
+
242
+ }
243
+ }
244
+ }
245
+
246
+ queryDevicesManually() {
247
+ let that = this;
248
+
249
+ let index = 0;
250
+
251
+ query(index);
252
+
253
+ function query(index) {
254
+ let device = that.manualDiscoverQueue[index];
255
+
256
+ if(index < that.manualDiscoverQueue.length) {
257
+ index++;
258
+
259
+ if(typeof device == "object") {
260
+ try {
261
+ if(device.shouldBeInManualMode()) {
262
+ that.getDevicePointListWithoutObjectList(device).then(function() {
263
+ that.buildJsonObject(device).then(function() {
264
+ query(index);
265
+ }).catch(function(e) {
266
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
267
+ query(index);
268
+ });
269
+ }).catch(function(e){
270
+ query(index);
271
+ });
272
+ } else {
273
+ that.removeDeviceFromManualQueue(device);
274
+ query(index);
275
+ }
276
+ } catch(e) {
277
+ query(index);
278
+ }
279
+ } else {
280
+ query(index);
281
+ }
282
+ } else if(index == that.manualDiscoverQueue.length) {
283
+ that.pollInProgress = false;
284
+ }
285
+ }
286
+ }
287
+
288
+ addDeviceToManualQueue(device) {
289
+ let that = this;
290
+
291
+ if(device.getPointListRetryCount() > that.deviceRetryCount) {
292
+ device.setManualDiscoveryMode(true);
293
+ let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
294
+ if(index == -1) {
295
+ that.manualDiscoverQueue.push(device);
296
+ }
297
+ } else {
298
+ device.incrementPointListRetryCount();
299
+ }
300
+ }
301
+
302
+ removeDeviceFromManualQueue(device) {
303
+ let that = this;
304
+ device.setManualDiscoveryMode(false);
305
+ device.clearPointListRetryCount()
306
+ let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
307
+ if(index !== -1) {
308
+ that.manualDiscoverQueue.splice(index, 1);
309
+ }
217
310
  }
218
311
 
219
312
  sanitizeDeviceList() {
220
313
  let that = this;
221
314
 
222
315
  //1 hour in seconds
223
- let timeoutThreshold = 3600;
316
+ let timeoutThreshold = parseInt(that.discover_polling_schedule);
224
317
 
225
- that.renderList.forEach(function(item, index) {
226
- if(((Date.now() - item.lastSeen) / 1000) > timeoutThreshold) {
227
- //render item hasnt responded to whoIs for over an hour
318
+ that.deviceList.forEach(function(device, index) {
319
+ if(((Date.now() - device.lastSeen) / 1000) > timeoutThreshold) {
320
+ //render device hasnt responded to whoIs for over an hour
228
321
 
229
- let deviceIndex = that.deviceList.findIndex(ele => ele.deviceId == item.deviceId);
230
- let device = that.deviceList[deviceIndex];
322
+ let renderListIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
231
323
 
232
324
  let ipAddr = typeof device.getAddress() == "object" ? device.getAddress().address : device.getAddress();
233
325
  let deviceKey = ipAddr + "-" + device.getDeviceId();
@@ -235,10 +327,10 @@ class BacnetClient extends EventEmitter {
235
327
  delete that.networkTree[deviceKey];
236
328
 
237
329
  if(((Date.now() - device.getLastSeen()) / 1000) > timeoutThreshold) {
238
- that.deviceList.splice(deviceIndex, 1);
330
+ that.renderList.splice(renderListIndex, 1);
239
331
  }
240
332
 
241
- that.renderList.splice(index, 1);
333
+ that.deviceList.splice(index, 1);
242
334
  }
243
335
  });
244
336
 
@@ -246,9 +338,10 @@ class BacnetClient extends EventEmitter {
246
338
 
247
339
  updateDeviceName(device) {
248
340
  let that = this;
249
- that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceName) {
250
- if(typeof deviceName == "string") {
251
- device.setDeviceName(deviceName);
341
+ that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceObject) {
342
+ if(typeof deviceObject.name == "string") {
343
+ device.setDeviceName(deviceObject.name);
344
+ device.setPointsList(deviceObject.devicePointEntry);
252
345
  }
253
346
  });
254
347
  }
@@ -269,7 +362,7 @@ class BacnetClient extends EventEmitter {
269
362
  that.manual_instance_range_enabled = config.manual_instance_range_enabled;
270
363
  that.manual_instance_range_start = config.manual_instance_range_start;
271
364
  that.manual_instance_range_end = config.manual_instance_range_end;
272
- that.bacnetServerEnabled = config.bacnetServerEnabled;
365
+ that.device_read_schedule = config.device_read_schedule;
273
366
 
274
367
  if(that.scheduler !== null) {
275
368
  that.scheduler.stop();
@@ -293,7 +386,25 @@ class BacnetClient extends EventEmitter {
293
386
 
294
387
  that.scheduler.addSimpleIntervalJob(job);
295
388
 
296
- that.globalWhoIs();
389
+
390
+ // //query device task
391
+ const queryDevices = new Task('simple task', () => {
392
+ if(!that.pollInProgress) that.queryDevices();
393
+ that.sanitizeDeviceList();
394
+ });
395
+
396
+ const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule), }, queryDevices)
397
+
398
+ that.scheduler.addSimpleIntervalJob(queryJob);
399
+
400
+ //buildNetworkTreeData task
401
+ const buildNetworkTree = new Task('simple task', () => {
402
+ that.buildNetworkTreeData();
403
+ });
404
+
405
+ const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
406
+
407
+ that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
297
408
 
298
409
  } catch(e){
299
410
  that.logOut("Error reinitializing bacnet client: ", e)
@@ -366,18 +477,20 @@ class BacnetClient extends EventEmitter {
366
477
  return new Promise((resolve, reject) => {
367
478
  that._readDeviceName(address, deviceId, (err, result) => {
368
479
  if(result) {
369
- result.values[0].values.forEach(object => {
370
- try {
371
- if(object.value[0]) {
372
- resolve(object.value[0].value);
373
- } else {
374
- that.logOut("Issue with deviceName payload, see object: ", object);
375
- }
376
- } catch(e){
377
- that.logOut("Unable to get device name: ", e);
480
+ try {
481
+ if(result.values[0].value) {
482
+ const deviceObject = {
483
+ name: result.values[0].value,
484
+ devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }]
485
+ };
486
+ resolve(deviceObject);
487
+ } else {
488
+ that.logOut("Issue with deviceName payload, see object: ", object);
378
489
  }
379
- });
380
- }
490
+ } catch(e){
491
+ that.logOut("Unable to get device name: ", e);
492
+ }
493
+ }
381
494
  });
382
495
  });
383
496
  }
@@ -429,7 +542,7 @@ class BacnetClient extends EventEmitter {
429
542
  device.setPointsList(result);
430
543
  resolve(result);
431
544
  } catch(e) {
432
- that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
545
+ that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
433
546
  reject(e);
434
547
  }
435
548
  });
@@ -439,7 +552,6 @@ class BacnetClient extends EventEmitter {
439
552
  let that = this;
440
553
  return new Promise(function(resolve, reject) {
441
554
  try {
442
- device.setManualDiscoveryMode(true);
443
555
  that.scanDeviceManually(device).then(function(result) {
444
556
  device.setPointsList(result);
445
557
  resolve(result);
@@ -447,7 +559,6 @@ class BacnetClient extends EventEmitter {
447
559
  reject(error);
448
560
  });
449
561
 
450
-
451
562
  } catch(e) {
452
563
  that.logOut("Error getting point list: ", e);
453
564
  reject(e);
@@ -458,11 +569,15 @@ class BacnetClient extends EventEmitter {
458
569
 
459
570
  scanDeviceManually(device) {
460
571
  let that = this;
572
+
461
573
  return new Promise(function(resolve, reject) {
574
+
462
575
  let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
463
576
  let address = device.getAddress();
464
- let objectTypeList = [0, 1, 2, 3];
465
- let instanceRange = {start: 0, end: 100};
577
+ let objectTypeList = [0, 1, 2, 3, 4, 5, 13, 14, 19];
578
+ //let objectTypeList = [0, 1, 2, 3, 4, 5, 6, 10, 13, 14, 15, 16, 17, ,19, 20, 56, 178];
579
+ //let instanceRange = {start: 0, end: 100};
580
+ let instanceRange = device.getmDiscoverInstanceRange();
466
581
  let requestArray = [];
467
582
  let maxRequestThreshold = 1000;
468
583
  let requestRate = 20;
@@ -491,8 +606,8 @@ class BacnetClient extends EventEmitter {
491
606
  instanceRange.end += requestRate;
492
607
  requestArray = [];
493
608
  if(i >= maxRequestThreshold) {
494
- instanceRange.end = maxRequestThreshold;
495
609
  if(typeListIndex == objectTypeList.length-1) {
610
+ device.setmDiscoverInstanceRange({start: instanceRange.end, end: instanceRange.end + 100})
496
611
  send();
497
612
  }
498
613
 
@@ -501,7 +616,6 @@ class BacnetClient extends EventEmitter {
501
616
  }
502
617
  }
503
618
 
504
- instanceRange.end = 100;
505
619
  };
506
620
 
507
621
  function send() {
@@ -510,7 +624,6 @@ class BacnetClient extends EventEmitter {
510
624
  let promise = requestBuffer[index];
511
625
  try {
512
626
  Promise.resolve(promise).then(function(result) {
513
- let keys = Object.keys(result);
514
627
  for (const [key, value] of Object.entries(result)) {
515
628
  if(key == "value" && typeof value == "object") {
516
629
  for(let x = 0; x < value.values.length; x++) {
@@ -535,6 +648,7 @@ class BacnetClient extends EventEmitter {
535
648
  }
536
649
  }
537
650
  }
651
+
538
652
  });
539
653
  }
540
654
 
@@ -550,6 +664,34 @@ class BacnetClient extends EventEmitter {
550
664
  });
551
665
  }
552
666
 
667
+ _readDeviceName(deviceAddress, deviceId, callback){
668
+ let that = this;
669
+ that.client.readProperty(
670
+ deviceAddress,
671
+ {type: baEnum.ObjectType.DEVICE, instance: deviceId },
672
+ baEnum.PropertyIdentifier.OBJECT_NAME,
673
+ that.readPropertyMultipleOptions,
674
+ callback
675
+ );
676
+ }
677
+
678
+ _readObjectList(deviceAddress, deviceId, callback) {
679
+ let that = this;
680
+
681
+ try {
682
+ that.client.readProperty(
683
+ deviceAddress,
684
+ {type: baEnum.ObjectType.DEVICE, instance: deviceId },
685
+ baEnum.PropertyIdentifier.OBJECT_LIST,
686
+ that.readPropertyMultipleOptions,
687
+ callback
688
+ );
689
+
690
+ } catch(e) {
691
+ that.logOut("Error reading object list: ", e);
692
+ }
693
+ }
694
+
553
695
  _readObject(deviceAddress, type, instance, properties) {
554
696
  let that = this;
555
697
  return new Promise((resolve, reject) => {
@@ -566,38 +708,49 @@ class BacnetClient extends EventEmitter {
566
708
  });
567
709
  }
568
710
 
569
- _readDeviceName(deviceAddress, deviceId, callback){
711
+ _readObjectFull(deviceAddress, type, instance) {
570
712
  let that = this;
571
- const requestArray = [{
572
- objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
573
- properties: [
574
- { id: baEnum.PropertyIdentifier.OBJECT_NAME }
575
- ]
576
- }];
577
-
578
- this.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
579
- }
580
713
 
581
- _readObjectList(deviceAddress, deviceId, callback) {
582
- let that = this;
583
- const requestArray = [{
584
- objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
585
- properties: [{ id: baEnum.PropertyIdentifier.OBJECT_LIST }
586
- ]
587
- }];
588
-
589
- try {
590
- that.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
591
- } catch(e) {
592
- that.logOut("Error reading object list: ", e);
593
- }
594
- }
714
+ const allProperties = [
715
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
716
+ { id: baEnum.PropertyIdentifier.DESCRIPTION },
717
+ { id: baEnum.PropertyIdentifier.UNITS },
718
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
719
+ { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
720
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
721
+ { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
722
+ { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
723
+ { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
724
+ { id: baEnum.PropertyIdentifier.RECORD_COUNT }
725
+ ];
595
726
 
596
- _readObjectFull(deviceAddress, type, instance) {
727
+ return new Promise((resolve, reject) => {
728
+ that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }]).then(function(result) {
729
+
730
+ if(result.value) {
731
+ resolve(result);
732
+ }
597
733
 
598
- return this._readObject(deviceAddress, type, instance, [
599
- { id: baEnum.PropertyIdentifier.ALL }
600
- ]);
734
+ if(result.error) {
735
+ const requestArray = [{
736
+ objectId: { type: type, instance: instance },
737
+ properties: allProperties
738
+ }];
739
+
740
+ that._readObjectWithRequestArray(deviceAddress, requestArray).then(function(manualRequest) {
741
+ if(manualRequest.value) {
742
+ resolve(manualRequest);
743
+ }
744
+ if(manualRequest.error) {
745
+ reject(manualRequest.error);
746
+ }
747
+ })
748
+ }
749
+
750
+ }).catch(function(error) {
751
+ reject(error);
752
+ });
753
+ });
601
754
 
602
755
  };
603
756
 
@@ -695,59 +848,13 @@ class BacnetClient extends EventEmitter {
695
848
  }
696
849
  };
697
850
 
698
- _mapToDeviceObject(object) {
699
- if (!object || !object.values) {
700
- return null;
701
- }
702
-
703
- const objectInfo = object.values[0].objectId;
704
- const deviceObjectId = new DeviceObjectId(objectInfo.type, objectInfo.instance);
705
- const objectProperties = object.values[0].values;
706
- const name = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_NAME);
707
- const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.PropertyIdentifier.DESCRIPTION);
708
- const type = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_TYPE);
709
- const PROP_UNITS = this._findValueById(objectProperties, baEnum.PropertyIdentifier.UNITS);
710
- const presentValue = this._findValueById(objectProperties, baEnum.PropertyIdentifier.PRESENT_VALUE);
711
-
712
- return new DeviceObject(deviceObjectId, name, PROP_DESCRIPTION, type, PROP_UNITS, presentValue);
713
- }
714
-
715
- scanForDevices(config) {
716
- let that = this;
717
-
718
- //scan on first poll
719
- if(that.lastWhoIs == null){
720
- doScan();
721
- that.lastWhoIs = Date.now();
722
-
723
- //scan every hour
724
- } else if (((Date.now() / 1000) - (that.lastWhoIs / 1000)) >= 3600) {
725
- doScan();
726
- that.lastWhoIs = Date.now();
727
- }
728
-
729
- function doScan() {
730
- let deviceIdRange = config.device.deviceId.split("-").sort(function(a, b){return a-b});
731
- let options = {
732
- lowLimit: deviceIdRange[0],
733
- highLimit: deviceIdRange[1]
734
- };
735
-
736
- if(that.client) {
737
- that.client.whoIs(options);
738
- } else {
739
- that.reinitializeClient(that.config);
740
- }
741
- }
742
- }
743
-
744
851
  scanDevice(device) {
745
852
  let that = this;
746
853
  return new Promise((resolve, reject) => {
747
854
  this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
748
855
  if (!err) {
749
856
  try {
750
- resolve(result.values[0].values[0].value);
857
+ resolve(result.values);
751
858
  } catch(e) {
752
859
  that.logOut("Issue with getting device point list, see error: ", e);
753
860
  }
@@ -800,6 +907,51 @@ class BacnetClient extends EventEmitter {
800
907
  });
801
908
  }
802
909
 
910
+ getDeviceList() {
911
+ let that = this;
912
+ return new Promise(async function(resolve, reject) {
913
+ try {
914
+ resolve({"deviceList": that.deviceList});
915
+ } catch(e){
916
+ reject(e);
917
+ }
918
+ });
919
+ }
920
+
921
+ updateDeviceList(json) {
922
+ let that = this;
923
+ return new Promise(async function(resolve, reject) {
924
+ try {
925
+ let deviceL = json.body.deviceList;
926
+ deviceL.forEach(function(device) {
927
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
928
+ if(foundIndex == -1) {
929
+ let newBacnetDevice = new BacnetDevice(false, device);
930
+ newBacnetDevice.setLastSeen(Date.now());
931
+ that.deviceList.push(newBacnetDevice);
932
+
933
+ } else if(foundIndex !== -1) {
934
+ that.deviceList[foundIndex].updateDeviceConfig(device);
935
+ that.deviceList[foundIndex].setLastSeen(Date.now());
936
+ }
937
+ });
938
+
939
+ resolve(true);
940
+ } catch(e) {
941
+ reject(e);
942
+ }
943
+ });
944
+ }
945
+
946
+ sortDevices(a, b) {
947
+ if (a.deviceId < b.deviceId) {
948
+ return -1;
949
+ } else if (a.deviceId > b.deviceId) {
950
+ return 1;
951
+ }
952
+ return 0; // deviceIds are equal
953
+ }
954
+
803
955
  sortPoints(a, b) {
804
956
  if(a.bacnetType > b.bacnetType) {
805
957
  return 1;
@@ -816,6 +968,9 @@ class BacnetClient extends EventEmitter {
816
968
  let that = this;
817
969
  that.buildTreeMutex = new Mutex();
818
970
  let displayNameCharThreshold = 40;
971
+
972
+ Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
973
+
819
974
  return new Promise(async function(resolve, reject) {
820
975
  if(!that.renderList) that.renderList = [];
821
976
  if(that.deviceList && that.networkTree) {
@@ -892,23 +1047,37 @@ class BacnetClient extends EventEmitter {
892
1047
  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});
893
1048
  }
894
1049
  if(index == that.deviceList.length - 1) {
1050
+ that.renderList.sort(that.sortDevices);
895
1051
  resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
896
1052
  }
897
1053
  } else {
898
1054
  if(index == that.deviceList.length - 1) {
1055
+ that.renderList.sort(that.sortDevices);
899
1056
  resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
900
1057
  }
901
1058
  }
902
1059
 
903
1060
  release();
904
1061
  });
1062
+
905
1063
  });
906
1064
  }
907
1065
  });
908
1066
  }
909
1067
 
1068
+ buildObjects() {
1069
+ let that = this;
1070
+
1071
+ that.deviceList.forEach(function(device) {
1072
+ that.buildJsonObject(device).then(function() {
1073
+ }).catch(function(e) {
1074
+ that.logOut(device.getAddress(), e)
1075
+ });
1076
+ });
1077
+ }
1078
+
910
1079
  buildJsonObject(device) {
911
- let that = this;
1080
+ let that = this;
912
1081
  let address = device.address;
913
1082
  let pointList = device.getPointsList();
914
1083
  let requestMutex = new Mutex();
@@ -951,7 +1120,6 @@ class BacnetClient extends EventEmitter {
951
1120
  reject(e);
952
1121
  });
953
1122
  }
954
-
955
1123
  });
956
1124
  });
957
1125
  });
@@ -964,6 +1132,7 @@ class BacnetClient extends EventEmitter {
964
1132
  // Builds response object for a fully qualified
965
1133
  buildResponse(fullObjects, device) {
966
1134
  let that = this;
1135
+
967
1136
  return new Promise(function(resolve, reject) {
968
1137
  let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
969
1138
  let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
@@ -1072,7 +1241,7 @@ class BacnetClient extends EventEmitter {
1072
1241
  }
1073
1242
  }
1074
1243
  }
1075
- reject("Unexpectedly found end of loop, line 1170");
1244
+ reject("Unexpectedly found end of loop, line 1214");
1076
1245
  });
1077
1246
  }
1078
1247
 
@@ -1169,9 +1338,7 @@ class BacnetClient extends EventEmitter {
1169
1338
  case 56:
1170
1339
  return "pi pi-sitemap";
1171
1340
  case 178:
1172
- return "pi pi-lock";
1173
- case 20:
1174
- return "pi pi-chart-line";
1341
+ return "pi pi-lock";
1175
1342
  case 17:
1176
1343
  return "pi pi-calendar";
1177
1344
  case 6:
@@ -1252,6 +1419,7 @@ class BacnetClient extends EventEmitter {
1252
1419
 
1253
1420
  getDeviceIcon(isMstp, manualDiscoveryMode) {
1254
1421
  if(manualDiscoveryMode == true) {
1422
+ //return "pi pi-server"
1255
1423
  return "pi pi-exclamation-triangle"
1256
1424
  } else if(manualDiscoveryMode == false) {
1257
1425
  if(isMstp == true) {