@bitpoolos/edge-bacnet 1.5.2 → 1.6.0
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 +151 -1
- package/bacnet_client.js +202 -108
- package/bacnet_device.js +3 -1
- package/bacnet_gateway.html +100 -2
- package/bacnet_gateway.js +382 -250
- package/bacnet_inspector.html +43 -0
- package/bacnet_inspector.js +1564 -0
- package/bacnet_inspector_worker.js +535 -0
- package/bacnet_read.html +47 -50
- package/bacnet_read.js +0 -3
- package/common.js +201 -38
- package/inspector.html +460 -0
- package/package.json +6 -2
- package/resources/Logo_Simplified_Positive.svg +32 -0
- package/resources/downloadAsHtml.js +654 -0
- package/resources/icons/device-id-change-icon.svg +4 -0
- package/resources/icons/device-id-conflict-icon.svg +4 -0
- package/resources/icons/favicon.ico +0 -0
- package/resources/icons/points-error-icon.svg +4 -0
- package/resources/icons/points-missing-icon.svg +4 -0
- package/resources/icons/points-ok-icon.svg +4 -0
- package/resources/icons/points-unmapped-icon.svg +5 -0
- package/resources/icons/points-warning-icon.svg +4 -0
- package/resources/inspector.css +25312 -0
- package/resources/inspectorStyle.css +254 -0
- package/resources/inspectorStyles.css +478 -0
- package/resources/node-bacstack-ts/dist/lib/client.js +7 -3
- package/resources/primevue.min.js +1 -0
- package/resources/style.css +17 -1
- package/resources/vue3513.global.prod.js +9 -0
- package/ssrHtmlExporter.js +535 -0
- package/treeBuilder.js +3 -3
package/bacnet_gateway.js
CHANGED
|
@@ -15,6 +15,7 @@ module.exports = function (RED) {
|
|
|
15
15
|
|
|
16
16
|
//bacnet local device info
|
|
17
17
|
this.localDeviceAddress = config.local_device_address;
|
|
18
|
+
this.local_interface_name = config.local_interface_name;
|
|
18
19
|
this.local_device_port = config.local_device_port;
|
|
19
20
|
this.apduSize = config.apduSize;
|
|
20
21
|
this.maxSegments = config.maxSegments;
|
|
@@ -46,126 +47,156 @@ module.exports = function (RED) {
|
|
|
46
47
|
//determines whether or not to log a found device on whoIs response
|
|
47
48
|
this.toLogIam = config.toLogIam;
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
node.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
nodeContext.set("bacnetClient", node.bacnetClient);
|
|
50
|
+
try {
|
|
51
|
+
node.bacnetConfig = new BacnetClientConfig(
|
|
52
|
+
node.apduTimeout,
|
|
53
|
+
node.localDeviceAddress,
|
|
54
|
+
node.local_device_port,
|
|
55
|
+
node.apduSize,
|
|
56
|
+
node.maxSegments,
|
|
57
|
+
node.broadCastAddr,
|
|
58
|
+
node.discover_polling_schedule,
|
|
59
|
+
node.toRestartNodeRed,
|
|
60
|
+
node.deviceId,
|
|
61
|
+
node.manual_instance_range_enabled,
|
|
62
|
+
node.manual_instance_range_start,
|
|
63
|
+
node.manual_instance_range_end,
|
|
64
|
+
node.device_read_schedule,
|
|
65
|
+
node.retries,
|
|
66
|
+
node.cacheFileEnabled,
|
|
67
|
+
node.sanitise_device_schedule,
|
|
68
|
+
node.portRangeRegisters.filter((ele) => ele.enabled === true)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (typeof node.bacnetClient !== "undefined") {
|
|
72
|
+
node.bacnetClient.removeAllListeners();
|
|
73
|
+
bindEventListeners();
|
|
74
|
+
node.bacnetClient.reinitializeClient(node.bacnetConfig);
|
|
75
|
+
} else {
|
|
76
|
+
node.bacnetClient = new BacnetClient(node.bacnetConfig);
|
|
77
|
+
nodeContext.set("bacnetClient", node.bacnetClient);
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
nodeContext.set("serverWritePropEvent", false);
|
|
80
|
+
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
node.bacnetClient.scanMatrix = node.deviceRangeRegisters.filter((ele) => ele.enabled === true);
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if (node.bacnetServerEnabled == true && node.bacnetClient && node.bacnetServer) {
|
|
85
|
+
node.bacnetServer.deviceId = node.deviceId;
|
|
86
|
+
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
node.bacnetClient.bacnetServerEnabled = node.bacnetServerEnabled;
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
if (node.bacnetServerEnabled == true && node.bacnetClient) {
|
|
91
|
+
if (node.bacnetServer == null) {
|
|
92
|
+
node.bacnetServer = new BacnetServer(node.bacnetClient, node.deviceId, RED.version());
|
|
93
|
+
nodeContext.set("bacnetServer", node.bacnetServer);
|
|
94
|
+
}
|
|
95
|
+
} else if (node.bacnetServerEnabled == false) {
|
|
96
|
+
node.bacnetServer = null;
|
|
94
97
|
}
|
|
95
|
-
} else if (node.bacnetServerEnabled == false) {
|
|
96
|
-
node.bacnetServer = null;
|
|
97
|
-
}
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
// Clears event handlers of all listeners, avoiding memory leak
|
|
100
|
+
node.bacnetClient.removeAllListeners();
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.log("Bacnet gateway client init error: ", e);
|
|
103
|
+
}
|
|
101
104
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
let useDeviceName = outputType.useDeviceName;
|
|
113
|
-
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
114
|
-
//json
|
|
115
|
-
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
116
|
-
//simpleWithStatus
|
|
117
|
-
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
118
|
-
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
119
|
-
//fullObject
|
|
120
|
-
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
121
|
-
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
122
|
-
//simplePayload
|
|
123
|
-
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
124
|
-
}
|
|
125
|
-
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
126
|
-
//mqtt
|
|
127
|
-
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
128
|
-
//simpleWithStatus
|
|
129
|
-
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
130
|
-
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
131
|
-
//fullObject
|
|
132
|
-
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
133
|
-
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
134
|
-
//simplePayload
|
|
135
|
-
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
105
|
+
try {
|
|
106
|
+
// Value response event handler for READ commands
|
|
107
|
+
node.bacnetClient.on("values", (values, outputType, objectPropertyType, readNodeName, deviceIndex, devicesToRead) => {
|
|
108
|
+
if (typeof values !== "undefined" && Object.keys(values).length) {
|
|
109
|
+
let publishText = `Publishing ${readNodeName} ${deviceIndex} / ${devicesToRead} `;
|
|
110
|
+
node.status({ fill: "blue", shape: "dot", text: publishText });
|
|
111
|
+
if (deviceIndex == devicesToRead) {
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
node.status({});
|
|
114
|
+
}, 3000);
|
|
136
115
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
116
|
+
let useDeviceName = outputType.useDeviceName;
|
|
117
|
+
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
118
|
+
//json
|
|
119
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
120
|
+
//simpleWithStatus
|
|
121
|
+
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
122
|
+
} else if (
|
|
123
|
+
objectPropertyType.fullObject &&
|
|
124
|
+
!objectPropertyType.simplePayload &&
|
|
125
|
+
!objectPropertyType.simpleWithStatus
|
|
126
|
+
) {
|
|
127
|
+
//fullObject
|
|
128
|
+
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
129
|
+
} else if (
|
|
130
|
+
objectPropertyType.simplePayload &&
|
|
131
|
+
!objectPropertyType.fullObject &&
|
|
132
|
+
!objectPropertyType.simpleWithStatus
|
|
133
|
+
) {
|
|
134
|
+
//simplePayload
|
|
135
|
+
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
136
|
+
}
|
|
137
|
+
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
138
|
+
//mqtt
|
|
139
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
140
|
+
//simpleWithStatus
|
|
141
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
142
|
+
} else if (
|
|
143
|
+
objectPropertyType.fullObject &&
|
|
144
|
+
!objectPropertyType.simplePayload &&
|
|
145
|
+
!objectPropertyType.simpleWithStatus
|
|
146
|
+
) {
|
|
147
|
+
//fullObject
|
|
148
|
+
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
149
|
+
} else if (
|
|
150
|
+
objectPropertyType.simplePayload &&
|
|
151
|
+
!objectPropertyType.fullObject &&
|
|
152
|
+
!objectPropertyType.simpleWithStatus
|
|
153
|
+
) {
|
|
154
|
+
//simplePayload
|
|
155
|
+
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
156
|
+
}
|
|
157
|
+
} else if (outputType.pointJson && !outputType.json && !outputType.mqtt) {
|
|
158
|
+
//pointJson
|
|
159
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
160
|
+
//simpleWithStatus
|
|
161
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
162
|
+
} else if (
|
|
163
|
+
objectPropertyType.fullObject &&
|
|
164
|
+
!objectPropertyType.simplePayload &&
|
|
165
|
+
!objectPropertyType.simpleWithStatus
|
|
166
|
+
) {
|
|
167
|
+
//fullObject
|
|
168
|
+
sendIndividualMsgJson(values, readNodeName, useDeviceName);
|
|
169
|
+
} else if (
|
|
170
|
+
objectPropertyType.simplePayload &&
|
|
171
|
+
!objectPropertyType.fullObject &&
|
|
172
|
+
!objectPropertyType.simpleWithStatus
|
|
173
|
+
) {
|
|
174
|
+
//simplePayload
|
|
175
|
+
sendSimpleJsonPerPoint(values, readNodeName, useDeviceName);
|
|
176
|
+
}
|
|
148
177
|
}
|
|
149
178
|
}
|
|
150
|
-
}
|
|
151
|
-
});
|
|
179
|
+
});
|
|
152
180
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
181
|
+
// Who Is / Iam event handler
|
|
182
|
+
node.bacnetClient.on("deviceFound", (device) => {
|
|
183
|
+
if (node.toLogIam) {
|
|
184
|
+
if (device.source) {
|
|
185
|
+
node.warn(
|
|
186
|
+
`BACnet-MS/TP device found: ${device.deviceId} - ${device.address} - Network Id: ${device.source.net} - Mac: ${device.source.adr[0]}`
|
|
187
|
+
);
|
|
188
|
+
} else {
|
|
189
|
+
node.warn(`BACnet device found: ${device.deviceId} - ${device.address}`);
|
|
190
|
+
}
|
|
162
191
|
}
|
|
163
|
-
}
|
|
164
|
-
});
|
|
192
|
+
});
|
|
165
193
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
194
|
+
node.bacnetClient.on("bacnetErrorLog", (param1, param2) => {
|
|
195
|
+
logOut(param1, param2);
|
|
196
|
+
});
|
|
197
|
+
} catch (e) {
|
|
198
|
+
console.log("Bacnet node event handler error: ", e);
|
|
199
|
+
}
|
|
169
200
|
|
|
170
201
|
if (
|
|
171
202
|
node.nodeName !== "gateway" &&
|
|
@@ -179,75 +210,99 @@ module.exports = function (RED) {
|
|
|
179
210
|
}
|
|
180
211
|
}
|
|
181
212
|
|
|
182
|
-
if (
|
|
183
|
-
node.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
213
|
+
if (
|
|
214
|
+
node.bacnetServerEnabled == true &&
|
|
215
|
+
node.bacnetClient &&
|
|
216
|
+
node.bacnetServer &&
|
|
217
|
+
nodeContext.get("serverWritePropEvent") == false
|
|
218
|
+
) {
|
|
219
|
+
try {
|
|
220
|
+
node.bacnetServer.on("writeProperty", (topic, newValue) => {
|
|
221
|
+
let formattedTopic = topic;
|
|
222
|
+
if (
|
|
223
|
+
node.nodeName !== "gateway" &&
|
|
224
|
+
node.nodeName !== "" &&
|
|
225
|
+
node.nodeName !== "null" &&
|
|
226
|
+
node.nodeName !== "undefined" &&
|
|
227
|
+
typeof node.nodeName == "string"
|
|
228
|
+
) {
|
|
229
|
+
formattedTopic = `${node.nodeName}/BITPOOL_EDGE_BACNET_GATEWAY/BACNET_SERVER/${topic}`;
|
|
230
|
+
} else {
|
|
231
|
+
formattedTopic = `BITPOOL_EDGE_BACNET_GATEWAY/BACNET_SERVER/${topic}`;
|
|
232
|
+
}
|
|
196
233
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
234
|
+
node.send({ payload: newValue, topic: formattedTopic });
|
|
235
|
+
});
|
|
236
|
+
nodeContext.set("serverWritePropEvent", true);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
console.log("Bacnet gateway node server writePoperty error: ", e);
|
|
239
|
+
}
|
|
200
240
|
}
|
|
201
241
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
node.bacnetServer
|
|
242
|
+
try {
|
|
243
|
+
node.on("input", function (msg) {
|
|
244
|
+
if (msg.topic && msg.payload !== null) {
|
|
245
|
+
if (node.bacnetServer) {
|
|
246
|
+
node.bacnetServer.addObject(msg.topic, msg.payload);
|
|
247
|
+
}
|
|
206
248
|
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (msg.type == "Read") {
|
|
210
|
-
node.bacnetClient.doRead(msg.options, msg.outputType, msg.objectPropertyType, msg.readNodeName);
|
|
211
|
-
} else if (msg.type == "Write") {
|
|
212
|
-
node.bacnetClient.doWrite(msg.value, msg.options);
|
|
213
|
-
} else if (msg.doDiscover == true) {
|
|
214
|
-
node.status({ fill: "blue", shape: "dot", text: "Sending global Who is" });
|
|
215
|
-
node.bacnetClient.globalWhoIs();
|
|
216
|
-
setTimeout(() => {
|
|
217
|
-
node.status({});
|
|
218
|
-
}, 2000);
|
|
219
|
-
} else if (msg.payload == "BindEvents") {
|
|
220
|
-
node.bacnetClient.removeAllListeners();
|
|
221
|
-
bindEventListeners();
|
|
222
|
-
} else if (msg.doUpdatePriorityDevices == true && msg.priorityDevices !== null) {
|
|
223
|
-
node.bacnetClient
|
|
224
|
-
.updatePriorityQueue(msg.priorityDevices)
|
|
225
|
-
.then(function (result) { })
|
|
226
|
-
.catch(function (error) {
|
|
227
|
-
logOut("Error updating priorityQueue: ", error);
|
|
228
|
-
});
|
|
229
|
-
} else if (msg.testFunc == true) {
|
|
230
|
-
node.bacnetClient.testFunction(msg.address, msg.port, msg.type, msg.instance, msg.property);
|
|
231
|
-
} else if (msg.applyDisplayNames) {
|
|
232
|
-
node.status({ fill: "blue", shape: "dot", text: "Updating display names" });
|
|
233
|
-
setTimeout(() => {
|
|
234
|
-
node.status({});
|
|
235
|
-
}, 2000);
|
|
236
249
|
|
|
237
|
-
|
|
238
|
-
.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
250
|
+
if (msg.type == "Read") {
|
|
251
|
+
node.bacnetClient.doRead(msg.options, msg.outputType, msg.objectPropertyType, msg.readNodeName);
|
|
252
|
+
} else if (msg.type == "Write") {
|
|
253
|
+
node.bacnetClient.doWrite(msg.value, msg.options);
|
|
254
|
+
} else if (msg.doDiscover == true) {
|
|
255
|
+
node.status({ fill: "blue", shape: "dot", text: "Sending global Who is" });
|
|
256
|
+
node.bacnetClient.globalWhoIs();
|
|
257
|
+
setTimeout(() => {
|
|
258
|
+
node.status({});
|
|
259
|
+
}, 2000);
|
|
260
|
+
} else if (msg.payload == "BindEvents") {
|
|
261
|
+
node.bacnetClient.removeAllListeners();
|
|
262
|
+
bindEventListeners();
|
|
263
|
+
} else if (msg.doUpdatePriorityDevices == true && msg.priorityDevices !== null) {
|
|
264
|
+
node.bacnetClient
|
|
265
|
+
.updatePriorityQueue(msg.priorityDevices)
|
|
266
|
+
.then(function (result) {})
|
|
267
|
+
.catch(function (error) {
|
|
268
|
+
logOut("Error updating priorityQueue: ", error);
|
|
269
|
+
});
|
|
270
|
+
} else if (msg.testFunc == true) {
|
|
271
|
+
node.bacnetClient.testFunction(msg.address, msg.port, msg.type, msg.instance, msg.property);
|
|
272
|
+
} else if (msg.applyDisplayNames) {
|
|
273
|
+
node.status({ fill: "blue", shape: "dot", text: "Updating display names" });
|
|
274
|
+
setTimeout(() => {
|
|
275
|
+
node.status({});
|
|
276
|
+
}, 2000);
|
|
277
|
+
|
|
278
|
+
node.bacnetClient
|
|
279
|
+
.applyDisplayNames(msg.pointsToRead)
|
|
280
|
+
.then(function (result) {})
|
|
281
|
+
.catch(function (error) {
|
|
282
|
+
logOut("Error in applyDisplayNames: ", error);
|
|
283
|
+
});
|
|
284
|
+
} else if (msg.forceUpdateDevices == true) {
|
|
285
|
+
node.bacnetClient.forceUpdateDevices(msg.deviceIdArray);
|
|
286
|
+
} else if (msg.reinitializeBacnetServer == true) {
|
|
287
|
+
if (node.bacnetServerEnabled == true && node.bacnetClient) {
|
|
288
|
+
node.bacnetServer.clearServerPoints();
|
|
289
|
+
if (msg.responseTopic) {
|
|
290
|
+
node.send({ topic: msg.responseTopic, payload: "Server sucessfully reinitialized" });
|
|
291
|
+
}
|
|
292
|
+
node.status({ fill: "blue", shape: "dot", text: "Reinitializing Server" });
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
node.status({});
|
|
295
|
+
}, 2000);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
247
299
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
300
|
+
node.on("close", function () {
|
|
301
|
+
//do nothing
|
|
302
|
+
});
|
|
303
|
+
} catch (e) {
|
|
304
|
+
console.log("Bacnet node event handler error: ", e);
|
|
305
|
+
}
|
|
251
306
|
|
|
252
307
|
//route handler for network data
|
|
253
308
|
RED.httpAdmin.get("/bitpool-bacnet-data/getNetworkTree", function (req, res) {
|
|
@@ -298,27 +353,33 @@ module.exports = function (RED) {
|
|
|
298
353
|
});
|
|
299
354
|
|
|
300
355
|
//route handler for the clear Bacnet server point function
|
|
301
|
-
RED.httpAdmin.post(
|
|
356
|
+
RED.httpAdmin.post("/bitpool-bacnet-data/clearBacnetServerPoint", function (req, res) {
|
|
302
357
|
if (node.bacnetServerEnabled == true && node.bacnetClient) {
|
|
303
|
-
node.bacnetServer
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
358
|
+
node.bacnetServer
|
|
359
|
+
.clearServerPoint(req)
|
|
360
|
+
.then(function (result) {
|
|
361
|
+
res.send(result);
|
|
362
|
+
})
|
|
363
|
+
.catch(function (error) {
|
|
364
|
+
res.send(error);
|
|
365
|
+
});
|
|
308
366
|
} else {
|
|
309
367
|
res.send(result);
|
|
310
368
|
}
|
|
311
369
|
});
|
|
312
370
|
|
|
313
371
|
//route handler for the retrieve Bacnet server points function
|
|
314
|
-
RED.httpAdmin.get(
|
|
372
|
+
RED.httpAdmin.get("/bitpool-bacnet-data/getBacnetServerPoints", function (req, res) {
|
|
315
373
|
if (node.bacnetServerEnabled == true && node.bacnetClient) {
|
|
316
|
-
node.bacnetServer
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
374
|
+
node.bacnetServer
|
|
375
|
+
.getServerPoints()
|
|
376
|
+
.then(function (result) {
|
|
377
|
+
res.send(result);
|
|
378
|
+
})
|
|
379
|
+
.catch(function (error) {
|
|
380
|
+
res.send(error);
|
|
381
|
+
logOut("Error getting server points: ", error);
|
|
382
|
+
});
|
|
322
383
|
} else {
|
|
323
384
|
res.send([]);
|
|
324
385
|
}
|
|
@@ -371,6 +432,42 @@ module.exports = function (RED) {
|
|
|
371
432
|
}
|
|
372
433
|
});
|
|
373
434
|
|
|
435
|
+
//route handler for getting data model
|
|
436
|
+
RED.httpAdmin.get("/bitpool-bacnet-data/getDataModel", function (req, res) {
|
|
437
|
+
if (!node.bacnetClient) {
|
|
438
|
+
logOut("Issue with the bacnetClient while getting data model: ", node.bacnetClient);
|
|
439
|
+
res.send(false);
|
|
440
|
+
} else {
|
|
441
|
+
node.bacnetClient
|
|
442
|
+
.getDataModel()
|
|
443
|
+
.then(function (result) {
|
|
444
|
+
res.send(result);
|
|
445
|
+
})
|
|
446
|
+
.catch(function (error) {
|
|
447
|
+
res.send(error);
|
|
448
|
+
logOut("Error getting data model: ", error);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
//route handler for updating data model
|
|
454
|
+
RED.httpAdmin.post("/bitpool-bacnet-data/updateDataModel", function (req, res) {
|
|
455
|
+
if (!node.bacnetClient) {
|
|
456
|
+
logOut("Issue with the bacnetClient while getting data model: ", node.bacnetClient);
|
|
457
|
+
res.send(false);
|
|
458
|
+
} else {
|
|
459
|
+
node.bacnetClient
|
|
460
|
+
.updateDataModel(req)
|
|
461
|
+
.then(function (result) {
|
|
462
|
+
res.send(result);
|
|
463
|
+
})
|
|
464
|
+
.catch(function (error) {
|
|
465
|
+
res.send(error);
|
|
466
|
+
logOut("Error getting data model: ", error);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
|
|
374
471
|
//route handler for purge device
|
|
375
472
|
RED.httpAdmin.post("/bitpool-bacnet-data/purgeDevice", function (req, res) {
|
|
376
473
|
if (!node.bacnetClient) {
|
|
@@ -407,6 +504,24 @@ module.exports = function (RED) {
|
|
|
407
504
|
}
|
|
408
505
|
});
|
|
409
506
|
|
|
507
|
+
//route handler for updatePoint
|
|
508
|
+
RED.httpAdmin.post("/bitpool-bacnet-data/updatePoint", function (req, res) {
|
|
509
|
+
if (!node.bacnetClient) {
|
|
510
|
+
logOut("Issue with the bacnetClient while updating device points list: ", node.bacnetClient);
|
|
511
|
+
res.send(false);
|
|
512
|
+
} else {
|
|
513
|
+
node.bacnetClient
|
|
514
|
+
.updateIndividualPoint(req.body.d, req.body.k)
|
|
515
|
+
.then(function (result) {
|
|
516
|
+
res.send(result);
|
|
517
|
+
})
|
|
518
|
+
.catch(function (error) {
|
|
519
|
+
res.send(error);
|
|
520
|
+
logOut("Error updating device: ", error);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
410
525
|
//route handler for setDeviceDisplayName
|
|
411
526
|
RED.httpAdmin.post("/bitpool-bacnet-data/setDeviceDisplayName", function (req, res) {
|
|
412
527
|
if (!node.bacnetClient) {
|
|
@@ -461,63 +576,90 @@ module.exports = function (RED) {
|
|
|
461
576
|
}
|
|
462
577
|
});
|
|
463
578
|
|
|
464
|
-
|
|
465
579
|
function bindEventListeners() {
|
|
466
580
|
// Value response event handler for READ commands
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
let useDeviceName = outputType.useDeviceName;
|
|
477
|
-
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
478
|
-
//json
|
|
479
|
-
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
480
|
-
//simpleWithStatus
|
|
481
|
-
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
482
|
-
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
483
|
-
//fullObject
|
|
484
|
-
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
485
|
-
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
486
|
-
//simplePayload
|
|
487
|
-
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
488
|
-
}
|
|
489
|
-
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
490
|
-
//mqtt
|
|
491
|
-
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
492
|
-
//simpleWithStatus
|
|
493
|
-
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
494
|
-
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
495
|
-
//fullObject
|
|
496
|
-
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
497
|
-
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
498
|
-
//simplePayload
|
|
499
|
-
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
581
|
+
try {
|
|
582
|
+
node.bacnetClient.on("values", (values, outputType, objectPropertyType, readNodeName, deviceIndex, devicesToRead) => {
|
|
583
|
+
if (typeof values !== "undefined" && Object.keys(values).length) {
|
|
584
|
+
let publishText = `Publishing ${readNodeName} ${deviceIndex} / ${devicesToRead} `;
|
|
585
|
+
node.status({ fill: "blue", shape: "dot", text: publishText });
|
|
586
|
+
if (deviceIndex == devicesToRead) {
|
|
587
|
+
setTimeout(() => {
|
|
588
|
+
node.status({});
|
|
589
|
+
}, 3000);
|
|
500
590
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
591
|
+
let useDeviceName = outputType.useDeviceName;
|
|
592
|
+
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
593
|
+
//json
|
|
594
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
595
|
+
//simpleWithStatus
|
|
596
|
+
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
597
|
+
} else if (
|
|
598
|
+
objectPropertyType.fullObject &&
|
|
599
|
+
!objectPropertyType.simplePayload &&
|
|
600
|
+
!objectPropertyType.simpleWithStatus
|
|
601
|
+
) {
|
|
602
|
+
//fullObject
|
|
603
|
+
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
604
|
+
} else if (
|
|
605
|
+
objectPropertyType.simplePayload &&
|
|
606
|
+
!objectPropertyType.fullObject &&
|
|
607
|
+
!objectPropertyType.simpleWithStatus
|
|
608
|
+
) {
|
|
609
|
+
//simplePayload
|
|
610
|
+
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
611
|
+
}
|
|
612
|
+
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
613
|
+
//mqtt
|
|
614
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
615
|
+
//simpleWithStatus
|
|
616
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
617
|
+
} else if (
|
|
618
|
+
objectPropertyType.fullObject &&
|
|
619
|
+
!objectPropertyType.simplePayload &&
|
|
620
|
+
!objectPropertyType.simpleWithStatus
|
|
621
|
+
) {
|
|
622
|
+
//fullObject
|
|
623
|
+
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
624
|
+
} else if (
|
|
625
|
+
objectPropertyType.simplePayload &&
|
|
626
|
+
!objectPropertyType.fullObject &&
|
|
627
|
+
!objectPropertyType.simpleWithStatus
|
|
628
|
+
) {
|
|
629
|
+
//simplePayload
|
|
630
|
+
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
631
|
+
}
|
|
632
|
+
} else if (outputType.pointJson && !outputType.json && !outputType.mqtt) {
|
|
633
|
+
//pointJson
|
|
634
|
+
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
635
|
+
//simpleWithStatus
|
|
636
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
637
|
+
} else if (
|
|
638
|
+
objectPropertyType.fullObject &&
|
|
639
|
+
!objectPropertyType.simplePayload &&
|
|
640
|
+
!objectPropertyType.simpleWithStatus
|
|
641
|
+
) {
|
|
642
|
+
//fullObject
|
|
643
|
+
sendIndividualMsgJson(values, readNodeName, useDeviceName);
|
|
644
|
+
} else if (
|
|
645
|
+
objectPropertyType.simplePayload &&
|
|
646
|
+
!objectPropertyType.fullObject &&
|
|
647
|
+
!objectPropertyType.simpleWithStatus
|
|
648
|
+
) {
|
|
649
|
+
//simplePayload
|
|
650
|
+
sendSimpleJsonPerPoint(values, readNodeName, useDeviceName);
|
|
651
|
+
}
|
|
512
652
|
}
|
|
513
653
|
}
|
|
514
|
-
}
|
|
515
|
-
});
|
|
654
|
+
});
|
|
516
655
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
656
|
+
// Who Is / Iam event handler
|
|
657
|
+
node.bacnetClient.on("deviceFound", (device) => {
|
|
658
|
+
if (node.toLogIam) node.warn(`BACnet device found: ${device.deviceId} - ${device.address}`);
|
|
659
|
+
});
|
|
660
|
+
} catch (e) {
|
|
661
|
+
console.log("Bacnet gateway BindListeners error: ", e);
|
|
662
|
+
}
|
|
521
663
|
}
|
|
522
664
|
|
|
523
665
|
function logOut(param1, param2) {
|
|
@@ -541,16 +683,12 @@ module.exports = function (RED) {
|
|
|
541
683
|
node.nodeName !== "undefined" &&
|
|
542
684
|
typeof node.nodeName == "string"
|
|
543
685
|
) {
|
|
544
|
-
if (readNodeName !==
|
|
545
|
-
readNodeName !== null &&
|
|
546
|
-
readNodeName !== undefined
|
|
547
|
-
) {
|
|
686
|
+
if (readNodeName !== "" && readNodeName !== null && readNodeName !== undefined) {
|
|
548
687
|
if (useDeviceName) {
|
|
549
688
|
topic = `${node.nodeName}/${readNodeName}/${device}`;
|
|
550
689
|
} else {
|
|
551
690
|
topic = `${node.nodeName}/${readNodeName}`;
|
|
552
691
|
}
|
|
553
|
-
|
|
554
692
|
} else {
|
|
555
693
|
if (useDeviceName) {
|
|
556
694
|
topic = `${node.nodeName}/${device}`;
|
|
@@ -559,16 +697,12 @@ module.exports = function (RED) {
|
|
|
559
697
|
}
|
|
560
698
|
}
|
|
561
699
|
} else {
|
|
562
|
-
if (readNodeName !==
|
|
563
|
-
readNodeName !== null &&
|
|
564
|
-
readNodeName !== undefined
|
|
565
|
-
) {
|
|
700
|
+
if (readNodeName !== "" && readNodeName !== null && readNodeName !== undefined) {
|
|
566
701
|
if (useDeviceName) {
|
|
567
702
|
topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}`;
|
|
568
703
|
} else {
|
|
569
704
|
topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}`;
|
|
570
705
|
}
|
|
571
|
-
|
|
572
706
|
} else {
|
|
573
707
|
if (useDeviceName) {
|
|
574
708
|
topic = `BITPOOL_BACNET_GATEWAY/${device}`;
|
|
@@ -616,7 +750,6 @@ module.exports = function (RED) {
|
|
|
616
750
|
}
|
|
617
751
|
|
|
618
752
|
return topic;
|
|
619
|
-
|
|
620
753
|
}
|
|
621
754
|
|
|
622
755
|
sendSimpleWithStatus = function (values, readNodeName, isJson, useDeviceName) {
|
|
@@ -635,7 +768,7 @@ module.exports = function (RED) {
|
|
|
635
768
|
let payload = {
|
|
636
769
|
presentValue: points[point]["presentValue"],
|
|
637
770
|
timestamp: points[point]["timestamp"],
|
|
638
|
-
status: points[point]["status"]
|
|
771
|
+
status: points[point]["status"],
|
|
639
772
|
};
|
|
640
773
|
|
|
641
774
|
if (isJson) {
|
|
@@ -661,7 +794,7 @@ module.exports = function (RED) {
|
|
|
661
794
|
}
|
|
662
795
|
}
|
|
663
796
|
});
|
|
664
|
-
}
|
|
797
|
+
};
|
|
665
798
|
|
|
666
799
|
sendSimpleMqtt = function (values, readNodeName, useDeviceName) {
|
|
667
800
|
let devices = Object.keys(values);
|
|
@@ -781,7 +914,7 @@ module.exports = function (RED) {
|
|
|
781
914
|
}
|
|
782
915
|
});
|
|
783
916
|
}
|
|
784
|
-
}
|
|
917
|
+
};
|
|
785
918
|
|
|
786
919
|
sendSimpleJsonPerPoint = function (values, readNodeName, useDeviceName) {
|
|
787
920
|
let devices = Object.keys(values);
|
|
@@ -796,7 +929,7 @@ module.exports = function (RED) {
|
|
|
796
929
|
|
|
797
930
|
msgg.topic = topic;
|
|
798
931
|
let payload = {
|
|
799
|
-
presentValue: points[point]["presentValue"]
|
|
932
|
+
presentValue: points[point]["presentValue"],
|
|
800
933
|
};
|
|
801
934
|
msgg.payload = payload;
|
|
802
935
|
node.send(msgg);
|
|
@@ -805,7 +938,7 @@ module.exports = function (RED) {
|
|
|
805
938
|
}
|
|
806
939
|
}
|
|
807
940
|
});
|
|
808
|
-
}
|
|
941
|
+
};
|
|
809
942
|
|
|
810
943
|
function getPointName(object, pointName) {
|
|
811
944
|
if (object.displayName) {
|
|
@@ -813,7 +946,6 @@ module.exports = function (RED) {
|
|
|
813
946
|
}
|
|
814
947
|
return pointName;
|
|
815
948
|
}
|
|
816
|
-
|
|
817
949
|
}
|
|
818
950
|
RED.nodes.registerType("Bacnet-Gateway", BitpoolBacnetGatewayDevice);
|
|
819
951
|
};
|