@bitpoolos/edge-bacnet 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/bacnet_client.js +650 -233
  2. package/bacnet_device.js +65 -16
  3. package/bacnet_gateway.html +242 -99
  4. package/bacnet_gateway.js +211 -27
  5. package/bacnet_object.js +1 -1
  6. package/bacnet_read.html +211 -133
  7. package/bacnet_read.js +24 -24
  8. package/bacnet_server.js +321 -0
  9. package/bacnet_write.html +24 -15
  10. package/bacnet_write.js +0 -2
  11. package/common.js +95 -9
  12. package/edge-bacnet-datastore.cfg +0 -0
  13. package/package.json +6 -4
  14. package/resources/confirmationservice.min.js +1 -0
  15. package/resources/confirmdialog.min.js +1 -0
  16. package/resources/fonts/primeicons.woff2 +0 -0
  17. package/resources/node-bacnet/CHANGELOG.md +481 -0
  18. package/resources/{bacstack → node-bacnet}/LICENSE.md +3 -1
  19. package/resources/node-bacnet/README.md +91 -0
  20. package/resources/node-bacnet/docs/Client.html +4422 -0
  21. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  22. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  23. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  24. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  25. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  26. package/resources/node-bacnet/docs/bacnet.html +7032 -0
  27. package/resources/node-bacnet/docs/client.js.html +1759 -0
  28. package/resources/node-bacnet/docs/enum.js.html +2530 -0
  29. package/resources/node-bacnet/docs/global.html +2068 -0
  30. package/resources/node-bacnet/docs/images/mocha-logo.svg +65 -0
  31. package/resources/node-bacnet/docs/index.html +283 -0
  32. package/resources/node-bacnet/docs/scripts/collapse.js +11 -0
  33. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +4 -0
  34. package/resources/node-bacnet/docs/scripts/linenumber.js +26 -0
  35. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  36. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +2 -0
  37. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +28 -0
  38. package/resources/node-bacnet/docs/scripts/search.js +47 -0
  39. package/resources/node-bacnet/docs/services_i-am.js.html +157 -0
  40. package/resources/node-bacnet/docs/services_time-sync.js.html +118 -0
  41. package/resources/node-bacnet/docs/services_who-is.js.html +138 -0
  42. package/resources/node-bacnet/docs/styles/jsdoc.css +683 -0
  43. package/resources/node-bacnet/docs/styles/prettify.css +82 -0
  44. package/resources/node-bacnet/examples/discover-devices.js +66 -0
  45. package/resources/node-bacnet/examples/read-device.js +510 -0
  46. package/resources/node-bacnet/examples/subscribe-cov.js +75 -0
  47. package/resources/{bacstack → node-bacnet}/index.js +3 -0
  48. package/resources/{bacstack → node-bacnet}/lib/apdu.js +56 -39
  49. package/resources/{bacstack → node-bacnet}/lib/asn1.js +550 -532
  50. package/resources/node-bacnet/lib/bvlc.js +90 -0
  51. package/resources/node-bacnet/lib/client.js +1695 -0
  52. package/resources/node-bacnet/lib/enum.js +2463 -0
  53. package/resources/node-bacnet/lib/npdu.js +123 -0
  54. package/resources/{bacstack → node-bacnet}/lib/services/add-list-element.js +12 -6
  55. package/resources/{bacstack → node-bacnet}/lib/services/alarm-acknowledge.js +3 -3
  56. package/resources/{bacstack → node-bacnet}/lib/services/alarm-summary.js +5 -4
  57. package/resources/{bacstack → node-bacnet}/lib/services/atomic-read-file.js +49 -26
  58. package/resources/{bacstack → node-bacnet}/lib/services/atomic-write-file.js +40 -23
  59. package/resources/{bacstack → node-bacnet}/lib/services/cov-notify.js +33 -17
  60. package/resources/{bacstack → node-bacnet}/lib/services/create-object.js +23 -13
  61. package/resources/{bacstack → node-bacnet}/lib/services/delete-object.js +7 -2
  62. package/resources/{bacstack → node-bacnet}/lib/services/device-communication-control.js +8 -3
  63. package/resources/{bacstack → node-bacnet}/lib/services/error.js +7 -0
  64. package/resources/{bacstack → node-bacnet}/lib/services/event-information.js +10 -9
  65. package/resources/{bacstack → node-bacnet}/lib/services/event-notify-data.js +38 -16
  66. package/resources/{bacstack → node-bacnet}/lib/services/get-enrollment-summary.js +24 -11
  67. package/resources/{bacstack → node-bacnet}/lib/services/get-event-information.js +28 -13
  68. package/resources/node-bacnet/lib/services/i-am.js +90 -0
  69. package/resources/{bacstack/lib/services/i-have-broadcast.js → node-bacnet/lib/services/i-have.js} +3 -2
  70. package/resources/{bacstack → node-bacnet}/lib/services/index.js +7 -4
  71. package/resources/{bacstack → node-bacnet}/lib/services/life-safety-operation.js +3 -2
  72. package/resources/{bacstack → node-bacnet}/lib/services/private-transfer.js +3 -2
  73. package/resources/{bacstack → node-bacnet}/lib/services/read-property-multiple.js +11 -6
  74. package/resources/{bacstack → node-bacnet}/lib/services/read-property.js +42 -24
  75. package/resources/{bacstack → node-bacnet}/lib/services/read-range.js +37 -27
  76. package/resources/node-bacnet/lib/services/register-foreign-device.js +18 -0
  77. package/resources/{bacstack → node-bacnet}/lib/services/reinitialize-device.js +9 -4
  78. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-cov.js +9 -4
  79. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-property.js +18 -8
  80. package/resources/{bacstack → node-bacnet}/lib/services/time-sync.js +28 -5
  81. package/resources/{bacstack → node-bacnet}/lib/services/who-has.js +3 -3
  82. package/resources/{bacstack → node-bacnet}/lib/services/who-is.js +42 -9
  83. package/resources/{bacstack → node-bacnet}/lib/services/write-property-multiple.js +33 -16
  84. package/resources/{bacstack → node-bacnet}/lib/services/write-property.js +23 -13
  85. package/resources/node-bacnet/lib/transport.js +82 -0
  86. package/resources/node-bacnet/package.json +92 -0
  87. package/resources/primeicons.css +90 -2
  88. package/resources/bacstack/.codeclimate.yml +0 -15
  89. package/resources/bacstack/.dockerignore +0 -5
  90. package/resources/bacstack/.editorconfig +0 -13
  91. package/resources/bacstack/.eslintrc.yml +0 -13
  92. package/resources/bacstack/.github/ISSUE_TEMPLATE.md +0 -26
  93. package/resources/bacstack/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  94. package/resources/bacstack/.github/workflows/ci.yml +0 -39
  95. package/resources/bacstack/.jscsrc +0 -8
  96. package/resources/bacstack/.jshintrc +0 -50
  97. package/resources/bacstack/.travis.yml +0 -27
  98. package/resources/bacstack/CHANGELOG.md +0 -232
  99. package/resources/bacstack/CODE_OF_CONDUCT.md +0 -74
  100. package/resources/bacstack/CONTRIBUTING.md +0 -77
  101. package/resources/bacstack/Dockerfile +0 -15
  102. package/resources/bacstack/FAQ.md +0 -64
  103. package/resources/bacstack/README.md +0 -157
  104. package/resources/bacstack/docker-compose.yml +0 -9
  105. package/resources/bacstack/lib/adpu.js +0 -190
  106. package/resources/bacstack/lib/bvlc.js +0 -43
  107. package/resources/bacstack/lib/client.js +0 -1028
  108. package/resources/bacstack/lib/enum.js +0 -1314
  109. package/resources/bacstack/lib/npdu.js +0 -119
  110. package/resources/bacstack/lib/services/i-am-broadcast.js +0 -51
  111. package/resources/bacstack/lib/services.js +0 -1963
  112. package/resources/bacstack/lib/transport.js +0 -52
  113. package/resources/bacstack/package-lock.json +0 -7974
  114. package/resources/bacstack/package.json +0 -84
  115. package/resources/bacstack/test/compliance/who-is.spec.js +0 -37
  116. package/resources/bacstack/test/integration/acknowledge-alarm.spec.js +0 -14
  117. package/resources/bacstack/test/integration/add-list-element.spec.js +0 -16
  118. package/resources/bacstack/test/integration/confirmed-event-notification.spec.js +0 -30
  119. package/resources/bacstack/test/integration/confirmed-private-transfer.spec.js +0 -15
  120. package/resources/bacstack/test/integration/create-object.spec.js +0 -16
  121. package/resources/bacstack/test/integration/delete-object.spec.js +0 -14
  122. package/resources/bacstack/test/integration/device-communication-control.spec.js +0 -14
  123. package/resources/bacstack/test/integration/get-alarm-summary.spec.js +0 -14
  124. package/resources/bacstack/test/integration/get-enrollment-summary.spec.js +0 -15
  125. package/resources/bacstack/test/integration/get-event-information.spec.js +0 -14
  126. package/resources/bacstack/test/integration/read-file.spec.js +0 -14
  127. package/resources/bacstack/test/integration/read-property-multiple.spec.js +0 -110
  128. package/resources/bacstack/test/integration/read-property.spec.js +0 -14
  129. package/resources/bacstack/test/integration/read-range.spec.js +0 -14
  130. package/resources/bacstack/test/integration/reinitialize-sevice.spec.js +0 -14
  131. package/resources/bacstack/test/integration/remove-list-element.spec.js +0 -16
  132. package/resources/bacstack/test/integration/subscribe-cov.spec.js +0 -14
  133. package/resources/bacstack/test/integration/subscribe-property.spec.js +0 -14
  134. package/resources/bacstack/test/integration/time-sync-utc.spec.js +0 -10
  135. package/resources/bacstack/test/integration/time-sync.spec.js +0 -10
  136. package/resources/bacstack/test/integration/unconfirmed-event-notification.spec.js +0 -28
  137. package/resources/bacstack/test/integration/unconfirmed-private-transfer.spec.js +0 -11
  138. package/resources/bacstack/test/integration/utils.js +0 -30
  139. package/resources/bacstack/test/integration/who-is.spec.js +0 -17
  140. package/resources/bacstack/test/integration/write-file.spec.js +0 -14
  141. package/resources/bacstack/test/integration/write-property-multiple.spec.js +0 -19
  142. package/resources/bacstack/test/integration/write-property.spec.js +0 -14
  143. package/resources/bacstack/test/unit/apdu.spec.js +0 -162
  144. package/resources/bacstack/test/unit/asn1.spec.js +0 -39
  145. package/resources/bacstack/test/unit/bacnet-apdu.spec.js +0 -161
  146. package/resources/bacstack/test/unit/bacnet-asn1.spec.js +0 -32
  147. package/resources/bacstack/test/unit/bacnet-bvlc.spec.js +0 -57
  148. package/resources/bacstack/test/unit/bacnet-npdu.spec.js +0 -118
  149. package/resources/bacstack/test/unit/bacnet-services.spec.js +0 -2052
  150. package/resources/bacstack/test/unit/bvlc.spec.js +0 -58
  151. package/resources/bacstack/test/unit/npdu.spec.js +0 -119
  152. package/resources/bacstack/test/unit/service-add-list-element.spec.js +0 -24
  153. package/resources/bacstack/test/unit/service-alarm-acknowledge.spec.js +0 -71
  154. package/resources/bacstack/test/unit/service-alarm-summary.spec.js +0 -22
  155. package/resources/bacstack/test/unit/service-atomic-read-file.spec.js +0 -54
  156. package/resources/bacstack/test/unit/service-atomic-write-file.spec.js +0 -56
  157. package/resources/bacstack/test/unit/service-cov-notify.spec.js +0 -98
  158. package/resources/bacstack/test/unit/service-create-object.spec.js +0 -90
  159. package/resources/bacstack/test/unit/service-delete-object.spec.js +0 -17
  160. package/resources/bacstack/test/unit/service-device-communication-control.spec.js +0 -29
  161. package/resources/bacstack/test/unit/service-error.spec.js +0 -17
  162. package/resources/bacstack/test/unit/service-event-information.spec.js +0 -48
  163. package/resources/bacstack/test/unit/service-event-notify-data.spec.js +0 -310
  164. package/resources/bacstack/test/unit/service-get-enrollment-summary.spec.js +0 -45
  165. package/resources/bacstack/test/unit/service-get-event-information.spec.js +0 -62
  166. package/resources/bacstack/test/unit/service-i-am.spec.js +0 -19
  167. package/resources/bacstack/test/unit/service-i-have-broadcast.spec.js +0 -18
  168. package/resources/bacstack/test/unit/service-life-safety-operation.spec.js +0 -19
  169. package/resources/bacstack/test/unit/service-private-transfer.spec.js +0 -18
  170. package/resources/bacstack/test/unit/service-read-property-multiple.spec.js +0 -131
  171. package/resources/bacstack/test/unit/service-read-property.spec.js +0 -541
  172. package/resources/bacstack/test/unit/service-read-range.spec.js +0 -97
  173. package/resources/bacstack/test/unit/service-reinitialize-device.spec.js +0 -27
  174. package/resources/bacstack/test/unit/service-subscribe-cov.spec.js +0 -32
  175. package/resources/bacstack/test/unit/service-subscribe-property.spec.js +0 -50
  176. package/resources/bacstack/test/unit/service-time-sync.spec.js +0 -18
  177. package/resources/bacstack/test/unit/service-who-has.spec.js +0 -33
  178. package/resources/bacstack/test/unit/service-who-is.spec.js +0 -17
  179. package/resources/bacstack/test/unit/service-write-property-multiple.spec.js +0 -143
  180. package/resources/bacstack/test/unit/service-write-property.spec.js +0 -198
  181. package/resources/bacstack/test/unit/utils.js +0 -6
