@bitpoolos/edge-bacnet 1.0.6 → 1.0.9

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 (179) hide show
  1. package/bacnet_client.js +585 -152
  2. package/bacnet_device.js +34 -11
  3. package/bacnet_gateway.html +189 -92
  4. package/bacnet_gateway.js +152 -21
  5. package/bacnet_object.js +1 -1
  6. package/bacnet_read.html +115 -113
  7. package/bacnet_read.js +24 -24
  8. package/bacnet_write.html +19 -15
  9. package/bacnet_write.js +0 -2
  10. package/common.js +63 -8
  11. package/package.json +6 -4
  12. package/resources/confirmationservice.min.js +1 -0
  13. package/resources/confirmdialog.min.js +1 -0
  14. package/resources/fonts/primeicons.woff2 +0 -0
  15. package/resources/node-bacnet/CHANGELOG.md +481 -0
  16. package/resources/{bacstack → node-bacnet}/LICENSE.md +3 -1
  17. package/resources/node-bacnet/README.md +91 -0
  18. package/resources/node-bacnet/docs/Client.html +4422 -0
  19. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  20. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  21. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  22. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  23. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  24. package/resources/node-bacnet/docs/bacnet.html +7032 -0
  25. package/resources/node-bacnet/docs/client.js.html +1759 -0
  26. package/resources/node-bacnet/docs/enum.js.html +2530 -0
  27. package/resources/node-bacnet/docs/global.html +2068 -0
  28. package/resources/node-bacnet/docs/images/mocha-logo.svg +65 -0
  29. package/resources/node-bacnet/docs/index.html +283 -0
  30. package/resources/node-bacnet/docs/scripts/collapse.js +11 -0
  31. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +4 -0
  32. package/resources/node-bacnet/docs/scripts/linenumber.js +26 -0
  33. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  34. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +2 -0
  35. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +28 -0
  36. package/resources/node-bacnet/docs/scripts/search.js +47 -0
  37. package/resources/node-bacnet/docs/services_i-am.js.html +157 -0
  38. package/resources/node-bacnet/docs/services_time-sync.js.html +118 -0
  39. package/resources/node-bacnet/docs/services_who-is.js.html +138 -0
  40. package/resources/node-bacnet/docs/styles/jsdoc.css +683 -0
  41. package/resources/node-bacnet/docs/styles/prettify.css +82 -0
  42. package/resources/node-bacnet/examples/discover-devices.js +66 -0
  43. package/resources/node-bacnet/examples/read-device.js +510 -0
  44. package/resources/node-bacnet/examples/subscribe-cov.js +75 -0
  45. package/resources/{bacstack → node-bacnet}/index.js +3 -0
  46. package/resources/{bacstack → node-bacnet}/lib/apdu.js +56 -39
  47. package/resources/{bacstack → node-bacnet}/lib/asn1.js +550 -532
  48. package/resources/node-bacnet/lib/bvlc.js +90 -0
  49. package/resources/node-bacnet/lib/client.js +1695 -0
  50. package/resources/node-bacnet/lib/enum.js +2463 -0
  51. package/resources/node-bacnet/lib/npdu.js +123 -0
  52. package/resources/{bacstack → node-bacnet}/lib/services/add-list-element.js +12 -6
  53. package/resources/{bacstack → node-bacnet}/lib/services/alarm-acknowledge.js +3 -3
  54. package/resources/{bacstack → node-bacnet}/lib/services/alarm-summary.js +5 -4
  55. package/resources/{bacstack → node-bacnet}/lib/services/atomic-read-file.js +49 -26
  56. package/resources/{bacstack → node-bacnet}/lib/services/atomic-write-file.js +40 -23
  57. package/resources/{bacstack → node-bacnet}/lib/services/cov-notify.js +33 -17
  58. package/resources/{bacstack → node-bacnet}/lib/services/create-object.js +23 -13
  59. package/resources/{bacstack → node-bacnet}/lib/services/delete-object.js +7 -2
  60. package/resources/{bacstack → node-bacnet}/lib/services/device-communication-control.js +8 -3
  61. package/resources/{bacstack → node-bacnet}/lib/services/error.js +7 -0
  62. package/resources/{bacstack → node-bacnet}/lib/services/event-information.js +10 -9
  63. package/resources/{bacstack → node-bacnet}/lib/services/event-notify-data.js +38 -16
  64. package/resources/{bacstack → node-bacnet}/lib/services/get-enrollment-summary.js +24 -11
  65. package/resources/{bacstack → node-bacnet}/lib/services/get-event-information.js +28 -13
  66. package/resources/node-bacnet/lib/services/i-am.js +90 -0
  67. package/resources/{bacstack/lib/services/i-have-broadcast.js → node-bacnet/lib/services/i-have.js} +3 -2
  68. package/resources/{bacstack → node-bacnet}/lib/services/index.js +7 -4
  69. package/resources/{bacstack → node-bacnet}/lib/services/life-safety-operation.js +3 -2
  70. package/resources/{bacstack → node-bacnet}/lib/services/private-transfer.js +3 -2
  71. package/resources/{bacstack → node-bacnet}/lib/services/read-property-multiple.js +11 -6
  72. package/resources/{bacstack → node-bacnet}/lib/services/read-property.js +42 -24
  73. package/resources/{bacstack → node-bacnet}/lib/services/read-range.js +37 -27
  74. package/resources/node-bacnet/lib/services/register-foreign-device.js +18 -0
  75. package/resources/{bacstack → node-bacnet}/lib/services/reinitialize-device.js +9 -4
  76. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-cov.js +9 -4
  77. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-property.js +18 -8
  78. package/resources/{bacstack → node-bacnet}/lib/services/time-sync.js +28 -5
  79. package/resources/{bacstack → node-bacnet}/lib/services/who-has.js +3 -3
  80. package/resources/{bacstack → node-bacnet}/lib/services/who-is.js +42 -9
  81. package/resources/{bacstack → node-bacnet}/lib/services/write-property-multiple.js +33 -16
  82. package/resources/{bacstack → node-bacnet}/lib/services/write-property.js +23 -13
  83. package/resources/node-bacnet/lib/transport.js +82 -0
  84. package/resources/node-bacnet/package.json +92 -0
  85. package/resources/primeicons.css +90 -2
  86. package/resources/bacstack/.codeclimate.yml +0 -15
  87. package/resources/bacstack/.dockerignore +0 -5
  88. package/resources/bacstack/.editorconfig +0 -13
  89. package/resources/bacstack/.eslintrc.yml +0 -13
  90. package/resources/bacstack/.github/ISSUE_TEMPLATE.md +0 -26
  91. package/resources/bacstack/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  92. package/resources/bacstack/.github/workflows/ci.yml +0 -39
  93. package/resources/bacstack/.jscsrc +0 -8
  94. package/resources/bacstack/.jshintrc +0 -50
  95. package/resources/bacstack/.travis.yml +0 -27
  96. package/resources/bacstack/CHANGELOG.md +0 -232
  97. package/resources/bacstack/CODE_OF_CONDUCT.md +0 -74
  98. package/resources/bacstack/CONTRIBUTING.md +0 -77
  99. package/resources/bacstack/Dockerfile +0 -15
  100. package/resources/bacstack/FAQ.md +0 -64
  101. package/resources/bacstack/README.md +0 -157
  102. package/resources/bacstack/docker-compose.yml +0 -9
  103. package/resources/bacstack/lib/adpu.js +0 -190
  104. package/resources/bacstack/lib/bvlc.js +0 -43
  105. package/resources/bacstack/lib/client.js +0 -1028
  106. package/resources/bacstack/lib/enum.js +0 -1314
  107. package/resources/bacstack/lib/npdu.js +0 -119
  108. package/resources/bacstack/lib/services/i-am-broadcast.js +0 -51
  109. package/resources/bacstack/lib/services.js +0 -1963
  110. package/resources/bacstack/lib/transport.js +0 -52
  111. package/resources/bacstack/package-lock.json +0 -7974
  112. package/resources/bacstack/package.json +0 -84
  113. package/resources/bacstack/test/compliance/who-is.spec.js +0 -37
  114. package/resources/bacstack/test/integration/acknowledge-alarm.spec.js +0 -14
  115. package/resources/bacstack/test/integration/add-list-element.spec.js +0 -16
  116. package/resources/bacstack/test/integration/confirmed-event-notification.spec.js +0 -30
  117. package/resources/bacstack/test/integration/confirmed-private-transfer.spec.js +0 -15
  118. package/resources/bacstack/test/integration/create-object.spec.js +0 -16
  119. package/resources/bacstack/test/integration/delete-object.spec.js +0 -14
  120. package/resources/bacstack/test/integration/device-communication-control.spec.js +0 -14
  121. package/resources/bacstack/test/integration/get-alarm-summary.spec.js +0 -14
  122. package/resources/bacstack/test/integration/get-enrollment-summary.spec.js +0 -15
  123. package/resources/bacstack/test/integration/get-event-information.spec.js +0 -14
  124. package/resources/bacstack/test/integration/read-file.spec.js +0 -14
  125. package/resources/bacstack/test/integration/read-property-multiple.spec.js +0 -110
  126. package/resources/bacstack/test/integration/read-property.spec.js +0 -14
  127. package/resources/bacstack/test/integration/read-range.spec.js +0 -14
  128. package/resources/bacstack/test/integration/reinitialize-sevice.spec.js +0 -14
  129. package/resources/bacstack/test/integration/remove-list-element.spec.js +0 -16
  130. package/resources/bacstack/test/integration/subscribe-cov.spec.js +0 -14
  131. package/resources/bacstack/test/integration/subscribe-property.spec.js +0 -14
  132. package/resources/bacstack/test/integration/time-sync-utc.spec.js +0 -10
  133. package/resources/bacstack/test/integration/time-sync.spec.js +0 -10
  134. package/resources/bacstack/test/integration/unconfirmed-event-notification.spec.js +0 -28
  135. package/resources/bacstack/test/integration/unconfirmed-private-transfer.spec.js +0 -11
  136. package/resources/bacstack/test/integration/utils.js +0 -30
  137. package/resources/bacstack/test/integration/who-is.spec.js +0 -17
  138. package/resources/bacstack/test/integration/write-file.spec.js +0 -14
  139. package/resources/bacstack/test/integration/write-property-multiple.spec.js +0 -19
  140. package/resources/bacstack/test/integration/write-property.spec.js +0 -14
  141. package/resources/bacstack/test/unit/apdu.spec.js +0 -162
  142. package/resources/bacstack/test/unit/asn1.spec.js +0 -39
  143. package/resources/bacstack/test/unit/bacnet-apdu.spec.js +0 -161
  144. package/resources/bacstack/test/unit/bacnet-asn1.spec.js +0 -32
  145. package/resources/bacstack/test/unit/bacnet-bvlc.spec.js +0 -57
  146. package/resources/bacstack/test/unit/bacnet-npdu.spec.js +0 -118
  147. package/resources/bacstack/test/unit/bacnet-services.spec.js +0 -2052
  148. package/resources/bacstack/test/unit/bvlc.spec.js +0 -58
  149. package/resources/bacstack/test/unit/npdu.spec.js +0 -119
  150. package/resources/bacstack/test/unit/service-add-list-element.spec.js +0 -24
  151. package/resources/bacstack/test/unit/service-alarm-acknowledge.spec.js +0 -71
  152. package/resources/bacstack/test/unit/service-alarm-summary.spec.js +0 -22
  153. package/resources/bacstack/test/unit/service-atomic-read-file.spec.js +0 -54
  154. package/resources/bacstack/test/unit/service-atomic-write-file.spec.js +0 -56
  155. package/resources/bacstack/test/unit/service-cov-notify.spec.js +0 -98
  156. package/resources/bacstack/test/unit/service-create-object.spec.js +0 -90
  157. package/resources/bacstack/test/unit/service-delete-object.spec.js +0 -17
  158. package/resources/bacstack/test/unit/service-device-communication-control.spec.js +0 -29
  159. package/resources/bacstack/test/unit/service-error.spec.js +0 -17
  160. package/resources/bacstack/test/unit/service-event-information.spec.js +0 -48
  161. package/resources/bacstack/test/unit/service-event-notify-data.spec.js +0 -310
  162. package/resources/bacstack/test/unit/service-get-enrollment-summary.spec.js +0 -45
  163. package/resources/bacstack/test/unit/service-get-event-information.spec.js +0 -62
  164. package/resources/bacstack/test/unit/service-i-am.spec.js +0 -19
  165. package/resources/bacstack/test/unit/service-i-have-broadcast.spec.js +0 -18
  166. package/resources/bacstack/test/unit/service-life-safety-operation.spec.js +0 -19
  167. package/resources/bacstack/test/unit/service-private-transfer.spec.js +0 -18
  168. package/resources/bacstack/test/unit/service-read-property-multiple.spec.js +0 -131
  169. package/resources/bacstack/test/unit/service-read-property.spec.js +0 -541
  170. package/resources/bacstack/test/unit/service-read-range.spec.js +0 -97
  171. package/resources/bacstack/test/unit/service-reinitialize-device.spec.js +0 -27
  172. package/resources/bacstack/test/unit/service-subscribe-cov.spec.js +0 -32
  173. package/resources/bacstack/test/unit/service-subscribe-property.spec.js +0 -50
  174. package/resources/bacstack/test/unit/service-time-sync.spec.js +0 -18
  175. package/resources/bacstack/test/unit/service-who-has.spec.js +0 -33
  176. package/resources/bacstack/test/unit/service-who-is.spec.js +0 -17
  177. package/resources/bacstack/test/unit/service-write-property-multiple.spec.js +0 -143
  178. package/resources/bacstack/test/unit/service-write-property.spec.js +0 -198
  179. package/resources/bacstack/test/unit/utils.js +0 -6
