@bitpoolos/edge-bacnet 1.2.8 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bacnet_server.js CHANGED
@@ -1,73 +1,85 @@
1
1
  const bacnet = require('./resources/node-bacstack-ts/dist/index.js');
2
2
  const pjson = require('./package.json');
3
3
  const baEnum = bacnet.enum;
4
- const {Store_Config_Server, Read_Config_Sync_Server } = require('./common');
5
-
4
+ const { Store_Config_Server, Read_Config_Sync_Server } = require('./common');
5
+
6
+ /**
7
+ * Class representing a BACnet Server.
8
+ *
9
+ * This class initializes a BACnet server with specified client, device ID, and Node-Red version.
10
+ * It provides methods to set device name, add objects, retrieve objects, clear server points, clear server point, and get server points.
11
+ *
12
+ * Simulates a BACnet IP device on a regular IP network
13
+ *
14
+ * @constructor
15
+ * @param {Object} client - The BACnet client object.
16
+ * @param {number} deviceId - The ID of the device.
17
+ * @param {string} nodeRedVersion - The version of Node-Red.
18
+ */
6
19
  class BacnetServer {
7
20
 
8
21
  constructor(client, deviceId, nodeRedVersion) {
9
- let that = this;
22
+ let that = this;
10
23
  that.bacnetClient = client;
11
-
24
+
12
25
  // object identifier init
13
26
  that.objectIdNumber = {};
14
27
  that.objectIdNumber[baEnum.ObjectType.ANALOG_VALUE] = 0;
15
28
  that.objectIdNumber[baEnum.ObjectType.CHARACTERSTRING_VALUE] = 0;
16
29
  that.objectIdNumber[baEnum.ObjectType.BINARY_VALUE] = 0;
17
-
18
30
  that.nodeRedVersion = nodeRedVersion;
19
31
  that.deviceId = deviceId;
20
32
  that.vendorId = 1401;
21
33
  that.objectList = [
22
- {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
34
+ { value: { type: baEnum.ObjectType.DEVICE, instance: that.deviceId }, type: 12 }
23
35
  ];
36
+
24
37
  that.objectStore = {
25
38
  [baEnum.ObjectType.DEVICE]: {
26
- [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}],
27
- [baEnum.PropertyIdentifier.OBJECT_LIST]: that.objectList,
28
- [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: 'Bitpool Edge BACnet Gateway', type: 7}],
29
- [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: 8, type: 9}],
30
- [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: 'Bitpool Edge BACnet gateway', type: 7}],
31
- [baEnum.PropertyIdentifier.SYSTEM_STATUS]: [{value: 0, type: 9}],
32
- [baEnum.PropertyIdentifier.VENDOR_NAME]: [{value: "Bitpool", type: 7}],
33
- [baEnum.PropertyIdentifier.VENDOR_IDENTIFIER]: [{value: that.vendorId, type: 2}],
34
- [baEnum.PropertyIdentifier.MODEL_NAME]: [{value: "bitpool-edge", type: 7}],
35
- [baEnum.PropertyIdentifier.FIRMWARE_REVISION]: [{value: "Node-Red " + that.nodeRedVersion, type: 7}],
36
- [baEnum.PropertyIdentifier.PROTOCOL_REVISION]: [{value: 19, type: 2}],
37
- [baEnum.PropertyIdentifier.PROTOCOL_VERSION]: [{value: 0, type: 2}],
38
- [baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION]: [{value: pjson.version, type: 7}],
39
- [baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED]: [{value: { value: [ 0, 80, 0, 4, 4 ], bitsUsed: 40 }, type: 8}],
40
- [baEnum.PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED]: [{value: { value: [ 0, 80, 0, 4, 4 ], bitsUsed: 40 }, type: 8}],
41
- [baEnum.PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED]: [{value: 1476, type: 2}],
42
- [baEnum.PropertyIdentifier.SEGMENTATION_SUPPORTED]: [{value: 0, type: 9}],
43
- [baEnum.PropertyIdentifier.APDU_TIMEOUT]: [{value: that.bacnetClient.config.apduTimeout, type: 2}],
44
- [baEnum.PropertyIdentifier.NUMBER_OF_APDU_RETRIES]: [{value: 3, type: 2}],
45
- [baEnum.PropertyIdentifier.DEVICE_ADDRESS_BINDING]: [{value: 0, type: 12}],
46
- [baEnum.PropertyIdentifier.DATABASE_REVISION]: [{value: 19, type: 2}],
47
- [baEnum.PropertyIdentifier.PROPERTY_LIST]: [
48
- {value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
49
- {value: baEnum.PropertyIdentifier.OBJECT_LIST, type: 9 },
50
- {value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
51
- {value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
52
- {value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
53
- {value: baEnum.PropertyIdentifier.SYSTEM_STATUS, type: 9 },
54
- {value: baEnum.PropertyIdentifier.VENDOR_NAME, type: 9 },
55
- {value: baEnum.PropertyIdentifier.VENDOR_IDENTIFIER, type: 9 },
56
- {value: baEnum.PropertyIdentifier.MODEL_NAME, type: 9 },
57
- {value: baEnum.PropertyIdentifier.FIRMWARE_REVISION, type: 9 },
58
- {value: baEnum.PropertyIdentifier.PROTOCOL_REVISION, type: 9 },
59
- {value: baEnum.PropertyIdentifier.PROTOCOL_VERSION, type: 9 },
60
- {value: baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION, type: 9 },
61
- {value: baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED, type: 9 },
62
- {value: baEnum.PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED, type: 9 },
63
- {value: baEnum.PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED, type: 9 },
64
- {value: baEnum.PropertyIdentifier.SEGMENTATION_SUPPORTED, type: 9 },
65
- {value: baEnum.PropertyIdentifier.APDU_TIMEOUT, type: 9 },
66
- {value: baEnum.PropertyIdentifier.NUMBER_OF_APDU_RETRIES, type: 9 },
67
- {value: baEnum.PropertyIdentifier.DEVICE_ADDRESS_BINDING, type: 9 },
68
- {value: baEnum.PropertyIdentifier.DATABASE_REVISION, type: 9 },
39
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: baEnum.ObjectType.DEVICE, instance: that.deviceId }, type: 12 }],
40
+ [baEnum.PropertyIdentifier.OBJECT_LIST]: that.objectList,
41
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: 'Bitpool Edge BACnet Gateway', type: 7 }],
42
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: 8, type: 9 }],
43
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: 'Bitpool Edge BACnet gateway', type: 7 }],
44
+ [baEnum.PropertyIdentifier.SYSTEM_STATUS]: [{ value: 0, type: 9 }],
45
+ [baEnum.PropertyIdentifier.VENDOR_NAME]: [{ value: "Bitpool", type: 7 }],
46
+ [baEnum.PropertyIdentifier.VENDOR_IDENTIFIER]: [{ value: that.vendorId, type: 2 }],
47
+ [baEnum.PropertyIdentifier.MODEL_NAME]: [{ value: "bitpool-edge", type: 7 }],
48
+ [baEnum.PropertyIdentifier.FIRMWARE_REVISION]: [{ value: "Node-Red " + that.nodeRedVersion, type: 7 }],
49
+ [baEnum.PropertyIdentifier.PROTOCOL_REVISION]: [{ value: 19, type: 2 }],
50
+ [baEnum.PropertyIdentifier.PROTOCOL_VERSION]: [{ value: 0, type: 2 }],
51
+ [baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION]: [{ value: pjson.version, type: 7 }],
52
+ [baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED]: [{ value: { value: [0, 10, 0, 32, 32], bitsUsed: 40 }, type: 8 }],
53
+ [baEnum.PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED]: [{ value: 1476, type: 2 }],
54
+ [baEnum.PropertyIdentifier.SEGMENTATION_SUPPORTED]: [{ value: 0, type: 9 }],
55
+ [baEnum.PropertyIdentifier.APDU_TIMEOUT]: [{ value: that.bacnetClient.config.apduTimeout, type: 2 }],
56
+ [baEnum.PropertyIdentifier.NUMBER_OF_APDU_RETRIES]: [{ value: 3, type: 2 }],
57
+ [baEnum.PropertyIdentifier.DEVICE_ADDRESS_BINDING]: [{ value: 0, type: 12 }],
58
+ [baEnum.PropertyIdentifier.DATABASE_REVISION]: [{ value: 19, type: 2 }],
59
+ [baEnum.PropertyIdentifier.PROPERTY_LIST]: [
60
+ { value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
61
+ { value: baEnum.PropertyIdentifier.OBJECT_LIST, type: 9 },
62
+ { value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
63
+ { value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
64
+ { value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
65
+ { value: baEnum.PropertyIdentifier.SYSTEM_STATUS, type: 9 },
66
+ { value: baEnum.PropertyIdentifier.VENDOR_NAME, type: 9 },
67
+ { value: baEnum.PropertyIdentifier.VENDOR_IDENTIFIER, type: 9 },
68
+ { value: baEnum.PropertyIdentifier.MODEL_NAME, type: 9 },
69
+ { value: baEnum.PropertyIdentifier.FIRMWARE_REVISION, type: 9 },
70
+ { value: baEnum.PropertyIdentifier.PROTOCOL_REVISION, type: 9 },
71
+ { value: baEnum.PropertyIdentifier.PROTOCOL_VERSION, type: 9 },
72
+ { value: baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION, type: 9 },
73
+ { value: baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED, type: 9 },
74
+ { value: baEnum.PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED, type: 9 },
75
+ { value: baEnum.PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED, type: 9 },
76
+ { value: baEnum.PropertyIdentifier.SEGMENTATION_SUPPORTED, type: 9 },
77
+ { value: baEnum.PropertyIdentifier.APDU_TIMEOUT, type: 9 },
78
+ { value: baEnum.PropertyIdentifier.NUMBER_OF_APDU_RETRIES, type: 9 },
79
+ { value: baEnum.PropertyIdentifier.DEVICE_ADDRESS_BINDING, type: 9 },
80
+ { value: baEnum.PropertyIdentifier.DATABASE_REVISION, type: 9 },
69
81
  ],
70
- },
82
+ },
71
83
  [baEnum.ObjectType.ANALOG_VALUE]: [],
72
84
  [baEnum.ObjectType.CHARACTERSTRING_VALUE]: [],
73
85
  [baEnum.ObjectType.BINARY_VALUE]: []
@@ -75,14 +87,16 @@ class BacnetServer {
75
87
 
76
88
  try {
77
89
  let cachedData = JSON.parse(Read_Config_Sync_Server());
78
- if(typeof cachedData == "object") {
79
-
80
- if(cachedData.objectList) that.objectList = cachedData.objectList;
81
- if(cachedData.objectStore) {
90
+ if (typeof cachedData == "object") {
91
+ if (cachedData.objectList) {
92
+ that.objectList = cachedData.objectList;
93
+ that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
94
+ }
95
+ if (cachedData.objectStore) {
82
96
  that.objectStore[baEnum.ObjectType.ANALOG_VALUE] = cachedData.objectStore[baEnum.ObjectType.ANALOG_VALUE];
83
97
  that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] = cachedData.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE];
84
98
  that.objectStore[baEnum.ObjectType.BINARY_VALUE] = cachedData.objectStore[baEnum.ObjectType.BINARY_VALUE];
85
- }
99
+ }
86
100
  }
87
101
  } catch (error) {
88
102
  //do nothing
@@ -94,98 +108,100 @@ class BacnetServer {
94
108
  });
95
109
 
96
110
  that.bacnetClient.client.on('readPropertyMultiple', (data) => {
97
-
98
111
  let senderAddress = data.address;
99
112
  let requestProps = data.request.properties;
100
113
  let responseObject = [];
101
114
 
102
115
  try {
103
- if(requestProps) {
104
-
105
- for(let i = 0; i < requestProps.length; i++) {
116
+ if (requestProps) {
117
+ for (let i = 0; i < requestProps.length; i++) {
106
118
  let prop = requestProps[i].properties[0].id;
107
119
  let type = requestProps[i].objectId.type;
108
120
  let instance = requestProps[i].objectId.instance;
109
121
  let foundObject = that.getObjectMultiple(type, prop, instance, requestProps[i].properties);
110
-
111
- if(foundObject !== null && foundObject !== undefined && foundObject !== "undefined") {
112
- responseObject.push({objectId: {type: type, instance: instance}, values: foundObject});
122
+ if (foundObject !== null && foundObject !== undefined && foundObject !== "undefined") {
123
+ responseObject.push({ objectId: { type: type, instance: instance }, values: foundObject });
113
124
  }
114
-
115
- if(i == requestProps.length - 1) {
116
- if(responseObject.length > 0) {
125
+ if (i == requestProps.length - 1) {
126
+ if (responseObject.length > 0) {
117
127
  that.bacnetClient.client.readPropertyMultipleResponse(senderAddress, data.invokeId, responseObject);
118
128
  } else {
119
129
  that.bacnetClient.client.errorResponse(
120
- data.address,
121
- baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
130
+ data.address,
131
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
122
132
  data.invokeId,
123
- baEnum.ErrorClass.PROPERTY,
133
+ baEnum.ErrorClass.PROPERTY,
124
134
  baEnum.ErrorCode.UNKNOWN_PROPERTY
125
135
  );
126
136
  }
127
137
  }
128
138
  }
129
139
  }
130
-
131
- } catch(e) {
140
+ } catch (e) {
132
141
  that.bacnetClient.client.errorResponse(
133
- data.address,
134
- baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
142
+ data.address,
143
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
135
144
  data.invokeId,
136
- baEnum.ErrorClass.PROPERTY,
145
+ baEnum.ErrorClass.PROPERTY,
137
146
  baEnum.ErrorCode.UNKNOWN_PROPERTY
138
147
  );
139
148
  }
140
-
141
149
  });
142
150
 
143
151
  that.bacnetClient.client.on('readProperty', (data) => {
144
-
145
152
  try {
146
-
147
153
  let objectId = data.request.objectId.type;
148
154
  let objectInstance = data.request.objectId.instance;
149
155
  let propId = data.request.property.id.toString();
150
-
151
156
  let responseObj = that.getObject(objectId, propId, objectInstance);
152
-
153
- if(propId == baEnum.PropertyIdentifier.OBJECT_LIST && ((Date.now() - that.lastWhoIsRecived) / 1000) < 0.7) {
154
- responseObj = [{value:that.objectList.length, type: 2}];
157
+ if (propId == baEnum.PropertyIdentifier.OBJECT_LIST) {
158
+ if (data.request.property.index !== 0xFFFFFFFF) {
159
+ responseObj = responseObj[data.request.property.index];
160
+ }
155
161
  }
156
- if(responseObj !== null && responseObj !== undefined && typeof responseObj !== "undefined") {
157
-
158
- that.bacnetClient.client.readPropertyResponse(data.address, data.invokeId, objectId, data.request.property, responseObj);
162
+ if (responseObj !== null && responseObj !== undefined && typeof responseObj !== "undefined") {
163
+ that.bacnetClient.client.readPropertyResponse(data.address, data.invokeId, data.request.objectId, data.request.property, responseObj);
159
164
  } else {
160
165
  that.bacnetClient.client.errorResponse(
161
- data.address,
162
- baEnum.ConfirmedServiceChoice.READ_PROPERTY,
166
+ data.address,
167
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY,
163
168
  data.invokeId,
164
- baEnum.ErrorClass.PROPERTY,
169
+ baEnum.ErrorClass.PROPERTY,
165
170
  baEnum.ErrorCode.UNKNOWN_PROPERTY
166
171
  );
167
172
  }
168
- } catch(e) {
169
- //console.log("Local BACnet device readProperty error: ", e);
173
+ } catch (e) {
174
+ console.log("Local BACnet device readProperty error: ", e);
170
175
  }
171
-
172
176
  });
173
177
 
174
178
  //do initial iAm broadcast when BACnet server starts
175
179
  that.bacnetClient.client.iAmResponse(that.deviceId, baEnum.Segmentation.SEGMENTED_BOTH, that.vendorId);
176
180
  }
177
181
 
182
+ /**
183
+ * Set the name of the device.
184
+ *
185
+ * @param {string} nodeName - The new name for the device.
186
+ */
178
187
  setDeviceName(nodeName) {
179
188
  let that = this;
180
- if(typeof nodeName == "string" && nodeName !== "") {
189
+ if (typeof nodeName == "string" && nodeName !== "") {
181
190
  that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_NAME][0].value = nodeName;
182
191
  }
183
192
  }
184
193
 
194
+ /**
195
+ * Adds a new object to the BacnetServer's object store based on the provided name and value.
196
+ *
197
+ * @param {string} name - The name of the object to be added.
198
+ * @param {number|boolean|string} value - The value of the object to be added.
199
+ * @returns {void}
200
+ */
185
201
  addObject(name, value) {
186
202
  let that = this;
187
203
  let objectType = that.getBacnetObjectType(value);
188
- if(name && objectType) {
204
+ if (name && objectType) {
189
205
  let instanceNumber;
190
206
  if (name.includes('|')) {
191
207
  // split name, assign last part to instanceNumber and the rest to name
@@ -196,111 +212,119 @@ class BacnetServer {
196
212
  }
197
213
  let formattedName = name.replaceAll('.', '_');
198
214
  formattedName = formattedName.replaceAll('/', '_');
199
- if(objectType == "number") {
215
+ if (objectType == "number") {
200
216
  let foundIndex = that.objectStore[baEnum.ObjectType.ANALOG_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
201
- if(foundIndex == -1) {
217
+ if (foundIndex == -1) {
202
218
  let objectId = that.getObjectIdentifier(baEnum.ObjectType.ANALOG_VALUE, instanceNumber);
203
219
  that.objectStore[baEnum.ObjectType.ANALOG_VALUE].push({
204
- [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
205
- [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.ANALOG_VALUE, type: 9}],
206
- [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
207
- [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12}],
208
- [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 4}],
209
- [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{value: 0, type: 8}],
210
- [baEnum.PropertyIdentifier.EVENT_STATE]: [{value: 0, type: 9}],
211
- [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{value: 0, type: 9}],
212
- [baEnum.PropertyIdentifier.UNITS]: [{value: 95, type: 9}],
213
- [baEnum.PropertyIdentifier.PRIORITY_ARRAY]: [{value: 0, type: 9}],
214
- [baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{value: value, type: 4}],
215
- [baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{value: value, type: 4}],
216
- [baEnum.PropertyIdentifier.RESOLUTION]: [{value: 0, type: 4}],
220
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: formattedName, type: 7 }],
221
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: baEnum.ObjectType.ANALOG_VALUE, type: 9 }],
222
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: '', type: 7 }],
223
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId }, type: 12 }],
224
+ [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: value, type: 4 }],
225
+ [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
226
+ [baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
227
+ [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
228
+ [baEnum.PropertyIdentifier.UNITS]: [{ value: 95, type: 9 }],
229
+ [baEnum.PropertyIdentifier.PRIORITY_ARRAY]: [{ value: 0, type: 9 }],
230
+ [baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{ value: value, type: 4 }],
231
+ [baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{ value: value, type: 4 }],
232
+ [baEnum.PropertyIdentifier.RESOLUTION]: [{ value: 0, type: 4 }],
217
233
  [baEnum.PropertyIdentifier.PROPERTY_LIST]:
218
- [
219
- {value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
220
- {value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
221
- {value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
222
- {value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
223
- {value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
224
- {value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
225
- {value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
226
- {value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
227
- {value: baEnum.PropertyIdentifier.UNITS, type: 9 },
228
- {value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
229
- {value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
230
- {value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
231
- {value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
232
- ],
234
+ [
235
+ { value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
236
+ { value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
237
+ { value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
238
+ { value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
239
+ { value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
240
+ { value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
241
+ { value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
242
+ { value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
243
+ { value: baEnum.PropertyIdentifier.UNITS, type: 9 },
244
+ { value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
245
+ { value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
246
+ { value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
247
+ { value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
248
+ ],
233
249
  });
234
-
235
- that.objectList.push({value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12})
236
- that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
237
- } else if(foundIndex !== -1) {
250
+
251
+ that.objectList.push({ value: { type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId }, type: 12 })
252
+ that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
253
+ } else if (foundIndex !== -1) {
238
254
  let foundObject = that.objectStore[baEnum.ObjectType.ANALOG_VALUE][foundIndex];
239
255
  foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
240
256
  that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
241
257
  }
242
258
  } else if (objectType == "boolean") {
243
259
  let foundIndex = that.objectStore[baEnum.ObjectType.BINARY_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
244
- if(foundIndex == -1) {
245
- let objectId = that.getObjectIdentifier(baEnum.ObjectType.BINARY_VALUE);
246
- that.objectStore[baEnum.ObjectType.BINARY_VALUE].push({
247
- [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
248
- [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.BINARY_VALUE, type: 9}],
249
- [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
250
- [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.BINARY_VALUE, instance: objectId}, type: 12}],
251
- [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 1}],
252
- [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{value: 0, type: 8}],
253
- [baEnum.PropertyIdentifier.EVENT_STATE]: [{value: 0, type: 9}],
254
- [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{value: 0, type: 9}],
255
- [baEnum.PropertyIdentifier.ACTIVE_TEXT]: [{value: 'ACTIVE', type: 7}],
256
- [baEnum.PropertyIdentifier.INACTIVE_TEXT]: [{value: 'INACTIVE', type: 7}],
257
- });
258
-
259
- that.objectList.push({value: {type: baEnum.ObjectType.BINARY_VALUE, instance: objectId}, type: 12})
260
- that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
261
- } else if(foundIndex !== -1) {
260
+ if (foundIndex == -1) {
261
+ let objectId = that.getObjectIdentifier(baEnum.ObjectType.BINARY_VALUE);
262
+ that.objectStore[baEnum.ObjectType.BINARY_VALUE].push({
263
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: formattedName, type: 7 }],
264
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: baEnum.ObjectType.BINARY_VALUE, type: 9 }],
265
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: '', type: 7 }],
266
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: baEnum.ObjectType.BINARY_VALUE, instance: objectId }, type: 12 }],
267
+ [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: value, type: 1 }],
268
+ [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
269
+ [baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
270
+ [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
271
+ [baEnum.PropertyIdentifier.ACTIVE_TEXT]: [{ value: 'ACTIVE', type: 7 }],
272
+ [baEnum.PropertyIdentifier.INACTIVE_TEXT]: [{ value: 'INACTIVE', type: 7 }],
273
+ });
274
+
275
+ that.objectList.push({ value: { type: baEnum.ObjectType.BINARY_VALUE, instance: objectId }, type: 12 })
276
+ that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
277
+ } else if (foundIndex !== -1) {
262
278
  let foundObject = that.objectStore[baEnum.ObjectType.BINARY_VALUE][foundIndex];
263
279
  foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
264
280
  that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
265
281
  }
266
- } else if(objectType == "string") {
282
+ } else if (objectType == "string") {
267
283
  let foundIndex = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
268
- if(foundIndex == -1) {
269
- let objectId = that.getObjectIdentifier(baEnum.ObjectType.CHARACTERSTRING_VALUE);
270
- that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].push({
271
- [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
272
- [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.CHARACTERSTRING_VALUE, type: 9}],
273
- [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
274
- [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId}, type: 12}],
275
- [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 7}],
276
- [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{value: 0, type: 8}],
277
- [baEnum.PropertyIdentifier.EVENT_STATE]: [{value: 0, type: 9}],
278
- [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{value: 0, type: 9}],
279
- [baEnum.PropertyIdentifier.UNITS]: [{value: 95, type: 9}]
280
- });
281
-
282
- that.objectList.push({value: {type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId}, type: 12})
283
- that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
284
- } else if(foundIndex !== -1) {
284
+ if (foundIndex == -1) {
285
+ let objectId = that.getObjectIdentifier(baEnum.ObjectType.CHARACTERSTRING_VALUE);
286
+ that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].push({
287
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: formattedName, type: 7 }],
288
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: baEnum.ObjectType.CHARACTERSTRING_VALUE, type: 9 }],
289
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: '', type: 7 }],
290
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId }, type: 12 }],
291
+ [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: value, type: 7 }],
292
+ [baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
293
+ [baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
294
+ [baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
295
+ [baEnum.PropertyIdentifier.UNITS]: [{ value: 95, type: 9 }]
296
+ });
297
+
298
+ that.objectList.push({ value: { type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId }, type: 12 })
299
+ that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
300
+ } else if (foundIndex !== -1) {
285
301
  let foundObject = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE][foundIndex];
286
302
  foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
287
303
  that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
288
304
  }
289
305
  }
290
306
  }
291
- Store_Config_Server(JSON.stringify({objectList: that.objectList, objectStore: that.objectStore}));
307
+ Store_Config_Server(JSON.stringify({ objectList: that.objectList, objectStore: that.objectStore }));
292
308
  }
293
309
 
310
+ /**
311
+ * Retrieves a specific property of an object based on the object ID, property ID, and instance number.
312
+ *
313
+ * @param {number} objectId - The ID of the object type.
314
+ * @param {number} propId - The ID of the property to retrieve.
315
+ * @param {number} instance - The instance number of the object.
316
+ * @returns {any} The requested property value if found, otherwise null.
317
+ */
294
318
  getObject(objectId, propId, instance) {
295
319
  let that = this;
296
- let objectGroup = that.objectStore[objectId];
320
+ let objectGroup = that.objectStore[objectId];
297
321
 
298
- if(Array.isArray(objectGroup)) {
299
- for(let i = 0; i < objectGroup.length; i++) {
322
+ if (Array.isArray(objectGroup)) {
323
+ for (let i = 0; i < objectGroup.length; i++) {
300
324
  let object = objectGroup[i];
301
- if(object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
325
+ if (object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
302
326
  let requestedProperty = object[propId];
303
- if(requestedProperty !== null && requestedProperty !== undefined && typeof requestedProperty !== "undefined") {
327
+ if (requestedProperty !== null && requestedProperty !== undefined && typeof requestedProperty !== "undefined") {
304
328
  return requestedProperty;
305
329
  }
306
330
  }
@@ -312,77 +336,91 @@ class BacnetServer {
312
336
  return null;
313
337
  }
314
338
 
339
+ /**
340
+ * Retrieves the properties of a specific object instance from the objectStore based on the provided parameters.
341
+ *
342
+ * @param {number} objectId - The type of the object to retrieve.
343
+ * @param {number} propId - The property identifier to retrieve.
344
+ * @param {number} instance - The instance number of the object to retrieve.
345
+ * @param {Array} properties - An array of additional properties to retrieve along with the main property.
346
+ * @returns {Array|null} - An array of properties with values for the specified object instance, or null if not found.
347
+ */
315
348
  getObjectMultiple(objectId, propId, instance, properties) {
316
349
  let that = this;
317
- let objectGroup = that.objectStore[objectId];
350
+ let objectGroup = that.objectStore[objectId];
318
351
 
319
352
  try {
320
-
321
- if(Array.isArray(objectGroup)) {
322
- for(let i = 0; i < objectGroup.length; i++) {
353
+ if (Array.isArray(objectGroup)) {
354
+ for (let i = 0; i < objectGroup.length; i++) {
323
355
  let object = objectGroup[i];
324
- if(object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
325
- if(propId == baEnum.PropertyIdentifier.ALL) {
356
+ if (object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
357
+ if (propId == baEnum.PropertyIdentifier.ALL) {
326
358
  let propList = [];
327
359
  let keys = Object.keys(object);
328
- keys.forEach(function(key) {
329
- propList.push({property: {id: key, index: 0xFFFFFFFF}, value: object[key]});
360
+ keys.forEach(function (key) {
361
+ propList.push({ property: { id: key, index: 0xFFFFFFFF }, value: object[key] });
330
362
  });
331
-
363
+
332
364
  return propList;
333
365
 
334
- } else if(properties && properties.length > 1) {
366
+ } else if (properties && properties.length > 1) {
335
367
  let propList = [];
336
- properties.forEach(function(p) {
337
- if(object[p.id]){
338
- propList.push({property: {id: p.id, index: 0xFFFFFFFF}, value: object[p.id]});
368
+ properties.forEach(function (p) {
369
+ if (object[p.id]) {
370
+ propList.push({ property: { id: p.id, index: 0xFFFFFFFF }, value: object[p.id] });
339
371
  }
340
372
  });
341
373
 
342
374
  return propList;
343
-
375
+
344
376
  } else {
345
- return [{property: {id: propId, index: 0xFFFFFFFF}, value: object[propId]}];
377
+ return [{ property: { id: propId, index: 0xFFFFFFFF }, value: object[propId] }];
346
378
  }
347
379
  }
348
380
  }
349
381
  } else {
350
- if(propId == baEnum.PropertyIdentifier.ALL) {
382
+ if (propId == baEnum.PropertyIdentifier.ALL) {
351
383
  let propList = [];
352
384
  let keys = Object.keys(objectGroup);
353
- keys.forEach(function(key) {
354
- propList.push({property: {id: key, index: 0xFFFFFFFF}, value: objectGroup[key]});
385
+ keys.forEach(function (key) {
386
+ propList.push({ property: { id: key, index: 0xFFFFFFFF }, value: objectGroup[key] });
355
387
  });
356
-
388
+
357
389
  return propList;
358
390
 
359
- } else if(properties && properties.length > 1) {
391
+ } else if (properties && properties.length > 1) {
360
392
  let propList = [];
361
- properties.forEach(function(p) {
362
- if(objectGroup[p.id]){
363
- propList.push({property: {id: p.id, index: 0xFFFFFFFF}, value: objectGroup[p.id]});
393
+ properties.forEach(function (p) {
394
+ if (objectGroup[p.id]) {
395
+ propList.push({ property: { id: p.id, index: 0xFFFFFFFF }, value: objectGroup[p.id] });
364
396
  }
365
397
  });
366
398
 
367
399
  return propList;
368
400
 
369
401
  } else {
370
- return [{property: {id: propId, index: 0xFFFFFFFF}, value: objectGroup[propId]}];
402
+ return [{ property: { id: propId, index: 0xFFFFFFFF }, value: objectGroup[propId] }];
371
403
  }
372
404
  }
373
405
 
374
- } catch(e) {
406
+ } catch (e) {
375
407
  //do nothing
376
408
  }
377
-
409
+
378
410
  return null;
379
411
  }
380
412
 
413
+ /**
414
+ * Clear all server points by resetting the object lists and object store.
415
+ * This method resets the object list for the device, clears the character string values,
416
+ * and clears the analog values. It also resets the object id numbers for analog, character string, and binary values.
417
+ * Finally, it stores the updated object list and object store in the server configuration.
418
+ */
381
419
  clearServerPoints() {
382
420
  let that = this;
383
-
421
+
384
422
  that.objectList = [
385
- {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
423
+ { value: { type: baEnum.ObjectType.DEVICE, instance: that.deviceId }, type: 12 }
386
424
  ];
387
425
  that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
388
426
  that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] = [];
@@ -393,9 +431,17 @@ class BacnetServer {
393
431
  that.objectIdNumber[baEnum.ObjectType.CHARACTERSTRING_VALUE] = 0;
394
432
  that.objectIdNumber[baEnum.ObjectType.BINARY_VALUE] = 0;
395
433
 
396
- Store_Config_Server(JSON.stringify({objectList: that.objectList, objectStore: that.objectStore}));
434
+ Store_Config_Server(JSON.stringify({ objectList: that.objectList, objectStore: that.objectStore }));
397
435
  }
398
436
 
437
+ /**
438
+ * Removes a server point from the objectStore and objectList based on the provided JSON data.
439
+ *
440
+ * @param {Object} json - The JSON data containing information about the server point to be removed.
441
+ * @param {string} json.body.type - The type of the server point ('SV' for CharacterString, 'BV' for BinaryValue, default is AnalogValue).
442
+ * @param {number} json.body.instance - The instance number of the server point to be removed.
443
+ * @returns {Promise<boolean>} A Promise that resolves to true if the server point is successfully removed, otherwise rejects with an error.
444
+ */
399
445
  clearServerPoint(json) {
400
446
  let that = this;
401
447
  return new Promise(async function (resolve, reject) {
@@ -446,6 +492,17 @@ class BacnetServer {
446
492
  });
447
493
  }
448
494
 
495
+ /**
496
+ * Retrieves all server points from the BacnetServer objectStore.
497
+ * Points include Analog Value, Character String Value, and Binary Value objects.
498
+ * Each point is represented as an object with properties:
499
+ * - name: The name of the object.
500
+ * - type: The type of the object (AV for Analog Value, SV for Character String Value, BV for Binary Value).
501
+ * - instance: The instance number of the object.
502
+ *
503
+ * @returns {Promise<Array>} A promise that resolves with an array of points sorted by instance number.
504
+ * @throws {Error} If an error occurs during the retrieval process.
505
+ */
449
506
  getServerPoints() {
450
507
  let that = this;
451
508
  let points = [];
@@ -453,7 +510,7 @@ class BacnetServer {
453
510
  return new Promise(async function (resolve, reject) {
454
511
  try {
455
512
  // iterate analog value objects
456
- if(that.objectStore[baEnum.ObjectType.ANALOG_VALUE] && that.objectStore[baEnum.ObjectType.ANALOG_VALUE].length > 0) {
513
+ if (that.objectStore[baEnum.ObjectType.ANALOG_VALUE] && that.objectStore[baEnum.ObjectType.ANALOG_VALUE].length > 0) {
457
514
  that.objectStore[baEnum.ObjectType.ANALOG_VALUE].forEach((point) => {
458
515
  let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
459
516
  let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
@@ -467,7 +524,7 @@ class BacnetServer {
467
524
  }
468
525
 
469
526
  // iterate character string value objects
470
- if(that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] && that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].length > 0) {
527
+ if (that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] && that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].length > 0) {
471
528
  that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].forEach((point) => {
472
529
  let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
473
530
  let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
@@ -481,7 +538,7 @@ class BacnetServer {
481
538
  }
482
539
 
483
540
  // iterate binary value objects
484
- if(that.objectStore[baEnum.ObjectType.BINARY_VALUE] && that.objectStore[baEnum.ObjectType.BINARY_VALUE].length > 0) {
541
+ if (that.objectStore[baEnum.ObjectType.BINARY_VALUE] && that.objectStore[baEnum.ObjectType.BINARY_VALUE].length > 0) {
485
542
  that.objectStore[baEnum.ObjectType.BINARY_VALUE].forEach((point) => {
486
543
  let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
487
544
  let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
@@ -501,10 +558,12 @@ class BacnetServer {
501
558
  });
502
559
  }
503
560
 
504
- getRandomArbitrary(min, max) {
505
- return Math.random() * (max - min) + min;
506
- }
507
-
561
+ /**
562
+ * Determines the BACnet object type based on the provided value.
563
+ *
564
+ * @param {any} value - The value to determine the BACnet object type for.
565
+ * @returns {string|null} The BACnet object type as a string ('string', 'number', 'boolean') or null if the type is not recognized.
566
+ */
508
567
  getBacnetObjectType(value) {
509
568
  let type = typeof value;
510
569
 
@@ -512,7 +571,7 @@ class BacnetServer {
512
571
  case "string":
513
572
  return "string"
514
573
  case "number":
515
- return "number"
574
+ return "number"
516
575
  case "boolean":
517
576
  return "boolean"
518
577
  default:
@@ -520,6 +579,13 @@ class BacnetServer {
520
579
  }
521
580
  }
522
581
 
582
+ /**
583
+ * Returns the object identifier for the given type and instance number.
584
+ *
585
+ * @param {string} type - The type of the object.
586
+ * @param {number} instanceNumber - The instance number of the object.
587
+ * @returns {number} The object identifier.
588
+ */
523
589
  getObjectIdentifier(type, instanceNumber) {
524
590
  let that = this;
525
591
  // manual instance numbering
@@ -532,7 +598,6 @@ class BacnetServer {
532
598
  that.objectIdNumber[type]++;
533
599
  return objectId;
534
600
  }
535
-
536
601
  }
537
602
 
538
603
  module.exports = { BacnetServer };