@halsystems/red-bacnet 2.2.0-alpha2 → 2.2.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/CHANGELOG.md +8 -0
- package/common/job/discover_device.js +29 -41
- package/common/job/discover_point.js +46 -59
- package/common/job/read_point.js +14 -23
- package/common/job/write_point.js +11 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.2.1]
|
|
4
|
+
### Fixed
|
|
5
|
+
- Fixed unhandled promise rejections in BACnet `jobs` that could hang the job queue or crash Node-RED; errors are now reported instead.
|
|
6
|
+
|
|
7
|
+
## [2.2.0]
|
|
8
|
+
### Changed
|
|
9
|
+
- Matched v2.2.0-alpha.2 release
|
|
10
|
+
|
|
3
11
|
## [2.2.0-alpha.2]
|
|
4
12
|
### Changed
|
|
5
13
|
- all `nodes` retained original `msg` properties
|
|
@@ -56,52 +56,40 @@ module.exports = {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
async execute() {
|
|
59
|
-
// discover device job will be
|
|
60
|
-
this.knownDevices.clear()
|
|
59
|
+
// discover device job will be reused
|
|
60
|
+
this.knownDevices.clear();
|
|
61
61
|
this.discoverList = [];
|
|
62
62
|
this.discoveredDevices = [];
|
|
63
63
|
|
|
64
|
-
this.#updateProgress(0)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const device = this.discoveredDevices[i];
|
|
77
|
-
const { error, value: result } = bacnetDeviceSchema.validate(device);
|
|
78
|
-
|
|
79
|
-
if (error) {
|
|
80
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
81
|
-
this.name, `BACnet device schema validation error (${device.deviceId})`, error
|
|
82
|
-
))
|
|
83
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
84
|
-
this.name, `${ERR_SCHEMA_VALIDATION} (${device.deviceId})`, error
|
|
85
|
-
))
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
validatedDevices.push(result);
|
|
89
|
-
}
|
|
64
|
+
this.#updateProgress(0);
|
|
65
|
+
try {
|
|
66
|
+
this.client.whoIs({ net: this.network, lowLimit: this.lowLimit, highLimit: this.highLimit });
|
|
67
|
+
|
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, this.whoIsTimeout));
|
|
69
|
+
|
|
70
|
+
this.#updateProgress(10);
|
|
71
|
+
await this.#readDevices();
|
|
72
|
+
|
|
73
|
+
const validatedDevices = [];
|
|
74
|
+
for (const device of this.discoveredDevices) {
|
|
75
|
+
const { error, value: result } = bacnetDeviceSchema.validate(device);
|
|
90
76
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
}, this.whoIsTimeout);
|
|
100
|
-
} catch (err) {
|
|
101
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)))
|
|
102
|
-
resolve();
|
|
77
|
+
if (error) {
|
|
78
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
79
|
+
this.name, `${ERR_SCHEMA_VALIDATION} (${device.deviceId})`, error
|
|
80
|
+
));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
validatedDevices.push(result);
|
|
103
84
|
}
|
|
104
|
-
|
|
85
|
+
|
|
86
|
+
this.msg.payload = validatedDevices;
|
|
87
|
+
this.eventEmitter.emit(EVENT_OUTPUT, this.msg);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)));
|
|
90
|
+
} finally {
|
|
91
|
+
this.#updateProgress(100);
|
|
92
|
+
}
|
|
105
93
|
}
|
|
106
94
|
|
|
107
95
|
/**
|
|
@@ -73,73 +73,60 @@ module.exports = {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
async execute() {
|
|
76
|
-
this.#updateProgress('discovering')
|
|
76
|
+
this.#updateProgress('discovering');
|
|
77
|
+
try {
|
|
78
|
+
// validate devices
|
|
79
|
+
if (!Array.isArray(this.inputDevices)) {
|
|
80
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
81
|
+
this.name, ERR_INVALID_DATA_TYPE,
|
|
82
|
+
{
|
|
83
|
+
devices: this?.inputDevices,
|
|
84
|
+
expected: 'array',
|
|
85
|
+
example: EG_BACNET_DEVICES
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const deviceNameSet = new Set();
|
|
92
|
+
for (const device of this.inputDevices) {
|
|
93
|
+
const { error, value: result } = bacnetDeviceSchema.validate(
|
|
94
|
+
device,
|
|
95
|
+
{ stripUnknown: true }
|
|
96
|
+
);
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
// validate devices
|
|
81
|
-
if (!Array.isArray(this.inputDevices)) {
|
|
98
|
+
if (error) {
|
|
82
99
|
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
83
|
-
this.name,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
expected: 'array',
|
|
87
|
-
example: EG_BACNET_DEVICES
|
|
88
|
-
})
|
|
89
|
-
)
|
|
90
|
-
this.#updateProgress('completed')
|
|
91
|
-
resolve();
|
|
92
|
-
return
|
|
100
|
+
this.name, ERR_SCHEMA_VALIDATION, error
|
|
101
|
+
));
|
|
102
|
+
continue;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const { error, value: result } = bacnetDeviceSchema.validate(
|
|
99
|
-
device,
|
|
100
|
-
{ stripUnknown: true }
|
|
101
|
-
);
|
|
102
|
-
// if device id is null, set to 4194303
|
|
103
|
-
if (result.deviceId == null)
|
|
104
|
-
result.deviceId = 4194303;
|
|
105
|
-
|
|
106
|
-
if (error) {
|
|
107
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
108
|
-
this.name, ERR_SCHEMA_VALIDATION, error
|
|
109
|
-
))
|
|
110
|
-
continue
|
|
111
|
-
}
|
|
105
|
+
// if device id is null, set to 4194303
|
|
106
|
+
if (result.deviceId == null)
|
|
107
|
+
result.deviceId = 4194303;
|
|
112
108
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
deviceNameSet.add(result.deviceName);
|
|
121
|
-
|
|
122
|
-
// add device to list
|
|
123
|
-
this.devices.push(result);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// If no valid devices, complete immediately
|
|
127
|
-
if (this.devices.length === 0) {
|
|
128
|
-
this.#updateProgress('completed')
|
|
129
|
-
resolve();
|
|
130
|
-
return
|
|
109
|
+
// ensure no duplicate device name
|
|
110
|
+
if (deviceNameSet.has(result.deviceName)) {
|
|
111
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(
|
|
112
|
+
this.name, ERR_IGNORE_DUPLICATED_DEVICE_NAME, result
|
|
113
|
+
));
|
|
114
|
+
continue;
|
|
131
115
|
}
|
|
116
|
+
deviceNameSet.add(result.deviceName);
|
|
132
117
|
|
|
133
|
-
|
|
134
|
-
this.#readAllDevicePoints().then(() => {
|
|
135
|
-
this.#updateProgress('completed')
|
|
136
|
-
resolve();
|
|
137
|
-
});
|
|
138
|
-
} catch (err) {
|
|
139
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)))
|
|
140
|
-
resolve();
|
|
118
|
+
this.devices.push(result);
|
|
141
119
|
}
|
|
142
|
-
|
|
120
|
+
|
|
121
|
+
// If no valid devices, nothing to do
|
|
122
|
+
if (this.devices.length === 0) return;
|
|
123
|
+
|
|
124
|
+
await this.#readAllDevicePoints();
|
|
125
|
+
} catch (err) {
|
|
126
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)));
|
|
127
|
+
} finally {
|
|
128
|
+
this.#updateProgress('completed');
|
|
129
|
+
}
|
|
143
130
|
}
|
|
144
131
|
|
|
145
132
|
async #readAllDevicePoints() {
|
package/common/job/read_point.js
CHANGED
|
@@ -39,28 +39,18 @@ module.exports = {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async execute() {
|
|
42
|
-
this.#updateProgress(0)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.#readPoints().then(() => {
|
|
55
|
-
this.#exportPoints();
|
|
56
|
-
this.#updateProgress(100)
|
|
57
|
-
resolve();
|
|
58
|
-
});
|
|
59
|
-
} catch (err) {
|
|
60
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)))
|
|
61
|
-
resolve();
|
|
62
|
-
}
|
|
63
|
-
})
|
|
42
|
+
this.#updateProgress(0);
|
|
43
|
+
try {
|
|
44
|
+
if (!this.#validateData()) return;
|
|
45
|
+
|
|
46
|
+
this.#updateProgress(10);
|
|
47
|
+
await this.#readPoints();
|
|
48
|
+
this.#exportPoints();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)));
|
|
51
|
+
} finally {
|
|
52
|
+
this.#updateProgress(100);
|
|
53
|
+
}
|
|
64
54
|
}
|
|
65
55
|
|
|
66
56
|
#validateData() {
|
|
@@ -284,8 +274,9 @@ module.exports = {
|
|
|
284
274
|
}
|
|
285
275
|
|
|
286
276
|
// add to result
|
|
277
|
+
const num = typeof value === 'number' ? value : null;
|
|
287
278
|
this.pointsList[`${p.deviceName}${this.devicePointSeparator}${p.pointName}`] = {
|
|
288
|
-
value: facetObj.precision != null ? +value.toFixed(facetObj.precision) : value,
|
|
279
|
+
value: (num != null && facetObj.precision != null) ? +value.toFixed(facetObj.precision) : value,
|
|
289
280
|
fvalue: fvalue,
|
|
290
281
|
}
|
|
291
282
|
if (err)
|
|
@@ -43,27 +43,17 @@ module.exports = {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async execute() {
|
|
46
|
-
this.#updateProgress(0)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.#writePoints().then(() => {
|
|
59
|
-
this.#updateProgress(100)
|
|
60
|
-
resolve();
|
|
61
|
-
});
|
|
62
|
-
} catch (err) {
|
|
63
|
-
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)))
|
|
64
|
-
resolve();
|
|
65
|
-
}
|
|
66
|
-
})
|
|
46
|
+
this.#updateProgress(0);
|
|
47
|
+
try {
|
|
48
|
+
if (!this.#validateData()) return;
|
|
49
|
+
|
|
50
|
+
this.#updateProgress(10);
|
|
51
|
+
await this.#writePoints();
|
|
52
|
+
} catch (err) {
|
|
53
|
+
this.eventEmitter.emit(EVENT_ERROR, errMsg(this.name, ERR_GENERIC, getErrMsg(err)));
|
|
54
|
+
} finally {
|
|
55
|
+
this.#updateProgress(100);
|
|
56
|
+
}
|
|
67
57
|
}
|
|
68
58
|
|
|
69
59
|
#validateData() {
|