package/bacnet_client.js CHANGED
@@ -1,11 +1,10 @@
1
1
  /*
2
2
  MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
3
3
  */
4
-
5
- const bacnet = require('./resources/bacstack/lib/client');
6
- const baEnum = require('./resources/bacstack/lib/enum');
7
- const baAsn1 = require('./resources/bacstack/lib/asn1');
8
- const { EventEmitter } = require('events');
4
+ const bacnet = require('./resources/node-bacnet/index.js');
5
+ const baEnum = bacnet.enum;
6
+ const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
7
+ const { EventEmitter, captureRejectionSymbol } = require('events');
9
8
  const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces } = require('./common');
10
9
  const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
11
10
  const { BacnetDevice } = require('./bacnet_device');
@@ -17,7 +16,6 @@ class BacnetClient extends EventEmitter {
17
16
  super();
18
17
  let that = this;
19
18
  that.deviceList = [];
20
- that.pointReferenceList = [];
21
19
  that.networkTree = {};
22
20
  that.lastWhoIs = null;
23
21
  that.client = null;
@@ -34,10 +32,34 @@ class BacnetClient extends EventEmitter {
34
32
  that.device_id_range_enabled = config.device_id_range_enabled;
35
33
  that.device_id_range_start = config.device_id_range_start;
36
34
  that.device_id_range_end = config.device_id_range_end;
35
+ that.deviceId = config.deviceId;
36
+ that.broadCastAddr = config.broadCastAddr;
37
+ that.manual_instance_range_enabled = config.manual_instance_range_enabled;
38
+ that.manual_instance_range_start = config.manual_instance_range_start;
39
+ that.manual_instance_range_end = config.manual_instance_range_end;
37
40
 
38
41
  that.readPropertyMultipleOptions = {
39
42
  maxSegments: that.maxSegments,
40
- apduSize: that.apduSize
43
+ maxApdu: that.apduSize
44
+ };
45
+
46
+ that.selfObjectList = [
47
+ {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
48
+ ];
49
+
50
+ that.selfData = {
51
+ 8: {
52
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}], // OBJECT_IDENTIFIER
53
+ [baEnum.PropertyIdentifier.OBJECT_LIST]: that.selfObjectList, // OBJECT_IDENTIFIER
54
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: 'Bitpool Edge BACnet Gateway', type: 7}], // OBJECT_NAME
55
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: 8, type: 9}], // OBJECT_TYPE
56
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: 'Bitpool Edge BACnet gateway', type: 7}], // DESCRIPTION
57
+ [baEnum.PropertyIdentifier.SYSTEM_STATUS]: [{value: 0, type: 9}], // SYSTEM_STATUS
58
+ [baEnum.PropertyIdentifier.VENDOR_NAME]: [{value: "Bitpool", type: 7}], //VENDOR_NAME
59
+ [baEnum.PropertyIdentifier.VENDOR_IDENTIFIER]: [{value: 9999, type: 7}], //VENDOR_IDENTIFIER
60
+ [baEnum.PropertyIdentifier.MODEL_NAME]: [{value: "bitpool-edge", type: 7}], //MODEL_NAME
61
+ [baEnum.PropertyIdentifier.FIRMWARE_REVISION]: [{value: "Node-Red v3.0.2", type: 7}], //FIRMWARE_REVISION
62
+ }
41
63
  };
