@bitpoolos/edge-bacnet 1.1.8 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/bacnet_client.js +331 -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,129 @@ 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
+ that.queryDevicesManually();
236
+ }
237
+ }
238
+ }
239
+
240
+ queryDevicesManually() {
241
+ let that = this;
242
+
243
+ let index = 0;
244
+
245
+ query(index);
246
+
247
+ function query(index) {
248
+ let device = that.manualDiscoverQueue[index];
249
+
250
+ if(index < that.manualDiscoverQueue.length) {
251
+ index++;
252
+
253
+ if(typeof device == "object") {
254
+ try {
255
+ if(device.shouldBeInManualMode()) {
256
+ that.getDevicePointListWithoutObjectList(device).then(function() {
257
+ that.buildJsonObject(device).then(function() {
258
+ query(index);
259
+ }).catch(function(e) {
260
+ that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
261
+ query(index);
262
+ });
263
+ }).catch(function(e){
264
+ query(index);
265
+ });
266
+ } else {
267
+ that.removeDeviceFromManualQueue(device);
268
+ query(index);
269
+ }
270
+ } catch(e) {
271
+ query(index);
272
+ }
273
+ } else {
274
+ query(index);
275
+ }
276
+ } else if(index == that.manualDiscoverQueue.length) {
277
+ that.pollInProgress = false;
278
+ }
279
+ }
280
+ }
281
+
282
+ addDeviceToManualQueue(device) {
283
+ let that = this;
284
+
285
+ if(device.getPointListRetryCount() > that.deviceRetryCount) {
286
+ device.setManualDiscoveryMode(true);
287
+ let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
288
+ if(index == -1) {
289
+ that.manualDiscoverQueue.push(device);
290
+ }
291
+ } else {
292
+ device.incrementPointListRetryCount();
293
+ }
294
+ }
295
+
296
+ removeDeviceFromManualQueue(device) {
297
+ let that = this;
298
+ device.setManualDiscoveryMode(false);
299
+ device.clearPointListRetryCount()
300
+ let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
301
+ if(index !== -1) {
302
+ that.manualDiscoverQueue.splice(index, 1);
303
+ }
217
304
  }
218
305
 
219
306
  sanitizeDeviceList() {
220
307
  let that = this;
221
308
 
222
309
  //1 hour in seconds
223
- let timeoutThreshold = 3600;
310
+ let timeoutThreshold = parseInt(that.discover_polling_schedule);
224
311
 
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
312
+ that.deviceList.forEach(function(device, index) {
313
+ if(((Date.now() - device.lastSeen) / 1000) > timeoutThreshold) {
314
+ //render device hasnt responded to whoIs for over an hour
228
315
 
229
- let deviceIndex = that.deviceList.findIndex(ele => ele.deviceId == item.deviceId);
230
- let device = that.deviceList[deviceIndex];
316
+ let renderListIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
231
317
 
232
318
  let ipAddr = typeof device.getAddress() == "object" ? device.getAddress().address : device.getAddress();
233
319
  let deviceKey = ipAddr + "-" + device.getDeviceId();
@@ -235,10 +321,10 @@ class BacnetClient extends EventEmitter {
235
321
  delete that.networkTree[deviceKey];
236
322
 
237
323
  if(((Date.now() - device.getLastSeen()) / 1000) > timeoutThreshold) {
238
- that.deviceList.splice(deviceIndex, 1);
324
+ that.renderList.splice(renderListIndex, 1);
239
325
  }
240
326
 
241
- that.renderList.splice(index, 1);
327
+ that.deviceList.splice(index, 1);
242
328
  }
243
329
  });
244
330
 
@@ -246,9 +332,10 @@ class BacnetClient extends EventEmitter {
246
332
 
247
333
  updateDeviceName(device) {
248
334
  let that = this;
249
- that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceName) {
250
- if(typeof deviceName == "string") {
251
- device.setDeviceName(deviceName);
335
+ that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceObject) {
336
+ if(typeof deviceObject.name == "string") {
337
+ device.setDeviceName(deviceObject.name);
338
+ device.setPointsList(deviceObject.devicePointEntry);
252
339
  }
253
340
  });
254
341
  }
@@ -269,7 +356,7 @@ class BacnetClient extends EventEmitter {
269
356
  that.manual_instance_range_enabled = config.manual_instance_range_enabled;
270
357
  that.manual_instance_range_start = config.manual_instance_range_start;
271
358
  that.manual_instance_range_end = config.manual_instance_range_end;
272
- that.bacnetServerEnabled = config.bacnetServerEnabled;
359
+ that.device_read_schedule = config.device_read_schedule;
273
360
 
274
361
  if(that.scheduler !== null) {
275
362
  that.scheduler.stop();
@@ -293,7 +380,26 @@ class BacnetClient extends EventEmitter {
293
380
 
294
381
  that.scheduler.addSimpleIntervalJob(job);
295
382
 
296
- that.globalWhoIs();
383
+
384
+ // //query device task
385
+ const queryDevices = new Task('simple task', () => {
386
+ if(!that.pollInProgress) that.queryDevices();
387
+ that.sanitizeDeviceList();
388
+ //that.queryDevicesManually();
389
+ });
390
+
391
+ const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule), }, queryDevices)
392
+
393
+ that.scheduler.addSimpleIntervalJob(queryJob);
394
+
395
+ //buildNetworkTreeData task
396
+ const buildNetworkTree = new Task('simple task', () => {
397
+ that.buildNetworkTreeData();
398
+ });
399
+
400
+ const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10, }, buildNetworkTree)
401
+
402
+ that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
297
403
 
