@bitpoolos/edge-bacnet 1.6.3 → 1.6.5
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 +113 -84
- package/bacnet_client.js +41 -35
- package/bacnet_gateway.js +5 -10
- package/bacnet_read.html +29 -34
- package/common.js +17 -78
- package/package.json +1 -1
- package/resources/node-bacstack-ts/dist/lib/client.js +16 -2
- package/treeBuilder.js +668 -627
package/bacnet_read.html
CHANGED
|
@@ -131,10 +131,7 @@
|
|
|
131
131
|
getData(initial) {
|
|
132
132
|
let app = this;
|
|
133
133
|
this.nodeService.getNetworkData().then(function (result) {
|
|
134
|
-
//remove after below fixed
|
|
135
134
|
app.devices = result.renderList;
|
|
136
|
-
//end remove
|
|
137
|
-
|
|
138
135
|
app.deviceList = result.deviceList;
|
|
139
136
|
app.pointList = result.pointList;
|
|
140
137
|
app.pollFrequency = parseInt(result.pollFrequency);
|
|
@@ -665,21 +662,24 @@
|
|
|
665
662
|
// Find the device in the device list
|
|
666
663
|
let device = app.getDeviceFromDeviceList(mstpDevice.ipAddr, mstpDevice.deviceId);
|
|
667
664
|
if (device) {
|
|
668
|
-
app.nodeService
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
665
|
+
app.nodeService
|
|
666
|
+
.updatePointsForDevice(device)
|
|
667
|
+
.then(function (result) {
|
|
668
|
+
updatedCount++;
|
|
669
|
+
})
|
|
670
|
+
.catch(function (error) {
|
|
671
|
+
// Handle error silently
|
|
672
|
+
});
|
|
673
673
|
}
|
|
674
674
|
});
|
|
675
675
|
|
|
676
676
|
// Show user feedback
|
|
677
677
|
if (mstpDevices.length > 0) {
|
|
678
678
|
app.$toast?.add({
|
|
679
|
-
severity:
|
|
680
|
-
summary:
|
|
679
|
+
severity: "info",
|
|
680
|
+
summary: "Update Started",
|
|
681
681
|
detail: `Updating points for ${mstpDevices.length} devices in ${slotProps.node.label}`,
|
|
682
|
-
life: 3000
|
|
682
|
+
life: 3000,
|
|
683
683
|
});
|
|
684
684
|
}
|
|
685
685
|
},
|
|
@@ -687,14 +687,14 @@
|
|
|
687
687
|
let app = this;
|
|
688
688
|
let device = app.getDeviceFromDeviceList(slotProps.node.ipAddr, slotProps.node.deviceId);
|
|
689
689
|
if (device) {
|
|
690
|
-
app.nodeService.purgeDevice(device).then(function (result) {
|
|
690
|
+
app.nodeService.purgeDevice(device).then(function (result) {});
|
|
691
691
|
}
|
|
692
692
|
},
|
|
693
693
|
updatePointsForDevice(slotProps) {
|
|
694
694
|
let app = this;
|
|
695
695
|
let device = app.getDeviceFromDeviceList(slotProps.node.ipAddr, slotProps.node.deviceId);
|
|
696
696
|
if (device) {
|
|
697
|
-
app.nodeService.updatePointsForDevice(device).then(function (result) {
|
|
697
|
+
app.nodeService.updatePointsForDevice(device).then(function (result) {});
|
|
698
698
|
}
|
|
699
699
|
},
|
|
700
700
|
updatePoint(slotProps) {
|
|
@@ -705,7 +705,7 @@
|
|
|
705
705
|
});
|
|
706
706
|
const deviceKey = `${app.getDeviceAddress(device.address)}-${device.deviceId}`;
|
|
707
707
|
if (device) {
|
|
708
|
-
app.nodeService.updatePoint(deviceKey, pointKey).then(function (result) {
|
|
708
|
+
app.nodeService.updatePoint(deviceKey, pointKey).then(function (result) {});
|
|
709
709
|
}
|
|
710
710
|
},
|
|
711
711
|
setDeviceName() {
|
|
@@ -765,27 +765,26 @@
|
|
|
765
765
|
// NEW: Update display name in main devices tree
|
|
766
766
|
updatePointDisplayNameInDevicesTree(deviceKey, pointName, newDisplayName) {
|
|
767
767
|
let app = this;
|
|
768
|
-
let [ipAddress, deviceId] = deviceKey.split(
|
|
768
|
+
let [ipAddress, deviceId] = deviceKey.split("-");
|
|
769
769
|
|
|
770
770
|
// Find the device in main tree
|
|
771
|
-
let deviceIndex = app.devices
|
|
772
|
-
device.ipAddr === ipAddress && device.deviceId.toString() === deviceId)
|
|
771
|
+
let deviceIndex = app.devices
|
|
772
|
+
? app.devices.findIndex((device) => device.ipAddr === ipAddress && device.deviceId.toString() === deviceId)
|
|
773
|
+
: -1;
|
|
773
774
|
|
|
774
775
|
if (deviceIndex !== -1) {
|
|
775
776
|
// Update direct device points
|
|
776
|
-
let pointIndex = app.devices[deviceIndex].children[0].children.findIndex(point =>
|
|
777
|
-
point.pointName === pointName);
|
|
777
|
+
let pointIndex = app.devices[deviceIndex].children[0].children.findIndex((point) => point.pointName === pointName);
|
|
778
778
|
if (pointIndex !== -1) {
|
|
779
779
|
app.devices[deviceIndex].children[0].children[pointIndex].label = newDisplayName;
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
// Update MSTP device points if applicable
|
|
783
|
-
app.devices[deviceIndex].children.forEach(child => {
|
|
783
|
+
app.devices[deviceIndex].children.forEach((child) => {
|
|
784
784
|
if (child.label && child.label.includes("MSTP") && child.children) {
|
|
785
|
-
child.children.forEach(mstpDevice => {
|
|
785
|
+
child.children.forEach((mstpDevice) => {
|
|
786
786
|
if (mstpDevice.deviceId.toString() === deviceId) {
|
|
787
|
-
let mstpPointIndex = mstpDevice.children[0].children.findIndex(point =>
|
|
788
|
-
point.pointName === pointName);
|
|
787
|
+
let mstpPointIndex = mstpDevice.children[0].children.findIndex((point) => point.pointName === pointName);
|
|
789
788
|
if (mstpPointIndex !== -1) {
|
|
790
789
|
mstpDevice.children[0].children[mstpPointIndex].label = newDisplayName;
|
|
791
790
|
}
|
|
@@ -798,17 +797,17 @@
|
|
|
798
797
|
// NEW: Update display name in read devices tree
|
|
799
798
|
updatePointDisplayNameInReadDevicesTree(deviceKey, pointName, newDisplayName) {
|
|
800
799
|
let app = this;
|
|
801
|
-
let [ipAddress, deviceId] = deviceKey.split(
|
|
800
|
+
let [ipAddress, deviceId] = deviceKey.split("-");
|
|
802
801
|
|
|
803
802
|
if (!app.readDevices) return;
|
|
804
803
|
|
|
805
804
|
// Find the device in read devices tree
|
|
806
|
-
let readDeviceIndex = app.readDevices.findIndex(device =>
|
|
807
|
-
device.deviceId.toString() === deviceId);
|
|
805
|
+
let readDeviceIndex = app.readDevices.findIndex((device) => device.deviceId.toString() === deviceId);
|
|
808
806
|
|
|
809
807
|
if (readDeviceIndex !== -1) {
|
|
810
|
-
let pointIndex = app.readDevices[readDeviceIndex].children[0].children.findIndex(
|
|
811
|
-
point.pointName === pointName
|
|
808
|
+
let pointIndex = app.readDevices[readDeviceIndex].children[0].children.findIndex(
|
|
809
|
+
(point) => point.pointName === pointName
|
|
810
|
+
);
|
|
812
811
|
if (pointIndex !== -1) {
|
|
813
812
|
app.readDevices[readDeviceIndex].children[0].children[pointIndex].label = newDisplayName;
|
|
814
813
|
}
|
|
@@ -1097,7 +1096,6 @@
|
|
|
1097
1096
|
let count = 0;
|
|
1098
1097
|
return count;
|
|
1099
1098
|
},
|
|
1100
|
-
|
|
1101
1099
|
},
|
|
1102
1100
|
components: {
|
|
1103
1101
|
"p-tree": primevue.tree,
|
|
@@ -1399,7 +1397,6 @@
|
|
|
1399
1397
|
filterMode="lenient"
|
|
1400
1398
|
filterPlaceholder="No results found."
|
|
1401
1399
|
v-if="hasData()">
|
|
1402
|
-
|
|
1403
1400
|
<template #device="slotProps">
|
|
1404
1401
|
<div @contextmenu="onDeviceRightClick(slotProps, $event)" class="p-treenode-label">
|
|
1405
1402
|
<div v-if="isDeviceActive(slotProps)" class="deviceLabelParent">
|
|
@@ -1439,13 +1436,12 @@
|
|
|
1439
1436
|
</div>
|
|
1440
1437
|
</template>
|
|
1441
1438
|
|
|
1442
|
-
|
|
1443
1439
|
<template #mstpfolder="slotProps">
|
|
1444
1440
|
<div @contextmenu="onMstpFolderRightClick(slotProps, $event)" class="p-treenode-label">
|
|
1445
1441
|
<div class="deviceLabelParent">
|
|
1446
1442
|
<b class="mstpLabel">
|
|
1447
1443
|
<span>{{slotProps.node.label}}</span>
|
|
1448
|
-
<span class="mstpDeviceCount"
|
|
1444
|
+
<span class="mstpDeviceCount">
|
|
1449
1445
|
{{slotProps.node.children ? slotProps.node.children.length : 0}}
|
|
1450
1446
|
</span>
|
|
1451
1447
|
</b>
|
|
@@ -1473,7 +1469,6 @@
|
|
|
1473
1469
|
</button>
|
|
1474
1470
|
</div>
|
|
1475
1471
|
</template>
|
|
1476
|
-
|
|
1477
1472
|
</p-tree>
|
|
1478
1473
|
<div v-else style="text-align: center; padding-top: 20px;">
|
|
1479
1474
|
<a>Building Tree...</a>
|
|
@@ -1713,4 +1708,4 @@
|
|
|
1713
1708
|
<li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
|
|
1714
1709
|
<li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
|
|
1715
1710
|
</ul>
|
|
1716
|
-
</script>
|
|
1711
|
+
</script>
|
package/common.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const { randomUUID } = require("crypto");
|
|
6
6
|
const os = require("os");
|
|
7
|
+
const path = require("path");
|
|
7
8
|
const baEnum = require("./resources/node-bacstack-ts/dist/index.js").enum;
|
|
8
9
|
const fs = require("fs");
|
|
9
10
|
const fs2 = require("fs").promises;
|
|
@@ -189,27 +190,16 @@ const roundDecimalPlaces = function (value, decimals) {
|
|
|
189
190
|
return value;
|
|
190
191
|
};
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
await fs.writeFile("edge-bacnet-datastore.cfg", data, { encoding: "utf8", flag: "w" }, (err) => {
|
|
201
|
-
if (err) {
|
|
202
|
-
console.log("Store_Config writeFile error: ", err);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
} catch (e) {
|
|
206
|
-
//do nothing
|
|
193
|
+
const getStoragePath = (fileName) => {
|
|
194
|
+
const storagePath = process.env.BACNET_STORAGE_PATH;
|
|
195
|
+
if (storagePath) {
|
|
196
|
+
if (!fs.existsSync(storagePath)) {
|
|
197
|
+
fs.mkdirSync(storagePath, { recursive: true });
|
|
198
|
+
}
|
|
199
|
+
return path.join(storagePath, fileName);
|
|
207
200
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
// refactor:
|
|
201
|
+
return fileName;
|
|
202
|
+
};
|
|
213
203
|
|
|
214
204
|
let storeQueue = [];
|
|
215
205
|
let isStoreProcessing = false;
|
|
@@ -235,9 +225,9 @@ async function queueConfigStore(data) {
|
|
|
235
225
|
}
|
|
236
226
|
|
|
237
227
|
async function Store_Config(data) {
|
|
238
|
-
const mainFile = "edge-bacnet-datastore.cfg";
|
|
239
|
-
const tempFile = "edge-bacnet-datastore.cfg.tmp";
|
|
240
|
-
const backupFile = "edge-bacnet-datastore.cfg.bak";
|
|
228
|
+
const mainFile = getStoragePath("edge-bacnet-datastore.cfg");
|
|
229
|
+
const tempFile = getStoragePath("edge-bacnet-datastore.cfg.tmp");
|
|
230
|
+
const backupFile = getStoragePath("edge-bacnet-datastore.cfg.bak");
|
|
241
231
|
|
|
242
232
|
try {
|
|
243
233
|
// First validate the JSON to ensure it's valid before writing
|
|
@@ -295,54 +285,10 @@ async function Store_Config(data) {
|
|
|
295
285
|
}
|
|
296
286
|
}
|
|
297
287
|
|
|
298
|
-
// READ CONFIG SYNC FUNCTION ======================================================
|
|
299
|
-
//
|
|
300
|
-
// ================================================================================
|
|
301
|
-
|
|
302
|
-
function Read_Config_Sync() {
|
|
303
|
-
const mainFile = "edge-bacnet-datastore.cfg";
|
|
304
|
-
const backupFile = "edge-bacnet-datastore.cfg.bak";
|
|
305
|
-
const defaultData = "{}";
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
// Try to read the main file
|
|
309
|
-
let data = fsSync.readFileSync(mainFile, { encoding: "utf8" });
|
|
310
|
-
|
|
311
|
-
// Validate JSON
|
|
312
|
-
try {
|
|
313
|
-
JSON.parse(data);
|
|
314
|
-
return data;
|
|
315
|
-
} catch (jsonError) {
|
|
316
|
-
console.error("Main file contains invalid JSON, attempting backup recovery");
|
|
317
|
-
|
|
318
|
-
// Try to read backup file
|
|
319
|
-
try {
|
|
320
|
-
const backupData = fsSync.readFileSync(backupFile, { encoding: "utf8" });
|
|
321
|
-
JSON.parse(backupData); // Validate backup JSON
|
|
322
|
-
|
|
323
|
-
// Restore from backup
|
|
324
|
-
fsSync.copyFileSync(backupFile, mainFile);
|
|
325
|
-
console.log("Successfully restored from backup file");
|
|
326
|
-
return backupData;
|
|
327
|
-
} catch (backupError) {
|
|
328
|
-
console.error("Backup recovery failed, creating new file");
|
|
329
|
-
fsSync.writeFileSync(mainFile, defaultData, { encoding: "utf8" });
|
|
330
|
-
return defaultData;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
} catch (error) {
|
|
334
|
-
console.error("Error reading config:", error);
|
|
335
|
-
fsSync.writeFileSync(mainFile, defaultData, { encoding: "utf8" });
|
|
336
|
-
return defaultData;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// refactor:
|
|
341
|
-
|
|
342
288
|
async function Read_Config_Async() {
|
|
343
289
|
// todo rename function, not using sync
|
|
344
|
-
const mainFile = "edge-bacnet-datastore.cfg";
|
|
345
|
-
const backupFile = "edge-bacnet-datastore.cfg.bak";
|
|
290
|
+
const mainFile = getStoragePath("edge-bacnet-datastore.cfg");
|
|
291
|
+
const backupFile = getStoragePath("edge-bacnet-datastore.cfg.bak");
|
|
346
292
|
const defaultData = "{}";
|
|
347
293
|
|
|
348
294
|
try {
|
|
@@ -366,15 +312,11 @@ async function Read_Config_Async() {
|
|
|
366
312
|
await fs.copyFile(backupFile, mainFile);
|
|
367
313
|
console.log("Successfully restored from backup file");
|
|
368
314
|
|
|
369
|
-
console.log("log2");
|
|
370
|
-
|
|
371
315
|
return backupData;
|
|
372
316
|
} catch (backupError) {
|
|
373
317
|
console.error("Backup recovery failed, creating new file");
|
|
374
318
|
await Store_Config(defaultData);
|
|
375
319
|
|
|
376
|
-
console.log("log3");
|
|
377
|
-
|
|
378
320
|
return defaultData;
|
|
379
321
|
}
|
|
380
322
|
}
|
|
@@ -382,8 +324,6 @@ async function Read_Config_Async() {
|
|
|
382
324
|
console.error("Error reading config:", error);
|
|
383
325
|
await Store_Config(defaultData);
|
|
384
326
|
|
|
385
|
-
console.log("log4");
|
|
386
|
-
|
|
387
327
|
return defaultData;
|
|
388
328
|
}
|
|
389
329
|
}
|
|
@@ -393,7 +333,7 @@ async function Read_Config_Async() {
|
|
|
393
333
|
// ================================================================================
|
|
394
334
|
async function Store_Config_Server(data) {
|
|
395
335
|
try {
|
|
396
|
-
await fs.writeFile("edge-bacnet-server-datastore.cfg", data, (err) => {
|
|
336
|
+
await fs.writeFile(getStoragePath("edge-bacnet-server-datastore.cfg"), data, (err) => {
|
|
397
337
|
if (err) {
|
|
398
338
|
//console.log("Store_Config_Server writeFile error: ", err);
|
|
399
339
|
}
|
|
@@ -407,7 +347,7 @@ async function Store_Config_Server(data) {
|
|
|
407
347
|
function Read_Config_Sync_Server() {
|
|
408
348
|
var data = "{}";
|
|
409
349
|
try {
|
|
410
|
-
data = fs.readFileSync("edge-bacnet-server-datastore.cfg", { encoding: "utf8", flag: "r" });
|
|
350
|
+
data = fs.readFileSync(getStoragePath("edge-bacnet-server-datastore.cfg"), { encoding: "utf8", flag: "r" });
|
|
411
351
|
} catch (err) {
|
|
412
352
|
if (err.errno == -4058) {
|
|
413
353
|
data = "{}";
|
|
@@ -485,7 +425,6 @@ module.exports = {
|
|
|
485
425
|
roundDecimalPlaces,
|
|
486
426
|
queueConfigStore,
|
|
487
427
|
Store_Config,
|
|
488
|
-
Read_Config_Sync,
|
|
489
428
|
Read_Config_Async,
|
|
490
429
|
Store_Config_Server,
|
|
491
430
|
Read_Config_Sync_Server,
|
package/package.json
CHANGED
|
@@ -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) {
|