42
64
 
43
65
  try {
@@ -59,6 +81,8 @@ class BacnetClient extends EventEmitter {
59
81
  });
60
82
 
61
83
  const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, queryDevices)
84
+ //const queryJob = new SimpleIntervalJob({ seconds: 10, }, queryDevices)
85
+
62
86
 
63
87
  that.scheduler.addSimpleIntervalJob(queryJob);
64
88
 
@@ -77,30 +101,85 @@ class BacnetClient extends EventEmitter {
77
101
  that.queryDevices();
78
102
  }, "5000")
79
103
 
80
- } catch(e){
104
+ } catch(e) {
81
105
  console.log("Issue initializing client: ", e)
82
106
  }
83
107
 
84
108
  //who is callback
85
109
  that.client.on('iAm', (device) => {
86
- //only add unique device to array
87
- let foundIndex = that.deviceList.findIndex(ele => ele.getAddress() == device.address);
88
- if(foundIndex == -1) {
89
- let newBacnetDevice = new BacnetDevice(device);
90
- newBacnetDevice.setLastSeen(Date.now());
91
- that.updateDeviceName(newBacnetDevice);
92
- that.deviceList.push(newBacnetDevice);
93
-
94
- } else if(foundIndex !== -1) {
95
- that.deviceList[foundIndex].updateDeviceConfig(device);
96
- that.deviceList[foundIndex].setLastSeen(Date.now());
97
- that.updateDeviceName(that.deviceList[foundIndex]);
110
+ if(device.header.sender.address !== that.config.localIpAdrress) {
111
+ //only add unique device to array
112
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
113
+ if(foundIndex == -1) {
114
+ let newBacnetDevice = new BacnetDevice(device);
115
+ newBacnetDevice.setLastSeen(Date.now());
116
+ that.updateDeviceName(newBacnetDevice);
117
+ that.deviceList.push(newBacnetDevice);
118
+
119
+ } else if(foundIndex !== -1) {
120
+ that.deviceList[foundIndex].updateDeviceConfig(device);
121
+ that.deviceList[foundIndex].setLastSeen(Date.now());
122
+ that.updateDeviceName(that.deviceList[foundIndex]);
123
+ }
124
+
125
+ //emit event for node-red to log
126
+ that.emit('deviceFound', device);
98
127
  }
99
-
100
- //emit event for node-red to log
101
- that.emit('deviceFound', device);
102
128
  });
103
- } catch(e){
129
+
130
+ that.client.on('whoIs', (device) => {
131
+ that.client.iAmResponse(that.broadCastAddr, that.deviceId, baEnum.Segmentation.SEGMENTED_BOTH, 27823);
132
+ });
133
+
134
+ that.client.on('readPropertyMultiple', (data) => {
135
+ try {
136
+ if(data.payload.properties[0]){
137
+ let objectId = data.payload.properties[0].objectId.type;
138
+ let objectInstance = data.payload.properties[0].objectId.instance;
139
+ let propId = data.payload.properties[0].properties[0].id.toString();
140
+ let responseObj = that.selfData[objectId][propId];
141
+
142
+ if(responseObj !== null && responseObj !== "undefined") {
143
+ that.client.readPropertyMultipleResponse(data.address, data.invokeId, responseObj);
144
+ } else {
145
+ this.client.errorResponse(
146
+ data.address,
147
+ baEnum.ConfirmedServices.SERVICE_CONFIRMED_READ_PROPERTY,
148
+ data.invokeId,
149
+ baEnum.ErrorClasses.ERROR_CLASS_PROPERTY,
150
+ baEnum.ErrorCodes.ERROR_CODE_UNKNOWN_PROPERTY
151
+ );
152
+ }
153
+ }
154
+
155
+ } catch(e) {
156
+ //console.log("Local BACnet device readPropertyMultiple error: ");
157
+ }
158
+ });
159
+
160
+ that.client.on('readProperty', (data) => {
161
+ try {
162
+ let objectId = data.payload.objectId.type;
163
+ let propId = data.payload.property.id.toString();
164
+ let responseObj = that.selfData[objectId][propId];
165
+ if(responseObj !== null && responseObj !== undefined && typeof responseObj !== "undefined") {
166
+ that.client.readPropertyResponse(data.header.sender.address, data.invokeId, objectId, data.payload.property, responseObj);
167
+ } else {
168
+ this.client.errorResponse(
169
+ data.address,
170
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY,
171
+ data.invokeId,
172
+ baEnum.ErrorClass.PROPERTY,
173
+ baEnum.ErrorCode.UNKNOWN_PROPERTY
174
+ );
175
+ }
176
+ } catch(e){
177
+ console.log("Local BACnet device readProperty error: ", e);
178
+ }
179
+
180
+ });
181
+
182
+ } catch(e) {
104
183
  console.log("Issue with creating bacnet client, see error: ", e);
105
184
  }
106
185
 
@@ -118,6 +197,21 @@ class BacnetClient extends EventEmitter {
118
197
 
119
198
  }
120
199
 
