@bitpoolos/edge-bacnet 1.6.4 → 1.6.6
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 +14 -0
- package/bacnet_client.js +116 -50
- package/bacnet_gateway.js +5 -10
- package/bacnet_read.html +45 -10
- package/package.json +2 -2
- package/resources/node-bacstack-ts/dist/lib/client.js +16 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.6] - 20-11-2025
|
|
4
|
+
|
|
5
|
+
Minor update:
|
|
6
|
+
|
|
7
|
+
- Added all stored point properties as columns to "Export point list" CSV in read node Properties tab.
|
|
8
|
+
- Adjustment to point polling, setting stricter maxApdu sizes
|
|
9
|
+
|
|
10
|
+
## [1.6.5] - 09-10-2025
|
|
11
|
+
|
|
12
|
+
Bug fix:
|
|
13
|
+
|
|
14
|
+
- Specific users found issues of spiking values. Results after a read query are now force ordered. An adjustment made to the bacnet stack _getInvokeId function as it was running out of array space to process a high volume of request responses.
|
|
15
|
+
|
|
16
|
+
|
|
3
17
|
## [1.6.4] - 02-09-2025
|
|
4
18
|
|
|
5
19
|
Minor feature:
|
package/bacnet_client.js
CHANGED
|
@@ -222,9 +222,31 @@ class BacnetClient extends EventEmitter {
|
|
|
222
222
|
port: port,
|
|
223
223
|
};
|
|
224
224
|
|
|
225
|
+
// Try to find the device to use device-specific options
|
|
226
|
+
let device = null;
|
|
227
|
+
if (type === 8) {
|
|
228
|
+
// Device object - instance is the device ID
|
|
229
|
+
device = that.deviceList.find(ele => ele.getDeviceId() === instance);
|
|
230
|
+
} else {
|
|
231
|
+
// For non-device objects, we can't determine the device from just address/instance
|
|
232
|
+
// This is a limitation of testFunction's current signature
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Use device-specific options if we found the device, otherwise use safer defaults
|
|
236
|
+
let readOptions;
|
|
237
|
+
if (device) {
|
|
238
|
+
readOptions = that.getDeviceSpecificOptions(device);
|
|
239
|
+
} else {
|
|
240
|
+
// Conservative defaults for unknown devices (assume small MSTP)
|
|
241
|
+
readOptions = {
|
|
242
|
+
maxSegments: 0, // No segmentation
|
|
243
|
+
maxApdu: 2 // 206 octets - safe for most MSTP devices
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
225
247
|
const propertiesArray = [{ objectId: { type: type, instance: instance }, properties: [{ id: property }] }];
|
|
226
248
|
|
|
227
|
-
that.client.readPropertyMultiple(addressObject, propertiesArray,
|
|
249
|
+
that.client.readPropertyMultiple(addressObject, propertiesArray, readOptions, (err, value) => {
|
|
228
250
|
console.log("1 - readPropertyMultiple: ");
|
|
229
251
|
|
|
230
252
|
console.log(value);
|
|
@@ -248,7 +270,7 @@ class BacnetClient extends EventEmitter {
|
|
|
248
270
|
addressObject,
|
|
249
271
|
{ type: type, instance: instance },
|
|
250
272
|
property,
|
|
251
|
-
|
|
273
|
+
readOptions,
|
|
252
274
|
(err, value) => {
|
|
253
275
|
console.log("2 - readProperty: ");
|
|
254
276
|
|
|
@@ -316,12 +338,13 @@ class BacnetClient extends EventEmitter {
|
|
|
316
338
|
address: device.getAddress(),
|
|
317
339
|
port: device.getPort(),
|
|
318
340
|
};
|
|
341
|
+
const readOptions = that.getDeviceSpecificOptions(device);
|
|
319
342
|
return new Promise((resolve, reject) => {
|
|
320
343
|
that.client.readProperty(
|
|
321
344
|
addressObject,
|
|
322
345
|
{ type: baEnum.ObjectType.DEVICE, instance: device.getDeviceId() },
|
|
323
346
|
baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED,
|
|
324
|
-
|
|
347
|
+
readOptions,
|
|
325
348
|
(err, value) => {
|
|
326
349
|
if (err) {
|
|
327
350
|
reject(err);
|
|
@@ -339,7 +362,7 @@ class BacnetClient extends EventEmitter {
|
|
|
339
362
|
let that = this;
|
|
340
363
|
let address = device.getAddress().address;
|
|
341
364
|
let deviceId = device.getDeviceId();
|
|
342
|
-
let foundParentIndex = that.deviceList.findIndex((ele) =>
|
|
365
|
+
let foundParentIndex = that.deviceList.findIndex((ele) => that.getDeviceAddress(ele) == address);
|
|
343
366
|
if (foundParentIndex !== -1) {
|
|
344
367
|
that.deviceList[foundParentIndex].addChildDevice(deviceId);
|
|
345
368
|
device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
|
|
@@ -827,16 +850,12 @@ class BacnetClient extends EventEmitter {
|
|
|
827
850
|
};
|
|
828
851
|
|
|
829
852
|
// Process the results of the batch
|
|
830
|
-
results.value.values.forEach((pointResult) => {
|
|
831
|
-
const cacheRef = requestArray
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
|
|
835
|
-
);
|
|
853
|
+
results.value.values.forEach((pointResult, index) => {
|
|
854
|
+
const cacheRef = requestArray[index];
|
|
855
|
+
const pointRef = cacheRef.pointRef;
|
|
856
|
+
const pointNameRef = cacheRef.pointName;
|
|
836
857
|
|
|
837
|
-
if (
|
|
838
|
-
const pointRef = cacheRef.pointRef;
|
|
839
|
-
const pointNameRef = cacheRef.pointName;
|
|
858
|
+
if (pointResult.values[0].value.length > 0) {
|
|
840
859
|
const val = pointResult.values[0].value[0].value;
|
|
841
860
|
|
|
842
861
|
if (isNumber(val)) {
|
|
@@ -865,13 +884,12 @@ class BacnetClient extends EventEmitter {
|
|
|
865
884
|
pointRef.status = "online";
|
|
866
885
|
}
|
|
867
886
|
}
|
|
868
|
-
|
|
869
|
-
pointRef.meta["device"] = deviceMetaInfo;
|
|
870
|
-
pointRef.timestamp = Date.now();
|
|
871
|
-
|
|
872
|
-
// Store the point data in results
|
|
873
|
-
bacnetResults[deviceName][pointNameRef] = pointRef;
|
|
874
887
|
}
|
|
888
|
+
pointRef.meta["device"] = deviceMetaInfo;
|
|
889
|
+
pointRef.timestamp = Date.now();
|
|
890
|
+
|
|
891
|
+
// Store the point data in results
|
|
892
|
+
bacnetResults[deviceName][pointNameRef] = pointRef;
|
|
875
893
|
});
|
|
876
894
|
} catch (err) {
|
|
877
895
|
that.logOut("Error processing batch:", err);
|
|
@@ -944,13 +962,46 @@ class BacnetClient extends EventEmitter {
|
|
|
944
962
|
|
|
945
963
|
async updateManyPoints(device, points) {
|
|
946
964
|
try {
|
|
947
|
-
|
|
965
|
+
// Use device-specific options instead of global options
|
|
966
|
+
const deviceOptions = this.getDeviceSpecificOptions(device);
|
|
967
|
+
const results = await this._readObjectWithRequestArray(device, points, deviceOptions);
|
|
948
968
|
return results;
|
|
949
969
|
} catch (error) {
|
|
950
970
|
throw error;
|
|
951
971
|
}
|
|
952
972
|
}
|
|
953
973
|
|
|
974
|
+
getDeviceSpecificOptions(device) {
|
|
975
|
+
let maxSegments = this.readPropertyMultipleOptions.maxSegments;
|
|
976
|
+
let maxApdu = this.readPropertyMultipleOptions.maxApdu;
|
|
977
|
+
|
|
978
|
+
// Adjust for devices with no segmentation support
|
|
979
|
+
if (device.getSegmentation() == 3) {
|
|
980
|
+
maxSegments = 0;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Adjust maxApdu based on device capability
|
|
984
|
+
const deviceMaxApdu = device.getMaxApdu();
|
|
985
|
+
if (deviceMaxApdu <= 50) {
|
|
986
|
+
maxApdu = 0; // 50 octets
|
|
987
|
+
} else if (deviceMaxApdu <= 128) {
|
|
988
|
+
maxApdu = 1; // 128 octets
|
|
989
|
+
} else if (deviceMaxApdu <= 206) {
|
|
990
|
+
maxApdu = 2; // 206 octets
|
|
991
|
+
} else if (deviceMaxApdu <= 480) {
|
|
992
|
+
maxApdu = 3; // 480 octets
|
|
993
|
+
} else if (deviceMaxApdu <= 1024) {
|
|
994
|
+
maxApdu = 4; // 1024 octets
|
|
995
|
+
} else {
|
|
996
|
+
maxApdu = 5; // 1476 octets
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
return {
|
|
1000
|
+
maxSegments: maxSegments,
|
|
1001
|
+
maxApdu: maxApdu
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
954
1005
|
updatePointWithRetry(device, point, retryCount = 1) {
|
|
955
1006
|
let that = this;
|
|
956
1007
|
const tryUpdate = (retriesLeft) => {
|
|
@@ -1002,21 +1053,8 @@ class BacnetClient extends EventEmitter {
|
|
|
1002
1053
|
port: device.getPort(),
|
|
1003
1054
|
};
|
|
1004
1055
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
if (device.getSegmentation() == 3) {
|
|
1009
|
-
maxSegments = 0;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
if (device.getMaxApdu() == 480) {
|
|
1013
|
-
maxApdu = 3;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
let settings = {
|
|
1017
|
-
maxSegments: maxSegments,
|
|
1018
|
-
maxApdu: maxApdu,
|
|
1019
|
-
};
|
|
1056
|
+
// Use device-specific options
|
|
1057
|
+
const settings = that.getDeviceSpecificOptions(device);
|
|
1020
1058
|
|
|
1021
1059
|
return new Promise((resolve, reject) => {
|
|
1022
1060
|
that.client.readProperty(
|
|
@@ -1037,8 +1075,15 @@ class BacnetClient extends EventEmitter {
|
|
|
1037
1075
|
}
|
|
1038
1076
|
|
|
1039
1077
|
estimateMaxObjectSize(apduSize) {
|
|
1040
|
-
|
|
1041
|
-
|
|
1078
|
+
// Be more conservative for very small MSTP devices
|
|
1079
|
+
if (apduSize <= 50) {
|
|
1080
|
+
return 1; // Only 1 object at a time for 50-byte devices
|
|
1081
|
+
} else if (apduSize <= 128) {
|
|
1082
|
+
return 3; // 3 objects for 128-byte devices
|
|
1083
|
+
} else if (apduSize <= 206) {
|
|
1084
|
+
return 5; // 5 objects for 206-byte devices
|
|
1085
|
+
} else if (apduSize < 500) {
|
|
1086
|
+
return 10; // Reduced from 20 for safety
|
|
1042
1087
|
} else if (apduSize > 500 && apduSize < 1000) {
|
|
1043
1088
|
//return Math.round(((apduSize - 30) / 7));
|
|
1044
1089
|
return 50;
|
|
@@ -1217,6 +1262,32 @@ class BacnetClient extends EventEmitter {
|
|
|
1217
1262
|
};
|
|
1218
1263
|
return new Promise((resolve, reject) => {
|
|
1219
1264
|
that.client.readPropertyMultiple(addressObject, requestArray, readOptions, (error, value) => {
|
|
1265
|
+
if (value && value.values) {
|
|
1266
|
+
const reorderedValues = requestArray.map((req) => {
|
|
1267
|
+
const foundValue = value.values.find(
|
|
1268
|
+
(val) => val.objectId.type === req.objectId.type && val.objectId.instance === req.objectId.instance
|
|
1269
|
+
);
|
|
1270
|
+
return (
|
|
1271
|
+
foundValue || {
|
|
1272
|
+
objectId: req.objectId,
|
|
1273
|
+
values: [
|
|
1274
|
+
{
|
|
1275
|
+
value: [
|
|
1276
|
+
{
|
|
1277
|
+
value: {
|
|
1278
|
+
errorClass: baEnum.ErrorClass.PROPERTY,
|
|
1279
|
+
errorCode: baEnum.ErrorCode.UNKNOWN_PROPERTY,
|
|
1280
|
+
},
|
|
1281
|
+
},
|
|
1282
|
+
],
|
|
1283
|
+
},
|
|
1284
|
+
],
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
});
|
|
1288
|
+
value.values = reorderedValues;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1220
1291
|
resolve({
|
|
1221
1292
|
error: error,
|
|
1222
1293
|
value: value,
|
|
@@ -1233,12 +1304,13 @@ class BacnetClient extends EventEmitter {
|
|
|
1233
1304
|
port: device.getPort(),
|
|
1234
1305
|
};
|
|
1235
1306
|
let deviceId = device.getDeviceId();
|
|
1307
|
+
const readOptions = that.getDeviceSpecificOptions(device);
|
|
1236
1308
|
|
|
1237
1309
|
that.client.readProperty(
|
|
1238
1310
|
addressObject,
|
|
1239
1311
|
{ type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
1240
1312
|
baEnum.PropertyIdentifier.OBJECT_NAME,
|
|
1241
|
-
|
|
1313
|
+
readOptions,
|
|
1242
1314
|
callback
|
|
1243
1315
|
);
|
|
1244
1316
|
}
|
|
@@ -1283,10 +1355,8 @@ class BacnetClient extends EventEmitter {
|
|
|
1283
1355
|
|
|
1284
1356
|
_readObjectFull(device, type, instance) {
|
|
1285
1357
|
const that = this;
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
1289
|
-
};
|
|
1358
|
+
// Use device-specific options for reading all properties
|
|
1359
|
+
const readOptions = that.getDeviceSpecificOptions(device);
|
|
1290
1360
|
|
|
1291
1361
|
const readIndividualPropsOptions = {
|
|
1292
1362
|
maxSegments: 0,
|
|
@@ -1384,10 +1454,8 @@ class BacnetClient extends EventEmitter {
|
|
|
1384
1454
|
|
|
1385
1455
|
_readObjectLite(device, type, instance) {
|
|
1386
1456
|
const that = this;
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
1390
|
-
};
|
|
1457
|
+
// Use device-specific options
|
|
1458
|
+
const readOptions = that.getDeviceSpecificOptions(device);
|
|
1391
1459
|
|
|
1392
1460
|
const readIndividualPropsOptions = {
|
|
1393
1461
|
maxSegments: 0,
|
|
@@ -1552,10 +1620,8 @@ class BacnetClient extends EventEmitter {
|
|
|
1552
1620
|
scanDevice(device) {
|
|
1553
1621
|
let that = this;
|
|
1554
1622
|
return new Promise((resolve, reject) => {
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
1558
|
-
};
|
|
1623
|
+
// Use device-specific options
|
|
1624
|
+
const readOptions = that.getDeviceSpecificOptions(device);
|
|
1559
1625
|
this._readObjectList(device, readOptions, (err, result) => {
|
|
1560
1626
|
if (!err) {
|
|
1561
1627
|
try {
|
package/bacnet_gateway.js
CHANGED
|
@@ -212,14 +212,10 @@ module.exports = function (RED) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
if (
|
|
216
|
-
node.bacnetServerEnabled == true &&
|
|
217
|
-
node.bacnetClient &&
|
|
218
|
-
node.bacnetServer
|
|
219
|
-
) {
|
|
215
|
+
if (node.bacnetServerEnabled == true && node.bacnetClient && node.bacnetServer) {
|
|
220
216
|
try {
|
|
221
217
|
// Clean up any existing listeners to prevent stale references
|
|
222
|
-
node.bacnetServer.removeAllListeners(
|
|
218
|
+
node.bacnetServer.removeAllListeners("writeProperty");
|
|
223
219
|
|
|
224
220
|
// Store the event handler function so we can clean it up later
|
|
225
221
|
node.writePropertyHandler = (topic, newValue) => {
|
|
@@ -269,7 +265,7 @@ module.exports = function (RED) {
|
|
|
269
265
|
} else if (msg.doUpdatePriorityDevices == true && msg.priorityDevices !== null) {
|
|
270
266
|
node.bacnetClient
|
|
271
267
|
.updatePriorityQueue(msg.priorityDevices)
|
|
272
|
-
.then(function (result) {
|
|
268
|
+
.then(function (result) {})
|
|
273
269
|
.catch(function (error) {
|
|
274
270
|
logOut("Error updating priorityQueue: ", error);
|
|
275
271
|
});
|
|
@@ -283,7 +279,7 @@ module.exports = function (RED) {
|
|
|
283
279
|
|
|
284
280
|
node.bacnetClient
|
|
285
281
|
.applyDisplayNames(msg.pointsToRead)
|
|
286
|
-
.then(function (result) {
|
|
282
|
+
.then(function (result) {})
|
|
287
283
|
.catch(function (error) {
|
|
288
284
|
logOut("Error in applyDisplayNames: ", error);
|
|
289
285
|
});
|
|
@@ -306,7 +302,7 @@ module.exports = function (RED) {
|
|
|
306
302
|
node.on("close", function () {
|
|
307
303
|
// Clean up the writeProperty event listener
|
|
308
304
|
if (node.bacnetServer && node.writePropertyHandler) {
|
|
309
|
-
node.bacnetServer.removeListener(
|
|
305
|
+
node.bacnetServer.removeListener("writeProperty", node.writePropertyHandler);
|
|
310
306
|
node.writePropertyHandler = null;
|
|
311
307
|
}
|
|
312
308
|
|
|
@@ -794,7 +790,6 @@ module.exports = function (RED) {
|
|
|
794
790
|
if (points[point] && "presentValue" in points[point]) {
|
|
795
791
|
let pointName = getPointName(points[point], point);
|
|
796
792
|
let topic = getTopicString("sendSimpleWithStatus", useDeviceName, readNodeName, device, pointName);
|
|
797
|
-
|
|
798
793
|
msgg.topic = topic;
|
|
799
794
|
let payload = {
|
|
800
795
|
presentValue: points[point]["presentValue"],
|
package/bacnet_read.html
CHANGED
|
@@ -433,8 +433,20 @@
|
|
|
433
433
|
},
|
|
434
434
|
exportPointListCsv() {
|
|
435
435
|
let app = this;
|
|
436
|
-
let csvContent = "ipAddress,deviceId,deviceName,pointName,objectType" + "\r\n";
|
|
436
|
+
let csvContent = "ipAddress,deviceId,deviceName,pointName,objectType,presentValue,description,units,objectName,displayName,systemStatus,modificationDate,programState,recordCount,hasPriorityArray,vendorName" + "\r\n";
|
|
437
437
|
const keys = Object.keys(app.pointList);
|
|
438
|
+
|
|
439
|
+
// Helper function to safely get property value and escape for CSV
|
|
440
|
+
const getCsvValue = (value) => {
|
|
441
|
+
if (value === null || value === undefined) return "";
|
|
442
|
+
const stringValue = String(value);
|
|
443
|
+
// Escape double quotes and wrap in quotes if contains comma, newline, or double quote
|
|
444
|
+
if (stringValue.includes(',') || stringValue.includes('\n') || stringValue.includes('"')) {
|
|
445
|
+
return '"' + stringValue.replace(/"/g, '""') + '"';
|
|
446
|
+
}
|
|
447
|
+
return stringValue;
|
|
448
|
+
};
|
|
449
|
+
|
|
438
450
|
for (key in keys) {
|
|
439
451
|
const guid = keys[key];
|
|
440
452
|
const ipAddress = guid.split("-")[0];
|
|
@@ -452,16 +464,39 @@
|
|
|
452
464
|
const points = Object.keys(deviceObject);
|
|
453
465
|
if (points.length > 0) {
|
|
454
466
|
for (point in points) {
|
|
467
|
+
const pointData = deviceObject[points[point]] || {};
|
|
455
468
|
csvContent +=
|
|
456
|
-
ipAddress +
|
|
469
|
+
getCsvValue(ipAddress) +
|
|
470
|
+
"," +
|
|
471
|
+
getCsvValue(deviceId) +
|
|
472
|
+
"," +
|
|
473
|
+
getCsvValue(deviceName) +
|
|
474
|
+
"," +
|
|
475
|
+
getCsvValue(points[point]) +
|
|
476
|
+
"," +
|
|
477
|
+
getCsvValue(pointData.meta?.objectId?.type) +
|
|
457
478
|
"," +
|
|
458
|
-
|
|
479
|
+
getCsvValue(pointData.presentValue) +
|
|
459
480
|
"," +
|
|
460
|
-
|
|
481
|
+
getCsvValue(pointData.description) +
|
|
461
482
|
"," +
|
|
462
|
-
|
|
483
|
+
getCsvValue(pointData.units) +
|
|
463
484
|
"," +
|
|
464
|
-
|
|
485
|
+
getCsvValue(pointData.objectName) +
|
|
486
|
+
"," +
|
|
487
|
+
getCsvValue(pointData.displayName) +
|
|
488
|
+
"," +
|
|
489
|
+
getCsvValue(pointData.systemStatus) +
|
|
490
|
+
"," +
|
|
491
|
+
getCsvValue(pointData.modificationDate) +
|
|
492
|
+
"," +
|
|
493
|
+
getCsvValue(pointData.programState) +
|
|
494
|
+
"," +
|
|
495
|
+
getCsvValue(pointData.recordCount) +
|
|
496
|
+
"," +
|
|
497
|
+
getCsvValue(pointData.hasPriorityArray) +
|
|
498
|
+
"," +
|
|
499
|
+
getCsvValue(pointData.vendorName) +
|
|
465
500
|
"\r\n";
|
|
466
501
|
|
|
467
502
|
if (parseInt(point) == points.length - 1 && parseInt(key) == keys.length - 1) {
|
|
@@ -687,14 +722,14 @@
|
|
|
687
722
|
let app = this;
|
|
688
723
|
let device = app.getDeviceFromDeviceList(slotProps.node.ipAddr, slotProps.node.deviceId);
|
|
689
724
|
if (device) {
|
|
690
|
-
app.nodeService.purgeDevice(device).then(function (result) {});
|
|
725
|
+
app.nodeService.purgeDevice(device).then(function (result) { });
|
|
691
726
|
}
|
|
692
727
|
},
|
|
693
728
|
updatePointsForDevice(slotProps) {
|
|
694
729
|
let app = this;
|
|
695
730
|
let device = app.getDeviceFromDeviceList(slotProps.node.ipAddr, slotProps.node.deviceId);
|
|
696
731
|
if (device) {
|
|
697
|
-
app.nodeService.updatePointsForDevice(device).then(function (result) {});
|
|
732
|
+
app.nodeService.updatePointsForDevice(device).then(function (result) { });
|
|
698
733
|
}
|
|
699
734
|
},
|
|
700
735
|
updatePoint(slotProps) {
|
|
@@ -705,7 +740,7 @@
|
|
|
705
740
|
});
|
|
706
741
|
const deviceKey = `${app.getDeviceAddress(device.address)}-${device.deviceId}`;
|
|
707
742
|
if (device) {
|
|
708
|
-
app.nodeService.updatePoint(deviceKey, pointKey).then(function (result) {});
|
|
743
|
+
app.nodeService.updatePoint(deviceKey, pointKey).then(function (result) { });
|
|
709
744
|
}
|
|
710
745
|
},
|
|
711
746
|
setDeviceName() {
|
|
@@ -1708,4 +1743,4 @@
|
|
|
1708
1743
|
<li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
|
|
1709
1744
|
<li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
|
|
1710
1745
|
</ul>
|
|
1711
|
-
</script>
|
|
1746
|
+
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitpoolos/edge-bacnet",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.6",
|
|
4
4
|
"description": "A bacnet gateway for node-red",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@plus4nodered/ts-node-bacnet": "^1.0.0-beta.2",
|
|
@@ -54,4 +54,4 @@
|
|
|
54
54
|
"type": "github",
|
|
55
55
|
"url": "git+https://github.com/bitpool/edge-bacnet.git"
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
}
|
|
@@ -67,9 +67,23 @@ class Client extends events_1.EventEmitter {
|
|
|
67
67
|
}
|
|
68
68
|
// Helper utils
|
|
69
69
|
_getInvokeId() {
|
|
70
|
+
// Try up to 256 times to find an unused invoke ID
|
|
71
|
+
for (let attempts = 0; attempts < 256; attempts++) {
|
|
72
|
+
const id = this._invokeCounter++;
|
|
73
|
+
if (id >= 256) this._invokeCounter = 1;
|
|
74
|
+
|
|
75
|
+
const invokeId = id - 1;
|
|
76
|
+
|
|
77
|
+
// If this invoke ID is not currently in use, return it
|
|
78
|
+
if (!this._invokeStore[invokeId]) {
|
|
79
|
+
return invokeId;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Edge case: if all 256 invoke IDs are in use, fall back to original behavior
|
|
84
|
+
// This prevents infinite loops while maintaining backwards compatibility
|
|
70
85
|
const id = this._invokeCounter++;
|
|
71
|
-
if (id >= 256)
|
|
72
|
-
this._invokeCounter = 1;
|
|
86
|
+
if (id >= 256) this._invokeCounter = 1;
|
|
73
87
|
return id - 1;
|
|
74
88
|
}
|
|
75
89
|
_invokeCallback(id, err, result) {
|