package/bacnet_client.js CHANGED
@@ -1,23 +1,26 @@
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');
9
- const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces } = require('./common');
10
- const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
4
+ const bacnet = require('./resources/node-bacnet/index.js');
5
+ const { BacnetServer } = require("./bacnet_server.js");
6
+ const baEnum = bacnet.enum;
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');
10
+ const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
11
11
  const { BacnetDevice } = require('./bacnet_device');
12
12
  const {Mutex, Semaphore, withTimeout} = require("async-mutex");
13
+
13
14
  class BacnetClient extends EventEmitter {
14
15
 
15
16
  //client constructor
16
17
  constructor(config) {
17
18
  super();
18
19
  let that = this;
20
+
21
+ let cachedData = JSON.parse(Read_Config_Sync());
22
+
19
23
  that.deviceList = [];
20
- that.pointReferenceList = [];
21
24
  that.networkTree = {};
22
25
  that.lastWhoIs = null;
23
26
  that.client = null;
@@ -25,6 +28,17 @@ class BacnetClient extends EventEmitter {
25
28
  that.scheduler = new ToadScheduler();
26
29
  that.mutex = new Mutex();
27
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
+ });
38
+ }
39
+ if(cachedData.pointList) that.networkTree = cachedData.pointList;
40
+ }
41
+
28
42
  try {
29
43
  that.config = config;
30
44
  that.roundDecimal = config.roundDecimal;
@@ -34,10 +48,16 @@ class BacnetClient extends EventEmitter {
34
48
  that.device_id_range_enabled = config.device_id_range_enabled;
35
49
  that.device_id_range_start = config.device_id_range_start;
36
50
  that.device_id_range_end = config.device_id_range_end;
51
+ that.deviceId = config.deviceId;
52
+ that.broadCastAddr = config.broadCastAddr;
53
+ that.manual_instance_range_enabled = config.manual_instance_range_enabled;
54
+ that.manual_instance_range_start = config.manual_instance_range_start;
55
+ that.manual_instance_range_end = config.manual_instance_range_end;
56
+ that.bacnetServerEnabled = config.bacnetServerEnabled;
37
57
 
38
58
  that.readPropertyMultipleOptions = {
39
59
  maxSegments: that.maxSegments,
40
- apduSize: that.apduSize
60
+ maxApdu: that.apduSize
41
61
  };
42
62
 
43
63
  try {
@@ -51,11 +71,12 @@ class BacnetClient extends EventEmitter {
51
71
 
52
72
  const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, task)
53
73
 
54
- that.scheduler.addSimpleIntervalJob(job)
74
+ that.scheduler.addSimpleIntervalJob(job);
55
75
 
56
76
  //query device task
57
- const queryDevices = new Task('simple task', () => {
77
+ const queryDevices = new Task('simple task', () => {
58
78
  that.queryDevices();
79
+ that.sanitizeDeviceList();
59
80
  });
60
81
 
61
82
  const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, queryDevices)
@@ -63,7 +84,7 @@ class BacnetClient extends EventEmitter {
63
84
  that.scheduler.addSimpleIntervalJob(queryJob);
64
85
 
65
86
  //buildNetworkTreeData task
66
- const buildNetworkTree = new Task('simple task', () => {
87
+ const buildNetworkTree = new Task('simple task', () => {
67
88
  that.buildNetworkTreeData();
68
89
  });
69
90
 
@@ -77,45 +98,88 @@ class BacnetClient extends EventEmitter {
77
98
  that.queryDevices();
78
99
  }, "5000")
79
100
 
80
- } catch(e){
81
- console.log("Issue initializing client: ", e)
101
+ } catch(e) {
102
+ that.logOut("Issue initializing client: ", e)
82
103
  }
83
104
 
84
105
  //who is callback
85
106
  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]);
107
+ if(device.header.sender.address !== that.config.localIpAdrress) {
108
+ if(that.device_id_range_enabled) {
109
+ if(device.payload.deviceId >= that.device_id_range_start && device.payload.deviceId <= that.device_id_range_end) {
110
+ //only add unique device to array
111
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
112
+ if(foundIndex == -1) {
113
+ let newBacnetDevice = new BacnetDevice(false, device);
114
+ newBacnetDevice.setLastSeen(Date.now());
115
+ that.updateDeviceName(newBacnetDevice);
116
+ that.deviceList.push(newBacnetDevice);
117
+
118
+ } else if(foundIndex !== -1) {
119
+ that.deviceList[foundIndex].updateDeviceConfig(device);
120
+ that.deviceList[foundIndex].setLastSeen(Date.now());
121
+ that.updateDeviceName(that.deviceList[foundIndex]);
122
+ }
123
+
124
+ //emit event for node-red to log
125
+ that.emit('deviceFound', device);
126
+ }
127
+ } else {
128
+ //only add unique device to array
129
+ let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
130
+ if(foundIndex == -1) {
131
+ let newBacnetDevice = new BacnetDevice(false, device);
132
+ newBacnetDevice.setLastSeen(Date.now());
133
+ that.updateDeviceName(newBacnetDevice);
134
+ that.deviceList.push(newBacnetDevice);
135
+
136
+ } else if(foundIndex !== -1) {
137
+ that.deviceList[foundIndex].updateDeviceConfig(device);
138
+ that.deviceList[foundIndex].setLastSeen(Date.now());
139
+ that.updateDeviceName(that.deviceList[foundIndex]);
140
+ }
141
+
142
+ //emit event for node-red to log
143
+ that.emit('deviceFound', device);
144
+ }
98
145
  }
99
-
100
- //emit event for node-red to log
101
- that.emit('deviceFound', device);
102
146
  });
103
- } catch(e){
104
- console.log("Issue with creating bacnet client, see error: ", e);
147
+
148
+ } catch(e) {
149
+ that.logOut("Issue with creating bacnet client, see error: ", e);
105
150
  }
