@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.
- package/LICENSE +201 -0
- package/README.md +171 -0
- package/docs/opcda.idl +1166 -0
- package/package.json +30 -0
- package/src/constants.js +212 -0
- package/src/enumString.js +161 -0
- package/src/filetime.js +79 -0
- package/src/index.js +62 -0
- package/src/opcAsyncIO.js +102 -0
- package/src/opcBrowser.js +285 -0
- package/src/opcCommon.js +84 -0
- package/src/opcGroupStateManager.js +248 -0
- package/src/opcItemIO.js +60 -0
- package/src/opcItemManager.js +415 -0
- package/src/opcItemProperties.js +102 -0
- package/src/opcServer.js +447 -0
- package/src/opcSyncIO.js +213 -0
- package/src/opctypes.js +116 -0
|
@@ -0,0 +1,285 @@
|
|
|
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 {CallBuilder, ComString, ComValue, Types, Pointer, Flags} = require('node-dcom');
|
|
9
|
+
const EnumString = require('./enumString');
|
|
10
|
+
const util = require('util');
|
|
11
|
+
const debug = util.debuglog('node-opc-da');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Represents an OPC Browser
|
|
15
|
+
*/
|
|
16
|
+
class OPCBrowser {
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this._comObj = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param {*} unknown
|
|
25
|
+
* @returns {Promise<?>}
|
|
26
|
+
*/
|
|
27
|
+
async init(unknown) {
|
|
28
|
+
debug("Initing OPCBrowser...");
|
|
29
|
+
if (this._comObj) throw new Error("Already initialized");
|
|
30
|
+
|
|
31
|
+
this._comObj = await unknown.queryInterface(constants.iid.IOPCBrowseServerAddressSpace_IID);
|
|
32
|
+
|
|
33
|
+
debug("OPCBrowser successfully created.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async end() {
|
|
37
|
+
debug("Destroying OPCBrowser...");
|
|
38
|
+
if (!this._comObj) return;
|
|
39
|
+
|
|
40
|
+
let obj = this._comObj;
|
|
41
|
+
this._comObj = null;
|
|
42
|
+
await obj.release();
|
|
43
|
+
debug("OPCBrowser successfully destroyed.");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @returns {Promise<number>}
|
|
49
|
+
* @opNum 0
|
|
50
|
+
*/
|
|
51
|
+
async queryOrganization() {
|
|
52
|
+
debug("Querying OPCServer for items organization...");
|
|
53
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
54
|
+
|
|
55
|
+
let callObject = new CallBuilder(true);
|
|
56
|
+
callObject.setOpnum(0);
|
|
57
|
+
|
|
58
|
+
callObject.addOutParamAsType(Types.SHORT, Flags.FLAG_NULL);
|
|
59
|
+
|
|
60
|
+
let resultObj = await this._comObj.call(callObject);
|
|
61
|
+
|
|
62
|
+
let hresult = resultObj.hresult;
|
|
63
|
+
let result = resultObj.getResults();
|
|
64
|
+
if (hresult != 0) {
|
|
65
|
+
if (result.lenght == 0)
|
|
66
|
+
throw new Error(String(hresult));
|
|
67
|
+
else
|
|
68
|
+
debug(String(new Error(String(hresult))));
|
|
69
|
+
}
|
|
70
|
+
debug("Item organization obtained.");
|
|
71
|
+
return result[0];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @param {string} position
|
|
77
|
+
* @param {number} direction
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
* @opNum 1
|
|
80
|
+
*/
|
|
81
|
+
async changePosition(position, direction) {
|
|
82
|
+
debug("Changing browsing position to " + direction);
|
|
83
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
84
|
+
|
|
85
|
+
let callObject = new CallBuilder(true);
|
|
86
|
+
callObject.setOpnum(1);
|
|
87
|
+
|
|
88
|
+
callObject.addInParamAsShort(direction, Flags.FLAG_NULL);
|
|
89
|
+
callObject.addInParamAsString(position, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
|
|
90
|
+
|
|
91
|
+
let resultObj = await this._comObj.call(callObject);
|
|
92
|
+
|
|
93
|
+
let hresult = resultObj.hresult;
|
|
94
|
+
let result = resultObj.getResults();
|
|
95
|
+
if (hresult != 0) {
|
|
96
|
+
if (result.lenght == 0)
|
|
97
|
+
throw new Error(String(hresult));
|
|
98
|
+
else {
|
|
99
|
+
if (hresult == 1) {
|
|
100
|
+
if (direction == constants.opc.browse.direction.TO)
|
|
101
|
+
debug("Already on top directory.");
|
|
102
|
+
else if (direction == constants.opc.browse.direction.DOWN)
|
|
103
|
+
debug("There is not directory to go down to.");
|
|
104
|
+
else if (direction == constants.opc.browse.direction.UP)
|
|
105
|
+
debug("There is not directory to go up to. Already on top directory");
|
|
106
|
+
} else if (hresult == 0x80004001) {
|
|
107
|
+
debug ("Browsing is not implemented by the server");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
debug("Browsing position successfully changed.");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
*
|
|
116
|
+
* @param {number} type
|
|
117
|
+
* @param {string} [filter=""]
|
|
118
|
+
* @param {number} [dataType=0]
|
|
119
|
+
* @param {number} [accessRights=0]
|
|
120
|
+
* @returns {Promise<EnumString>}
|
|
121
|
+
* @opNum 2
|
|
122
|
+
*/
|
|
123
|
+
async browse(type, filter, accessRights, dataType) {
|
|
124
|
+
debug("Browsing OPCServer with type: " + type + " filter: " + filter + " accessRights: " + accessRights + " dataType: " + dataType + "...");
|
|
125
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
126
|
+
|
|
127
|
+
let callObject = new CallBuilder(true);
|
|
128
|
+
callObject.setOpnum(2);
|
|
129
|
+
|
|
130
|
+
callObject.addInParamAsShort(type, Flags.FLAG_NULL);
|
|
131
|
+
callObject.addInParamAsString(filter, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
|
|
132
|
+
callObject.addInParamAsShort(dataType, Flags.FLAG_NULL);
|
|
133
|
+
callObject.addInParamAsInt(accessRights, Flags.FLAG_NULL);
|
|
134
|
+
callObject.addOutParamAsType(Types.COMOBJECT, Flags.FLAG_NULL);
|
|
135
|
+
|
|
136
|
+
let resultObj = await this._comObj.call(callObject);
|
|
137
|
+
|
|
138
|
+
let hresult = resultObj.hresult;
|
|
139
|
+
let result = resultObj.getResults();
|
|
140
|
+
if (hresult != 0) {
|
|
141
|
+
if (result.lenght == 0)
|
|
142
|
+
throw new Error(String(hresult));
|
|
143
|
+
else {
|
|
144
|
+
if (hresult == 1) {
|
|
145
|
+
if (type == constants.opc.browse.type.LEAF)
|
|
146
|
+
debug("No more leafs found for the current level.");
|
|
147
|
+
else if (type = constants.opc.browse.type.BRANCH)
|
|
148
|
+
debug("No more branches found for the current level.")
|
|
149
|
+
} else if (hresult == 0x80004001) {
|
|
150
|
+
debug("Browsing is not implemented by the server");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let enumResults = new EnumString();
|
|
156
|
+
await enumResults.init(result[0].getValue());
|
|
157
|
+
debug("Browsing request successfully executed.");
|
|
158
|
+
return enumResults;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Gets the complete item id from an item at the local position.
|
|
163
|
+
*
|
|
164
|
+
* Browsing a hierarchical namespace the browse method will return items based on the
|
|
165
|
+
* local level in the namespace. So actually only the last part of the item ID hierarchy
|
|
166
|
+
* is returned. In order to convert this to the full item ID one can use this method. It
|
|
167
|
+
* will only work if the browser is still at the position in question.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} item the local item
|
|
170
|
+
* @returns {Promise<string>} the complete item ID
|
|
171
|
+
* @opNum 3
|
|
172
|
+
*/
|
|
173
|
+
async getItemID(item) {
|
|
174
|
+
debug("Querying OPCServer for itemID: " + item + "...");
|
|
175
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
176
|
+
|
|
177
|
+
let callObject = new CallBuilder(true);
|
|
178
|
+
callObject.setOpnum(3);
|
|
179
|
+
|
|
180
|
+
let strValue = new ComValue(new ComString(Flags.FLAG_REPRESENTATION_STRING_LPWSTR), Types.COMSTRING);
|
|
181
|
+
let strPointerValue = new ComValue(new Pointer(strValue), Types.POINTER);
|
|
182
|
+
callObject.addInParamAsString(item, Flags.FLAG_REPRESENTATION_STRING_LPWSTR );
|
|
183
|
+
callObject.addOutParamAsObject(strPointerValue, Flags.FLAG_NULL);
|
|
184
|
+
|
|
185
|
+
let resultObj = await this._comObj.call(callObject);
|
|
186
|
+
|
|
187
|
+
let hresult = resultObj.hresult;
|
|
188
|
+
let result = resultObj.getResults();
|
|
189
|
+
if (hresult != 0) {
|
|
190
|
+
if (result.lenght == 0)
|
|
191
|
+
throw new Error(String(hresult));
|
|
192
|
+
else
|
|
193
|
+
debug(new Error(String(hresult)));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let resultPtr = result[0].getValue();
|
|
197
|
+
let resultPtrRef = resultPtr.getReferent();
|
|
198
|
+
debug("Item request successfully executed.");
|
|
199
|
+
return resultPtrRef.getString();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Returns the possible access paths for an item
|
|
204
|
+
*
|
|
205
|
+
* @param {string} itemID the item to query
|
|
206
|
+
* @returns {Promise<EnumString>} the complete item ID
|
|
207
|
+
* @opNum 4
|
|
208
|
+
*/
|
|
209
|
+
async browseAccessPaths(itemID) {
|
|
210
|
+
debug("Querying OPCServer for browseAcessPaths for the item " + itemID + "...");
|
|
211
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
212
|
+
|
|
213
|
+
let callObject = new CallBuilder(true);
|
|
214
|
+
callObject.setOpnum(4);
|
|
215
|
+
|
|
216
|
+
callObject.addInParamAsString(itemID, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
|
|
217
|
+
callObject.addOutParamAsType (Types.COMOBJECT, Flags.FLAG_NULL );
|
|
218
|
+
|
|
219
|
+
let resultObj = await this._comObj.call(callObject);
|
|
220
|
+
|
|
221
|
+
let hresult = resultObj.hresult;
|
|
222
|
+
let result = resultObj.getResults();
|
|
223
|
+
if (hresult != 0) {
|
|
224
|
+
if (result.lenght == 0)
|
|
225
|
+
throw new Error(String(hresult));
|
|
226
|
+
else
|
|
227
|
+
debug(new Error(String(hresult)));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let enumResults = new EnumString();
|
|
231
|
+
await enumResults.init(result[0]);
|
|
232
|
+
debug("Item browseAccessPaths successfully obtained.");
|
|
233
|
+
return enumResults;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// -------
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @returns {Promise<Array<string>>} an array with all items in a flat address space
|
|
240
|
+
*/
|
|
241
|
+
async browseAllFlat() {
|
|
242
|
+
debug("Browsing OPCServer on Flat mode...");
|
|
243
|
+
await this.changePosition(null, constants.opc.browse.direction.TO);
|
|
244
|
+
let enumItems = await this.browse(constants.opc.browse.type.FLAT)
|
|
245
|
+
.catch(function(reject) {
|
|
246
|
+
throw reject;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
let result = await enumItems.asArray();
|
|
250
|
+
debug("Successfully browsed OPCServer and obtained " + result.length + " items.");
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @returns {Promise<object>} an object representing the hierarchy of items
|
|
256
|
+
*/
|
|
257
|
+
async browseAllTree() {
|
|
258
|
+
await this.changePosition(null, constants.opc.browse.direction.TO);
|
|
259
|
+
return await this.browseLevel();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* change the browsing level
|
|
264
|
+
*/
|
|
265
|
+
async browseLevel() {
|
|
266
|
+
let res = {}
|
|
267
|
+
|
|
268
|
+
// get items on this level
|
|
269
|
+
let enumItems = await this.browse(constants.opc.browse.type.LEAF);
|
|
270
|
+
let items = await enumItems.asArray();
|
|
271
|
+
for (const item of items) {
|
|
272
|
+
res[item] = await this.getItemID(item);
|
|
273
|
+
}
|
|
274
|
+
let enumBranches = await this.browse(constants.opc.browse.type.BRANCH);
|
|
275
|
+
let branches = await enumBranches.asArray();
|
|
276
|
+
for (const branch of branches) {
|
|
277
|
+
await this.changePosition(branch, constants.opc.browse.direction.DOWN);
|
|
278
|
+
res[branch] = await this.browseLevel();
|
|
279
|
+
await this.changePosition(null, constants.opc.browse.direction.UP);
|
|
280
|
+
}
|
|
281
|
+
return res;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
module.exports = OPCBrowser;
|
package/src/opcCommon.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
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 Server
|
|
11
|
+
*/
|
|
12
|
+
class OPCCommon {
|
|
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.IOPCCommon_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 {number} localeId
|
|
40
|
+
* @opNum 0
|
|
41
|
+
*/
|
|
42
|
+
async setLocaleID(localeId) {
|
|
43
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @returns the current localeID
|
|
49
|
+
* @opNum 1
|
|
50
|
+
*/
|
|
51
|
+
async getLocaleID() {
|
|
52
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @returns the available localeIDs
|
|
57
|
+
* @opNum 2
|
|
58
|
+
*/
|
|
59
|
+
async queryAvailableLocaleIDs() {
|
|
60
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @param {number} error
|
|
66
|
+
* @param {number} [localeID]
|
|
67
|
+
* @returns a descriptive error string for the error code
|
|
68
|
+
* @opNum 3
|
|
69
|
+
*/
|
|
70
|
+
async getErrorString(error, localeID) {
|
|
71
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @param {string} name the client name
|
|
77
|
+
* @opNum 4
|
|
78
|
+
*/
|
|
79
|
+
async setClientName(name) {
|
|
80
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = OPCCommon;
|
|
@@ -0,0 +1,248 @@
|
|
|
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 OPCItemManager = require('./opcItemManager.js');
|
|
9
|
+
const OPCSyncIO = require('./opcSyncIO.js');
|
|
10
|
+
const OPCAsyncIO = require('./opcAsyncIO.js');
|
|
11
|
+
const util = require('util');
|
|
12
|
+
const debug = util.debuglog('node-opc-da');
|
|
13
|
+
const { EventEmitter } = require('events');
|
|
14
|
+
|
|
15
|
+
const { CallBuilder, ComString, ComValue, Flags, Pointer, types} = require('node-dcom');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Group properties
|
|
20
|
+
* @typedef {object} GroupProperties
|
|
21
|
+
* @property {number} updateRate
|
|
22
|
+
* @property {boolean} active
|
|
23
|
+
* @property {number} timeBias
|
|
24
|
+
* @property {number} deadband
|
|
25
|
+
* @property {number} localeID
|
|
26
|
+
* @property {number} [clientHandle]
|
|
27
|
+
* @property {number} [serverHandle]
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents an OPC Server
|
|
33
|
+
* @emits data
|
|
34
|
+
*/
|
|
35
|
+
class OPCGroupStateManager extends EventEmitter {
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
|
|
40
|
+
this._opcItemManager = null;
|
|
41
|
+
this._syncIO = null;
|
|
42
|
+
this._asyncIO = null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @param {*} unknown
|
|
48
|
+
* @returns {Promise<?>}
|
|
49
|
+
*/
|
|
50
|
+
async init(unknown) {
|
|
51
|
+
debug("Initing opcGroupStateManager...");
|
|
52
|
+
if (this._comObj) throw new Error("Already initialized");
|
|
53
|
+
|
|
54
|
+
this._comObj = await unknown.queryInterface(constants.iid.IOPCGroupStateMgt_IID);
|
|
55
|
+
debug("opcGroupStateManager successfully inited");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async end() {
|
|
59
|
+
debug("Destryoing opcGroupStateManager...")
|
|
60
|
+
if (!this._comObj) return;
|
|
61
|
+
|
|
62
|
+
let obj = this._comObj;
|
|
63
|
+
let opcItemManager = this._opcItemManager;
|
|
64
|
+
let syncIO = this._syncIO;
|
|
65
|
+
let asyncIO = this._asyncIO;
|
|
66
|
+
this._comObj = null;
|
|
67
|
+
this._opcItemManager = null;
|
|
68
|
+
this._syncIO = null;
|
|
69
|
+
this._asyncIO = null;
|
|
70
|
+
|
|
71
|
+
//TODO maybe paralelize this with Promise.all
|
|
72
|
+
if (opcItemManager) await opcItemManager.end();
|
|
73
|
+
if (syncIO) await syncIO.end();
|
|
74
|
+
if (asyncIO) await asyncIO.end();
|
|
75
|
+
await obj.release();
|
|
76
|
+
|
|
77
|
+
debug("opcGroupStateManager successfully desroyed.");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @returns {Object<{name: string}, {state: GroupProperties}}>}
|
|
82
|
+
*/
|
|
83
|
+
async getState() {
|
|
84
|
+
debug("Querying OPCServer for the current state of the group...");
|
|
85
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
86
|
+
|
|
87
|
+
let callObject = new CallBuilder(true);
|
|
88
|
+
callObject.setOpnum(0);
|
|
89
|
+
|
|
90
|
+
let namePtr = new Pointer(new ComValue(new ComString(Flags.FLAG_REPRESENTATION_STRING_LPWSTR), types.COMSTRING));
|
|
91
|
+
|
|
92
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
93
|
+
callObject.addOutParamAsType(types.BOOLEAN, Flags.FLAG_NULL);
|
|
94
|
+
callObject.addOutParamAsObject(new ComValue(namePtr, types.POINTER), Flags.FLAG_NULL);
|
|
95
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
96
|
+
callObject.addOutParamAsType(types.FLOAT, Flags.FLAG_NULL);
|
|
97
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
98
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
99
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
100
|
+
|
|
101
|
+
let result = await this._comObj.call(callObject);
|
|
102
|
+
|
|
103
|
+
debug("Group State successfully obtained.");
|
|
104
|
+
return {
|
|
105
|
+
name: result[2].getReferent().getString(),
|
|
106
|
+
state: {
|
|
107
|
+
updateRate: result[0],
|
|
108
|
+
active: result[1],
|
|
109
|
+
timeBias: result[3],
|
|
110
|
+
deadband: result[4],
|
|
111
|
+
localeID: result[5],
|
|
112
|
+
clientHandle: result[6],
|
|
113
|
+
serverHandle: result[7]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @param {GroupProperties} state
|
|
121
|
+
* @returns {Promise<number>} the granted update rate
|
|
122
|
+
* @opNum 1
|
|
123
|
+
*/
|
|
124
|
+
async setState(state) {
|
|
125
|
+
debug("Querying OPCServer to set the group properties: " + state);
|
|
126
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
127
|
+
|
|
128
|
+
let callObject = new CallBuilder(true);
|
|
129
|
+
callObject.setOpnum(1);
|
|
130
|
+
|
|
131
|
+
let activeCV = state.active === null ? null : new ComValue(state.active ? 1 : 0, types.INTEGER);
|
|
132
|
+
|
|
133
|
+
callObject.addInParamAsPointer(new Pointer(new ComValue(state.updateRate, types.INTEGER)), Flags.FLAG_NULL);
|
|
134
|
+
callObject.addInParamAsPointer(new Pointer(activeCV), Flags.FLAG_NULL);
|
|
135
|
+
callObject.addInParamAsPointer(new Pointer(new ComValue(state.timeBias, types.INTEGER)), Flags.FLAG_NULL);
|
|
136
|
+
callObject.addInParamAsPointer(new Pointer(new ComValue(state.deadband, types.FLOAT)), Flags.FLAG_NULL);
|
|
137
|
+
callObject.addInParamAsPointer(new Pointer(new ComValue(state.localeID, types.INTEGER)), Flags.FLAG_NULL);
|
|
138
|
+
callObject.addInParamAsPointer(new Pointer(new ComValue(state.clientHandle, types.INTEGER)), Flags.FLAG_NULL);
|
|
139
|
+
|
|
140
|
+
callObject.addOutParamAsType(types.INTEGER, Flags.FLAG_NULL);
|
|
141
|
+
|
|
142
|
+
let result = await this._comObj.call(callObject);
|
|
143
|
+
debug("Group Properties sucessfully set.");
|
|
144
|
+
return result[0];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* @param {string} name
|
|
150
|
+
* @returns {Promise<void>}
|
|
151
|
+
* @opNum 2
|
|
152
|
+
*/
|
|
153
|
+
async setName(name) {
|
|
154
|
+
debug("Setting group name to: " + name + "...");
|
|
155
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
156
|
+
|
|
157
|
+
let callObject = new CallBuilder(true);
|
|
158
|
+
callObject.setOpnum(2);
|
|
159
|
+
|
|
160
|
+
callObject.addInParamAsString(name, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
|
|
161
|
+
|
|
162
|
+
await this._comObj.call(callObject);
|
|
163
|
+
debug("Group Name successfully set");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
*
|
|
168
|
+
* @param {string} name
|
|
169
|
+
* @returns {Promise<OPCGroupStateManager>}
|
|
170
|
+
* @opNum 3
|
|
171
|
+
*/
|
|
172
|
+
async clone(name) {
|
|
173
|
+
debug("Cloning group named: " + name + "...");
|
|
174
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
175
|
+
|
|
176
|
+
let callObject = new CallBuilder(true);
|
|
177
|
+
callObject.setOpnum(3);
|
|
178
|
+
|
|
179
|
+
callObject.addInParamAsString(name, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
|
|
180
|
+
callObject.addInParamAsUUID(constants.iid.IOPCGroupStateMgt_IID, Flags.FLAG_NULL);
|
|
181
|
+
callObject.addOutParamAsType(types.COMOBJECT, Flags.FLAG_NULL);
|
|
182
|
+
|
|
183
|
+
let result = await this._comObj.call(callObject);
|
|
184
|
+
|
|
185
|
+
let group = new OPCGroupStateManager();
|
|
186
|
+
await group.init(result[0]);
|
|
187
|
+
|
|
188
|
+
return group;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* enables receiving events to this group
|
|
193
|
+
*
|
|
194
|
+
* @returns {Promise<void>}
|
|
195
|
+
*/
|
|
196
|
+
async atach() {
|
|
197
|
+
throw new Error("Not yet supported");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @returns {Promise<OPCItemManager>}
|
|
202
|
+
*/
|
|
203
|
+
async getItemManager() {
|
|
204
|
+
debug("Querying server for an ItemManager for the current group...");
|
|
205
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
206
|
+
|
|
207
|
+
if (!this._opcItemManager) {
|
|
208
|
+
let opcItemManager = new OPCItemManager();
|
|
209
|
+
await opcItemManager.init(this._comObj);
|
|
210
|
+
this._opcItemManager = opcItemManager;
|
|
211
|
+
}
|
|
212
|
+
debug("ItemManager successfully obtained.");
|
|
213
|
+
return this._opcItemManager;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @returns {Promise<OPCSyncIO>}
|
|
218
|
+
*/
|
|
219
|
+
async getSyncIO() {
|
|
220
|
+
debug("Querying OPCServer for a SyncIO object...");
|
|
221
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
222
|
+
|
|
223
|
+
if (!this._syncIO) {
|
|
224
|
+
let syncIO = new OPCSyncIO();
|
|
225
|
+
await syncIO.init(this._comObj);
|
|
226
|
+
this._syncIO = syncIO;
|
|
227
|
+
}
|
|
228
|
+
debug("SyncIO object successfully obtained.");
|
|
229
|
+
return this._syncIO;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @returns {Promise<OPCAsyncIO>}
|
|
234
|
+
*/
|
|
235
|
+
async getAsyncIO2() {
|
|
236
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
237
|
+
|
|
238
|
+
if (!this._asyncIO) {
|
|
239
|
+
let asyncIO = new OPCAsyncIO();
|
|
240
|
+
await asyncIO.init(this._comObj);
|
|
241
|
+
this._asyncIO = asyncIO;
|
|
242
|
+
}
|
|
243
|
+
return this._asyncIO;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = OPCGroupStateManager;
|
package/src/opcItemIO.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
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 OPCItemIO {
|
|
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.IOPCItemIO_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 {object[]} items
|
|
40
|
+
* @param {string} items[].itemID
|
|
41
|
+
* @param {number} items[].maxAge
|
|
42
|
+
* @returns {Promise<?>}
|
|
43
|
+
* @opNum 0
|
|
44
|
+
*/
|
|
45
|
+
async read(items) {
|
|
46
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {object[]} items ????
|
|
52
|
+
* @returns {Promise<?>}
|
|
53
|
+
* @opNum 1
|
|
54
|
+
*/
|
|
55
|
+
async writeVQT(items) {
|
|
56
|
+
if (!this._comObj) throw new Error("Not initialized");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = OPCItemIO;
|