298
404
  } catch(e){
299
405
  that.logOut("Error reinitializing bacnet client: ", e)
@@ -366,18 +472,20 @@ class BacnetClient extends EventEmitter {
366
472
  return new Promise((resolve, reject) => {
367
473
  that._readDeviceName(address, deviceId, (err, result) => {
368
474
  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);
475
+ try {
476
+ if(result.values[0].value) {
477
+ const deviceObject = {
478
+ name: result.values[0].value,
479
+ devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }]
480
+ };
481
+ resolve(deviceObject);
482
+ } else {
483
+ that.logOut("Issue with deviceName payload, see object: ", object);
378
484
  }
379
- });
380
- }
485
+ } catch(e){
486
+ that.logOut("Unable to get device name: ", e);
487
+ }
488
+ }
381
489
  });
382
490
  });
383
491
  }
@@ -429,7 +537,7 @@ class BacnetClient extends EventEmitter {
429
537
  device.setPointsList(result);
430
538
  resolve(result);
431
539
  } catch(e) {
432
- that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
540
+ that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
433
541
  reject(e);
434
542
  }
435
543
  });
@@ -439,7 +547,6 @@ class BacnetClient extends EventEmitter {
439
547
  let that = this;
440
548
  return new Promise(function(resolve, reject) {
441
549
  try {
442
- device.setManualDiscoveryMode(true);
443
550
  that.scanDeviceManually(device).then(function(result) {
444
551
  device.setPointsList(result);
445
552
  resolve(result);
@@ -447,7 +554,6 @@ class BacnetClient extends EventEmitter {
447
554
  reject(error);
448
555
  });
449
556
 
450
-
451
557
  } catch(e) {
452
558
  that.logOut("Error getting point list: ", e);
453
559
  reject(e);
@@ -458,11 +564,15 @@ class BacnetClient extends EventEmitter {
458
564
 
459
565
  scanDeviceManually(device) {
460
566
  let that = this;
567
+
461
568
  return new Promise(function(resolve, reject) {
569
+
462
570
  let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
463
571
  let address = device.getAddress();
464
- let objectTypeList = [0, 1, 2, 3];
465
- let instanceRange = {start: 0, end: 100};
572
+ let objectTypeList = [0, 1, 2, 3, 4, 5, 13, 14, 19];
573
+ //let objectTypeList = [0, 1, 2, 3, 4, 5, 6, 10, 13, 14, 15, 16, 17, ,19, 20, 56, 178];
574
+ //let instanceRange = {start: 0, end: 100};
575
+ let instanceRange = device.getmDiscoverInstanceRange();
466
576
  let requestArray = [];
467
577
  let maxRequestThreshold = 1000;
468
578
  let requestRate = 20;
@@ -491,8 +601,8 @@ class BacnetClient extends EventEmitter {
491
601
  instanceRange.end += requestRate;
492
602
  requestArray = [];
493
603
  if(i >= maxRequestThreshold) {
494
- instanceRange.end = maxRequestThreshold;
495
604
  if(typeListIndex == objectTypeList.length-1) {
605
+ device.setmDiscoverInstanceRange({start: instanceRange.end, end: instanceRange.end + 100})
496
606
  send();
497
607
  }
498
608
 
@@ -501,7 +611,6 @@ class BacnetClient extends EventEmitter {
501
611
  }
502
612
  }
503
613
 
504
- instanceRange.end = 100;
505
614
  };
506
615
 
507
616
  function send() {
@@ -510,7 +619,6 @@ class BacnetClient extends EventEmitter {
510
619
  let promise = requestBuffer[index];
511
620
  try {
512
621
  Promise.resolve(promise).then(function(result) {
513
- let keys = Object.keys(result);
514
622
  for (const [key, value] of Object.entries(result)) {
515
623
  if(key == "value" && typeof value == "object") {
516
624
  for(let x = 0; x < value.values.length; x++) {
@@ -535,6 +643,7 @@ class BacnetClient extends EventEmitter {
535
643
  }
536
644
  }
537
645
  }
646
+
538
647
  });
539
648
  }
540
649
 
@@ -550,6 +659,34 @@ class BacnetClient extends EventEmitter {
550
659
  });
551
660
  }
552
661
 
662
+ _readDeviceName(deviceAddress, deviceId, callback){
663
+ let that = this;
664
+ that.client.readProperty(
665
+ deviceAddress,
666
+ {type: baEnum.ObjectType.DEVICE, instance: deviceId },
667
+ baEnum.PropertyIdentifier.OBJECT_NAME,
668
+ that.readPropertyMultipleOptions,
669
+ callback
670
+ );
671
+ }
672
+
673
+ _readObjectList(deviceAddress, deviceId, callback) {
674
+ let that = this;
675
+
676
+ try {
677
+ that.client.readProperty(
678
+ deviceAddress,
679
+ {type: baEnum.ObjectType.DEVICE, instance: deviceId },
680
+ baEnum.PropertyIdentifier.OBJECT_LIST,
681
+ that.readPropertyMultipleOptions,
682
+ callback
683
+ );
684
+
685
+ } catch(e) {
686
+ that.logOut("Error reading object list: ", e);
687
+ }
688
+ }
689
+
553
690
  _readObject(deviceAddress, type, instance, properties) {
554
691
  let that = this;
555
692
  return new Promise((resolve, reject) => {
@@ -566,38 +703,49 @@ class BacnetClient extends EventEmitter {
566
703
  });
567
704
  }
568
705
 
569
- _readDeviceName(deviceAddress, deviceId, callback){
706
+ _readObjectFull(deviceAddress, type, instance) {
570
707
  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
708
 
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
- }
709
+ const allProperties = [
710
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
711
+ { id: baEnum.PropertyIdentifier.DESCRIPTION },
712
+ { id: baEnum.PropertyIdentifier.UNITS },
713
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
714
+ { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
715
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
716
+ { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
717
+ { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
718
+ { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
719
+ { id: baEnum.PropertyIdentifier.RECORD_COUNT }
720
+ ];
595
721
 
596
- _readObjectFull(deviceAddress, type, instance) {
722
+ return new Promise((resolve, reject) => {
723
+ that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }]).then(function(result) {
724
+
725
+ if(result.value) {
726
+ resolve(result);
727
+ }
597
728
 
598
- return this._readObject(deviceAddress, type, instance, [
599
- { id: baEnum.PropertyIdentifier.ALL }
600
- ]);
729
+ if(result.error) {
730
+ const requestArray = [{
731
+ objectId: { type: type, instance: instance },
732
+ properties: allProperties
733
+ }];
734
+
735
+ that._readObjectWithRequestArray(deviceAddress, requestArray).then(function(manualRequest) {
736
+ if(manualRequest.value) {
737
+ resolve(manualRequest);
738
+ }
739
+ if(manualRequest.error) {
740
+ reject(manualRequest.error);
741
+ }
742
+ })
743
+ }
744
+
745
+ }).catch(function(error) {
746
+ reject(error);
747
+ });
748
+ });
601
749
 
602
750
  };
603
751
 
@@ -695,59 +843,13 @@ class BacnetClient extends EventEmitter {
695
843
  }
696
844
  };
697
845
 
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
846
  scanDevice(device) {
745
847
  let that = this;
746
848
  return new Promise((resolve, reject) => {
747
849
  this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
748
850
  if (!err) {
749
851
  try {
750
- resolve(result.values[0].values[0].value);
852
+ resolve(result.values);
751
853
  } catch(e) {
752
854
  that.logOut("Issue with getting device point list, see error: ", e);
753
855
  }
@@ -800,6 +902,51 @@ class BacnetClient extends EventEmitter {
800
902
  });
801
903
  }
802
904
 
905
+ getDeviceList() {
906
+ let that = this;
907
+ return new Promise(async function(resolve, reject) {
908
+ try {
909
+ resolve({"deviceList": that.deviceList});
910
+ } catch(e){
911
+ reject(e);
912
+ }
913
+ });
914
+ }
915
+
916
+ updateDeviceList(json) {
917
+ let that = this;
918
+ return new Promise(async function(resolve, reject) {
919
+ try {
920
+ let deviceL = json.body.deviceList;
921
+ deviceL.forEach(function(device) {
922
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
923
+ if(foundIndex == -1) {
924
+ let newBacnetDevice = new BacnetDevice(false, device);
925
+ newBacnetDevice.setLastSeen(Date.now());
926
+ that.deviceList.push(newBacnetDevice);
927
+
928
+ } else if(foundIndex !== -1) {
929
+ that.deviceList[foundIndex].updateDeviceConfig(device);
930
+ that.deviceList[foundIndex].setLastSeen(Date.now());
931
+ }
932
+ });
933
+
934
+ resolve(true);
935
+ } catch(e) {
936
+ reject(e);
937
+ }
938
+ });
939
+ }
940
+
941
+ sortDevices(a, b) {
942
+ if (a.deviceId < b.deviceId) {
943
+ return -1;
944
+ } else if (a.deviceId > b.deviceId) {
945
+ return 1;
946
+ }
947
+ return 0; // deviceIds are equal
948
+ }
949
+
803
950
  sortPoints(a, b) {
804
951
  if(a.bacnetType > b.bacnetType) {
805
952
  return 1;
@@ -816,6 +963,9 @@ class BacnetClient extends EventEmitter {
816
963
  let that = this;
817
964
  that.buildTreeMutex = new Mutex();
818
965
  let displayNameCharThreshold = 40;
966
+
967
+ Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
968
+
819
969
  return new Promise(async function(resolve, reject) {
820
970
  if(!that.renderList) that.renderList = [];
821
971
  if(that.deviceList && that.networkTree) {
@@ -892,23 +1042,37 @@ class BacnetClient extends EventEmitter {
892
1042
  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
1043
  }
894
1044
  if(index == that.deviceList.length - 1) {
1045
+ that.renderList.sort(that.sortDevices);
895
1046
  resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
896
1047
  }
897
1048
  } else {
898
1049
  if(index == that.deviceList.length - 1) {
1050
+ that.renderList.sort(that.sortDevices);
899
1051
  resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
900
1052
  }
901
1053
  }
902
1054
 
903
1055
  release();
904
1056
  });
1057
+
905
1058
  });
906
1059
  }
907
1060
  });
908
1061
  }
909
1062
 
1063
+ buildObjects() {
1064
+ let that = this;
1065
+
1066
+ that.deviceList.forEach(function(device) {
1067
+ that.buildJsonObject(device).then(function() {
1068
+ }).catch(function(e) {
1069
+ that.logOut(device.getAddress(), e)
1070
+ });
1071
+ });
1072
+ }
1073
+
910
1074
  buildJsonObject(device) {
911
- let that = this;
1075
+ let that = this;
912
1076
  let address = device.address;
913
1077
  let pointList = device.getPointsList();
914
1078
  let requestMutex = new Mutex();
@@ -951,7 +1115,6 @@ class BacnetClient extends EventEmitter {
951
1115
  reject(e);
952
1116
  });
953
1117
  }
954
-
955
1118
  });
956
1119
  });
957
1120
  });
@@ -964,6 +1127,7 @@ class BacnetClient extends EventEmitter {
964
1127
  // Builds response object for a fully qualified
965
1128
  buildResponse(fullObjects, device) {
966
1129
  let that = this;
1130
+
967
1131
  return new Promise(function(resolve, reject) {
968
1132
  let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
969
1133
  let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
@@ -1072,7 +1236,7 @@ class BacnetClient extends EventEmitter {
1072
1236
  }
1073
1237
  }
1074
1238
  }
1075
- reject("Unexpectedly found end of loop, line 1170");
1239
+ reject("Unexpectedly found end of loop, line 1214");
1076
1240
  });
1077
1241
  }
1078
1242
 
@@ -1169,9 +1333,7 @@ class BacnetClient extends EventEmitter {
1169
1333
  case 56:
1170
1334
  return "pi pi-sitemap";
1171
1335
  case 178:
1172
- return "pi pi-lock";
1173
- case 20:
1174
- return "pi pi-chart-line";
1336
+ return "pi pi-lock";
1175
1337
  case 17:
1176
1338
  return "pi pi-calendar";
1177
1339
  case 6:
@@ -1252,6 +1414,7 @@ class BacnetClient extends EventEmitter {
1252
1414
 
1253
1415
  getDeviceIcon(isMstp, manualDiscoveryMode) {
1254
1416
  if(manualDiscoveryMode == true) {
1417
+ //return "pi pi-server"
1255
1418
  return "pi pi-exclamation-triangle"
1256
1419
  } else if(manualDiscoveryMode == false) {
1257
1420
  if(isMstp == true) {