@tier0/node-opc-da 1.0.7

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.
@@ -0,0 +1,415 @@
1
+ //@ts-check
2
+ /*
3
+ Copyright: (c) 2019, Guilherme Francescon Cittolin <gfcittolin@gmail.com>
4
+ GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+ */
6
+
7
+ const constants = require('./constants.js');
8
+ const util = require('util');
9
+ const debug = util.debuglog('node-opc-da');
10
+
11
+ const { CallBuilder, ComArray, ComString, ComValue, Flags, Pointer, Struct, Variant, Types } = require('node-dcom');
12
+
13
+ /**
14
+ * @typedef {object} ItemStruct
15
+ * @property {string} itemID
16
+ * @property {number} clientHandle
17
+ * @property {string} [accessPath]
18
+ * @property {boolean} [active]
19
+ * @property {number} [requestedDataType]
20
+ * @property {number} [reserved]
21
+ */
22
+
23
+ /**
24
+ * @typedef {object} ItemResponse
25
+ * @property {string} itemID
26
+ * @property {number} serverHandle
27
+ * @property {number} cannonicalDataType
28
+ * @property {number} reserved
29
+ * @property {number} accessRights
30
+ */
31
+
32
+ /**
33
+ *
34
+ * @param {ItemStruct} item
35
+ * @returns {Struct}
36
+ */
37
+ function getItemDefStruct(item) {
38
+
39
+ let itemID, clientHandle, accessPath, active, requestedDataType, reserved;
40
+
41
+ if (item.itemID === null || item.itemID === undefined) {
42
+ throw new Error("Missing required itemID")
43
+ }
44
+ itemID = item.itemID;
45
+ clientHandle = item.clientHandle || Math.random() * 0xffffffff;
46
+ accessPath = item.accessPath || '';
47
+ active = item.active !== undefined ? item.active : true;
48
+ requestedDataType = item.requestedDataType || 0;
49
+ reserved = item.reserved || 0;
50
+
51
+ let struct = new Struct();
52
+ struct.addMember(new ComValue(new ComString(accessPath, Flags.FLAG_REPRESENTATION_STRING_LPWSTR), Types.COMSTRING));
53
+ struct.addMember(new ComValue(new ComString(itemID, Flags.FLAG_REPRESENTATION_STRING_LPWSTR), Types.COMSTRING));
54
+ struct.addMember(new ComValue(active ? 1 : 0, Types.INTEGER));
55
+ struct.addMember(new ComValue(clientHandle, Types.INTEGER));
56
+ struct.addMember(new ComValue(0, Types.INTEGER)); //blob size
57
+ struct.addMember(new ComValue(new Pointer(null), Types.POINTER)); // blob
58
+ struct.addMember(new ComValue(requestedDataType, Types.SHORT));
59
+ struct.addMember(new ComValue(reserved, Types.SHORT));
60
+
61
+ return struct;
62
+ }
63
+
64
+ /**
65
+ * @returns {Struct}
66
+ */
67
+ function getItemResultStruct() {
68
+ let struct = new Struct();
69
+
70
+ struct.addMember(new ComValue(null, Types.INTEGER)); // Server handle
71
+ struct.addMember(new ComValue(null, Types.SHORT)); // data type
72
+ struct.addMember(new ComValue(null, Types.SHORT)); // reserved
73
+ struct.addMember(new ComValue(null, Types.INTEGER)); // access rights
74
+ struct.addMember(new ComValue(null, Types.INTEGER)); // blob size
75
+ struct.addMember(new ComValue(new Pointer(new ComValue(new ComArray(new ComValue(null, Types.BYTE), null, 1, true, false), Types.COMARRAY)), Types.POINTER)); // blob size
76
+
77
+ return struct;
78
+ }
79
+
80
+ /**
81
+ * Represents an OPC Server
82
+ */
83
+ class OPCItemManager {
84
+
85
+ constructor() {
86
+ this._comObj = null;
87
+ }
88
+
89
+ /**
90
+ *
91
+ * @param {*} unknown
92
+ * @returns {Promise<void>}
93
+ */
94
+ async init(unknown) {
95
+ debug("Initing ItemManager...");
96
+ if (this._comObj) throw new Error("Already initialized");
97
+
98
+ this._comObj = await unknown.queryInterface(constants.iid.IOPCItemMgt_IID);
99
+ debug("ItemManager successfully initted");
100
+ }
101
+
102
+ /**
103
+ * @returns {Promise<void>}
104
+ */
105
+ async end() {
106
+ debug("Destroyin ItemManager...");
107
+ if (!this._comObj) return;
108
+
109
+ let obj = this._comObj;
110
+ this._comObj = null;
111
+ await obj.release();
112
+ debug("ItemManager successfully destroyed.");
113
+ }
114
+
115
+ /**
116
+ *
117
+ * @param {Array<ItemStruct>} items
118
+ * @returns {Promise<Array<Array<number,ItemResponse>>>}
119
+ * @opNum 0
120
+ */
121
+ async add(items) {
122
+ debug("Adding " + items.length + " to the current group: ");
123
+ for (let i = 0; i < items.length; i++)
124
+ debug(items[i].itemID);
125
+
126
+ if (!this._comObj) throw new Error("Not initialized");
127
+
128
+ if (!(items.length > 0)) return [];
129
+
130
+ let structs = [];
131
+ for (const item of items) {
132
+ structs.push(new ComValue(getItemDefStruct(item), Types.STRUCT));
133
+ }
134
+
135
+ let itemArray = new ComArray(new ComValue(structs, Types.STRUCT), true);
136
+
137
+ let callObject = new CallBuilder(true);
138
+ callObject.setOpnum(0);
139
+
140
+ callObject.addInParamAsInt(items.length, Flags.FLAG_NULL);
141
+ callObject.addInParamAsArray(itemArray, Flags.FLAG_NULL);
142
+ let resStructArray = new ComArray(new ComValue(getItemResultStruct(), Types.STRUCT), null, 1, true)
143
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
144
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(resStructArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
145
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
146
+
147
+ let resultObj = await this._comObj.call(callObject);
148
+
149
+ let hresult = resultObj.hresult;
150
+ let result = resultObj.getResults();
151
+ if (hresult != 0) {
152
+ if (result.lenght == 0)
153
+ throw new Error(String(hresult));
154
+ else
155
+ debug(new Error(String(hresult)));
156
+ }
157
+
158
+ let results = result[0].getValue().getReferent().getArrayInstance();
159
+ let errorCodes = result[1].getValue().getReferent().getArrayInstance();
160
+
161
+ let res = [];
162
+ let failed = [];
163
+ for (let i = 0; i < items.length; i++) {
164
+ let resObj = {
165
+ itemID: items[i].itemID,
166
+ serverHandle: results[i].getValue().getMember(0).getValue(),
167
+ cannonicalDataType: results[i].getValue().getMember(1).getValue(),
168
+ reserved: results[i].getValue().getMember(2).getValue(),
169
+ accessRights: results[i].getValue().getMember(3).getValue()
170
+
171
+ };
172
+ res.push([errorCodes[i].getValue(), resObj]);
173
+ if (errorCodes[i].getValue() != 0)
174
+ failed.push([errorCodes[i].getValue(), resObj.itemID]);
175
+ }
176
+ debug("A total of " + (res.length - failed.length) + " items were successfully added to the group.");
177
+ if (failed.length > 0) {
178
+ debug("The following items were not added: ");
179
+ for (let i = 0; i < failed.length; i++)
180
+ debug("Item: " + failed[i][0] + " ErrorCode: " + failed[i][1]);
181
+ }
182
+ return res;
183
+ }
184
+
185
+ /**
186
+ *
187
+ * @param {Array<ItemStruct>} items
188
+ * @returns {Promise<Array<Array<number,ItemResponse>>>}
189
+ * @opNum 1
190
+ */
191
+ async validate(items) {
192
+ debug("Querying server to validade " + items.length + " items: ");
193
+ for (let i = 0; i < items.length; i++)
194
+ debug(items[i].itemID);
195
+
196
+ if (!this._comObj) throw new Error("Not initialized");
197
+
198
+ if (!(items.length > 0)) return [];
199
+
200
+ let structs = [];
201
+ for (const item of items) {
202
+ structs.push(new ComValue(getItemDefStruct(item), Types.STRUCT));
203
+ }
204
+
205
+ let itemArray = new ComArray(new ComValue(structs, Types.STRUCT), true);
206
+
207
+ let callObject = new CallBuilder(true);
208
+ callObject.setOpnum(1);
209
+
210
+ callObject.addInParamAsInt(items.length, Flags.FLAG_NULL);
211
+ callObject.addInParamAsArray(itemArray, Flags.FLAG_NULL);
212
+ callObject.addInParamAsInt(0, Flags.FLAG_NULL); // don't update blobs
213
+ let resStructArray = new ComArray(new ComValue(getItemResultStruct(), Types.STRUCT), null, 1, true)
214
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
215
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(resStructArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
216
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
217
+
218
+ let resultObj = await this._comObj.call(callObject);
219
+
220
+ let hresult = resultObj.hresult;
221
+ let result = resultObj.getResults();
222
+ if (hresult != 0) {
223
+ if (result.lenght == 0)
224
+ throw new Error(String(hresult));
225
+ else
226
+ debug(new Error(String(hresult)));
227
+ }
228
+
229
+ let results = result[0].getValue().getReferent().getArrayInstance();
230
+ let errorCodes = result[1].getValue().getReferent().getArrayInstance();
231
+
232
+ let res = [];
233
+ let failed = []
234
+ for (let i = 0; i < items.length; i++) {
235
+ let resObj = {
236
+ itemID: items[i].itemID,
237
+ serverHandle: results[i].getValue().getMember(0),
238
+ cannonicalDataType: results[i].getValue().getMember(1),
239
+ reserved: results[i].getValue().getMember(2),
240
+ accessRights: results[i].getValue().getMember(3),
241
+ errorCode: errorCodes[i].getValue()
242
+ };
243
+ res.push([errorCodes[i], resObj]);
244
+ if (errorCodes[i].getValue() != 0) {
245
+ failed.push([errorCodes[i].getValue(), resObj.itemID])
246
+ }
247
+ }
248
+ debug("A total of " + res.length + " were successfully validated.");
249
+ if (failed.length > 0) {
250
+ debug("The following items were not added: ");
251
+ for (let i = 0; i < failed.length; i++)
252
+ debug("Item: " + failed[i][0] + " ErrorCode: " + failed[i][1]);
253
+ }
254
+ return res;
255
+ }
256
+
257
+ /**
258
+ *
259
+ * @param {Array<number>} items array of server handles
260
+ * @returns {Promise<Array<object>>}
261
+ * @opNum 2
262
+ */
263
+ async remove(items) {
264
+ debug("Removing " + items.length + "items: ");
265
+ for (let i = 0; i < items.length; i++)
266
+ debug(String(items[i]));
267
+ if (!this._comObj) throw new Error("Not initialized");
268
+
269
+ if (!(items.length > 0)) return [];
270
+
271
+ let temporary = new Array();
272
+ for (let i = 0; i < items.length; i++) {
273
+ temporary.push(new ComValue(items[i], Types.INTEGER));
274
+ }
275
+
276
+ let itemArray = new ComArray(new ComValue(temporary, Types.INTEGER), true);
277
+
278
+ let callObject = new CallBuilder(true);
279
+ callObject.setOpnum(2);
280
+
281
+ callObject.addInParamAsInt(items.length, Flags.FLAG_NULL);
282
+ callObject.addInParamAsArray(itemArray, Flags.FLAG_NULL);
283
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
284
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
285
+
286
+ let resultObj = await this._comObj.call(callObject);
287
+
288
+ let hresult = resultObj.hresult;
289
+ let result = resultObj.getResults();
290
+ if (hresult != 0) {
291
+ if (result.lenght == 0)
292
+ throw new Error(String(hresult));
293
+ else
294
+ debug(new Error(String(hresult)));
295
+ }
296
+ debug("Items successfully removed.");
297
+ return result[0].getValue().getReferent().getArrayInstance();
298
+ }
299
+
300
+ /**
301
+ *
302
+ * @param {boolean} state
303
+ * @param {Array<number>} items
304
+ * @returns {Promise<Array<number>>}
305
+ * @opNum 3
306
+ */
307
+ async setActiveState(state, items) {
308
+ debug("Changing the active state of " + items.length + "items: ");
309
+ for (let i = 0; i < items.length; i++)
310
+ debug(String(items[i]), state[i]);
311
+
312
+ if (!this._comObj) throw new Error("Not initialized");
313
+
314
+ if (!(items.length > 0)) return [];
315
+
316
+ let temporary = new Array();
317
+ for (let i = 0; i < items.length; i++)
318
+ temporary.push(new ComValue(items[i], Types.INTEGER));
319
+
320
+ let itemArray = new ComArray(new ComValue(temporary, Types.INTEGER), true);
321
+
322
+ let callObject = new CallBuilder(true);
323
+ callObject.setOpnum(3);
324
+
325
+ callObject.addInParamAsInt(items.length, Flags.FLAG_NULL);
326
+ callObject.addInParamAsArray(itemArray, Flags.FLAG_NULL);
327
+ callObject.addInParamAsInt(state ? 1 : 0, Flags.FLAG_NULL);
328
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
329
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
330
+
331
+ let resultObj = await this._comObj.call(callObject);
332
+
333
+ let hresult = resultObj.hresult;
334
+ let result = resultObj.getResults();
335
+ if (hresult != 0) {
336
+ if (result.lenght == 0)
337
+ throw new Error(String(hresult));
338
+ else
339
+ debugg(new Error(String(hresult)));
340
+ }
341
+
342
+ let errorCodes = result[0].getValue().getReferent().getArrayInstance();
343
+ let results = new Array();
344
+ let failed = new Array();
345
+ for (let i = 0; i < items.length; i++) {
346
+ results.push({value: items[i], errorCode: errorCodes[i]});
347
+ if (errorCodes[i].getValue() != 0) {
348
+ failed.push([errorCodes[i].getValue(), items[i]]);
349
+ }
350
+ }
351
+
352
+ debug("A total of " + (results.length - failed.length) + " had their active status setted to " + state + ".");
353
+ if (failed.length > 0) {
354
+ debug("The following items were not added: ");
355
+ for (let i = 0; i < failed.length; i++)
356
+ debug("Item: " + failed[i][0] + " ErrorCode: " + failed[i][1]);
357
+ }
358
+ return results;
359
+ }
360
+
361
+ /**
362
+ *
363
+ * @param {Array<number>} items array of server handles
364
+ * @param {Array<number>} handles array of client handles
365
+ * @returns {Promise<Array<number>>}
366
+ * @opNum 4
367
+ */
368
+ async setClientHandles(items, handles) {
369
+ debug("Setting the handle of " + items.length + "items: ");
370
+ for (let i = 0; i < items.length; i++)
371
+ debug(String(items[i]), handles[i]);
372
+
373
+ if (!this._comObj) throw new Error("Not initialized");
374
+
375
+ if (items.length !== handles.length) throw new Error("Array sizes must be the same");
376
+
377
+ if (!(items.length > 0)) return [];
378
+
379
+ let temporaryItems = new Array();
380
+ for (let i = 0; i < items.length; i++)
381
+ temporaryItems.push(new ComValue(items[i], Types.INTEGER));
382
+
383
+ let temporaryHandles = new Array();
384
+ for (let i = 0; i < handles.length; i++)
385
+ temporaryHandles.push(new ComValue(handles[i], Types.INTEGER));
386
+
387
+ let itemArray = new ComArray(new ComValue(temporaryItems, Types.INTEGER), true);
388
+ let handlesArray = new ComArray(new ComValue(temporaryHandles, Types.INTEGER), true);
389
+
390
+ let callObject = new CallBuilder(true);
391
+ callObject.setOpnum(4);
392
+
393
+ callObject.addInParamAsInt(items.length, Flags.FLAG_NULL);
394
+ callObject.addInParamAsArray(itemArray, Flags.FLAG_NULL);
395
+ callObject.addInParamAsArray(handlesArray, Flags.FLAG_NULL);
396
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
397
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
398
+
399
+ let resultObj = await this._comObj.call(callObject);
400
+
401
+ let hresult = resultObj.hresult;
402
+ let result = resultObj.getResults();
403
+ if (hresult != 0) {
404
+ if (result.lenght == 0)
405
+ throw new Error(String(hresult));
406
+ else
407
+ debug(new Error(String(hresult)));
408
+ }
409
+
410
+ debug("Clients handles setted.");
411
+ return result[0].getValue().getReferent().getArrayInstance();
412
+ }
413
+ }
414
+
415
+ module.exports = OPCItemManager;
@@ -0,0 +1,102 @@
1
+ //@ts-check
2
+ /*
3
+ Copyright: (c) 2019, Guilherme Francescon Cittolin <gfcittolin@gmail.com>
4
+ GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+ */
6
+
7
+ const constants = require('./constants.js');
8
+
9
+ /**
10
+ * Represents an OPC Item I/O object
11
+ */
12
+ class OPCItemProperties {
13
+
14
+ constructor() {
15
+ this._comObj = null;
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param {*} unknown
21
+ * @returns {Promise<?>}
22
+ */
23
+ async init(unknown) {
24
+ if (this._comObj) throw new Error("Already initialized");
25
+
26
+ this._comObj = await unknown.queryInterface(constants.iid.IOPCItemProperties_IID);
27
+ }
28
+
29
+ async end() {
30
+ if (!this._comObj) return;
31
+
32
+ let obj = this._comObj;
33
+ this._comObj = null;
34
+ await obj.release();
35
+ }
36
+
37
+ /**
38
+ *
39
+ * @param {string} itemID
40
+ * @returns {Promise<Array<object>>} the item's properties
41
+ * @opNum 0
42
+ */
43
+ async queryAvailableProperties(itemID) {
44
+ if (!this._comObj) throw new Error("Not initialized");
45
+
46
+ //should return array of {id, description, varType}
47
+ }
48
+
49
+ /**
50
+ *
51
+ * @param {string} itemID
52
+ * @param {number[]} props
53
+ * @returns {Promise<Array<object>>}
54
+ * @opNum 1
55
+ */
56
+ async getItemProperties(itemID, props) {
57
+ if (!this._comObj) throw new Error("Not initialized");
58
+
59
+ // should return array of {id, value, errorCode}
60
+ }
61
+
62
+ /**
63
+ *
64
+ * @param {string} itemID
65
+ * @param {number[]} props
66
+ * @returns {Promise<object>}
67
+ * @opNum 2
68
+ */
69
+ async lookupItemIDs(itemID, props) {
70
+ if (!this._comObj) throw new Error("Not initialized");
71
+
72
+ }
73
+
74
+ // --------
75
+
76
+ /**
77
+ *
78
+ * @param {string} itemID
79
+ * @returns {Promise<Array<object>}
80
+ */
81
+ async getAllItemProperties(itemID){
82
+ let props = await this.queryAvailableProperties(itemID);
83
+ let propIDs = props.map(elm => elm.id)
84
+ let propVals = await this.getItemProperties(itemID, propIDs);
85
+ let result = [];
86
+
87
+ for(let i = 0; i < propIDs.length; i++){
88
+ result.push({
89
+ id: props[i].id,
90
+ description: props[i].description,
91
+ varType: props[i].varType,
92
+ value: propVals[i].value,
93
+ errorCode: propVals[i].errorCode
94
+ });
95
+ }
96
+
97
+ return result;
98
+ }
99
+
100
+ }
101
+
102
+ module.exports = OPCItemProperties;