200
+ rebuildDataModel() {
201
+ let that = this;
202
+ return new Promise((resolve, reject) => {
203
+ try {
204
+ that.deviceList = [];
205
+ that.renderList = [];
206
+ that.networkTree = {};
207
+ resolve(true);
208
+ } catch(e) {
209
+ console.log("Error clearing BACnet data model: ", e);
210
+ reject(e);
211
+ }
212
+ });
213
+ }
214
+
121
215
  queryDevices() {
122
216
  let that = this;
123
217
  that.deviceList.forEach(function(device, index){
@@ -125,15 +219,37 @@ class BacnetClient extends EventEmitter {
125
219
  .acquire()
126
220
  .then(function(release) {
127
221
  try {
222
+
223
+ // that.getDevicePointListWithoutObjectList(device).then(function() {
224
+ // that.buildJsonObject(device).then(function() {
225
+ // release();
226
+ // }).catch(function(e) {
227
+ // release();
228
+ // });
229
+ // }).catch(function(e) {
230
+ // release();
231
+ // });
232
+
128
233
  that.getDevicePointList(device).then(function() {
129
234
  that.buildJsonObject(device).then(function() {
130
235
  release();
131
236
  }).catch(function(e) {
132
237
  release();
133
238
  });
134
- }).catch(function(e){
239
+ }).catch(function(e) {
240
+ that.getDevicePointListWithoutObjectList(device).then(function() {
241
+ that.buildJsonObject(device).then(function() {
242
+ release();
243
+ }).catch(function(e) {
244
+ release();
245
+ });
246
+ }).catch(function(e) {
247
+ release();
248
+ });
135
249
  release();
136
250
  });
251
+
252
+
137
253
  } catch(e) {
138
254
  console.log("Error while querying devices: ", e);
139
255
  release();
@@ -144,7 +260,7 @@ class BacnetClient extends EventEmitter {
144
260
 
145
261
  updateDeviceName(device) {
146
262
  let that = this;
147
- that._getDeviceName(device.address, device.deviceId).then(function(deviceName) {
263
+ that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceName) {
148
264
  device.setDeviceName(deviceName);
149
265
  });
150
266
  }
@@ -183,21 +299,6 @@ class BacnetClient extends EventEmitter {
183
299
  }
184
300
  };
185
301
 
186
- buildPointReferenceList(promiseArray){
187
- let that = this;
188
-
189
- let points = promiseArray.map(function(element){return element.point})
190
- let promises = promiseArray.map(function(element){return element.promise})
191
- promiseArray.forEach(function(element){
192
- let point = element.point;
193
-
194
- Promise.resolve(element.promise).then(function(result){
195
- that.pointReferenceList.push({})
196
- });
197
- });
198
-
199
- }
200
-
201
302
  getValidPointProperties(point, requestedProps){
202
303
  let availableProps = point.propertyList;
203
304
  let newProps = [];
@@ -208,7 +309,7 @@ class BacnetClient extends EventEmitter {
208
309
  if(foundInAvailable) newProps.push(prop);
209
310
  });
210
311
  //add object name for use in formatting
211
- newProps.push({id: baEnum.PropertyIds.PROP_OBJECT_NAME});
312
+ newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
212
313
  } catch(e){
213
314
  console.log("Issue finding valid object properties, see error: ", e);
214
315
  }
@@ -216,7 +317,7 @@ class BacnetClient extends EventEmitter {
216
317
  return newProps;
217
318
  }
218
319
 
219
- doRead(readConfig, outputType, msgId) {
320
+ doRead(readConfig, outputType, objectPropertyType, msgId) {
220
321
  let that = this;
221
322
 
222
323
  that.roundDecimal = readConfig.precision;
@@ -224,16 +325,37 @@ class BacnetClient extends EventEmitter {
224
325
  let propertiesToRead = readConfig.objectProperties;
225
326
 
226
327
  try {
227
- devicesToRead.forEach(function(deviceAddress) {
228
- let requestArray = [];
328
+
329
+ // const requestArray1 = [{
330
+ // objectId: { type: baEnum.ObjectType.OBJECT_TRENDLOG, instance: 300002 },
331
+ // properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
332
+ // { id: baEnum.PropertyIdentifier.LOG_BUFFER }]
333
+ // }];
334
+
335
+ // this.client.readPropertyMultiple("10.0.8.202", requestArray1, that.readPropertyMultipleOptions, (error, value) => {
336
+ // console.log("error: ", error);
337
+ // console.log("value: ", value.values[0].values[0]);
338
+ // console.log("value: ", value.values[0].values[1]);
339
+ // //console.log(JSON.stringify(value));
340
+ // });
341
+
342
+ // that.client.readRange("10.0.8.202", 300002, 1, 5, {}, (error, value) => {
343
+ // console.log("that.client.readRange: ");
344
+ // console.log("error: ", error);
345
+ // console.log("value: ", value);
346
+ // });
347
+
348
+
349
+
350
+ devicesToRead.forEach(function(deviceId) {
229
351
  let readPromiseArray = [];
230
- let pointsToReadNames = Object.keys(readConfig.pointsToRead[deviceAddress]);
231
- let device = that.deviceList.find(ele => ele.address == deviceAddress);
352
+ let pointsToReadNames = Object.keys(readConfig.pointsToRead[deviceId]);
353
+ let device = that.deviceList.find(ele => ele.getDeviceId() == deviceId);
232
354
  pointsToReadNames.forEach(function(pointName, index) {
233
- let point = readConfig.pointsToRead[deviceAddress][pointName];
234
- readPromiseArray.push(that._readObjectFull(deviceAddress, point.meta.objectId.type, point.meta.objectId.instance));
355
+ let point = readConfig.pointsToRead[deviceId][pointName];
356
+ readPromiseArray.push(that._readObjectFull(device.getAddress(), point.meta.objectId.type, point.meta.objectId.instance));
235
357
  });
236
- that.readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId);
358
+ that.readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId);
237
359
  });
238
360
 
239
361
  } catch(e){
@@ -242,9 +364,9 @@ class BacnetClient extends EventEmitter {
242
364
 
243
365
  }
244
366
 
245
- readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId) {
367
+ readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId) {
246
368
  let that = this;
247
- let deviceName = device.deviceName;
369
+ let deviceName = device.getDeviceName();
248
370
 
249
371
  let bacnetResults = {
250
372
  [deviceName]: []
@@ -261,45 +383,71 @@ class BacnetClient extends EventEmitter {
261
383
  element.values.forEach(function(point){
262
384
  point.values.forEach(function(object) {
263
385
  let toReadProperty = propertiesToRead.findIndex(ele => ele.id == object.id);
386
+ let objectName = that._findValueById(point.values, baEnum.PropertyIdentifier.OBJECT_NAME);
264
387
  //checks for error code json structure, returned for invalid bacnet requests
265
- if(!object.value.value && toReadProperty !== -1) {
388
+ if(!object.value.value && toReadProperty !== -1 && objectName !== "") {
266
389
  var currobjectId = point.objectId.type
267
390
  let bac_obj = that.getObjectType(currobjectId);
268
- let objectName = that._findValueById(point.values, baEnum.PropertyIds.PROP_OBJECT_NAME);
269
-
270
391
  let objectId;
392
+ objectId = objectName;
393
+
394
+ /*
271
395
  if(objectName !== null) {
272
396
  objectName = objectName.split(" ").join("_");
273
397
  objectId = objectName + "_" + bac_obj + '_' + point.objectId.instance;
274
398
  } else {
275
399
  objectId = bac_obj + '_' + point.objectId.instance;
276
400
  }
401
+ */
277
402
 
278
403
  //init json object
279
404
  if(!values[objectId]) values[objectId] = {};
280
405
 
281
406
  switch(object.id) {
282
- case baEnum.PropertyIds.PROP_PRESENT_VALUE:
283
- if(object.value[0] && object.value[0].value) values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
407
+ case baEnum.PropertyIdentifier.PRESENT_VALUE:
408
+ if(object.value[0] &&
409
+ object.value[0].value !== "undefined" &&
410
+ object.value[0].value !== null &&
411
+ typeof object.value[0].value == "number") values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
284
412
  break;
285
- case baEnum.PropertyIds.PROP_DESCRIPTION:
413
+ case baEnum.PropertyIdentifier.DESCRIPTION:
286
414
  if(object.value[0]) values[objectId].description = object.value[0].value;
287
415
  break;
288
- case baEnum.PropertyIds.PROP_STATUS_FLAGS:
416
+ case baEnum.PropertyIdentifier.STATUS_FLAGS:
289
417
  if(object.value[0] && object.value[0].value) values[objectId].statusFlags = that.getStatusFlags(object);
290
418
  break;
291
- case baEnum.PropertyIds.PROP_RELIABILITY:
419
+ case baEnum.PropertyIdentifier.RELIABILITY:
292
420
  if(object.value[0]) values[objectId].reliability = that.getPROP_RELIABILITY(object.value[0].value);
293
421
  break;
294
- case baEnum.PropertyIds.PROP_OUT_OF_SERVICE:
422
+ case baEnum.PropertyIdentifier.OUT_OF_SERVICE:
295
423
  if(object.value[0]) values[objectId].outOfService = object.value[0].value;
296
424
  break;
297
- case baEnum.PropertyIds.PROP_UNITS:
425
+ case baEnum.PropertyIdentifier.UNITS:
298
426
  if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
299
427
  break;
300
- case baEnum.PropertyIds.PROP_OBJECT_NAME:
428
+ case baEnum.PropertyIdentifier.OBJECT_NAME:
301
429
  if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
302
430
  break;
431
+ case baEnum.PropertyIdentifier.SYSTEM_STATUS:
432
+ if(object.value[0]){
433
+ values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
434
+ }
435
+ break;
436
+ case baEnum.PropertyIdentifier.MODIFICATION_DATE:
437
+ if(object.value[0]) {
438
+ values[objectId].modificationDate = object.value[0].value;
439
+ }
440
+ break;
441
+ case baEnum.PropertyIdentifier.PROGRAM_STATE:
442
+ if(object.value[0]){
443
+ values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
444
+ }
445
+ break;
446
+ case baEnum.PropertyIdentifier.RECORD_COUNT:
447
+ if(object.value[0] ) {
448
+ values[objectId].recordCount = object.value[0].value;
449
+ }
450
+ break;
303
451
  }
304
452
  }
305
453
  });
@@ -311,7 +459,7 @@ class BacnetClient extends EventEmitter {
311
459
  }
312
460
  });
313
461
  if(Object.keys(bacnetResults[deviceName]).length !== 0) {
314
- that.emit('values', device, bacnetResults, outputType, msgId, successfulResults);
462
+ that.emit('values', bacnetResults, outputType, objectPropertyType);
315
463
  }
316
464
 
317
465
  }).catch(function (error) {
@@ -323,8 +471,6 @@ class BacnetClient extends EventEmitter {
323
471
  }
324
472
  }
325
473
 
326
-
327
-
328
474
  _getDeviceName(address, deviceId) {
329
475
  let that = this;
330
476
  return new Promise((resolve, reject) => {
@@ -370,13 +516,13 @@ class BacnetClient extends EventEmitter {
370
516
  newProps.push(prop);
371
517
  break;
372
518
  case 13:
373
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
519
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
374
520
  break;
375
521
  case 14:
376
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
522
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
377
523
  break;
378
524
  case 19:
379
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
525
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
380
526
  break;
381
527
  }
382
528
  });
@@ -387,9 +533,27 @@ class BacnetClient extends EventEmitter {
387
533
  let that = this;
388
534
  return new Promise(async function(resolve, reject) {
389
535
  try {
390
- let result = await that.scanDevice(device);
536
+ let result = await that.scanDevice(device);
391
537
  device.setPointsList(result);
392
538
  resolve(result);
539
+ } catch(e) {
540
+ console.log(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
541
+ reject(e);
542
+ }
543
+ });
544
+ }
545
+
546
+ getDevicePointListWithoutObjectList(device) {
547
+ let that = this;
548
+ return new Promise(function(resolve, reject) {
549
+ try {
550
+ that.scanDeviceManually(device).then(function(result) {
551
+ device.setPointsList(result);
552
+ resolve(result);
553
+ }).catch(function(error) {
554
+ reject(error);
555
+ });
556
+
393
557
 
394
558
  } catch(e) {
395
559
  console.log("Error getting point list: ", e);
@@ -399,6 +563,97 @@ class BacnetClient extends EventEmitter {
399
563
  });
400
564
  }
401
565
 
566
+ scanDeviceManually(device) {
567
+ let that = this;
568
+ // console.log("scanning device: ", device.getAddress());
569
+ return new Promise(function(resolve, reject) {
570
+ let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
571
+ let address = device.getAddress();
572
+ //let deviceInstance = device.deviceId();
573
+ //let objectTypeList = [0, 1, 2, 3, 4, 5, 8, 13, 14, 19];
574
+ let objectTypeList = [0, 1, 2, 3];
575
+ let instanceRange = {start: 0, end: 100};
576
+ let requestArray = [];
577
+ let maxRequestThreshold = 1000;
578
+ let requestRate = 20;
579
+ let requestBuffer = [];
580
+ let sendBuffer = [];
581
+
582
+ //requestBuffer.push(that._readObjectFull(address, 8, deviceInstance));
583
+
584
+ if(that.manual_instance_range_enabled == true) {
585
+ instanceRange.start = that.manual_instance_range_start;
586
+ maxRequestThreshold = that.manual_instance_range_end;
587
+ if(that.manual_instance_range_end < requestRate) {
588
+ requestRate = that.manual_instance_range_end;
589
+ }
590
+ }
591
+
592
+ for(let typeListIndex = 0; typeListIndex < objectTypeList.length; typeListIndex++){
593
+ let objectType = objectTypeList[typeListIndex];
594
+ for(let i = instanceRange.start; i <= instanceRange.end; i++) {
595
+
596
+ requestArray.push({
597
+ objectId: { type: objectType, instance: i },
598
+ properties: objectNameProperty
599
+ })
600
+
601
+ if(requestArray.length == requestRate ) {
602
+ requestBuffer.push(that._readObjectWithRequestArray(address, requestArray));
603
+ instanceRange.end += requestRate;
604
+ requestArray = [];
605
+ if(i >= maxRequestThreshold) {
606
+ instanceRange.end = maxRequestThreshold;
607
+ if(typeListIndex == objectTypeList.length-1) {
608
+ send();
609
+ }
610
+
611
+ break;
612
+ }
613
+ }
614
+ }
615
+
616
+ instanceRange.end = 100;
617
+ };
618
+
619
+ function send() {
620
+ //console.log("request buffer size: ", requestBuffer.length);
621
+
622
+ for(let index = 0; index < requestBuffer.length; index++) {
623
+ let promise = requestBuffer[index];
624
+ try {
625
+ Promise.resolve(promise).then(function(result) {
626
+ let keys = Object.keys(result);
627
+ for (const [key, value] of Object.entries(result)) {
628
+ if(key == "value" && typeof value == "object") {
629
+ for(let x = 0; x < value.values.length; x++) {
630
+ let ele = value.values[x];
631
+ let valueRoot = ele.values[0].value[0];
632
+ if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
633
+ // console.log("pushing to send buffer");
634
+ sendBuffer.push({"value": ele.objectId, "type": 12});
635
+ }
636
+ }
637
+ }
638
+ }
639
+
640
+ if(index == requestBuffer.length - 1) {
641
+ // console.log("resolving send buffer");
642
+ resolve(sendBuffer);
643
+ }
644
+
645
+ }).catch(function(error) {
646
+ reject(error);
647
+ });
648
+
649
+ } catch(e) {
650
+ reject(e)
651
+ }
652
+ }
653
+ }
654
+ });
655
+ }
656
+
402
657
  _readObjectWithRequestArray(deviceAddress, requestArray) {
403
658
  let that = this;
404
659
 
@@ -431,9 +686,9 @@ class BacnetClient extends EventEmitter {
431
686
  _readDeviceName(deviceAddress, deviceId, callback){
432
687
  let that = this;
433
688
  const requestArray = [{
434
- objectId: { type: baEnum.ObjectTypes.OBJECT_DEVICE, instance: deviceId },
689
+ objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
435
690
  properties: [
436
- { id: baEnum.PropertyIds.PROP_OBJECT_NAME }
691
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME }
437
692
  ]
438
693
  }];
439
694
 
@@ -443,8 +698,8 @@ class BacnetClient extends EventEmitter {
443
698
  _readObjectList(deviceAddress, deviceId, callback) {
444
699
  let that = this;
445
700
  const requestArray = [{
446
- objectId: { type: baEnum.ObjectTypes.OBJECT_DEVICE, instance: deviceId },
447
- properties: [{ id: baEnum.PropertyIds.PROP_OBJECT_LIST }
701
+ objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
702
+ properties: [{ id: baEnum.PropertyIdentifier.OBJECT_LIST }
448
703
  ]
449
704
  }];
450
705
 
@@ -458,38 +713,44 @@ class BacnetClient extends EventEmitter {
458
713
  _readObjectFull(deviceAddress, type, instance) {
459
714
 
460
715
  return this._readObject(deviceAddress, type, instance, [
461
- { id: baEnum.PropertyIds.PROP_OBJECT_IDENTIFIER },
462
- { id: baEnum.PropertyIds.PROP_OBJECT_NAME },
463
- { id: baEnum.PropertyIds.PROP_OBJECT_TYPE },
464
- { id: baEnum.PropertyIds.PROP_DESCRIPTION },
465
- { id: baEnum.PropertyIds.PROP_UNITS },
466
- { id: baEnum.PropertyIds.PROP_PRESENT_VALUE },
467
- { id: baEnum.PropertyIds.PROP_PROPERTY_LIST },
468
- { id: baEnum.PropertyIds.PROP_STATUS_FLAGS },
469
- { id: baEnum.PropertyIds.PROP_RELIABILITY },
470
- { id: baEnum.PropertyIds.PROP_OUT_OF_SERVICE }
716
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
717
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
718
+ { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
719
+ { id: baEnum.PropertyIdentifier.DESCRIPTION },
720
+ { id: baEnum.PropertyIdentifier.UNITS },
721
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
722
+ { id: baEnum.PropertyIdentifier.PROPERTY_LIST },
723
+ { id: baEnum.PropertyIdentifier.STATUS_FLAGS },
724
+ { id: baEnum.PropertyIdentifier.RELIABILITY },
725
+ { id: baEnum.PropertyIdentifier.OUT_OF_SERVICE },
726
+
727
+ { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
728
+ { id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
729
+ { id: baEnum.PropertyIdentifier.PROGRAM_STATE },
730
+ { id: baEnum.PropertyIdentifier.RECORD_COUNT }
731
+
471
732
  ]);
472
733
  };
473
734
 
474
735
  _readObjectPropList(deviceAddress, type, instance) {
475
736
 
476
737
  return this._readObject(deviceAddress, type, instance, [
477
- { id: baEnum.PropertyIds.PROP_PROPERTY_LIST }
738
+ { id: baEnum.PropertyIdentifier.PROPERTY_LIST }
478
739
  ]);
479
740
  };
480
741
 
481
742
  _readObjectId(deviceAddress, type, instance) {
482
743
 
483
744
  return this._readObject(deviceAddress, type, instance, [
484
- { id: baEnum.PropertyIds.PROP_OBJECT_IDENTIFIER }
745
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }
485
746
  ]);
486
747
  }
487
748
 
488
749
  _readObjectPresentValue(deviceAddress, type, instance) {
489
750
 
490
751
  return this._readObject(deviceAddress, type, instance, [
491
- { id: baEnum.PropertyIds.PROP_PRESENT_VALUE },
492
- { id: baEnum.PropertyIds.PROP_OBJECT_NAME}
752
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
753
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME}
493
754
  ]);
494
755
  }
495
756
 
@@ -573,11 +834,11 @@ class BacnetClient extends EventEmitter {
573
834
  const objectInfo = object.values[0].objectId;
574
835
  const deviceObjectId = new DeviceObjectId(objectInfo.type, objectInfo.instance);
575
836
  const objectProperties = object.values[0].values;
576
- const name = this._findValueById(objectProperties, baEnum.PropertyIds.PROP_OBJECT_NAME);
577
- const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.PropertyIds.PROP_DESCRIPTION);
578
- const type = this._findValueById(objectProperties, baEnum.PropertyIds.PROP_OBJECT_TYPE);
579
- const PROP_UNITS = this._findValueById(objectProperties, baEnum.PropertyIds.PROP_UNITS);
580
- const presentValue = this._findValueById(objectProperties, baEnum.PropertyIds.PROP_PRESENT_VALUE);
837
+ const name = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_NAME);
838
+ const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.PropertyIdentifier.DESCRIPTION);
839
+ const type = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_TYPE);
840
+ const PROP_UNITS = this._findValueById(objectProperties, baEnum.PropertyIdentifier.UNITS);
841
+ const presentValue = this._findValueById(objectProperties, baEnum.PropertyIdentifier.PRESENT_VALUE);
581
842
 
582
843
  return new DeviceObject(deviceObjectId, name, PROP_DESCRIPTION, type, PROP_UNITS, presentValue);
583
844
  }
@@ -613,7 +874,7 @@ class BacnetClient extends EventEmitter {
613
874
 
614
875
  scanDevice(device) {
615
876
  return new Promise((resolve, reject) => {
616
- this._readObjectList(device.address, device.deviceId, (err, result) => {
877
+ this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
617
878
  if (!err) {
618
879
  try {
619
880
  resolve(result.values[0].values[0].value);
@@ -640,7 +901,8 @@ class BacnetClient extends EventEmitter {
640
901
  let that = this;
641
902
  let options = {
642
903
  lowLimit: 0,
643
- highLimit: baAsn1.BACNET_MAX_INSTANCE
904
+ highLimit: bacnetIdMax,
905
+ 'net': 65535
644
906
  };
645
907
 
646
908
  if(that.device_id_range_enabled == true) {
@@ -649,7 +911,25 @@ class BacnetClient extends EventEmitter {
649
911
  }
650
912
 
651
913
  if(that.client) {
652
- that.client.whoIs(options);
914
+ that.client.whoIs({'net': 65535});
915
+
916
+ //that.client.whoIs(options);
917
+ //that.client.whoIs({'net':3});
918
+
919
+ // that.client.whoIs({'net':3001});
920
+
921
+ // read a point through a router to an MSTP device
922
+ // that.client.readProperty({address: '10.0.8.212',net:3001,adr:[20]} , {type: 8, instance: 2002}, 77, (err, value) => {
923
+ // console.log('value: ', value);
924
+ // console.log('err: ', err);
925
+ // });
926
+
927
+ // that.client.readProperty({address: '10.0.8.212',net:3001,adr:[20]} , {type: 8, instance: 2002}, 77, (err, value) => {
928
+ // console.log('value: ', value);
929
+ // console.log('err: ', err);
930
+ // });
931
+
932
+
653
933
  } else {
654
934
  that.reinitializeClient(that.config);
655
935
  }
@@ -681,22 +961,37 @@ class BacnetClient extends EventEmitter {
681
961
  }
682
962
 
683
963
  buildNetworkTreeData() {
684
- let that = this;
964
+ let that = this;
965
+ let displayNameCharThreshold = 40;
685
966
  return new Promise(async function(resolve, reject) {
686
967
  if(!that.renderList) that.renderList = [];
687
968
  if(that.deviceList && that.networkTree) {
688
969
  that.deviceList.forEach(function(deviceInfo, index) {
689
970
  let ipAddr = deviceInfo.getAddress();
971
+ let deviceId = deviceInfo.getDeviceId();
690
972
  let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
691
- let deviceObject = that.networkTree[ipAddr];
973
+ let deviceObject = that.networkTree[deviceId];
974
+ let isMstpDevice = deviceInfo.getIsMstpDevice();
692
975
 
693
976
  if(deviceObject) {
694
977
  let children = [];
695
978
  let pointIndex = 0;
696
979
 
697
980
  for(const pointName in deviceObject) {
981
+ //console.log("buidling tree obj for: ", pointName);
698
982
  let pointProperties = [];
699
983
  let values = deviceObject[pointName];
984
+ let displayName = pointName;
985
+ if(pointName.length > displayNameCharThreshold) {
986
+ displayName = "";
987
+ let charArray = pointName.split("");
988
+ for(let i = 0; i < charArray.length; i++){
989
+ if(i < displayNameCharThreshold){
990
+ displayName += charArray[i];
991
+ }
992
+ }
993
+ displayName += "...";
994
+ }
700
995
 
701
996
  if(values.objectName){
702
997
  pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
@@ -713,17 +1008,30 @@ class BacnetClient extends EventEmitter {
713
1008
  if(values.units){
714
1009
  pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
715
1010
  }
716
- if(values.presentValue !== "undefined" && values.presentValue !== null) {
1011
+ if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
717
1012
  pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
718
1013
  }
719
- children.push({"key": `${index}-${pointIndex}`, "label": pointName, "data": pointName, "icon": "", "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
1014
+ if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
1015
+ pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
1016
+ }
1017
+ if(values.modificationDate && !values.modificationDate.errorClass) {
1018
+ pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
1019
+ }
1020
+ if(values.programState){
1021
+ pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
1022
+ }
1023
+ if(values.recordCount && !values.recordCount.errorClass){
1024
+ pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
1025
+ }
1026
+
1027
+ children.push({"key": `${index}-${pointIndex}`, "label": displayName, "data": displayName, "pointName": pointName, "icon": that.getPointIcon(values.meta.objectId.type), "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
720
1028
  pointIndex++;
721
1029
  }
722
- let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.ipAddr == ipAddr);
1030
+ let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
723
1031
  if(foundIndex !== -1) {
724
- that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": "pi pi-box", "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr};
1032
+ that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
725
1033
  } else if(foundIndex == -1) {
726
- that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": "pi pi-box", "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr});
1034
+ that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
727
1035
  }
728
1036
  if(index == that.deviceList.length - 1) {
729
1037
  resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
@@ -741,73 +1049,68 @@ class BacnetClient extends EventEmitter {
741
1049
  let address = device.address;
742
1050
  let pointList = device.getPointsList();
743
1051
 
744
- return new Promise(function(resolve, reject) {
1052
+ return new Promise(function(resolve, reject) {
745
1053
  let promiseArray = [];
746
- pointList.forEach(function(point, pointListIndex) {
747
- promiseArray.push(that._readObjectFull(address, point.value.type, point.value.instance));
748
- if(pointListIndex == pointList.length - 1) {
749
- Promise.all(promiseArray).then(function(objectList){
750
- that.buildResponse(objectList, device).then(function() {
751
- that.lastNetworkPoll = Date.now();
752
- resolve({deviceList: that.deviceList, pointList: that.networkTree});
753
- }).catch(function(e){
1054
+ if(typeof pointList !== "undefined" && pointList.length > 0) {
1055
+ pointList.forEach(function(point, pointListIndex) {
1056
+ promiseArray.push(that._readObjectFull(address, point.value.type, point.value.instance));
1057
+ if(pointListIndex == pointList.length - 1) {
1058
+ Promise.all(promiseArray).then(function(objectList){
1059
+ that.buildResponse(objectList, device).then(function() {
1060
+ that.lastNetworkPoll = Date.now();
1061
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1062
+ }).catch(function(e){
1063
+ console.log("Error while building json object: ", e);
1064
+ reject(e);
1065
+ });
1066
+ }).catch(function(e) {
754
1067
  console.log("Error while building json object: ", e);
755
1068
  reject(e);
756
1069
  });
757
- }).catch(function(e) {
758
- console.log("Error while building json object: ", e);
759
- reject(e);
760
- });
761
- }
762
- });
1070
+ }
1071
+ });
1072
+ } else {
1073
+ reject("Unable to build network tree, empty point list");
1074
+ }
763
1075
  });
764
1076
  }
765
1077
 
766
1078
  // Builds response object for a fully qualified
767
1079
  buildResponse(fullObjects, device) {
768
1080
  let that = this;
769
- let deviceName = device.getDeviceName();
770
- let ipAddr = device.getAddress();
771
-
772
1081
  return new Promise(function(resolve, reject) {
773
- let values = that.networkTree[device.getAddress()] ? that.networkTree[device.getAddress()] : {};
774
-
775
- for(let i = 0; i < fullObjects.length; i++) {
776
-
1082
+ let values = that.networkTree[device.getDeviceId()] ? that.networkTree[device.getDeviceId()] : {};
1083
+ for(let i = 0; i < fullObjects.length; i++) {
777
1084
  let obj = fullObjects[i];
778
1085
  let successfulResult = !obj.error ? obj.value : null;
779
-
780
1086
  if(successfulResult) {
781
1087
  successfulResult.values.forEach(function(pointProperty, pointPropertyIndex) {
782
-
783
1088
  let currobjectId = pointProperty.objectId.type
784
1089
  let bac_obj = that.getObjectType(currobjectId);
785
-
786
- let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIds.PROP_OBJECT_NAME);
787
- let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIds.PROP_OBJECT_TYPE);
788
-
1090
+ let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
1091
+ let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
789
1092
  let objectId;
790
1093
  if(objectName !== null) {
791
- objectName = objectName.split(" ").join("_");
1094
+ //objectName = objectName.split(" ").join("_");
792
1095
  objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
793
1096
  } else {
794
1097
  objectId = bac_obj + '_' + pointProperty.objectId.instance;
795
1098
  }
796
-
797
- if(!values[objectId]) values[objectId] = {};
798
- values[objectId].meta = {
799
- objectId: pointProperty.objectId
800
- };
801
-
802
1099
  try {
803
1100
  pointProperty.values.forEach(function(object, objectIndex) {
804
1101
  //checks for error code json structure, returned for invalid bacnet requests
805
- if(!object.value.value) {
1102
+ if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1103
+
1104
+ if(!values[objectId]) values[objectId] = {};
1105
+ values[objectId].meta = {
1106
+ objectId: pointProperty.objectId
1107
+ };
1108
+
806
1109
  switch(object.id) {
807
- case baEnum.PropertyIds.PROP_PRESENT_VALUE:
1110
+ case baEnum.PropertyIdentifier.PRESENT_VALUE:
808
1111
  if(object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
809
1112
  //check for binary object type
810
- if(objectType == 3 || objectType == 4 || objectType == 5){
1113
+ if(objectType == 3 || objectType == 4 || objectType == 5) {
811
1114
  if(object.value[0].value == 0) {
812
1115
  values[objectId].presentValue = false;
813
1116
  } else if(object.value[0].value == 1) {
@@ -819,29 +1122,52 @@ class BacnetClient extends EventEmitter {
819
1122
  }
820
1123
  values[objectId].meta.arrayIndex = object.index;
821
1124
  break;
822
- case baEnum.PropertyIds.PROP_DESCRIPTION:
1125
+ case baEnum.PropertyIdentifier.DESCRIPTION:
823
1126
  if(object.value[0]) values[objectId].description = object.value[0].value;
824
1127
  break;
825
- case baEnum.PropertyIds.PROP_UNITS:
1128
+ case baEnum.PropertyIdentifier.UNITS:
826
1129
  if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
827
1130
  break;
828
- case baEnum.PropertyIds.PROP_OBJECT_NAME:
1131
+ case baEnum.PropertyIdentifier.OBJECT_NAME:
829
1132
  if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
830
1133
  break;
831
- case baEnum.PropertyIds.PROP_OBJECT_TYPE:
1134
+ case baEnum.PropertyIdentifier.OBJECT_TYPE:
832
1135
  if(object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
833
1136
  break;
834
- case baEnum.PropertyIds.PROP_OBJECT_IDENTIFIER:
1137
+ case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
835
1138
  if(object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
836
1139
  break;
837
- case baEnum.PropertyIds.PROP_PROPERTY_LIST:
1140
+ case baEnum.PropertyIdentifier.PROPERTY_LIST:
838
1141
  if(object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
839
- break;
1142
+ break;
1143
+
1144
+ case baEnum.PropertyIdentifier.SYSTEM_STATUS:
1145
+ if(object.value[0]){
1146
+ values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
1147
+ }
1148
+ break;
1149
+
1150
+ case baEnum.PropertyIdentifier.MODIFICATION_DATE:
1151
+ if(object.value[0]) {
1152
+ values[objectId].modificationDate = object.value[0].value;
1153
+ }
1154
+ break;
1155
+
1156
+ case baEnum.PropertyIdentifier.PROGRAM_STATE:
1157
+ if(object.value[0]){
1158
+ values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
1159
+ }
1160
+ break;
1161
+
1162
+ case baEnum.PropertyIdentifier.RECORD_COUNT:
1163
+ if(object.value[0] ) {
1164
+ values[objectId].recordCount = object.value[0].value;
1165
+ }
1166
+ break;
840
1167
  }
841
1168
  }
842
-
843
1169
  if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
844
- that.networkTree[device.getAddress()] = values;
1170
+ that.networkTree[device.getDeviceId()] = values;
845
1171
  resolve(that.networkTree);
846
1172
  }
847
1173
  });
@@ -853,12 +1179,12 @@ class BacnetClient extends EventEmitter {
853
1179
  } else {
854
1180
  //error found in point property
855
1181
  if(i == fullObjects.length - 1) {
856
- that.networkTree[device.getAddress()] = values;
1182
+ that.networkTree[device.getDeviceId()] = values;
857
1183
  resolve(that.networkTree);
858
1184
  }
859
1185
  }
860
1186
  }
861
- reject("Unexpectedly found end of loop, line 861");
1187
+ reject("Unexpectedly found end of loop, line 1170");
862
1188
  });
863
1189
  }
864
1190
 
@@ -870,6 +1196,104 @@ class BacnetClient extends EventEmitter {
870
1196
  return uniquePropArray;
871
1197
  }
872
1198
 
1199
+ getPROP_PROGRAM_STATE(value) {
1200
+ switch(value) {
1201
+ case 0:
1202
+ return "0 - Idle";
1203
+ case 1:
1204
+ return "1 - Loading";
1205
+ case 2:
1206
+ return "2 - Running";
1207
+ case 3:
1208
+ return "3 - Waiting";
1209
+ case 4:
1210
+ return "4 - Halted";
1211
+ case 5:
1212
+ return "5 - Unloading";
1213
+ default:
1214
+ return "";
1215
+ }
1216
+ }
1217
+
1218
+ getPROP_SYSTEM_STATUS(value) {
1219
+ switch(value) {
1220
+ case 0:
1221
+ return "0 - Operational";
1222
+ case 1:
1223
+ return "1 - Operational Readonly";
1224
+ case 2:
1225
+ return "2 - Download Required";
1226
+ case 3:
1227
+ return "3 - Download In Progress";
1228
+ case 4:
1229
+ return "4 - Non Operational";
1230
+ case 5:
1231
+ return "5 - Backup In Progress";
1232
+ default:
1233
+ return "";
1234
+ }
1235
+ }
1236
+
1237
+ getPointIcon(objectId) {
1238
+ switch(objectId) {
1239
+ case 0:
1240
+ //AI
1241
+ return "pi pi-tags";
1242
+ case 1:
1243
+ //AO
1244
+ return "pi pi-tags";
1245
+ case 2:
1246
+ //AV
1247
+ return "pi pi-tags";
1248
+ case 3:
1249
+ //BI
1250
+ return "pi pi-tags";
1251
+ case 4:
1252
+ //BO
1253
+ return "pi pi-tags";
1254
+ case 5:
1255
+ //BV
1256
+ return "pi pi-tags";
1257
+ case 8:
1258
+ //Device
1259
+ return "pi pi-box";
1260
+ case 13:
1261
+ //MI
1262
+ return "pi pi-tags";
1263
+ case 14:
1264
+ //MO
1265
+ return "pi pi-tags";
1266
+ case 19:
1267
+ //MV
1268
+ return "pi pi-tags";
1269
+ case 10:
1270
+ //File
1271
+ return "pi pi-file";
1272
+ case 16:
1273
+ //Program
1274
+ return "pi pi-database";
1275
+ case 20:
1276
+ //Trendlog
1277
+ return "pi pi-chart-line";
1278
+ case 15:
1279
+ //Notification Class
1280
+ return "pi pi-bell";
1281
+ case 56:
1282
+ return "pi pi-sitemap";
1283
+ case 178:
1284
+ return "pi pi-lock";
1285
+ case 20:
1286
+ return "pi pi-chart-line";
1287
+ case 17:
1288
+ return "pi pi-calendar";
1289
+ case 6:
1290
+ return "pi pi-calendar";
1291
+ default:
1292
+ //Return circle for all other types
1293
+ return "pi pi-tags";
1294
+ }
1295
+ }
1296
+
873
1297
  getObjectType(objectId) {
874
1298
  switch(objectId) {
875
1299
  case 0:
@@ -935,6 +1359,15 @@ class BacnetClient extends EventEmitter {
935
1359
  getStatusFlags(flags) {
936
1360
  return flags.value[0].value;
937
1361
  }
1362
+
1363
+ getDeviceIcon(isMstp){
1364
+ if(isMstp == true) {
1365
+ return "pi pi-share-alt"
1366
+ } else if(isMstp == false) {
1367
+ return "pi pi-server"
1368
+ }
1369
+ return "pi pi-server";
1370
+ }
938
1371
  }
939
1372
 
940
1373
  module.exports = { BacnetClient };