@bitpoolos/edge-bacnet 1.5.3 → 1.6.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.
package/CHANGELOG.md CHANGED
@@ -1,27 +1,160 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.0] - 09-04-2025
4
+
5
+ New features:
6
+
7
+ - New node - Inspector version 1:
8
+
9
+ - Link the outputs of all of your Read nodes and Gateway node into the inspector node for a more detailed analysis of that current state of your site.
10
+ - There is a custom UI which can be viewed once the node is placed and deployed, via the open webpage link in the node properties view.
11
+ - Basic point status statistics can be output in MQTT format via an injection of msg.type = "sendMqttStats" directly into the inspector node. This can be done with a node-red inject node or a bitpool-inject node.
12
+ - The custom UI shows a data table with rich meta data, that can be filtered.
13
+ - The inspector node comes with a variety of API routes that can be used for analysis and engineering
14
+ - API routes available:
15
+
16
+ - /inspector
17
+ - view UI in web browser
18
+
19
+ - /inspector-downloadhtml
20
+ - downloads the html of the inspector in its current state
21
+
22
+ - /inspector-downloadhtml?filter=tableKey&value=value1,value2
23
+ - downloads the html of the inspector, but with a applied filter to the table.
24
+ - tableKey in the above example can be any of the table columns, only 1 tableKey may be filtered on:
25
+ deviceID, objectType, objectInstance, presentValue, dataModelStatus, pointName, discoveredBACnetPointName, displayName, deviceName, ipAddress, area, key, topic, lastSeen, error
26
+ - value=value1,value2 etc can be any value that the tableKey can contain. This parameter can accept many comma separated values
27
+ - an example filter request may look like:
28
+ /inspector-downloadhtml?filter=dataModelStatus&value=error,missing
29
+
30
+ - /getModelStats
31
+ - returns JSON data with analysis of the BACnet model
32
+ - contains point status, metrics, and detailed information
33
+
34
+ - /pointstoread
35
+ - downloads CSV file with all points in the read list
36
+ - format: [siteName]_PointsToRead_[timestamp].csv
37
+
38
+ - /getpointerrors
39
+ - downloads CSV file with all points that have errors
40
+ - format: [siteName]_PointErrors_[timestamp].csv
41
+
42
+ - /getmodelstatscsv
43
+ - downloads CSV file with all model stats data in CSV format
44
+ - format: [siteName]_ModelStats_[timestamp].csv
45
+
46
+ - /publishedpointslist
47
+ - downloads CSV file with all published points and their current values
48
+ - format: [siteName]_PublishedPointsList_[timestamp].csv
49
+ - outputs mqtt topic and payloads with statistics about the current state of the bacnet network
50
+ - output topics:
51
+ EDGE_DEVICE_{IP_ID}/STATUS/LAST_POINT_PUSHED_TIME
52
+ payload: Timestamp of when the last point was pushed (ISO string)
53
+ EDGE_DEVICE_{IP_ID}/STATUS/LAST_STAT_CALC_TIME
54
+ payload: Current timestamp (ISO string)
55
+ EDGE_DEVICE_{IP_ID}/STATUS/UPTIME
56
+ payload: System uptime formatted as string (e.g., "Uptime: 3 days, 5 hours, 12 minutes, 45 seconds")
57
+ EDGE_DEVICE_{IP_ID}/STATUS/ONLINE_POINTS
58
+ payload: Number of online points
59
+ EDGE_DEVICE_{IP_ID}/STATUS/OFFLINE_POINTS
60
+ payload: Number of offline points
61
+ EDGE_DEVICE_{IP_ID}/STATUS/TOTAL_POLLED_POINTS
62
+ payload: Total number of polled points
63
+ EDGE_DEVICE_{IP_ID}/STATUS/AVERAGE_TIME_SINCE_COV_IN_SECONDS
64
+ payload: Average time since last change of value in seconds
65
+ EDGE_DEVICE_{IP_ID}/STATUS/TOTAL_POINTS_TO_READ
66
+ payload: Total number of points to read
67
+ EDGE_DEVICE_{IP_ID}/STATUS/DISCOVERED_POINT_COUNT
68
+ payload: Number of discovered points
69
+ EDGE_DEVICE_{IP_ID}/STATUS/DISCOVERED_DEVICE_COUNT
70
+ payload: Number of discovered devices
71
+
72
+ where {IP_ID} is the IP address of the device with periods removed (e.g., 192.168.1.100 becomes 192168110).
73
+ each of these topics includes the site name as a tag in the message metadata with format geoAddr={siteName}.
74
+
75
+ - Additional input options:
76
+ - reset - resets the complete data model used for all of the inspector analytics
77
+ - msg input format: msg.reset = true
78
+
79
+ - sendMqttStats - outputs additional mqtt statistics
80
+ - msg input format: msg.type = sendMqttStats
81
+ - output topics:
82
+ EDGE_DEVICE_{siteName}/BACNETSTATS/ok
83
+ payload: Number of points with OK status
84
+ EDGE_DEVICE_{siteName}/BACNETSTATS/error
85
+ payload: Number of points with error status
86
+ EDGE_DEVICE_{siteName}/BACNETSTATS/missing
87
+ payload: Number of missing points
88
+ EDGE_DEVICE_{siteName}/BACNETSTATS/warnings
89
+ payload: Number of points with warnings
90
+ EDGE_DEVICE_{siteName}/BACNETSTATS/moved
91
+ payload: Number of points that have moved (e.g changed object instance)
92
+ EDGE_DEVICE_{siteName}/BACNETSTATS/deviceIdChange
93
+ payload: Number of points with changed device IDs
94
+ EDGE_DEVICE_{siteName}/BACNETSTATS/deviceIdConflict
95
+ payload: Number of points with conflicting device IDs
96
+ EDGE_DEVICE_{siteName}/BACNETSTATS/unmapped
97
+ payload: Number of unmapped points
98
+ EDGE_DEVICE_{siteName}/BACNETSTATS/offlinePercentage
99
+ payload: Percentage of points that are offline
100
+
101
+ where {siteName} is the site name configured in the inspector node.
102
+
103
+
104
+ - Right click -> Update Point on a individual point in the device tree. (Read node UI)
105
+
106
+ - Added programmatic reinitialize/clear points on BACnet server via injecting { msg.reinitializeBacnetServer: true } into the gateway node. Optionally can include a msg.responseTopic string to get a confrimation published to that topic output from the gateway node on sucessfull reinitialize.
107
+ - Example workflow:
108
+ -inject into gateway node:
109
+ ```javascript
110
+ msg = {
111
+ reinitializeBacnetServer: true,
112
+ responseTopic: "/mqtt/subscriber/topic",
113
+ };
114
+ ```
115
+ -upon sucessfull reinitialize, gateway outputs:
116
+ ```javascript
117
+ {
118
+ topic: "/mqtt/subscriber/topic";
119
+ payload: "Server successfully reinitialized";
120
+ }
121
+ ```
122
+
123
+ Refactor:
124
+
125
+ - Reading and Writing to the cache file of the datamodel.
126
+ - write operations are now locked to 1 operation at a time
127
+ - a rolling secondary backup file is now created, which can be used in case of corruption of the primary file
128
+
129
+ - Ported more of the project to async / await program flow vs Promise.then
130
+
131
+ Bug fixes:
132
+
133
+ - timeouts removed from import and export database file, as they can be very large.
134
+
3
135
  ## [1.5.3] - 23-01-2025