106
151
 
107
152
  that.client.on('error', (err) => {
108
- console.log('Error occurred: ', err);
153
+ that.logOut('Error occurred: ', err);
109
154
 
110
155
  if(err.errno == -4090){
111
- console.log("Invalid Client information or incorrect IP address provided");
156
+ that.logOut("Invalid Client information or incorrect IP address provided");
112
157
  } else if(err.errno == -49) {
113
- console.log("Invalid IP address provided");
158
+ that.logOut("Invalid IP address provided");
114
159
  } else {
115
160
  that.reinitializeClient(that.config);
116
161
  }
117
162
  });
163
+ }
118
164
 
165
+ logOut(param1, param2) {
166
+ let that = this;
167
+ that.emit('bacnetErrorLog', param1, param2);
168
+ }
169
+
170
+ rebuildDataModel() {
171
+ let that = this;
172
+ return new Promise((resolve, reject) => {
173
+ try {
174
+ that.deviceList = [];
175
+ that.renderList = [];
176
+ that.networkTree = {};
177
+ resolve(true);
178
+ } catch(e) {
179
+ that.logOut("Error clearing BACnet data model: ", e);
180
+ reject(e);
181
+ }
182
+ });
119
183
  }
120
184
 
121
185
  queryDevices() {
@@ -125,26 +189,60 @@ class BacnetClient extends EventEmitter {
125
189
  .acquire()
126
190
  .then(function(release) {
127
191
  try {
192
+
128
193
  that.getDevicePointList(device).then(function() {
129
194
  that.buildJsonObject(device).then(function() {
130
195
  release();
131
196
  }).catch(function(e) {
132
197
  release();
133
198
  });
134
- }).catch(function(e){
199
+ }).catch(function(e) {
200
+ that.getDevicePointListWithoutObjectList(device).then(function() {
201
+ that.buildJsonObject(device).then(function() {
202
+ release();
203
+ }).catch(function(e) {
204
+ release();
205
+ });
206
+ }).catch(function(e) {
207
+ release();
208
+ });
135
209
  release();
136
210
  });
211
+
137
212
  } catch(e) {
138
- console.log("Error while querying devices: ", e);
213
+ that.logOut("Error while querying devices: ", e);
139
214
  release();
140
215
  }
141
216
  });
142
217
  });
218
+ Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
219
+ }
220
+
221
+ sanitizeDeviceList() {
222
+ let that = this;
223
+
224
+ that.deviceList.forEach(function(device, index) {
225
+ if(((Date.now() - device.getLastSeen()) / 1000) > 3600) {
226
+ //device hasnt responded to whoIs for over an hour
227
+
228
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
229
+ delete that.networkTree[deviceKey];
230
+
231
+ if(that.renderList){
232
+ let foundIndex = that.renderList.findIndex(ele => ele.ipAddr == device.getAddress() && ele.deviceId == device.getDeviceId());
233
+ if(foundIndex !== -1) {
234
+ that.renderList.splice(foundIndex, 1);
235
+ }
236
+ }
237
+
238
+ that.deviceList.splice(index, 1);
239
+ }
240
+ });
143
241
  }
144
242
 
145
243
  updateDeviceName(device) {
146
244
  let that = this;
147
- that._getDeviceName(device.address, device.deviceId).then(function(deviceName) {
245
+ that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceName) {
148
246
  device.setDeviceName(deviceName);
149
247
  });
150
248
  }
