@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 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 reuse
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
- return new Promise((resolve, reject) => {
67
- try {
68
- this.client.whoIs({ net: this.network, lowLimit: this.lowLimit, highLimit: this.highLimit })
69
-
70
- setTimeout(() => {
71
- this.#updateProgress(10)
72
-
73
- this.#readDevices().then(() => {
74
- let validatedDevices = [];
75
- for (let i = 0; i < this.discoveredDevices.length; i++) {
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
- this.msg.payload = validatedDevices;
92
- this.eventEmitter.emit(EVENT_OUTPUT, this.msg);
93
- this.#updateProgress(100)
94
- resolve();
95
- }).catch(error => {
96
- this.#updateProgress(100)
97
- reject(error);
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
- return new Promise((resolve) => {
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, ERR_INVALID_DATA_TYPE,
84
- {
85
- devices: this?.inputDevices,
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
- let deviceNameSet = new Set();
96
- for (let i = 0; i < this.inputDevices.length; i++) {
97
- const device = this.inputDevices[i];
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
- // ensure no duplicate device name
114
- if (deviceNameSet.has(result.deviceName)) {
115
- this.eventEmitter.emit(EVENT_ERROR, errMsg(
116
- this.name, ERR_IGNORE_DUPLICATED_DEVICE_NAME, result
117
- ))
118
- continue
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
- // read all device points
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() {
@@ -39,28 +39,18 @@ module.exports = {
39
39
  }
40
40
 
41
41
  async execute() {
42
- this.#updateProgress(0)
43
-
44
- return new Promise((resolve) => {
45
- try {
46
- if (!this.#validateData()) {
47
- this.#updateProgress(100)
48
- resolve()
49
- return
50
- }
51
-
52
- this.#updateProgress(10)
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
- return new Promise((resolve) => {
49
- try {
50
- if (!this.#validateData()) {
51
- this.#updateProgress(100)
52
- resolve()
53
- return
54
- }
55
-
56
- this.#updateProgress(10)
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() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halsystems/red-bacnet",
3
- "version": "2.2.0-alpha2",
3
+ "version": "2.2.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"