4
136
 
5
- New feature:
6
- - import / export buttons added to new tab in gateway node, used to manage the complete data model for backup or restore
7
- - associated API end points for programatic backing up or restoring - /bitpool-bacnet-data/getDataModel; /bitpool-bacnet-data/updateDataModel;
137
+ New feature:
138
+
139
+ - import / export buttons added to new tab in gateway node, used to manage the complete data model for backup or restore
140
+ - associated API end points for programatic backing up or restoring - /bitpool-bacnet-data/getDataModel; /bitpool-bacnet-data/updateDataModel;
8
141
 
9
142
  Further async / await refactoring
10
143
 
11
144
  Bug fixes:
12
- - incorrect device name in read list export
13
- - read command indexing unhandled scenario
14
- - duplicating points in read list after pressing refresh tree button
15
- - Multi State Values and other state text based points not being handled correctly in large volume scenarios
16
145
 
17
- NOTE:
18
- New importing and exporting feature handles a .json file instead of the .cfg file used in the back end. This is due to browsers flagging .cfg files as malicious. The contents of the file are unchanged.
146
+ - incorrect device name in read list export
147
+ - read command indexing unhandled scenario
148
+ - duplicating points in read list after pressing refresh tree button
149
+ - Multi State Values and other state text based points not being handled correctly in large volume scenarios
150
+
151
+ NOTE:
152
+ New importing and exporting feature handles a .json file instead of the .cfg file used in the back end. This is due to browsers flagging .cfg files as malicious. The contents of the file are unchanged.
19
153
 
