@halsystems/red-bacnet 1.1.0 → 1.1.2
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 +12 -0
- package/common/bacnet.js +18 -9
- package/common/core/concurrent.js +6 -2
- package/common/job/discover_point.js +10 -7
- package/common/job/read_point.js +4 -2
- package/common/job/write_point.js +9 -3
- package/ext/node-bacstack/dist/lib/bvlc.js +1 -0
- package/ext/node-bacstack/dist/lib/transport.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.2]
|
|
4
|
+
### Change
|
|
5
|
+
- WritePoint to not fail if point not found in points config, only raise error
|
|
6
|
+
|
|
7
|
+
## [1.1.1]
|
|
8
|
+
### Added
|
|
9
|
+
- Unit test for BACnet string points
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Reading offline device points run infinitely
|
|
13
|
+
- Unit test failure
|
|
14
|
+
|
|
3
15
|
## [1.1.0]
|
|
4
16
|
### Changed
|
|
5
17
|
- Implemented auto resize batch size when querying using readPropertyMultiple to improve performance
|
package/common/bacnet.js
CHANGED
|
@@ -115,7 +115,6 @@ module.exports = {
|
|
|
115
115
|
if (item?.type === 105) break
|
|
116
116
|
|
|
117
117
|
result.push(item);
|
|
118
|
-
console.log(item)
|
|
119
118
|
} catch (err) {
|
|
120
119
|
void err
|
|
121
120
|
break;
|
|
@@ -155,13 +154,15 @@ module.exports = {
|
|
|
155
154
|
* maximum concurrent point to read in single read mode
|
|
156
155
|
* @param {number} singleReadFailedRetry
|
|
157
156
|
* retry times for single read failed
|
|
157
|
+
* @param {number} concurrentTaskDelay
|
|
158
|
+
* delay between concurrent tasks
|
|
158
159
|
* @returns array of objects
|
|
159
160
|
* eg: [{type: 12, value: {type: 8, instance: 123}, ...],
|
|
160
161
|
* @async
|
|
161
162
|
*/
|
|
162
163
|
smartReadProperty: async function (
|
|
163
164
|
client, device, reqArr, readMethod = 1, maxConcurrentSinglePointRead = 5,
|
|
164
|
-
singleReadFailedRetry = 5
|
|
165
|
+
singleReadFailedRetry = 5, concurrentTaskDelay = 50
|
|
165
166
|
) {
|
|
166
167
|
/* reqArr example
|
|
167
168
|
[{
|
|
@@ -182,8 +183,11 @@ module.exports = {
|
|
|
182
183
|
batchSizes.add(20);
|
|
183
184
|
else {
|
|
184
185
|
const perValueBytes = [30] // typical numeric point is 17 byte
|
|
185
|
-
for (let x = 0; x < perValueBytes.length; x++)
|
|
186
|
-
|
|
186
|
+
for (let x = 0; x < perValueBytes.length; x++) {
|
|
187
|
+
let batchSize = Math.trunc(device.maxApdu / perValueBytes[x])
|
|
188
|
+
if (batchSize > 0)
|
|
189
|
+
batchSizes.add(batchSize)
|
|
190
|
+
}
|
|
187
191
|
}
|
|
188
192
|
}
|
|
189
193
|
|
|
@@ -261,7 +265,6 @@ module.exports = {
|
|
|
261
265
|
if (!success) {
|
|
262
266
|
let failedCount = 0
|
|
263
267
|
let result_single = []
|
|
264
|
-
|
|
265
268
|
const dummyEventEmitter = new EventEmitter();
|
|
266
269
|
const tasks = reqArr.slice(reqArrIndexNext).flatMap((req, x) =>
|
|
267
270
|
req.properties.map((prop, y) => ({
|
|
@@ -285,7 +288,8 @@ module.exports = {
|
|
|
285
288
|
return value;
|
|
286
289
|
} catch (err) {
|
|
287
290
|
failedCount++;
|
|
288
|
-
if (readMethod < 1 && failedCount >= singleReadFailedRetry)
|
|
291
|
+
// if (readMethod < 1 && failedCount >= singleReadFailedRetry)
|
|
292
|
+
if (failedCount >= singleReadFailedRetry)
|
|
289
293
|
throw err
|
|
290
294
|
}
|
|
291
295
|
}
|
|
@@ -293,7 +297,7 @@ module.exports = {
|
|
|
293
297
|
);
|
|
294
298
|
|
|
295
299
|
try {
|
|
296
|
-
await concurrentTasks(dummyEventEmitter, tasks, maxConcurrentSinglePointRead);
|
|
300
|
+
await concurrentTasks(dummyEventEmitter, tasks, maxConcurrentSinglePointRead, concurrentTaskDelay);
|
|
297
301
|
} catch (err) {
|
|
298
302
|
void err
|
|
299
303
|
}
|
|
@@ -342,9 +346,14 @@ module.exports = {
|
|
|
342
346
|
* @param {EventEmitter} eventEmitter
|
|
343
347
|
* @param {number} maxConcurrentWrite
|
|
344
348
|
* maximum concurrent point to write
|
|
349
|
+
* @param {number} concurrentTaskDelay
|
|
350
|
+
* delay between concurrent tasks
|
|
345
351
|
* @async
|
|
346
352
|
*/
|
|
347
|
-
smartWriteProperty: async function (
|
|
353
|
+
smartWriteProperty: async function (
|
|
354
|
+
client, device, writePoints, eventEmitter, maxConcurrentWrite,
|
|
355
|
+
concurrentTaskDelay = 50
|
|
356
|
+
) {
|
|
348
357
|
const entries = Object.entries(writePoints);
|
|
349
358
|
|
|
350
359
|
// current writePropertyMultiple will throw ERR_TIMEOUT if any of the write fails
|
|
@@ -370,7 +379,7 @@ module.exports = {
|
|
|
370
379
|
}
|
|
371
380
|
}));
|
|
372
381
|
|
|
373
|
-
await concurrentTasks(eventEmitter, tasks, maxConcurrentWrite);
|
|
382
|
+
await concurrentTasks(eventEmitter, tasks, maxConcurrentWrite, concurrentTaskDelay);
|
|
374
383
|
|
|
375
384
|
// write properties multiples example
|
|
376
385
|
// const values = [
|
|
@@ -17,10 +17,13 @@ module.exports = {
|
|
|
17
17
|
* @param {EventEmitter} eventEmitter - The event emitter to emit events to.
|
|
18
18
|
* @param {Array} tasks - The list of tasks to execute.
|
|
19
19
|
* @param {number} maxConcurrent - The maximum number of concurrent tasks.
|
|
20
|
+
* @param {number} concurrentTaskDelay - The delay between concurrent tasks.
|
|
20
21
|
* @returns {Promise<Array>} - A promise that resolves with an array of results.
|
|
21
22
|
* @async
|
|
22
23
|
*/
|
|
23
|
-
concurrentTasks: async function (
|
|
24
|
+
concurrentTasks: async function (
|
|
25
|
+
eventEmitter, tasks, maxConcurrent, concurrentTaskDelay = 50
|
|
26
|
+
) {
|
|
24
27
|
const executing = new Set();
|
|
25
28
|
const results = [];
|
|
26
29
|
|
|
@@ -44,7 +47,8 @@ module.exports = {
|
|
|
44
47
|
await Promise.race(executing);
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
if (concurrentTaskDelay > 0)
|
|
51
|
+
await delay(concurrentTaskDelay)
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
await Promise.allSettled(executing);
|
|
@@ -53,7 +53,8 @@ module.exports = {
|
|
|
53
53
|
|
|
54
54
|
constructor(
|
|
55
55
|
client, eventEmitter, inputDevices, discoverMode, readMethod, groupExportDeviceCount,
|
|
56
|
-
maxConcurrentDeviceRead, maxConcurrentSinglePointRead,
|
|
56
|
+
maxConcurrentDeviceRead, maxConcurrentSinglePointRead, concurrentTaskDelay = 50,
|
|
57
|
+
name = 'discover point'
|
|
57
58
|
) {
|
|
58
59
|
super();
|
|
59
60
|
this.client = client
|
|
@@ -64,6 +65,7 @@ module.exports = {
|
|
|
64
65
|
this.groupExportDeviceCount = groupExportDeviceCount
|
|
65
66
|
this.maxConcurrentDeviceRead = maxConcurrentDeviceRead
|
|
66
67
|
this.maxConcurrentSinglePointRead = maxConcurrentSinglePointRead
|
|
68
|
+
this.concurrentTaskDelay = concurrentTaskDelay
|
|
67
69
|
this.name = name
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -194,7 +196,7 @@ module.exports = {
|
|
|
194
196
|
|
|
195
197
|
return await readPoints(
|
|
196
198
|
d, objectListFinal, discoverPointEvent, this.name, this.client, this.readMethod,
|
|
197
|
-
this.maxConcurrentSinglePointRead
|
|
199
|
+
this.maxConcurrentSinglePointRead, this.concurrentTaskDelay
|
|
198
200
|
);
|
|
199
201
|
} catch (error) {
|
|
200
202
|
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, `Error reading ${d.deviceName} points`, error));
|
|
@@ -237,7 +239,8 @@ module.exports = {
|
|
|
237
239
|
|
|
238
240
|
// ---------------------------------- functions ----------------------------------
|
|
239
241
|
const readPoints = async (
|
|
240
|
-
device, objects, eventEmitter, name, client, readMethod, maxConcurrentSinglePointRead
|
|
242
|
+
device, objects, eventEmitter, name, client, readMethod, maxConcurrentSinglePointRead,
|
|
243
|
+
concurrentTaskDelay
|
|
241
244
|
) => {
|
|
242
245
|
const points = [];
|
|
243
246
|
|
|
@@ -258,7 +261,7 @@ const readPoints = async (
|
|
|
258
261
|
try {
|
|
259
262
|
// First request - get basic properties
|
|
260
263
|
const result = await smartReadProperty(
|
|
261
|
-
client, device, reqArr, readMethod, maxConcurrentSinglePointRead, 50
|
|
264
|
+
client, device, reqArr, readMethod, maxConcurrentSinglePointRead, 50, concurrentTaskDelay
|
|
262
265
|
);
|
|
263
266
|
|
|
264
267
|
// Process basic properties first
|
|
@@ -279,7 +282,7 @@ const readPoints = async (
|
|
|
279
282
|
try {
|
|
280
283
|
// Force use single read on state text to reduce loss especially long text
|
|
281
284
|
const stateTextResult = await smartReadProperty(
|
|
282
|
-
client, device, stateTextReqArr, 0, 1, 50
|
|
285
|
+
client, device, stateTextReqArr, 0, 1, 50, concurrentTaskDelay
|
|
283
286
|
);
|
|
284
287
|
|
|
285
288
|
// Update points with STATE_TEXT
|
|
@@ -374,7 +377,7 @@ const setPointValues = (point, i) => {
|
|
|
374
377
|
|
|
375
378
|
const processValue = (value, facets) => {
|
|
376
379
|
if (value?.errorClass != null && value?.errorCode != null) return null;
|
|
377
|
-
const match = facets
|
|
380
|
+
const match = facets?.match(/precision:(\d+)/);
|
|
378
381
|
const precision = match ? +match[1] : null;
|
|
379
382
|
|
|
380
383
|
if (typeof value === 'number')
|
|
@@ -382,4 +385,4 @@ const processValue = (value, facets) => {
|
|
|
382
385
|
else
|
|
383
386
|
return value
|
|
384
387
|
|
|
385
|
-
};
|
|
388
|
+
};
|
package/common/job/read_point.js
CHANGED
|
@@ -23,7 +23,7 @@ module.exports = {
|
|
|
23
23
|
|
|
24
24
|
constructor(
|
|
25
25
|
client, eventEmitter, devices, points, readMethod, maxConcurrentDeviceRead = 2,
|
|
26
|
-
maxConcurrentSinglePointRead = 5, name = 'read point'
|
|
26
|
+
maxConcurrentSinglePointRead = 5, concurrentTaskDelay = 50, name = 'read point'
|
|
27
27
|
) {
|
|
28
28
|
super();
|
|
29
29
|
this.client = client
|
|
@@ -33,6 +33,7 @@ module.exports = {
|
|
|
33
33
|
this.readMethod = readMethod
|
|
34
34
|
this.maxConcurrentDeviceRead = maxConcurrentDeviceRead
|
|
35
35
|
this.maxConcurrentSinglePointRead = maxConcurrentSinglePointRead
|
|
36
|
+
this.concurrentTaskDelay = concurrentTaskDelay
|
|
36
37
|
this.name = name
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -219,7 +220,8 @@ module.exports = {
|
|
|
219
220
|
id: k,
|
|
220
221
|
task: async () => {
|
|
221
222
|
return await smartReadProperty(
|
|
222
|
-
this.client, v.device, v.points, this.readMethod,
|
|
223
|
+
this.client, v.device, v.points, this.readMethod,
|
|
224
|
+
this.maxConcurrentSinglePointRead, 10, this.concurrentTaskDelay
|
|
223
225
|
);
|
|
224
226
|
}
|
|
225
227
|
}));
|
|
@@ -25,6 +25,7 @@ module.exports = {
|
|
|
25
25
|
constructor(
|
|
26
26
|
client, eventEmitter, devices, points, writePoints,
|
|
27
27
|
maxConcurrentDeviceWrite = 2, maxConcurrentPointWrite = 1,
|
|
28
|
+
concurrentTaskDelay = 50,
|
|
28
29
|
name = 'write point'
|
|
29
30
|
) {
|
|
30
31
|
super();
|
|
@@ -35,6 +36,7 @@ module.exports = {
|
|
|
35
36
|
this.writePoints = writePoints
|
|
36
37
|
this.maxConcurrentDeviceWrite = maxConcurrentDeviceWrite
|
|
37
38
|
this.maxConcurrentPointWrite = maxConcurrentPointWrite
|
|
39
|
+
this.concurrentTaskDelay = concurrentTaskDelay
|
|
38
40
|
this.name = name
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -231,10 +233,14 @@ module.exports = {
|
|
|
231
233
|
});
|
|
232
234
|
|
|
233
235
|
if (missingPoints.length > 0) {
|
|
236
|
+
// do not fail writing, just log the missing points and remove them from writePoints
|
|
234
237
|
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
235
238
|
this.name, ERR_WRITE_POINT_NOT_FOUND, missingPoints
|
|
236
239
|
))
|
|
237
|
-
|
|
240
|
+
|
|
241
|
+
missingPoints.forEach(point => {
|
|
242
|
+
delete this.writePointDetails[point];
|
|
243
|
+
});
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
if (priorityErrList.length > 0) {
|
|
@@ -277,7 +283,7 @@ module.exports = {
|
|
|
277
283
|
task: async () => {
|
|
278
284
|
return await smartWriteProperty(
|
|
279
285
|
this.client, v.device, v.writePoints, smartWriteEvent,
|
|
280
|
-
this.maxConcurrentPointWrite
|
|
286
|
+
this.maxConcurrentPointWrite, this.concurrentTaskDelay
|
|
281
287
|
);
|
|
282
288
|
}
|
|
283
289
|
}));
|
|
@@ -302,4 +308,4 @@ module.exports = {
|
|
|
302
308
|
}
|
|
303
309
|
|
|
304
310
|
}
|
|
305
|
-
}
|
|
311
|
+
}
|
|
@@ -46,6 +46,7 @@ const decode = (buffer, offset) => {
|
|
|
46
46
|
if (isValidIp && isValidPort && !isBroadcast && !isMulticast && !isZero) {
|
|
47
47
|
const ip = ipParts.join(".");
|
|
48
48
|
linkAddress = (port === 47808) ? ip : `${ip}:${port}`;
|
|
49
|
+
// linkAddress = `${ip}:${port}`;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
break;
|
|
@@ -14,6 +14,7 @@ class Transport extends events_1.EventEmitter {
|
|
|
14
14
|
this._server.on('message', (msg, rinfo) => {
|
|
15
15
|
// NOTE HAL modified
|
|
16
16
|
const port = rinfo.port || DEFAULT_BACNET_PORT;
|
|
17
|
+
// this.emit('message', msg, `${rinfo.address}:${port}`);
|
|
17
18
|
if (port === DEFAULT_BACNET_PORT)
|
|
18
19
|
this.emit('message', msg, rinfo.address);
|
|
19
20
|
else
|