@bitpoolos/edge-bacnet 1.6.2 → 1.6.4
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 +114 -66
- package/bacnet_client.js +65 -56
- package/bacnet_gateway.html +233 -18
- package/bacnet_gateway.js +41 -8
- package/bacnet_inspector.js +88 -12
- package/bacnet_inspector_worker.js +13 -3
- package/bacnet_read.html +223 -7
- package/bacnet_read.js +13 -1
- package/common.js +17 -78
- package/inspector.html +35 -1
- package/package.json +2 -2
- package/resources/style.css +28 -1
- package/treeBuilder.js +683 -567
package/CHANGELOG.md
CHANGED
|
@@ -1,39 +1,80 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.4] - 02-09-2025
|
|
4
|
+
|
|
5
|
+
Minor feature:
|
|
6
|
+
|
|
7
|
+
- Small update to file read / write logic for database files. Some deployments require a different storage location outside of the default. If a nodejs environment variable of BACNET_STORAGE_PATH is defined and set for that deployment, it will prefix that location to the file path, otherwise functionality will remain the same.
|
|
8
|
+
|
|
9
|
+
Bug fix:
|
|
10
|
+
|
|
11
|
+
- Some mstp devices were not showing in device list UI tree.
|
|
12
|
+
|
|
13
|
+
## [1.6.3] - 01-06-2025
|
|
14
|
+
|
|
15
|
+
Minor feature:
|
|
16
|
+
|
|
17
|
+
- Device List - new right click option to MSTP NET folders - Update All Devices. Specifically updates the mstp device listed in that selected network
|
|
18
|
+
- Inspector - Added statistic percentages as MQTT output in the Inspector node
|
|
19
|
+
- Inspector - Added online / offline stats and Total points to read as status on node
|
|
20
|
+
- Test Functions - Outputs results to both node-red console and node-red debug window now
|
|
21
|
+
|
|
22
|
+
Minor update / refactor:
|
|
23
|
+
|
|
24
|
+
- Datamodel - Importing and Exporting datamodel displays process status and related stats (file size etc) while importing or exporting, informing the user of current state
|
|
25
|
+
- Device List - UI tree no longer stored in datamodel, as it is generated dynamically on a schedule. This significantly reduces datamodel file size, read / write time, system start up processes.
|
|
26
|
+
- Datamodel - writes to file system for persistance and backup was being executed more often than needed. Process schedule is now on a larger interval, and write algorithm refactored and optimized.
|
|
27
|
+
- Device List - right click -> Set Point Name feature refactored, due to many scenarios where it wasnt executing as expected.
|
|
28
|
+
- BACnet read output - error and status field setting optimized
|
|
29
|
+
- Inspector - updated ObjectType column values to show object type enum string instead of integer
|
|
30
|
+
|
|
31
|
+
Bug fixes:
|
|
32
|
+
|
|
33
|
+
- Inspector - incorrect percentages, statistics and values in the statistics bar. Fixed and tested to represent site status more accurately
|
|
34
|
+
- Inpsector - not flagging offline points in error statistic and table filter. Now correctly identifies "offline" points as an Error type
|
|
35
|
+
- BACnet read output - was not updating error and status correctly for full object payloads.
|
|
36
|
+
- BACnet Server - was not outputting sucessfull write update MQTT msg after node-red deploy.
|
|
37
|
+
|
|
38
|
+
Updating:
|
|
39
|
+
|
|
40
|
+
- There shouldnt be a need for users to remove nodes or do any specific action when updating to this version, however backing up a datamodel export is advised.
|
|
41
|
+
|
|
3
42
|
## [1.6.2] - 07-05-2025
|
|
4
43
|
|
|
5
|
-
Minor feature:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
44
|
+
Minor feature:
|
|
45
|
+
|
|
46
|
+
- Added "Enable device discovery" check box to gateway settings, discovery tab.
|
|
47
|
+
- This check box controls whether on not the auto point discovery and property discovery is enabled.
|
|
48
|
+
- This can be used to turn off unecessary network traffic once you have discovered all of the desired devices and points.
|
|
49
|
+
- IMPORTANT - if you are updating a existing deployment, the new property will be unticked, however new installs / dragging from the pallete will by default have the option checked. So if you want to keep this enabled on an existing deployment, please check the setting.
|
|
50
|
+
- Note - This does not turn off the whoIs task schedule.
|
|
51
|
+
- A user can use Right Click -> Update points on desired deviced in the read node tree if you would like to manually discover devices.
|
|
12
52
|
|
|
13
|
-
Minor update:
|
|
14
|
-
- Adjusted initial whoIs broadcast delay from 5seconds to 15seconds after node-red is started with a deployed gateway. This is to ensure large cached files are completely read and loaded.
|
|
53
|
+
Minor update:
|
|
15
54
|
|
|
16
|
-
|
|
17
|
-
- Inspector:
|
|
18
|
-
- Table resized to avoid scroll bars
|
|
19
|
-
- Percentage rounding to nearest 2 decimal places rather than whole integer for more detailed data.
|
|
20
|
-
- Loading animation added
|
|
21
|
-
- NAN years ago - removed as invalid time differential
|
|
22
|
-
- Last seen for device points adjusted to be more accurate
|
|
55
|
+
- Adjusted initial whoIs broadcast delay from 5seconds to 15seconds after node-red is started with a deployed gateway. This is to ensure large cached files are completely read and loaded.
|
|
23
56
|
|
|
24
|
-
|
|
57
|
+
Bug fixes:
|
|
58
|
+
|
|
59
|
+
- Inspector:
|
|
60
|
+
- Table resized to avoid scroll bars
|
|
61
|
+
- Percentage rounding to nearest 2 decimal places rather than whole integer for more detailed data.
|
|
62
|
+
- Loading animation added
|
|
63
|
+
- NAN years ago - removed as invalid time differential
|
|
64
|
+
- Last seen for device points adjusted to be more accurate
|
|
25
65
|
|
|
26
66
|
## [1.6.1] - 14-04-2025
|
|
27
67
|
|
|
28
|
-
Bug fixes:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
68
|
+
Bug fixes:
|
|
69
|
+
|
|
70
|
+
- Inspector stats were calculating incorrectly in certain scenarios
|
|
71
|
+
- Inspector downloaded HTML files had incorrect stat percentages
|
|
72
|
+
- Inspector Last_Polled_Time stat was always "UNKNOWN", now shows correct date time.
|
|
32
73
|
|
|
33
|
-
Minor updates:
|
|
34
|
-
- Inspector BACnet main stats now output on msg.type = getBacnetStats inject. Can be set on a scheduled inject.
|
|
35
|
-
- Updated Examples with Inspector
|
|
74
|
+
Minor updates:
|
|
36
75
|
|
|
76
|
+
- Inspector BACnet main stats now output on msg.type = getBacnetStats inject. Can be set on a scheduled inject.
|
|
77
|
+
- Updated Examples with Inspector
|
|
37
78
|
|
|
38
79
|
## [1.6.0] - 09-04-2025
|
|
39
80
|
|
|
@@ -49,93 +90,99 @@ New features:
|
|
|
49
90
|
- API routes available:
|
|
50
91
|
|
|
51
92
|
- /inspector
|
|
93
|
+
|
|
52
94
|
- view UI in web browser
|
|
53
95
|
|
|
54
96
|
- /inspector-downloadhtml
|
|
97
|
+
|
|
55
98
|
- downloads the html of the inspector in its current state
|
|
56
99
|
|
|
57
100
|
- /inspector-downloadhtml?filter=tableKey&value=value1,value2
|
|
58
|
-
|
|
59
|
-
-
|
|
101
|
+
|
|
102
|
+
- downloads the html of the inspector, but with a applied filter to the table.
|
|
103
|
+
- tableKey in the above example can be any of the table columns, only 1 tableKey may be filtered on:
|
|
60
104
|
deviceID, objectType, objectInstance, presentValue, dataModelStatus, pointName, discoveredBACnetPointName, displayName, deviceName, ipAddress, area, key, topic, lastSeen, error
|
|
61
105
|
- value=value1,value2 etc can be any value that the tableKey can contain. This parameter can accept many comma separated values
|
|
62
|
-
- an example filter request may look like:
|
|
106
|
+
- an example filter request may look like:
|
|
63
107
|
/inspector-downloadhtml?filter=dataModelStatus&value=error,missing
|
|
64
108
|
|
|
65
109
|
- /getModelStats
|
|
110
|
+
|
|
66
111
|
- returns JSON data with analysis of the BACnet model
|
|
67
112
|
- contains point status, metrics, and detailed information
|
|
68
113
|
|
|
69
114
|
- /pointstoread
|
|
115
|
+
|
|
70
116
|
- downloads CSV file with all points in the read list
|
|
71
117
|
- format: [siteName]_PointsToRead_[timestamp].csv
|
|
72
118
|
|
|
73
119
|
- /getpointerrors
|
|
74
120
|
- downloads CSV file with all points that have errors
|
|
75
121
|
- format: [siteName]_PointErrors_[timestamp].csv
|
|
76
|
-
|
|
77
122
|
- /getmodelstatscsv
|
|
78
123
|
- downloads CSV file with all model stats data in CSV format
|
|
79
124
|
- format: [siteName]_ModelStats_[timestamp].csv
|
|
80
|
-
|
|
81
125
|
- /publishedpointslist
|
|
126
|
+
|
|
82
127
|
- downloads CSV file with all published points and their current values
|
|
83
128
|
- format: [siteName]_PublishedPointsList_[timestamp].csv
|
|
84
129
|
- outputs mqtt topic and payloads with statistics about the current state of the bacnet network
|
|
85
130
|
- output topics:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- Additional input options:
|
|
131
|
+
EDGE*DEVICE*{IP*ID}/STATUS/LAST_POINT_PUSHED_TIME
|
|
132
|
+
payload: Timestamp of when the last point was pushed (ISO string)
|
|
133
|
+
EDGE_DEVICE*{IP*ID}/STATUS/LAST_STAT_CALC_TIME
|
|
134
|
+
payload: Current timestamp (ISO string)
|
|
135
|
+
EDGE_DEVICE*{IP*ID}/STATUS/UPTIME
|
|
136
|
+
payload: System uptime formatted as string (e.g., "Uptime: 3 days, 5 hours, 12 minutes, 45 seconds")
|
|
137
|
+
EDGE_DEVICE*{IP*ID}/STATUS/ONLINE_POINTS
|
|
138
|
+
payload: Number of online points
|
|
139
|
+
EDGE_DEVICE*{IP*ID}/STATUS/OFFLINE_POINTS
|
|
140
|
+
payload: Number of offline points
|
|
141
|
+
EDGE_DEVICE*{IP*ID}/STATUS/TOTAL_POLLED_POINTS
|
|
142
|
+
payload: Total number of polled points
|
|
143
|
+
EDGE_DEVICE*{IP*ID}/STATUS/AVERAGE_TIME_SINCE_COV_IN_SECONDS
|
|
144
|
+
payload: Average time since last change of value in seconds
|
|
145
|
+
EDGE_DEVICE*{IP*ID}/STATUS/TOTAL_POINTS_TO_READ
|
|
146
|
+
payload: Total number of points to read
|
|
147
|
+
EDGE_DEVICE*{IP*ID}/STATUS/DISCOVERED_POINT_COUNT
|
|
148
|
+
payload: Number of discovered points
|
|
149
|
+
EDGE_DEVICE*{IP_ID}/STATUS/DISCOVERED_DEVICE_COUNT
|
|
150
|
+
payload: Number of discovered devices
|
|
151
|
+
|
|
152
|
+
where {IP_ID} is the IP address of the device with periods removed (e.g., 192.168.1.100 becomes 192168110).
|
|
153
|
+
each of these topics includes the site name as a tag in the message metadata with format geoAddr={siteName}.
|
|
154
|
+
|
|
155
|
+
- Additional input options:
|
|
156
|
+
|
|
111
157
|
- reset - resets the complete data model used for all of the inspector analytics
|
|
158
|
+
|
|
112
159
|
- msg input format: msg.reset = true
|
|
113
160
|
|
|
114
161
|
- sendMqttStats - outputs additional mqtt statistics
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
|
|
162
|
+
|
|
163
|
+
- msg input format: msg.type = sendMqttStats
|
|
164
|
+
- output topics:
|
|
165
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/ok
|
|
118
166
|
payload: Number of points with OK status
|
|
119
|
-
|
|
167
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/error
|
|
120
168
|
payload: Number of points with error status
|
|
121
|
-
|
|
169
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/missing
|
|
122
170
|
payload: Number of missing points
|
|
123
|
-
|
|
171
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/warnings
|
|
124
172
|
payload: Number of points with warnings
|
|
125
|
-
|
|
173
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/moved
|
|
126
174
|
payload: Number of points that have moved (e.g changed object instance)
|
|
127
|
-
|
|
175
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/deviceIdChange
|
|
128
176
|
payload: Number of points with changed device IDs
|
|
129
|
-
|
|
177
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/deviceIdConflict
|
|
130
178
|
payload: Number of points with conflicting device IDs
|
|
131
|
-
|
|
179
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/unmapped
|
|
132
180
|
payload: Number of unmapped points
|
|
133
|
-
|
|
181
|
+
EDGE*DEVICE*{siteName}/BACNETSTATS/offlinePercentage
|
|
134
182
|
payload: Percentage of points that are offline
|
|
135
183
|
|
|
136
184
|
where {siteName} is the site name configured in the inspector node.
|
|
137
185
|
|
|
138
|
-
|
|
139
186
|
- Right click -> Update Point on a individual point in the device tree. (Read node UI)
|
|
140
187
|
|
|
141
188
|
- Added programmatic reinitialize/clear points on BACnet server via injecting { msg.reinitializeBacnetServer: true } into the gateway node. Optionally can include a msg.responseTopic string to get a confrimation published to that topic output from the gateway node on sucessfull reinitialize.
|
|
@@ -158,6 +205,7 @@ New features:
|
|
|
158
205
|
Refactor:
|
|
159
206
|
|
|
160
207
|
- Reading and Writing to the cache file of the datamodel.
|
|
208
|
+
|
|
161
209
|
- write operations are now locked to 1 operation at a time
|
|
162
210
|
- a rolling secondary backup file is now created, which can be used in case of corruption of the primary file
|
|
163
211
|
|
package/bacnet_client.js
CHANGED
|
@@ -11,7 +11,6 @@ const {
|
|
|
11
11
|
parseBacnetError,
|
|
12
12
|
getBacnetErrorString,
|
|
13
13
|
Read_Config_Async,
|
|
14
|
-
Read_Config_Sync,
|
|
15
14
|
isNumber,
|
|
16
15
|
decodeBitArray,
|
|
17
16
|
} = require("./common");
|
|
@@ -28,6 +27,7 @@ class BacnetClient extends EventEmitter {
|
|
|
28
27
|
that.config = config;
|
|
29
28
|
that.deviceList = [];
|
|
30
29
|
that.networkTree = {};
|
|
30
|
+
that.renderList = [];
|
|
31
31
|
that.lastWhoIs = null;
|
|
32
32
|
that.client = null;
|
|
33
33
|
that.lastNetworkPoll = null;
|
|
@@ -41,7 +41,6 @@ class BacnetClient extends EventEmitter {
|
|
|
41
41
|
that.portRangeMatrix = config.portRangeMatrix;
|
|
42
42
|
|
|
43
43
|
try {
|
|
44
|
-
|
|
45
44
|
that.roundDecimal = config.roundDecimal;
|
|
46
45
|
that.apduSize = config.apduSize;
|
|
47
46
|
that.maxSegments = config.maxSegments;
|
|
@@ -116,13 +115,11 @@ class BacnetClient extends EventEmitter {
|
|
|
116
115
|
}
|
|
117
116
|
}, "4000");
|
|
118
117
|
}, "15000");
|
|
119
|
-
|
|
120
118
|
} catch (e) {
|
|
121
119
|
that.logOut("Issue initializing client: ", e);
|
|
122
120
|
}
|
|
123
121
|
|
|
124
122
|
try {
|
|
125
|
-
|
|
126
123
|
//who is callback
|
|
127
124
|
that.client.on("iAm", (device) => {
|
|
128
125
|
if (device.address !== that.config.localIpAdrress) {
|
|
@@ -201,7 +198,8 @@ class BacnetClient extends EventEmitter {
|
|
|
201
198
|
const cachedData = await Read_Config_Async();
|
|
202
199
|
const parsedData = JSON.parse(cachedData);
|
|
203
200
|
if (parsedData && typeof parsedData == "object") {
|
|
204
|
-
|
|
201
|
+
// renderList is no longer cached - will be rebuilt by tree builder
|
|
202
|
+
// if (parsedData.renderList) that.renderList = parsedData.renderList;
|
|
205
203
|
if (parsedData.deviceList) {
|
|
206
204
|
parsedData.deviceList.forEach(function (device) {
|
|
207
205
|
let newBacnetDevice = new BacnetDevice(true, device);
|
|
@@ -209,12 +207,13 @@ class BacnetClient extends EventEmitter {
|
|
|
209
207
|
});
|
|
210
208
|
}
|
|
211
209
|
if (parsedData.pointList) that.networkTree = parsedData.pointList;
|
|
212
|
-
|
|
210
|
+
// renderListCount is no longer cached - will be recalculated by tree builder
|
|
211
|
+
// if (parsedData.renderListCount) that.renderListCount = parsedData.renderListCount;
|
|
213
212
|
}
|
|
214
213
|
}
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
testFunction(address, port, type, instance, property) {
|
|
216
|
+
testFunction(address, port, type, instance, property, nodeWarnCallback) {
|
|
218
217
|
let that = this;
|
|
219
218
|
console.log("test function ");
|
|
220
219
|
|
|
@@ -229,6 +228,11 @@ class BacnetClient extends EventEmitter {
|
|
|
229
228
|
console.log("1 - readPropertyMultiple: ");
|
|
230
229
|
|
|
231
230
|
console.log(value);
|
|
231
|
+
|
|
232
|
+
if (nodeWarnCallback) {
|
|
233
|
+
nodeWarnCallback(value);
|
|
234
|
+
}
|
|
235
|
+
|
|
232
236
|
if (value) {
|
|
233
237
|
// If the result has value, resolve the promise
|
|
234
238
|
console.log(value.values[0]);
|
|
@@ -720,35 +724,30 @@ class BacnetClient extends EventEmitter {
|
|
|
720
724
|
const that = this;
|
|
721
725
|
const roundDecimal = readConfig.precision;
|
|
722
726
|
const devicesToRead = Object.keys(readConfig.pointsToRead);
|
|
723
|
-
|
|
724
|
-
let pendingRequests = 0;
|
|
727
|
+
let completedDevices = 0;
|
|
725
728
|
|
|
726
729
|
try {
|
|
727
|
-
//
|
|
728
|
-
|
|
729
|
-
const key = devicesToRead[deviceIndex];
|
|
730
|
+
// Create array of device processing promises
|
|
731
|
+
const devicePromises = devicesToRead.map(async (key, deviceIndex) => {
|
|
730
732
|
const device = that.findDeviceByKey(key);
|
|
731
|
-
if (!device)
|
|
733
|
+
if (!device) return null;
|
|
732
734
|
|
|
733
735
|
const deviceName = that.computeDeviceName(device);
|
|
734
736
|
const deviceKey = that.createDeviceKey(device);
|
|
735
737
|
const deviceObject = that.networkTree[deviceKey];
|
|
736
738
|
const maxObjectCount = that.estimateMaxObjectSize(device.getMaxApdu());
|
|
737
739
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
}
|
|
740
|
+
const bacnetResults = {};
|
|
741
|
+
bacnetResults[deviceName] = {};
|
|
741
742
|
|
|
742
743
|
// Process points for the current device
|
|
743
744
|
const pointsToRead = readConfig.pointsToRead[key];
|
|
744
745
|
const pointNames = Object.keys(pointsToRead);
|
|
745
746
|
let totalPoints = pointNames.length - 1;
|
|
746
747
|
let requestArray = [];
|
|
747
|
-
let processedPoints = 0; // Counter for processed points
|
|
748
748
|
|
|
749
749
|
// Process each point for the device in batches
|
|
750
750
|
for (let i = 0; i < pointNames.length; i++) {
|
|
751
|
-
|
|
752
751
|
const pointName = pointNames[i];
|
|
753
752
|
if (pointName === "deviceName") {
|
|
754
753
|
continue;
|
|
@@ -771,17 +770,7 @@ class BacnetClient extends EventEmitter {
|
|
|
771
770
|
}
|
|
772
771
|
|
|
773
772
|
// Process the batch when the request array is full or the last point is reached
|
|
774
|
-
if (requestArray.length === maxObjectCount) {
|
|
775
|
-
if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
|
|
776
|
-
await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
777
|
-
} else {
|
|
778
|
-
await that.processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
requestArray = [];
|
|
782
|
-
// Increment the processed points counter
|
|
783
|
-
processedPoints += maxObjectCount;
|
|
784
|
-
} else if (i === pointNames.length - 1) {
|
|
773
|
+
if (requestArray.length === maxObjectCount || i === pointNames.length - 1) {
|
|
785
774
|
if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
|
|
786
775
|
await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
787
776
|
} else {
|
|
@@ -789,28 +778,34 @@ class BacnetClient extends EventEmitter {
|
|
|
789
778
|
}
|
|
790
779
|
|
|
791
780
|
requestArray = [];
|
|
792
|
-
// Increment the processed points counter
|
|
793
|
-
processedPoints += i;
|
|
794
781
|
}
|
|
782
|
+
}
|
|
795
783
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
}
|
|
784
|
+
// Return results for this device
|
|
785
|
+
return {
|
|
786
|
+
deviceName,
|
|
787
|
+
results: bacnetResults,
|
|
788
|
+
deviceIndex: deviceIndex + 1,
|
|
789
|
+
totalDevices: devicesToRead.length,
|
|
790
|
+
};
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// Process all devices in parallel and emit results as they complete
|
|
794
|
+
const results = await Promise.allSettled(devicePromises);
|
|
795
|
+
|
|
796
|
+
results.forEach((result, index) => {
|
|
797
|
+
if (result.status === "fulfilled" && result.value) {
|
|
798
|
+
completedDevices++;
|
|
799
|
+
const { deviceName, results: bacnetResults, deviceIndex, totalDevices } = result.value;
|
|
800
|
+
|
|
801
|
+
// Emit the `values` event for this device immediately
|
|
802
|
+
that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName, completedDevices, totalDevices);
|
|
803
|
+
} else {
|
|
804
|
+
// Handle failed device (offline/error)
|
|
805
|
+
completedDevices++;
|
|
806
|
+
that.logOut(`Device ${devicesToRead[index]} failed:`, result.reason);
|
|
812
807
|
}
|
|
813
|
-
}
|
|
808
|
+
});
|
|
814
809
|
} catch (error) {
|
|
815
810
|
that.logOut("doRead error: ", error);
|
|
816
811
|
}
|
|
@@ -847,6 +842,7 @@ class BacnetClient extends EventEmitter {
|
|
|
847
842
|
if (isNumber(val)) {
|
|
848
843
|
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
849
844
|
pointRef.error = "none";
|
|
845
|
+
pointRef.status = "online";
|
|
850
846
|
if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
|
|
851
847
|
if (pointRef.stateTextArray && typeof pointRef.stateTextArray[0].value !== "object") {
|
|
852
848
|
if (val != 0) {
|
|
@@ -860,14 +856,18 @@ class BacnetClient extends EventEmitter {
|
|
|
860
856
|
if (typeof val !== "object") {
|
|
861
857
|
pointRef.presentValue = val;
|
|
862
858
|
pointRef.error = "none";
|
|
859
|
+
pointRef.status = "online";
|
|
863
860
|
} else if (val.errorClass && val.errorClass) {
|
|
864
861
|
pointRef.error = getBacnetErrorString(val.errorClass, val.errorClass);
|
|
862
|
+
pointRef.status = "offline";
|
|
863
|
+
} else {
|
|
864
|
+
pointRef.error = "none";
|
|
865
|
+
pointRef.status = "online";
|
|
865
866
|
}
|
|
866
867
|
}
|
|
867
868
|
|
|
868
869
|
pointRef.meta["device"] = deviceMetaInfo;
|
|
869
870
|
pointRef.timestamp = Date.now();
|
|
870
|
-
pointRef.status = "online";
|
|
871
871
|
|
|
872
872
|
// Store the point data in results
|
|
873
873
|
bacnetResults[deviceName][pointNameRef] = pointRef;
|
|
@@ -891,7 +891,6 @@ class BacnetClient extends EventEmitter {
|
|
|
891
891
|
for (const request of requestArray) {
|
|
892
892
|
const { objectId, pointRef, pointName } = request;
|
|
893
893
|
try {
|
|
894
|
-
|
|
895
894
|
const result = await that.updatePoint(device, pointRef);
|
|
896
895
|
|
|
897
896
|
if (result.objectId.type == objectId.type && result.objectId.instance == objectId.instance) {
|
|
@@ -899,6 +898,8 @@ class BacnetClient extends EventEmitter {
|
|
|
899
898
|
|
|
900
899
|
if (isNumber(val)) {
|
|
901
900
|
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
901
|
+
pointRef.error = "none";
|
|
902
|
+
pointRef.status = "online";
|
|
902
903
|
|
|
903
904
|
if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
|
|
904
905
|
if (pointRef.stateTextArray && typeof pointRef.stateTextArray[0].value !== "object") {
|
|
@@ -910,13 +911,21 @@ class BacnetClient extends EventEmitter {
|
|
|
910
911
|
}
|
|
911
912
|
}
|
|
912
913
|
} else {
|
|
913
|
-
|
|
914
|
+
if (typeof val !== "object") {
|
|
915
|
+
pointRef.presentValue = val;
|
|
916
|
+
pointRef.error = "none";
|
|
917
|
+
pointRef.status = "online";
|
|
918
|
+
} else if (val.errorClass && val.errorClass) {
|
|
919
|
+
pointRef.error = getBacnetErrorString(val.errorClass, val.errorClass);
|
|
920
|
+
pointRef.status = "offline";
|
|
921
|
+
} else {
|
|
922
|
+
pointRef.error = "none";
|
|
923
|
+
pointRef.status = "online";
|
|
924
|
+
}
|
|
914
925
|
}
|
|
915
926
|
|
|
916
927
|
pointRef.meta["device"] = deviceMetaInfo;
|
|
917
928
|
pointRef.timestamp = Date.now();
|
|
918
|
-
pointRef.status = "online";
|
|
919
|
-
pointRef.error = "none";
|
|
920
929
|
|
|
921
930
|
// Store the point data in results
|
|
922
931
|
bacnetResults[deviceName][pointName] = pointRef;
|
|
@@ -981,7 +990,7 @@ class BacnetClient extends EventEmitter {
|
|
|
981
990
|
|
|
982
991
|
return true;
|
|
983
992
|
} catch (e) {
|
|
984
|
-
throw e
|
|
993
|
+
throw e;
|
|
985
994
|
}
|
|
986
995
|
}
|
|
987
996
|
|
|
@@ -1007,7 +1016,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1007
1016
|
let settings = {
|
|
1008
1017
|
maxSegments: maxSegments,
|
|
1009
1018
|
maxApdu: maxApdu,
|
|
1010
|
-
}
|
|
1019
|
+
};
|
|
1011
1020
|
|
|
1012
1021
|
return new Promise((resolve, reject) => {
|
|
1013
1022
|
that.client.readProperty(
|
|
@@ -1681,7 +1690,7 @@ class BacnetClient extends EventEmitter {
|
|
|
1681
1690
|
if (json.body.renderListCount) {
|
|
1682
1691
|
that.renderListCount = json.body.renderListCount;
|
|
1683
1692
|
}
|
|
1684
|
-
resolve();
|
|
1693
|
+
resolve(true);
|
|
1685
1694
|
} catch (e) {
|
|
1686
1695
|
reject(e);
|
|
1687
1696
|
}
|