20
154
  ## [1.5.2] - 10-01-2025
21
155
 
22
156
  Mismatched network request hot fix
23
157
 
24
-
25
158
  ## [1.5.1] - 13-11-2024
26
159
 
27
160
  ### Summary
package/bacnet_client.js CHANGED
@@ -4,13 +4,13 @@
4
4
 
5
5
  const bacnet = require("./resources/node-bacstack-ts/dist/index.js");
6
6
  const baEnum = bacnet.enum;
7
- const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
8
7
  const { EventEmitter } = require("events");
9
8
  const {
10
9
  getUnit,
11
10
  roundDecimalPlaces,
12
11
  parseBacnetError,
13
12
  getBacnetErrorString,
13
+ Read_Config_Async,
14
14
  Read_Config_Sync,
15
15
  isNumber,
16
16
  decodeBitArray,
@@ -41,20 +41,6 @@ class BacnetClient extends EventEmitter {
41
41
  that.portRangeMatrix = config.portRangeMatrix;
42
42
 
43
43
  try {
44
- if (that.config.cacheFileEnabled) {
45
- let cachedData = JSON.parse(Read_Config_Sync());
46
- if (cachedData && typeof cachedData == "object") {
47
- if (cachedData.renderList) that.renderList = cachedData.renderList;
48
- if (cachedData.deviceList) {
49
- cachedData.deviceList.forEach(function (device) {
50
- let newBacnetDevice = new BacnetDevice(true, device);
51
- that.deviceList.push(newBacnetDevice);
52
- });
53
- }
54
- if (cachedData.pointList) that.networkTree = cachedData.pointList;
55
- if (cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
56
- }
57
- }
58
44
 
59
45
  that.roundDecimal = config.roundDecimal;
60
46
  that.apduSize = config.apduSize;
@@ -73,6 +59,8 @@ class BacnetClient extends EventEmitter {
73
59
  };
74
60
 
75
61
  try {
62
+ that.readCachedFile();
63
+
76
64
  that.client = new bacnet.Client({
77
65
  apduTimeout: config.apduTimeout,
78
66
  interface: config.localIpAdrress,
@@ -115,22 +103,48 @@ class BacnetClient extends EventEmitter {
115
103
 
116
104
  that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
117
105
 
118
- that.globalWhoIs();
119
-
120
106
  setTimeout(() => {
121
- that.queryDevices();
122
- that.buildJsonTree();
107
+ that.globalWhoIs();
108
+ setTimeout(() => {
109
+ that.queryDevices();
110
+ that.buildJsonTree();
111
+ }, "4000");
123
112
  }, "5000");
113
+
124
114
  } catch (e) {
125
115
  that.logOut("Issue initializing client: ", e);
126
116
  }
127
117
 
128
- //who is callback
129
- that.client.on("iAm", (device) => {
130
- if (device.address !== that.config.localIpAdrress) {
131
- if (that.scanMatrix.length > 0) {
132
- let matrixMap = that.scanMatrix.filter((ele) => device.deviceId >= ele.start && device.deviceId <= ele.end);
133
- if (matrixMap.length > 0) {
118
+ try {
119
+
120
+ //who is callback
121
+ that.client.on("iAm", (device) => {
122
+ if (device.address !== that.config.localIpAdrress) {
123
+ if (that.scanMatrix.length > 0) {
124
+ let matrixMap = that.scanMatrix.filter((ele) => device.deviceId >= ele.start && device.deviceId <= ele.end);
125
+ if (matrixMap.length > 0) {
126
+ //only add unique device to array
127
+ let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
128
+ if (foundIndex == -1) {
129
+ let newBacnetDevice = new BacnetDevice(false, device);
130
+ newBacnetDevice.setLastSeen(Date.now());
131
+ if (newBacnetDevice.getIsMstpDevice()) {
132
+ that.addToParentMstpNetwork(newBacnetDevice);
133
+ }
134
+ that.deviceList.push(newBacnetDevice);
135
+ that.addToNetworkTree(newBacnetDevice);
136
+ } else if (foundIndex !== -1) {
137
+ that.deviceList[foundIndex].updateDeviceConfig(device);
138
+ that.deviceList[foundIndex].setLastSeen(Date.now());
139
+ if (that.deviceList[foundIndex].getIsMstpDevice()) {
140
+ that.addToParentMstpNetwork(that.deviceList[foundIndex]);
141
+ }
142
+ that.addToNetworkTree(that.deviceList[foundIndex]);
143
+ }
144
+ //emit event for node-red to log
145
+ that.emit("deviceFound", device);
146
+ }
147
+ } else {
134
148
  //only add unique device to array
135
149
  let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
136
150
  if (foundIndex == -1) {
@@ -149,49 +163,49 @@ class BacnetClient extends EventEmitter {
149
163
  }
150
164
  that.addToNetworkTree(that.deviceList[foundIndex]);
151
165
  }
166
+
152
167
  //emit event for node-red to log
153
168
  that.emit("deviceFound", device);
154
169
  }
155
- } else {
156
- //only add unique device to array
157
- let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
158
- if (foundIndex == -1) {
159
- let newBacnetDevice = new BacnetDevice(false, device);
160
- newBacnetDevice.setLastSeen(Date.now());
161
- if (newBacnetDevice.getIsMstpDevice()) {
162
- that.addToParentMstpNetwork(newBacnetDevice);
163
- }
164
- that.deviceList.push(newBacnetDevice);
165
- that.addToNetworkTree(newBacnetDevice);
166
- } else if (foundIndex !== -1) {
167
- that.deviceList[foundIndex].updateDeviceConfig(device);
168
- that.deviceList[foundIndex].setLastSeen(Date.now());
169
- if (that.deviceList[foundIndex].getIsMstpDevice()) {
170
- that.addToParentMstpNetwork(that.deviceList[foundIndex]);
171
- }
172
- that.addToNetworkTree(that.deviceList[foundIndex]);
173
- }
174
-
175
- //emit event for node-red to log
176
- that.emit("deviceFound", device);
177
170
  }
171
+ });
172
+ } catch (e) {
173
+ that.logOut("Issue with creating bacnet client, see error: ", e);
174
+ }
175
+
176
+ that.client.on("error", (err) => {
177
+ that.logOut("Error occurred: ", err);
178
+
179
+ if (err.errno == -4090) {
180
+ that.logOut("Invalid Client information or incorrect IP address provided");
181
+ } else if (err.errno == -49) {
182
+ that.logOut("Invalid IP address provided");
183
+ } else {
184
+ that.reinitializeClient(that.config);
178
185
  }
179
186
  });
180
187
  } catch (e) {
181
- that.logOut("Issue with creating bacnet client, see error: ", e);
188
+ console.log("BACnet Client client binder error: ", e);
182
189
  }
190
+ }
183
191
 
184
- that.client.on("error", (err) => {
185
- that.logOut("Error occurred: ", err);
186
-
187
- if (err.errno == -4090) {
188
- that.logOut("Invalid Client information or incorrect IP address provided");
189
- } else if (err.errno == -49) {
190
- that.logOut("Invalid IP address provided");
191
- } else {
192
- that.reinitializeClient(that.config);
192
+ async readCachedFile() {
193
+ let that = this;
194
+ if (that.config.cacheFileEnabled) {
195
+ const cachedData = await Read_Config_Async();
196
+ const parsedData = JSON.parse(cachedData);
197
+ if (parsedData && typeof parsedData == "object") {
198
+ if (parsedData.renderList) that.renderList = parsedData.renderList;
199
+ if (parsedData.deviceList) {
200
+ parsedData.deviceList.forEach(function (device) {
201
+ let newBacnetDevice = new BacnetDevice(true, device);
202
+ that.deviceList.push(newBacnetDevice);
203
+ });
204
+ }
205
+ if (parsedData.pointList) that.networkTree = parsedData.pointList;
206
+ if (parsedData.renderListCount) that.renderListCount = parsedData.renderListCount;
193
207
  }
194
- });
208
+ }
195
209
  }
196
210
 
197
211
  testFunction(address, port, type, instance, property) {
@@ -578,25 +592,6 @@ class BacnetClient extends EventEmitter {
578
592
  }
579
593
  }
580
594
 
581
- // updateDeviceName(device) {
582
- // let that = this;
583
- // return new Promise((resolve, reject) => {
584
- // that
585
- // ._getDeviceName(device)
586
- // .then(function (deviceObject) {
587
- // if (typeof deviceObject.name == "string") {
588
- // device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
589
- // device.setPointsList(deviceObject.devicePointEntry);
590
- // }
591
- // resolve();
592
- // })
593
- // .catch(function (e) {
594
- // that.logOut("updateDeviceName error: ", e);
595
- // resolve();
596
- // });
597
- // });
598
- // }
599
-
600
595
  async updateDeviceName(device) {
601
596
  try {
602
597
  const deviceObject = await this._getDeviceName(device);
@@ -931,32 +926,8 @@ class BacnetClient extends EventEmitter {
931
926
  }
932
927
  }
933
928
 
934
- // updateManyPoints(device, points) {
935
- // let that = this;
936
- // return new Promise((resolve, reject) => {
937
- // // let readOptions = {
938
- // // maxSegments: device.getMaxSe,
939
- // // maxApdu: that.readPropertyMultipleOptions.maxApdu,
940
- // // };
941
-
942
- // that
943
- // ._readObjectWithRequestArray(device, points, that.readPropertyMultipleOptions)
944
- // .then(function (results) {
945
- // resolve(results);
946
- // })
947
- // .catch(function (err) {
948
- // reject(err);
949
- // });
950
- // });
951
- // }
952
-
953
929
  async updateManyPoints(device, points) {
954
930
  try {
955
- // let readOptions = {
956
- // maxSegments: device.getMaxSe,
957
- // maxApdu: that.readPropertyMultipleOptions.maxApdu,
958
- // };
959
-
960
931
  const results = await this._readObjectWithRequestArray(device, points, this.readPropertyMultipleOptions);
961
932
  return results;
962
933
  } catch (error) {
@@ -980,18 +951,63 @@ class BacnetClient extends EventEmitter {
980
951
  return tryUpdate(retryCount);
981
952
  }
982
953
 
954
+ //used for manual point updates in the UI tree
955
+ async updateIndividualPoint(deviceKey, pointKey) {
956
+ let that = this;
957
+ try {
958
+ let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceKey.split("-")[1]);
959
+ const pointType = parseInt(pointKey.split(":")[0]);
960
+ const pointInstance = parseInt(pointKey.split(":")[1]);
961
+ const promiseArray = [];
962
+ const result = await that._readObjectFull(device, pointType, pointInstance);
963
+
964
+ if (!result.error) {
965
+ device.setLastSeen(Date.now());
966
+ if (result.length > 0 && Array.isArray(result)) {
967
+ promiseArray.push(...result);
968
+ } else {
969
+ promiseArray.push(result);
970
+ }
971
+ }
972
+
973
+ await that.buildNetworkModel(promiseArray, device);
974
+
975
+ return true;
976
+ } catch (e) {
977
+ throw e
978
+ }
979
+ }
980
+
981
+ //used in the doRead querying work flow
983
982
  updatePoint(device, point) {
984
983
  let that = this;
985
984
  let addressObject = {
986
985
  address: device.getAddress(),
987
986
  port: device.getPort(),
988
987
  };
988
+
989
+ let maxSegments = that.readPropertyMultipleOptions.maxSegments;
990
+ let maxApdu = that.readPropertyMultipleOptions.maxApdu;
991
+
992
+ if (device.getSegmentation() == 3) {
993
+ maxSegments = 0;
994
+ }
995
+
996
+ if (device.getMaxApdu() == 480) {
997
+ maxApdu = 3;
998
+ }
999
+
1000
+ let settings = {
1001
+ maxSegments: maxSegments,
1002
+ maxApdu: maxApdu,
1003
+ }
1004
+
989
1005
  return new Promise((resolve, reject) => {
990
1006
  that.client.readProperty(
991
1007
  addressObject,
992
1008
  { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
993
1009
  baEnum.PropertyIdentifier.PRESENT_VALUE,
994
- that.readPropertyMultipleOptions,
1010
+ settings,
995
1011
  (err, value) => {
996
1012
  if (err) {
997
1013
  reject(err);
@@ -1855,7 +1871,7 @@ class BacnetClient extends EventEmitter {
1855
1871
  requestMutex.release();
1856
1872
  }
1857
1873
 
1858
- await this.buildResponse(promiseArray, device);
1874
+ await this.buildNetworkModel(promiseArray, device);
1859
1875
  this.lastNetworkPoll = Date.now();
1860
1876
 
1861
1877
  return { deviceList: this.deviceList, pointList: this.networkTree };
@@ -1865,8 +1881,8 @@ class BacnetClient extends EventEmitter {
1865
1881
  }
1866
1882
  }
1867
1883
 
1868
- // Builds response object for a fully qualified
1869
- buildResponse(fullObjects, device) {
1884
+ // Builds the data rich bacnet network model
1885
+ buildNetworkModel(fullObjects, device) {
1870
1886
  let that = this;
1871
1887
  const reg = /[$#\/\\+,]/gi;
1872
1888
  return new Promise(function (resolve, reject) {
@@ -1934,7 +1950,7 @@ class BacnetClient extends EventEmitter {
1934
1950
  }
1935
1951
  values[objectId].meta.arrayIndex = object.index;
1936
1952
  } catch (e) {
1937
- that.logOut("buildResponse PRESENT_VALUE error: ", e);
1953
+ that.logOut("buildNetworkModel PRESENT_VALUE error: ", e);
1938
1954
  }
1939
1955
  break;
1940
1956
  case baEnum.PropertyIdentifier.DESCRIPTION:
@@ -2000,7 +2016,7 @@ class BacnetClient extends EventEmitter {
2000
2016
  }
2001
2017
  }
2002
2018
  } catch (e) {
2003
- that.logOut("buildResponse STATE_TEXT error: ", e);
2019
+ that.logOut("buildNetworkModel STATE_TEXT error: ", e);
2004
2020
  }
2005
2021
  break;
2006
2022
  case baEnum.PropertyIdentifier.VENDOR_NAME:
@@ -106,6 +106,16 @@
106
106
  body: JSON.stringify({ d: device }),
107
107
  }).then((res) => res.json());
108
108
  }
109
+ updatePoint(device, pointKey) {
110
+ return fetch(RED.settings.httpNodeRoot + "bitpool-bacnet-data/updatePoint", {
111
+ method: "POST",
112
+ headers: {
113
+ Accept: "application/json",
114
+ "Content-Type": "application/json",
115
+ },
116
+ body: JSON.stringify({ d: device, k: pointKey }),
117
+ }).then((res) => res.json());
118
+ }
109
119
  setDeviceDisplayName(device, displayName) {
110
120
  return fetch(RED.settings.httpNodeRoot + "bitpool-bacnet-data/setDeviceDisplayName", {
111
121
  method: "POST",
@@ -143,6 +153,7 @@
143
153
  defaults: {
144
154
  name: { value: "" },
145
155
  local_device_address: { value: "", required: true },
156
+ local_interface_name: { value: "", required: false },
146
157
  apduTimeout: { value: 6000 },
147
158
  roundDecimal: { value: 2 },
148
159
  local_device_port: { value: 47808, required: true },
@@ -241,6 +252,13 @@
241
252
  });
242
253
  }
243
254
 
255
+ //sets name of network adapter
256
+ document.getElementById("node-input-local_device_address").addEventListener("change", function () {
257
+ let selectedText = this.options[this.selectedIndex].innerText;
258
+ let nicName = selectedText.split(":")[0];
259
+ node.local_interface_name = nicName;
260
+ });
261
+
244
262
  queryAdapters();
245
263
 
246
264
  window.confirmDialogExists = window.confirmDialogExists || false;
@@ -338,7 +356,6 @@
338
356
  vueapp.use(primevue.confirmationservice);
339
357
  node.vm1 = vueapp.mount("#serverParent");
340
358
 
341
-
342
359
  // Import Device List
343
360
  $("#file-upload").on("change", function (event) {
344
361
  const input = event.target.files[0];
@@ -356,7 +373,7 @@
356
373
  contentType: "application/json",
357
374
  data: JSON.stringify(jsonPayload),
358
375
  success: function (result) { },
359
- timeout: 15000,
376
+ timeout: 0,
360
377
  });
361
378
  };
362
379
 
@@ -374,7 +391,7 @@
374
391
  aEle.setAttribute("download", "bitpool-bacnet-devices.json");
375
392
  aEle.click();
376
393
  },
377
- timeout: 10000,
394
+ timeout: 0,
378
395
  });
379
396
  });
380
397
 
@@ -395,7 +412,7 @@
395
412
  contentType: "application/json",
396
413
  data: JSON.stringify(jsonPayload),
397
414
  success: function (result) { },
398
- timeout: 15000,
415
+ timeout: 0,
399
416
  });
400
417
  };
401
418
 
@@ -413,7 +430,7 @@
413
430
  aEle.setAttribute("download", "edge-bacnet-datastore.json");
414
431
  aEle.click();
415
432
  },
416
- timeout: 10000,
433
+ timeout: 0,
417
434
  });
418
435
  });
419
436
 
@@ -796,7 +813,6 @@
796
813
  font-weight: bold;
797
814
  font-size: 16px;
798
815
  width: auto !important;
799
-
800
816
  }
801
817
  .database-file-label-div {
802
818
  padding-top: 15px;