@@ -152,21 +250,34 @@ class BacnetClient extends EventEmitter {
152
250
  reinitializeClient(config) {
153
251
  let that = this;
154
252
 
253
+ that.config = config;
254
+ that.roundDecimal = config.roundDecimal;
255
+ that.apduSize = config.apduSize;
256
+ that.maxSegments = config.maxSegments;
257
+ that.discover_polling_schedule = config.discover_polling_schedule;
155
258
  that.device_id_range_enabled = config.device_id_range_enabled;
156
259
  that.device_id_range_start = config.device_id_range_start;
157
260
  that.device_id_range_end = config.device_id_range_end;
158
-
159
- if(that.client !== null) {
160
- that.client.close();
161
- that.client = null;
162
- }
261
+ that.deviceId = config.deviceId;
262
+ that.broadCastAddr = config.broadCastAddr;
263
+ that.manual_instance_range_enabled = config.manual_instance_range_enabled;
264
+ that.manual_instance_range_start = config.manual_instance_range_start;
265
+ that.manual_instance_range_end = config.manual_instance_range_end;
266
+ that.bacnetServerEnabled = config.bacnetServerEnabled;
163
267
 
164
268
  if(that.scheduler !== null) {
165
269
  that.scheduler.stop();
166
270
  }
167
271
 
168
- try{
169
- that.client = new bacnet({ apduTimeout: config.apduTimeout, interface: config.localIpAdrress, port: config.port, broadcastAddress: config.broadCastAddr});
272
+ try {
273
+ that.client._settings.apduTimeout = config.apduTimeout;
274
+ that.client._settings.interface = config.localIpAdrress;
275
+ that.client._settings.port = config.port;
276
+ that.client._settings.broadcastAddress = config.broadCastAddr;
277
+
278
+ that.client._transport.interface = config.localIpAdrress;
279
+ that.client._transport.port = config.port;
280
+ that.client._transport.broadcastAddress = config.broadCastAddr;
170
281
 
171
282
  const task = new Task('simple task', () => {
172
283
  that.globalWhoIs();
@@ -179,26 +290,12 @@ class BacnetClient extends EventEmitter {
179
290
  that.globalWhoIs();
180
291
 
181
292
  } catch(e){
182
- console.log("Error reinitializing bacnet client: ", e)
293
+ that.logOut("Error reinitializing bacnet client: ", e)
183
294
  }
184
295
  };
185
296
 
186
- buildPointReferenceList(promiseArray){
297
+ getValidPointProperties(point, requestedProps) {
187
298
  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
- getValidPointProperties(point, requestedProps){
202
299
  let availableProps = point.propertyList;
203
300
  let newProps = [];
204
301
 
@@ -208,43 +305,46 @@ class BacnetClient extends EventEmitter {
208
305
  if(foundInAvailable) newProps.push(prop);
209
306
  });
210
307
  //add object name for use in formatting
211
- newProps.push({id: baEnum.PropertyIds.PROP_OBJECT_NAME});
308
+ newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
212
309
  } catch(e){
213
- console.log("Issue finding valid object properties, see error: ", e);
310
+ that.logOut("Issue finding valid object properties, see error: ", e);
214
311
  }
215
312
 
216
313
  return newProps;
217
314
  }
218
315
 
219
- doRead(readConfig, outputType, msgId) {
316
+ doRead(readConfig, outputType, objectPropertyType, msgId) {
220
317
  let that = this;
221
-
222
318
  that.roundDecimal = readConfig.precision;
223
319
  let devicesToRead = Object.keys(readConfig.pointsToRead);
224
- let propertiesToRead = readConfig.objectProperties;
225
320
 
226
321
  try {
227
- devicesToRead.forEach(function(deviceAddress) {
228
- let requestArray = [];
229
- let readPromiseArray = [];
230
- let pointsToReadNames = Object.keys(readConfig.pointsToRead[deviceAddress]);
231
- let device = that.deviceList.find(ele => ele.address == deviceAddress);
232
- 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));
235
- });
236
- that.readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId);
322
+ let bacnetResults = {};
323
+ devicesToRead.forEach(function(key, index) {
324
+ let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
325
+ let deviceName = device.getDeviceName();
326
+ bacnetResults[deviceName] = readConfig.pointsToRead[key];
327
+ if(index == devicesToRead.length - 1) that.emit('values', bacnetResults, outputType, objectPropertyType);
237
328
  });
238
-
239
- } catch(e){
240
- console.log("Issue doing read, see error: ", e);
329
+ } catch(e) {
330
+ that.logOut("Issue doing read, see error: ", e);
241
331
  }
332
+ }
242
333
 
334
+ getDeviceAddress(device){
335
+ switch(typeof device.getAddress()) {
336
+ case "object":
337
+ return device.getAddress().address;
338
+ case "string":
339
+ return device.getAddress();
340
+ default:
341
+ return device.getAddress();
342
+ }
243
343
  }
244
344
 
245
- readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId) {
345
+ readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId) {
246
346
  let that = this;
247
- let deviceName = device.deviceName;
347
+ let deviceName = device.getDeviceName();
248
348
 
249
349
  let bacnetResults = {
250
350
  [deviceName]: []
@@ -261,45 +361,69 @@ class BacnetClient extends EventEmitter {
261
361
  element.values.forEach(function(point){
262
362
  point.values.forEach(function(object) {
263
363
  let toReadProperty = propertiesToRead.findIndex(ele => ele.id == object.id);
364
+ let objectName = that._findValueById(point.values, baEnum.PropertyIdentifier.OBJECT_NAME);
264
365
  //checks for error code json structure, returned for invalid bacnet requests
265
- if(!object.value.value && toReadProperty !== -1) {
366
+ if(!object.value.value && toReadProperty !== -1 && objectName !== "") {
266
367
  var currobjectId = point.objectId.type
267
368
  let bac_obj = that.getObjectType(currobjectId);
268
- let objectName = that._findValueById(point.values, baEnum.PropertyIds.PROP_OBJECT_NAME);
269
-
270
369
  let objectId;
271
- if(objectName !== null) {
272
- objectName = objectName.split(" ").join("_");
273
- objectId = objectName + "_" + bac_obj + '_' + point.objectId.instance;
274
- } else {
275
- objectId = bac_obj + '_' + point.objectId.instance;
276
- }
370
+ objectId = objectName;
277
371
 
278
372
  //init json object
279
373
  if(!values[objectId]) values[objectId] = {};
280
374
 
281
375
  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);
376
+ case baEnum.PropertyIdentifier.PRESENT_VALUE:
377
+ if(object.value[0] &&
378
+ object.value[0].value !== "undefined" &&
379
+ object.value[0].value !== null &&
380
+ typeof object.value[0].value == "number") {
381
+ values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
382
+ } else if(object.value[0] &&
383
+ object.value[0].value !== "undefined" &&
384
+ object.value[0].value !== null &&
385
+ typeof object.value[0].value == "string") {
386
+ values[objectId].presentValue = object.value[0].value;
387
+ }
284
388
  break;
285
- case baEnum.PropertyIds.PROP_DESCRIPTION:
389
+ case baEnum.PropertyIdentifier.DESCRIPTION:
286
390
  if(object.value[0]) values[objectId].description = object.value[0].value;
287
391
  break;
288
- case baEnum.PropertyIds.PROP_STATUS_FLAGS:
392
+ case baEnum.PropertyIdentifier.STATUS_FLAGS:
289
393
  if(object.value[0] && object.value[0].value) values[objectId].statusFlags = that.getStatusFlags(object);
290
394
  break;
291
- case baEnum.PropertyIds.PROP_RELIABILITY:
395
+ case baEnum.PropertyIdentifier.RELIABILITY:
292
396
  if(object.value[0]) values[objectId].reliability = that.getPROP_RELIABILITY(object.value[0].value);
293
397
  break;
294
- case baEnum.PropertyIds.PROP_OUT_OF_SERVICE:
398
+ case baEnum.PropertyIdentifier.OUT_OF_SERVICE:
295
399
  if(object.value[0]) values[objectId].outOfService = object.value[0].value;
296
400
  break;
297
- case baEnum.PropertyIds.PROP_UNITS:
401
+ case baEnum.PropertyIdentifier.UNITS:
298
402
  if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
299
403
  break;
300
- case baEnum.PropertyIds.PROP_OBJECT_NAME:
404
+ case baEnum.PropertyIdentifier.OBJECT_NAME:
301
405
  if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
302
406
  break;
407
+ case baEnum.PropertyIdentifier.SYSTEM_STATUS:
408
+ if(object.value[0]){
409
+ values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
410
+ }
411
+ break;
412
+ case baEnum.PropertyIdentifier.MODIFICATION_DATE:
413
+ if(object.value[0]) {
414
+ values[objectId].modificationDate = object.value[0].value;
415
+ }
416
+ break;
417
+ case baEnum.PropertyIdentifier.PROGRAM_STATE:
418
+ if(object.value[0]){
419
+ values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
420
+ }
421
+ break;
422
+ case baEnum.PropertyIdentifier.RECORD_COUNT:
423
+ if(object.value[0] ) {
424
+ values[objectId].recordCount = object.value[0].value;
425
+ }
426
+ break;
303
427
  }
304
428
  }
305
429
  });
@@ -307,11 +431,11 @@ class BacnetClient extends EventEmitter {
307
431
  bacnetResults[deviceName] = values;
308
432
 
309
433
  } catch(e) {
310
- console.log("issue resolving bacnet payload, see error: ", e);
434
+ that.logOut("issue resolving bacnet payload, see error: ", e);
311
435
  }
312
436
  });
313
437
  if(Object.keys(bacnetResults[deviceName]).length !== 0) {
314
- that.emit('values', device, bacnetResults, outputType, msgId, successfulResults);
438
+ that.emit('values', bacnetResults, outputType, objectPropertyType);
315
439
  }
316
440
 
317
441
  }).catch(function (error) {
@@ -319,12 +443,10 @@ class BacnetClient extends EventEmitter {
319
443
  });
320
444
 
321
445
  } catch(e){
322
- console.log("Issue reading from device, see error: ", e);
446
+ that.logOut("Issue reading from device, see error: ", e);
323
447
  }
324
448
  }
325
449
 
326
-
327
-
328
450
  _getDeviceName(address, deviceId) {
329
451
  let that = this;
330
452
  return new Promise((resolve, reject) => {
@@ -335,10 +457,10 @@ class BacnetClient extends EventEmitter {
335
457
  if(object.value[0]) {
336
458
  resolve(object.value[0].value);
337
459
  } else {
338
- console.log("Issue with deviceName payload, see object: ", object);
460
+ that.logOut("Issue with deviceName payload, see object: ", object);
339
461
  }
340
462
  } catch(e){
341
- console.log("Unable to get device name: ", e);
463
+ that.logOut("Unable to get device name: ", e);
342
464
  }
343
465
  });
344
466
  }
@@ -347,9 +469,10 @@ class BacnetClient extends EventEmitter {
347
469
  }
348
470
 
349
471
  getPropertiesForType(props, type) {
472
+ let that = this;
350
473
  let newProps = [];
351
474
  props.forEach(function(prop) {
352
- //console.log(prop);
475
+ //that.logOut(prop);
353
476
  switch(type){
354
477
  case 0: //analog-input
355
478
  newProps.push(prop);
@@ -370,13 +493,13 @@ class BacnetClient extends EventEmitter {
370
493
  newProps.push(prop);
371
494
  break;
372
495
  case 13:
373
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
496
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
374
497
  break;
375
498
  case 14:
376
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
499
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
377
500
  break;
378
501
  case 19:
379
- if(prop.id == baEnum.PropertyIds.PROP_PRESENT_VALUE || prop.id == baEnum.PropertyIds.PROP_OBJECT_NAME) newProps.push(prop);
502
+ if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
380
503
  break;
381
504
  }
382
505
  });
@@ -387,21 +510,122 @@ class BacnetClient extends EventEmitter {
387
510
  let that = this;
388
511
  return new Promise(async function(resolve, reject) {
389
512
  try {
513
+ device.setManualDiscoveryMode(false);
390
514
  let result = await that.scanDevice(device);
391
515
  device.setPointsList(result);
392
516
  resolve(result);
517
+ } catch(e) {
518
+ that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
519
+ reject(e);
520
+ }
521
+ });
522
+ }
523
+
524
+ getDevicePointListWithoutObjectList(device) {
525
+ let that = this;
526
+ return new Promise(function(resolve, reject) {
527
+ try {
528
+ device.setManualDiscoveryMode(true);
529
+ that.scanDeviceManually(device).then(function(result) {
530
+ device.setPointsList(result);
531
+ resolve(result);
532
+ }).catch(function(error) {
533
+ reject(error);
534
+ });
535
+
393
536
 
394
537
  } catch(e) {
395
- console.log("Error getting point list: ", e);
538
+ that.logOut("Error getting point list: ", e);
396
539
  reject(e);
397
540
  }
398
541
 
399
542
  });
400
543
  }
401
544
 
402
- _readObjectWithRequestArray(deviceAddress, requestArray) {
545
+ scanDeviceManually(device) {
403
546
  let that = this;
547
+ return new Promise(function(resolve, reject) {
548
+ let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
549
+ let address = device.getAddress();
550
+ let objectTypeList = [0, 1, 2, 3];
551
+ let instanceRange = {start: 0, end: 100};
552
+ let requestArray = [];
553
+ let maxRequestThreshold = 1000;
554
+ let requestRate = 20;
555
+ let requestBuffer = [];
556
+ let sendBuffer = [];
557
+
558
+ if(that.manual_instance_range_enabled == true) {
559
+ instanceRange.start = that.manual_instance_range_start;
560
+ maxRequestThreshold = that.manual_instance_range_end;
561
+ if(that.manual_instance_range_end < requestRate) {
562
+ requestRate = that.manual_instance_range_end;
563
+ }
564
+ }
565
+
566
+ for(let typeListIndex = 0; typeListIndex < objectTypeList.length; typeListIndex++){
567
+ let objectType = objectTypeList[typeListIndex];
568
+ for(let i = instanceRange.start; i <= instanceRange.end; i++) {
569
+
570
+ requestArray.push({
571
+ objectId: { type: objectType, instance: i },
572
+ properties: objectNameProperty
573
+ })
574
+
575
+ if(requestArray.length == requestRate ) {
576
+ requestBuffer.push(that._readObjectWithRequestArray(address, requestArray));
577
+ instanceRange.end += requestRate;
578
+ requestArray = [];
579
+ if(i >= maxRequestThreshold) {
580
+ instanceRange.end = maxRequestThreshold;
581
+ if(typeListIndex == objectTypeList.length-1) {
582
+ send();
583
+ }
584
+
585
+ break;
586
+ }
587
+ }
588
+ }
404
589
 
590
+ instanceRange.end = 100;
591
+ };
592
+
593
+ function send() {
594
+
595
+ for(let index = 0; index < requestBuffer.length; index++) {
596
+ let promise = requestBuffer[index];
597
+ try {
598
+ Promise.resolve(promise).then(function(result) {
599
+ let keys = Object.keys(result);
600
+ for (const [key, value] of Object.entries(result)) {
601
+ if(key == "value" && typeof value == "object") {
602
+ for(let x = 0; x < value.values.length; x++) {
603
+ let ele = value.values[x];
604
+ let valueRoot = ele.values[0].value[0];
605
+ if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
606
+ sendBuffer.push({"value": ele.objectId, "type": 12});
607
+ }
608
+ }
609
+ }
610
+ }
611
+
612
+ if(index == requestBuffer.length - 1) {
613
+ resolve(sendBuffer);
614
+ }
615
+
616
+ }).catch(function(error) {
617
+ reject(error);
618
+ });
619
+ } catch(e) {
620
+ reject(e)
621
+ }
622
+ }
623
+ }
624
+ });
625
+ }
626
+
627
+ _readObjectWithRequestArray(deviceAddress, requestArray) {
628
+ let that = this;
405
629
  return new Promise((resolve, reject) => {
406
630
  this.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, (error, value) => {
407
631
  resolve({
@@ -431,9 +655,9 @@ class BacnetClient extends EventEmitter {
431
655
  _readDeviceName(deviceAddress, deviceId, callback){
432
656
  let that = this;
433
657
  const requestArray = [{
434
- objectId: { type: baEnum.ObjectTypes.OBJECT_DEVICE, instance: deviceId },
658
+ objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
435
659
  properties: [
436
- { id: baEnum.PropertyIds.PROP_OBJECT_NAME }
660
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME }
437
661
  ]
438
662
  }];
439
663
 
@@ -443,53 +667,45 @@ class BacnetClient extends EventEmitter {
443
667
  _readObjectList(deviceAddress, deviceId, callback) {
444
668
  let that = this;
445
669
  const requestArray = [{
446
- objectId: { type: baEnum.ObjectTypes.OBJECT_DEVICE, instance: deviceId },
447
- properties: [{ id: baEnum.PropertyIds.PROP_OBJECT_LIST }
670
+ objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
671
+ properties: [{ id: baEnum.PropertyIdentifier.OBJECT_LIST }
448
672
  ]
449
673
  }];
450
674
 
451
675
  try {
452
676
  that.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
453
677
  } catch(e) {
454
- console.log("Error reading object list: ", e);
678
+ that.logOut("Error reading object list: ", e);
455
679
  }
456
680
  }
457
681
 
458
682
  _readObjectFull(deviceAddress, type, instance) {
459
683
 
460
684
  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 }
685
+ { id: baEnum.PropertyIdentifier.ALL }
471
686
  ]);
687
+
472
688
  };
473
689
 
474
690
  _readObjectPropList(deviceAddress, type, instance) {
475
691
 
476
692
  return this._readObject(deviceAddress, type, instance, [
477
- { id: baEnum.PropertyIds.PROP_PROPERTY_LIST }
693
+ { id: baEnum.PropertyIdentifier.PROPERTY_LIST }
478
694
  ]);
479
695
  };
480
696
 
481
697
  _readObjectId(deviceAddress, type, instance) {
482
698
 
483
699
  return this._readObject(deviceAddress, type, instance, [
484
- { id: baEnum.PropertyIds.PROP_OBJECT_IDENTIFIER }
700
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }
485
701
  ]);
486
702
  }
487
703
 
488
704
  _readObjectPresentValue(deviceAddress, type, instance) {
489
705
 
490
706
  return this._readObject(deviceAddress, type, instance, [
491
- { id: baEnum.PropertyIds.PROP_PRESENT_VALUE },
492
- { id: baEnum.PropertyIds.PROP_OBJECT_NAME}
707
+ { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
708
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME}
493
709
  ]);
494
710
  }
495
711
 
@@ -500,7 +716,7 @@ class BacnetClient extends EventEmitter {
500
716
  options.pointsToWrite.forEach(function(point){
501
717
 
502
718
  let deviceAddress = point.deviceAddress;
503
-
719
+
504
720
  if(valuesArray[deviceAddress] == null || valuesArray[deviceAddress] == undefined){
505
721
  valuesArray[deviceAddress] = [];
506
722
  }
@@ -546,11 +762,11 @@ class BacnetClient extends EventEmitter {
546
762
  Promise.all(writePromises).then(function(result) {
547
763
  resolve(result);
548
764
  }).catch(function(e) {
549
- console.log("Error writing: ", e);
765
+ that.logOut("Error writing: ", e);
550
766
  });
551
767
  });
552
768
  } catch (error) {
553
- console.log(error);
769
+ that.logOut(error);
554
770
  }
555
771
  }
556
772
 
@@ -573,11 +789,11 @@ class BacnetClient extends EventEmitter {
573
789
  const objectInfo = object.values[0].objectId;
574
790
  const deviceObjectId = new DeviceObjectId(objectInfo.type, objectInfo.instance);
575
791
  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);
792
+ const name = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_NAME);
793
+ const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.PropertyIdentifier.DESCRIPTION);
794
+ const type = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_TYPE);
795
+ const PROP_UNITS = this._findValueById(objectProperties, baEnum.PropertyIdentifier.UNITS);
796
+ const presentValue = this._findValueById(objectProperties, baEnum.PropertyIdentifier.PRESENT_VALUE);
581
797
 
582
798
  return new DeviceObject(deviceObjectId, name, PROP_DESCRIPTION, type, PROP_UNITS, presentValue);
583
799
  }
@@ -612,16 +828,17 @@ class BacnetClient extends EventEmitter {
612
828
  }
613
829
 
614
830
  scanDevice(device) {
831
+ let that = this;
615
832
  return new Promise((resolve, reject) => {
616
- this._readObjectList(device.address, device.deviceId, (err, result) => {
833
+ this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
617
834
  if (!err) {
618
835
  try {
619
836
  resolve(result.values[0].values[0].value);
620
837
  } catch(e) {
621
- console.log("Issue with getting device point list, see error: ", e);
838
+ that.logOut("Issue with getting device point list, see error: ", e);
622
839
  }
623
840
  } else {
624
- logger.log('error', `Error while fetching objects: ${err}`);
841
+ that.logOut(`Error while fetching objects: ${err}`);
625
842
  reject(err);
626
843
  }
627
844
  });
@@ -632,7 +849,7 @@ class BacnetClient extends EventEmitter {
632
849
  shutDownClient() {
633
850
  let that = this;
634
851
  if(that.client) that.client.close((err, result) => {
635
- console.log(err, result);
852
+ that.logOut(err, result);
636
853
  });
637
854
  };
638
855
 
@@ -640,7 +857,8 @@ class BacnetClient extends EventEmitter {
640
857
  let that = this;
641
858
  let options = {
642
859
  lowLimit: 0,
643
- highLimit: baAsn1.BACNET_MAX_INSTANCE
860
+ highLimit: bacnetIdMax,
861
+ 'net': 65535
644
862
  };
645
863
 
646
864
  if(that.device_id_range_enabled == true) {
@@ -649,7 +867,7 @@ class BacnetClient extends EventEmitter {
649
867
  }
650
868
 
651
869
  if(that.client) {
652
- that.client.whoIs(options);
870
+ that.client.whoIs({'net': 65535});
653
871
  } else {
654
872
  that.reinitializeClient(that.config);
655
873
  }
@@ -681,56 +899,95 @@ class BacnetClient extends EventEmitter {
681
899
  }
682
900
 
683
901
  buildNetworkTreeData() {
684
- let that = this;
902
+ let that = this;
903
+ that.buildTreeMutex = new Mutex();
904
+ let displayNameCharThreshold = 40;
685
905
  return new Promise(async function(resolve, reject) {
686
906
  if(!that.renderList) that.renderList = [];
687
907
  if(that.deviceList && that.networkTree) {
688
908
  that.deviceList.forEach(function(deviceInfo, index) {
689
- let ipAddr = deviceInfo.getAddress();
690
- let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
691
- let deviceObject = that.networkTree[ipAddr];
692
-
693
- if(deviceObject) {
694
- let children = [];
695
- let pointIndex = 0;
909
+ that.buildTreeMutex
910
+ .acquire()
911
+ .then(function(release) {
912
+
913
+ let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
914
+ let deviceId = deviceInfo.getDeviceId();
915
+ let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
916
+ let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
917
+ let deviceObject = that.networkTree[deviceKey];
918
+ let isMstpDevice = deviceInfo.getIsMstpDevice();
919
+ let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
920
+
921
+ if(deviceObject) {
922
+ let children = [];
923
+ let pointIndex = 0;
924
+
925
+ for(const pointName in deviceObject) {
926
+ let pointProperties = [];
927
+ let values = deviceObject[pointName];
928
+ let displayName = pointName;
929
+ if(pointName.length > displayNameCharThreshold) {
930
+ displayName = "";
931
+ let charArray = pointName.split("");
932
+ for(let i = 0; i < charArray.length; i++) {
933
+ if(i < displayNameCharThreshold){
934
+ displayName += charArray[i];
935
+ }
936
+ }
937
+ displayName += "...";
938
+ }
696
939
 
697
- for(const pointName in deviceObject) {
698
- let pointProperties = [];
699
- let values = deviceObject[pointName];
940
+ if(values.objectName){
941
+ pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
942
+ }
943
+ if(values.objectType){
944
+ pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
945
+ }
946
+ if(values.objectID && values.objectID.instance) {
947
+ pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
948
+ }
949
+ if(values.description){
950
+ pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
951
+ }
952
+ if(values.units){
953
+ pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
954
+ }
955
+ if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
956
+ pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
957
+ }
958
+ if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
959
+ pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
960
+ }
961
+ if(values.modificationDate && !values.modificationDate.errorClass) {
962
+ pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
963
+ }
964
+ if(values.programState){
965
+ pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
966
+ }
967
+ if(values.recordCount && !values.recordCount.errorClass){
968
+ pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
969
+ }
700
970
 
701
- if(values.objectName){
702
- pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
703
- }
704
- if(values.objectType){
705
- pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
706
- }
707
- if(values.objectID && values.objectID.instance) {
708
- pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
971
+ 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})
972
+ pointIndex++;
709
973
  }
710
- if(values.description){
711
- pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
974
+ let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
975
+ if(foundIndex !== -1) {
976
+ that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
977
+ } else if(foundIndex == -1) {
978
+ 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});
712
979
  }
713
- if(values.units){
714
- pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
980
+ if(index == that.deviceList.length - 1) {
981
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
715
982
  }
716
- if(values.presentValue !== "undefined" && values.presentValue !== null) {
717
- pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
983
+ } else {
984
+ if(index == that.deviceList.length - 1) {
985
+ resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
718
986
  }
719
- children.push({"key": `${index}-${pointIndex}`, "label": pointName, "data": pointName, "icon": "", "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
720
- pointIndex++;
721
- }
722
- let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.ipAddr == ipAddr);
723
- 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};
725
- } 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});
727
987
  }
728
- if(index == that.deviceList.length - 1) {
729
- resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
730
- }
731
- } else {
732
- if(index == that.deviceList.length - 1) resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
733
- }
988
+
989
+ release();
990
+ });
734
991
  });
735
992
  }
736
993
  });
@@ -740,125 +997,171 @@ class BacnetClient extends EventEmitter {
740
997
  let that = this;
741
998
  let address = device.address;
742
999
  let pointList = device.getPointsList();
1000
+ let requestMutex = new Mutex();
743
1001
 
744
- return new Promise(function(resolve, reject) {
1002
+ return new Promise(function(resolve, reject) {
745
1003
  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){
754
- console.log("Error while building json object: ", e);
755
- reject(e);
1004
+ if(typeof pointList !== "undefined" && pointList.length > 0) {
1005
+ pointList.forEach(function(point, pointListIndex) {
1006
+ requestMutex
1007
+ .acquire()
1008
+ .then(function(release) {
1009
+ that._readObjectFull(address, point.value.type, point.value.instance).then(function(result) {
1010
+
1011
+ if(!result.error) {
1012
+ promiseArray.push(result);
1013
+ }
1014
+
1015
+ release();
1016
+
1017
+ if(pointListIndex == pointList.length - 1) {
1018
+ that.buildResponse(promiseArray, device).then(function() {
1019
+ that.lastNetworkPoll = Date.now();
1020
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1021
+ }).catch(function(e){
1022
+ that.logOut("Error while building json object: ", e);
1023
+ reject(e);
1024
+ });
1025
+ }
1026
+
1027
+ }).catch(function(e) {
1028
+ release();
1029
+ that.logOut("_readObjectFull error: ", e);
1030
+
1031
+ if(pointListIndex == pointList.length - 1) {
1032
+ that.buildResponse(promiseArray, device).then(function() {
1033
+ that.lastNetworkPoll = Date.now();
1034
+ resolve({deviceList: that.deviceList, pointList: that.networkTree});
1035
+ }).catch(function(e){
1036
+ that.logOut("Error while building json object: ", e);
1037
+ reject(e);
1038
+ });
1039
+ }
1040
+
756
1041
  });
757
- }).catch(function(e) {
758
- console.log("Error while building json object: ", e);
759
- reject(e);
760
1042
  });
761
- }
762
- });
1043
+ });
1044
+ } else {
1045
+ reject("Unable to build network tree, empty point list");
1046
+ }
763
1047
  });
764
1048
  }
765
1049
 
766
1050
  // Builds response object for a fully qualified
767
1051
  buildResponse(fullObjects, device) {
768
1052
  let that = this;
769
- let deviceName = device.getDeviceName();
770
- let ipAddr = device.getAddress();
771
-
772
1053
  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
-
1054
+ let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
1055
+ let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
1056
+ for(let i = 0; i < fullObjects.length; i++) {
777
1057
  let obj = fullObjects[i];
778
1058
  let successfulResult = !obj.error ? obj.value : null;
779
-
780
1059
  if(successfulResult) {
781
1060
  successfulResult.values.forEach(function(pointProperty, pointPropertyIndex) {
782
-
783
1061
  let currobjectId = pointProperty.objectId.type
784
1062
  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
-
1063
+ let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
1064
+ let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
789
1065
  let objectId;
790
1066
  if(objectName !== null) {
791
- objectName = objectName.split(" ").join("_");
792
1067
  objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
793
1068
  } else {
794
1069
  objectId = bac_obj + '_' + pointProperty.objectId.instance;
795
1070
  }
796
-
797
- if(!values[objectId]) values[objectId] = {};
798
- values[objectId].meta = {
799
- objectId: pointProperty.objectId
800
- };
801
-
802
1071
  try {
803
1072
  pointProperty.values.forEach(function(object, objectIndex) {
804
1073
  //checks for error code json structure, returned for invalid bacnet requests
805
- if(!object.value.value) {
1074
+ //if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
1075
+ if(object && object.value && !object.value.errorClass) {
1076
+
1077
+
1078
+ if(!values[objectId]) values[objectId] = {};
1079
+ values[objectId].meta = {
1080
+ objectId: pointProperty.objectId
1081
+ };
1082
+
806
1083
  switch(object.id) {
807
- case baEnum.PropertyIds.PROP_PRESENT_VALUE:
1084
+ case baEnum.PropertyIdentifier.PRESENT_VALUE:
808
1085
  if(object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
809
1086
  //check for binary object type
810
- if(objectType == 3 || objectType == 4 || objectType == 5){
1087
+ if(objectType == 3 || objectType == 4 || objectType == 5) {
811
1088
  if(object.value[0].value == 0) {
812
1089
  values[objectId].presentValue = false;
813
1090
  } else if(object.value[0].value == 1) {
814
1091
  values[objectId].presentValue = true;
815
1092
  }
1093
+ } else if(objectType == 40) {
1094
+ //character string
1095
+ values[objectId].presentValue = object.value[0].value;
816
1096
  } else {
817
1097
  values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
818
1098
  }
819
1099
  }
820
1100
  values[objectId].meta.arrayIndex = object.index;
821
1101
  break;
822
- case baEnum.PropertyIds.PROP_DESCRIPTION:
1102
+ case baEnum.PropertyIdentifier.DESCRIPTION:
823
1103
  if(object.value[0]) values[objectId].description = object.value[0].value;
824
1104
  break;
825
- case baEnum.PropertyIds.PROP_UNITS:
1105
+ case baEnum.PropertyIdentifier.UNITS:
826
1106
  if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
827
1107
  break;
828
- case baEnum.PropertyIds.PROP_OBJECT_NAME:
1108
+ case baEnum.PropertyIdentifier.OBJECT_NAME:
829
1109
  if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
830
1110
  break;
831
- case baEnum.PropertyIds.PROP_OBJECT_TYPE:
1111
+ case baEnum.PropertyIdentifier.OBJECT_TYPE:
832
1112
  if(object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
833
1113
  break;
834
- case baEnum.PropertyIds.PROP_OBJECT_IDENTIFIER:
1114
+ case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
835
1115
  if(object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
836
1116
  break;
837
- case baEnum.PropertyIds.PROP_PROPERTY_LIST:
1117
+ case baEnum.PropertyIdentifier.PROPERTY_LIST:
838
1118
  if(object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
839
- break;
1119
+ break;
1120
+
1121
+ case baEnum.PropertyIdentifier.SYSTEM_STATUS:
1122
+ if(object.value[0]){
1123
+ values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
1124
+ }
1125
+ break;
1126
+
1127
+ case baEnum.PropertyIdentifier.MODIFICATION_DATE:
1128
+ if(object.value[0]) {
1129
+ values[objectId].modificationDate = object.value[0].value;
1130
+ }
1131
+ break;
1132
+
1133
+ case baEnum.PropertyIdentifier.PROGRAM_STATE:
1134
+ if(object.value[0]){
1135
+ values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
1136
+ }
1137
+ break;
1138
+
1139
+ case baEnum.PropertyIdentifier.RECORD_COUNT:
1140
+ if(object.value[0] ) {
1141
+ values[objectId].recordCount = object.value[0].value;
1142
+ }
1143
+ break;
840
1144
  }
841
1145
  }
842
-
843
1146
  if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
844
- that.networkTree[device.getAddress()] = values;
1147
+ that.networkTree[deviceKey] = values;
845
1148
  resolve(that.networkTree);
846
1149
  }
847
1150
  });
848
1151
  } catch(e) {
849
- console.log("issue resolving bacnet payload, see error: ", e);
1152
+ that.logOut("issue resolving bacnet payload, see error: ", e);
850
1153
  reject(e);
851
1154
  }
852
1155
  });
853
1156
  } else {
854
1157
  //error found in point property
855
1158
  if(i == fullObjects.length - 1) {
856
- that.networkTree[device.getAddress()] = values;
1159
+ that.networkTree[deviceKey] = values;
857
1160
  resolve(that.networkTree);
858
1161
  }
859
1162
  }
860
1163
  }
861
- reject("Unexpectedly found end of loop, line 861");
1164
+ reject("Unexpectedly found end of loop, line 1170");
862
1165
  });
863
1166
  }
864
1167
 
@@ -870,6 +1173,104 @@ class BacnetClient extends EventEmitter {
870
1173
  return uniquePropArray;
871
1174
  }
872
1175
 
1176
+ getPROP_PROGRAM_STATE(value) {
1177
+ switch(value) {
1178
+ case 0:
1179
+ return "0 - Idle";
1180
+ case 1:
1181
+ return "1 - Loading";
1182
+ case 2:
1183
+ return "2 - Running";
1184
+ case 3:
1185
+ return "3 - Waiting";
1186
+ case 4:
1187
+ return "4 - Halted";
1188
+ case 5:
1189
+ return "5 - Unloading";
1190
+ default:
1191
+ return "";
1192
+ }
1193
+ }
1194
+
1195
+ getPROP_SYSTEM_STATUS(value) {
1196
+ switch(value) {
1197
+ case 0:
1198
+ return "0 - Operational";
1199
+ case 1:
1200
+ return "1 - Operational Readonly";
1201
+ case 2:
1202
+ return "2 - Download Required";
1203
+ case 3:
1204
+ return "3 - Download In Progress";
1205
+ case 4:
1206
+ return "4 - Non Operational";
1207
+ case 5:
1208
+ return "5 - Backup In Progress";
1209
+ default:
1210
+ return "";
1211
+ }
1212
+ }
1213
+
1214
+ getPointIcon(objectId) {
1215
+ switch(objectId) {
1216
+ case 0:
1217
+ //AI
1218
+ return "pi pi-tags";
1219
+ case 1:
1220
+ //AO
1221
+ return "pi pi-tags";
1222
+ case 2:
1223
+ //AV
1224
+ return "pi pi-tags";
1225
+ case 3:
1226
+ //BI
1227
+ return "pi pi-tags";
1228
+ case 4:
1229
+ //BO
1230
+ return "pi pi-tags";
1231
+ case 5:
1232
+ //BV
1233
+ return "pi pi-tags";
1234
+ case 8:
1235
+ //Device
1236
+ return "pi pi-box";
1237
+ case 13:
1238
+ //MI
1239
+ return "pi pi-tags";
1240
+ case 14:
1241
+ //MO
1242
+ return "pi pi-tags";
1243
+ case 19:
1244
+ //MV
1245
+ return "pi pi-tags";
1246
+ case 10:
1247
+ //File
1248
+ return "pi pi-file";
1249
+ case 16:
1250
+ //Program
1251
+ return "pi pi-database";
1252
+ case 20:
1253
+ //Trendlog
1254
+ return "pi pi-chart-line";
1255
+ case 15:
1256
+ //Notification Class
1257
+ return "pi pi-bell";
1258
+ case 56:
1259
+ return "pi pi-sitemap";
1260
+ case 178:
1261
+ return "pi pi-lock";
1262
+ case 20:
1263
+ return "pi pi-chart-line";
1264
+ case 17:
1265
+ return "pi pi-calendar";
1266
+ case 6:
1267
+ return "pi pi-calendar";
1268
+ default:
1269
+ //Return circle for all other types
1270
+ return "pi pi-tags";
1271
+ }
1272
+ }
1273
+
873
1274
  getObjectType(objectId) {
874
1275
  switch(objectId) {
875
1276
  case 0:
@@ -892,6 +1293,8 @@ class BacnetClient extends EventEmitter {
892
1293
  return "MO";
893
1294
  case 19:
894
1295
  return "MV";
1296
+ case 40:
1297
+ return "CS";
895
1298
  default:
896
1299
  return "";
897
1300
  }
@@ -935,6 +1338,20 @@ class BacnetClient extends EventEmitter {
935
1338
  getStatusFlags(flags) {
936
1339
  return flags.value[0].value;
937
1340
  }
1341
+
1342
+ getDeviceIcon(isMstp, manualDiscoveryMode) {
1343
+ if(manualDiscoveryMode == true) {
1344
+ return "pi pi-exclamation-triangle"
1345
+ } else if(manualDiscoveryMode == false) {
1346
+ if(isMstp == true) {
1347
+ return "pi pi-share-alt"
1348
+ } else if(isMstp == false) {
1349
+ return "pi pi-server"
1350
+ }
1351
+ }
1352
+
1353
+ return "pi pi-server";
1354
+ };
938
1355
  }
939
1356
 
940
1357
  module.exports = { BacnetClient };