@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/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@tier0/node-opc-da",
3
+ "version": "1.0.7",
4
+ "description": "A library to communicate with OPC-DA servers",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/FREEZONEX/node-opc-da.git"
12
+ },
13
+ "keywords": [
14
+ "opc",
15
+ "opc-da",
16
+ "automation",
17
+ "plc",
18
+ "hardware"
19
+ ],
20
+ "author": "Guilherme Francescon <guilherme.francescon@netsmarttech.com>",
21
+ "license": "Apache-2.0",
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "dependencies": {
26
+ "@tier0/node-dcom": "^1.2.0",
27
+ "random": "^2.1.1",
28
+ "long": "^4.0.0"
29
+ }
30
+ }
@@ -0,0 +1,212 @@
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 = {
8
+ clsid: {
9
+ OPCServerList_CLSID: "13486D51-4821-11D2-A494-3CB306C10000"
10
+ },
11
+ iid: {
12
+ IConnectionPointContainer_IID: "B196B284-BAB4-101A-B69C-00AA00341D07",
13
+ IConnectionPoint_IID: "B196B286-BAB4-101A-B69C-00AA00341D07",
14
+ IOPCCommon_IID: "F31DFDE2-07B6-11D2-B2D8-0060083BA1FB",
15
+ IEnumString_IID: "00000101-0000-0000-C000-000000000046",
16
+ IEnumGUID_IID: "0002E000-0000-0000-C000-000000000046",
17
+ IOPCServer_IID: "39C13A4D-011E-11D0-9675-0020AFD8ADB3",
18
+ IOPCGroupStateMgt_IID: "39C13A50-011E-11D0-9675-0020AFD8ADB3",
19
+ IOPCBrowse_IID: "39227004-A18F-4B57-8B0A-5235670F4468",
20
+ IOPCBrowseServerAddressSpace_IID: "39C13A4F-011E-11D0-9675-0020AFD8ADB3",
21
+ IOPCItemMgt_IID: "39C13A54-011E-11D0-9675-0020AFD8ADB3",
22
+ IOPCItemProperties_IID: "39C13A72-011E-11D0-9675-0020AFD8ADB3",
23
+ IOPCItemIO_IID: "85C0B427-2893-4CBC-BD78-E5FC5146F08F",
24
+ IOPCDataCallback_IID: "39C13A70-011E-11D0-9675-0020AFD8ADB3",
25
+ IOPCAsyncIO2_IID: "39C13A71-011E-11D0-9675-0020AFD8ADB3",
26
+ IOPCSyncIO_IID: "39C13A52-011E-11D0-9675-0020AFD8ADB3",
27
+ IOPCServerList_IID: "13486D50-4821-11D2-A494-3CB306C10000"
28
+ },
29
+ category: {
30
+ OPCDAServer10: "63D5F430-CFE4-11d1-B2C8-0060083BA1FB",
31
+ OPCDAServer20: "63D5F432-CFE4-11d1-B2C8-0060083BA1FB",
32
+ OPCDAServer30: "CC603642-66D7-48f1-B69A-B625E73652D7",
33
+ XMLDAServer10: "3098EDA4-A006-48b2-A27F-247453959408"
34
+ },
35
+ opc: {
36
+ browse: {
37
+ direction: {
38
+ UNKNOWN: 0,
39
+ UP: 1,
40
+ DOWN: 2,
41
+ TO: 3
42
+ },
43
+ type: {
44
+ UNKNOWN: 0,
45
+ BRANCH: 1,
46
+ LEAF: 2,
47
+ FLAT: 3
48
+ }
49
+ },
50
+ dataSource: {
51
+ UNKNOWN: 0,
52
+ CACHE: 1,
53
+ DEVICE: 2
54
+ },
55
+ scope: {
56
+ UNKNOWN: 0,
57
+ PRIVATE_CONNECTIONS: 1,
58
+ PUBLIC_CONNECTIONS: 2,
59
+ ALL_CONNECTIONS: 3,
60
+ PRIVATE: 4,
61
+ PUBLIC: 5,
62
+ ALL: 6
63
+ },
64
+ namespaceType: {
65
+ UNKNOWN: 0,
66
+ HIERARCHIAL: 1,
67
+ FLAT: 2
68
+ },
69
+ state: {
70
+ UNKNOWN: 0,
71
+ RUNNING: 1,
72
+ FAILED: 2,
73
+ NOCONFIG: 3,
74
+ SUSPENDED: 4,
75
+ TEST: 5,
76
+ COMM_FAULT: 6
77
+ },
78
+ stateLabel: {
79
+ "0": "unknown",
80
+ "1": "running",
81
+ "2": "failed",
82
+ "3": "noconfig",
83
+ "4": "suspended",
84
+ "5": "test",
85
+ "6": "comm_fault"
86
+ },
87
+ error: {
88
+ OPCInvalidHandle: 3221487617,
89
+ OPCBadType: 3221487620,
90
+ OPCPublic: 3221487621,
91
+ OPCBadRights: 3221487622,
92
+ OPCUnknownItemID: 3221487623,
93
+ OPCInvalidItemID: 3221487624,
94
+ OPCInvalidFilter: 3221487625,
95
+ OPCUnknownPath: 3221487626,
96
+ OPCRange: 3221487627,
97
+ OPCDuplicateName: 3221487628,
98
+ OPCUnsupportedRate: 262157,
99
+ OPCClamp: 262158,
100
+ OPCInuse: 262159,
101
+ OPCInvalidConfig: 3221487632,
102
+ OPCNotFound: 3221487633,
103
+ OPCInvalidPID: 3221488131
104
+ },
105
+ errorDesc: {
106
+ "3221487617": "The value of the handle is invalid",
107
+ "3221487620": "The server cannot convert the data between the specified format/requested data type and the canonical data type",
108
+ "3221487621": "The requested operation cannot be done on a public group",
109
+ "3221487622": "The Items AccessRights do not allow the operation",
110
+ "3221487623": "The item ID is not defined in the server address space (on add or validate) or no longer exists in the server address space (for read or write)",
111
+ "3221487624": "The item ID doesn't conform to the server's syntax",
112
+ "3221487625": "The filter string was not valid",
113
+ "3221487626": "The item's access path is not known to the server",
114
+ "3221487627": "The value was out of range",
115
+ "3221487628": "Duplicate name not allowed",
116
+ "262157": "The server does not support the requested data rate but will use the closest available rate",
117
+ "262158": "A value passed to WRITE was accepted but the output was clamped",
118
+ "262159": "The operation cannot be performed because the object is bering referenced",
119
+ "3221487632": "The server's configuration file is in an invalid format",
120
+ "3221487633": "Requested Object (e.g. a public group) was not found",
121
+ "3221488131": "The passed property ID is not valid for the item"
122
+ },
123
+ property: {
124
+ DATATYPE: 1,
125
+ VALUE: 2,
126
+ QUALITY: 3,
127
+ TIMESTAMP: 4,
128
+ ACCESS_RIGHTS: 5,
129
+ SCAN_RATE: 6,
130
+ EU_TYPE: 7,
131
+ EU_INFO: 8,
132
+ EU_UNITS: 100,
133
+ DESCRIPTION: 101,
134
+ HIGH_EU: 102,
135
+ LOW_EU: 103,
136
+ HIGH_IR: 104,
137
+ LOW_IR: 105,
138
+ CLOSE_LABEL: 106,
139
+ OPEN_LABEL: 107,
140
+ TIMEZONE: 108,
141
+ CONDITION_STATUS: 300,
142
+ ALARM_QUICK_HELP: 301,
143
+ ALARM_AREA_LIST: 302,
144
+ PRIMARY_ALARM_AREA: 303,
145
+ CONDITION_LOGIC: 304,
146
+ LIMIT_EXCEEDED: 305,
147
+ DEADBAND: 306,
148
+ HIHI_LIMIT: 307,
149
+ HI_LIMIT: 308,
150
+ LO_LIMIT: 309,
151
+ LOLO_LIMIT: 310,
152
+ CHANGE_RATE_LIMIT: 311,
153
+ DEVIATION_LIMIT: 312,
154
+ SOUND_FILE: 313,
155
+ TYPE_SYSTEM_ID: 600,
156
+ DICTIONARY_ID: 601,
157
+ TYPE_ID: 602,
158
+ DICTIONARY: 603,
159
+ TYPE_DESCRIPTION: 604,
160
+ CONSISTENCY_WINDOW: 605,
161
+ WRITE_BEHAVIOR: 606,
162
+ UNCONVERTED_ITEM_ID: 607,
163
+ UNFILTERED_ITEM_ID: 608,
164
+ DATA_FILTER_VALUE: 609,
165
+ },
166
+ propertyDesc: {
167
+ "1": "Item Canonical Data Type",
168
+ "2": "Item Value",
169
+ "3": "Item Quality",
170
+ "4": "Item Timestamp",
171
+ "5": "Item Access Rights",
172
+ "6": "Server Scan Rate",
173
+ "7": "Item EU Type",
174
+ "8": "Item EU Info",
175
+ "100": "EU Units",
176
+ "101": "Item Description",
177
+ "102": "High EU",
178
+ "103": "Low EU",
179
+ "104": "High Instrument Range",
180
+ "105": "Low Instrument Range",
181
+ "106": "Contact Close Label",
182
+ "107": "Contact Open Label",
183
+ "108": "Item Timezone",
184
+ "300": "Condition Status",
185
+ "301": "Alarm Quick Help",
186
+ "302": "Alarm Area List",
187
+ "303": "Primary Alarm Area",
188
+ "304": "Condition Logic",
189
+ "305": "Limit Exceeded",
190
+ "306": "Deadband",
191
+ "307": "HiHi Limit",
192
+ "308": "Hi Limit",
193
+ "309": "Lo Limit",
194
+ "310": "LoLo Limit",
195
+ "311": "Rate of Change Limit",
196
+ "312": "Deviation Limit",
197
+ "313": "Sound File",
198
+ "600": "Type System ID",
199
+ "601": "Dictionary ID",
200
+ "602": "Type ID",
201
+ "603": "Dictionary",
202
+ "604": "Type Description",
203
+ "605": "Consistency Window",
204
+ "606": "Write Behavior",
205
+ "607": "Unconverted Item ID",
206
+ "608": "Unfiltered Item ID",
207
+ "609": "Data Filter Value"
208
+ }
209
+ }
210
+ };
211
+
212
+ module.exports = Object.freeze(constants);
@@ -0,0 +1,161 @@
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 dcom = require('node-dcom');
9
+ const util = require('util');
10
+ const debug = util.debuglog('node-opc-da');
11
+
12
+ /**
13
+ * Represents an EnumString
14
+ */
15
+ class EnumString {
16
+
17
+ /**
18
+ *
19
+ * @param {number} [batchSize=10]
20
+ */
21
+ constructor(batchSize){
22
+ this._batchSize = batchSize || 10;
23
+
24
+ this._comObj = null;
25
+ }
26
+
27
+ /**
28
+ *
29
+ * @param {*} unknown
30
+ * @returns {Promise<?>}
31
+ */
32
+ async init(unknown) {
33
+ debug("Initing EnumString...");
34
+ if (this._comObj) throw new Error("Already initialized");
35
+
36
+ this._comObj = await unknown.queryInterface(constants.iid.IEnumString_IID);
37
+ debug("EnumString successfully inited.");
38
+ }
39
+
40
+ async end(hresult) {
41
+ debug("Destroying EnumString...");
42
+ if (!this._comObj) return;
43
+
44
+ let obj = this._comObj;
45
+ debug(String(new Error(String(hresult))));
46
+ this._comObj = null;
47
+ await obj.release();
48
+ debug("EnumString successfully destroyed.");
49
+ }
50
+
51
+ /**
52
+ *
53
+ * @param {number} num
54
+ * @returns {Promise<string[]>}
55
+ * @opNum 0
56
+ */
57
+ async next(num) {
58
+ debug("Querying the server for a batch of " + num + " items...");
59
+ if (!this._comObj) throw new Error("Not initialized");
60
+
61
+ if (num <= 0) return [];
62
+
63
+ let callObject = new dcom.CallBuilder(true);
64
+ callObject.setOpnum(0);
65
+
66
+ let strValue = new dcom.ComValue(new dcom.ComString(dcom.Flags.FLAG_REPRESENTATION_STRING_LPWSTR), dcom.Types.COMSTRING);
67
+ let strArrayValue = new dcom.ComValue(new dcom.ComArray(strValue, null, 1, true, true), dcom.Types.COMARRAY);
68
+ callObject.addInParamAsInt(num, dcom.Flags.FLAG_NULL);
69
+ callObject.addOutParamAsObject(strArrayValue, dcom.Flags.FLAG_NULL);
70
+ callObject.addOutParamAsType(dcom.Types.INTEGER, dcom.Flags.FLAG_NULL);
71
+
72
+ let resultObj = await this._comObj.call(callObject);
73
+
74
+ let hresult = resultObj.hresult;
75
+ let result = resultObj.getResults();
76
+ if (hresult != 0) {
77
+ if (result.lenght == 0)
78
+ throw new Error(String(hresult));
79
+ else
80
+ debug("No more items.");
81
+ }
82
+
83
+ let resultData;
84
+ if (result instanceof dcom.ComValue)
85
+ resultData = result[0].getValue().getArrayInstance();
86
+ else
87
+ resultData = result[0].getValue().getArrayInstance();
88
+ let count = result[1].getValue();
89
+
90
+ let res = [];
91
+ for (let i = 0; i < count; i++) {
92
+ res.push(resultData[i].getValue().getString());
93
+ }
94
+ debug("Items successfullly obtained.");
95
+ return res;
96
+ }
97
+
98
+ /**
99
+ *
100
+ * @param {number} num
101
+ * @returns {Promise<>}
102
+ * @opnum 1
103
+ */
104
+ async skip(num) {
105
+ if (!this._comObj) throw new Error("Not initialized");
106
+
107
+ if (num <= 0) return [];
108
+
109
+ let callObject = new dcom.CallBuilder(true);
110
+ callObject.setOpnum(1);
111
+
112
+ callObject.addInParamAsInt(num, dcom.Flags.FLAG_NULL);
113
+
114
+ await this._comObj.call(callObject)
115
+ .catch(function(reject) {
116
+ throw reject;
117
+ });
118
+ }
119
+
120
+ /**
121
+ *
122
+ * @returns {Promise<>}
123
+ * @opnum 2
124
+ */
125
+ async reset() {
126
+ debug("Reseting EnumString...");
127
+ if (!this._comObj) throw new Error("Not initialized");
128
+
129
+ let callObject = new dcom.CallBuilder(true);
130
+ callObject.setOpnum(2);
131
+
132
+ await this._comObj.call(callObject)
133
+ .catch(function(reject) {
134
+ throw reject;
135
+ });
136
+ debug("EnumString successfully reseted.");
137
+ }
138
+
139
+ // ------
140
+
141
+ /**
142
+ * @returns {Promise<string[]>}
143
+ */
144
+ async asArray(){
145
+ debug("Creating an Array for the current EnumString...");
146
+ await this.reset();
147
+ let part, res = [];
148
+ do {
149
+ part = await this.next(this._batchSize)
150
+ .catch(function(reject) {
151
+ throw reject;
152
+ });
153
+ res.push(...part);
154
+ } while (part.length == this._batchSize);
155
+
156
+ debug("Array of EnumString itens sucessfully created.");
157
+ return res;
158
+ }
159
+ }
160
+
161
+ module.exports = EnumString;
@@ -0,0 +1,79 @@
1
+ //@ts-check
2
+
3
+ const {Struct} = require('node-dcom');
4
+ const Long = require('long');
5
+
6
+ class FileTime {
7
+
8
+ constructor(hi, lo){
9
+ this._hi = hi;
10
+ this._lo = lo;
11
+ this._date = null;
12
+ }
13
+
14
+ get hi(){
15
+ return this._hi;
16
+ }
17
+ get lo(){
18
+ return this._lo;
19
+ }
20
+ set hi(hi){
21
+ this._hi = hi;
22
+ this._date = null;
23
+ }
24
+ set lo(lo){
25
+ this._lo = lo;
26
+ this._date = null;
27
+ }
28
+
29
+ /**
30
+ * @returns {Date}
31
+ */
32
+ getDate() {
33
+ if (!this._date) this._computeDate();
34
+ return this._date;
35
+ }
36
+
37
+ _computeDate(){
38
+ let ulong = new Long(this._lo, this._hi, true).div(10000);
39
+ let epochBase = ulong.sub(11644473600000);
40
+
41
+ if (epochBase.greaterThan(ulong))
42
+ epochBase = epochBase.toSigned();
43
+ else
44
+ epochBase = epochBase.toNumber();
45
+
46
+ this._date = new Date(epochBase);
47
+ }
48
+
49
+ toString(){
50
+ return `FileTime[${this._hi && this._lo ? this.getDate() : 'null'}]`;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * @returns {Struct}
56
+ */
57
+ function getStruct(){
58
+ let struct = new Struct();
59
+ struct.addMember(0); //lo
60
+ struct.addMember(0); //hi
61
+
62
+ return struct;
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @param {Struct} struct
68
+ * @returns {FileTime}
69
+ */
70
+ function fromStruct(struct){
71
+ let lo = struct.getMember(0).getValue();
72
+ let hi = struct.getMember(1).getValue();
73
+
74
+ return new FileTime(hi, lo);
75
+ }
76
+
77
+ module.exports = {
78
+ FileTime, getStruct, fromStruct
79
+ }
package/src/index.js ADDED
@@ -0,0 +1,62 @@
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');
8
+ const OPCAsyncIO = require('./opcAsyncIO');
9
+ const OPCBrowser = require('./opcBrowser');
10
+ const OPCCommon = require('./opcCommon');
11
+ const OPCGroupStateManager = require('./opcGroupStateManager');
12
+ const OPCItemIO = require('./opcItemIO');
13
+ const OPCItemManager = require('./opcItemManager');
14
+ const OPCItemProperties = require('./opcItemProperties');
15
+ const OPCServer = require('./opcServer');
16
+ const OPCSyncIO = require('./opcSyncIO');
17
+ const dcom = require('node-dcom');
18
+ const EventEmitter = require('events').EventEmitter;
19
+ const {ComServer, Session, Clsid} = dcom;
20
+
21
+ /**
22
+ *
23
+ * @param {String} address
24
+ * @param {String} domain
25
+ * @param {String} user
26
+ * @param {String} pass
27
+ * @param {String} clsid
28
+ * @param {object} [opts]
29
+ * @returns {Promise<{comServer:ComServer, opcServer:OPCServer}>}
30
+ */
31
+ async function createServer(address, domain, user, pass, clsid, opts) {
32
+ EventEmitter.call(this);
33
+ let session = new Session();
34
+ session = session.createSession(domain, user, pass);
35
+ session.setGlobalSocketTimeout(7000);
36
+
37
+ let comServer = new ComServer(new Clsid(clsid), address, session);
38
+
39
+ await comServer.init();
40
+ console.log(`debug`);
41
+ let comObject = await comServer.createInstance();
42
+
43
+ let opcServer = new OPCServer(opts);
44
+ await opcServer.init(comObject);
45
+
46
+ return {comServer, opcServer};
47
+ }
48
+
49
+ module.exports = {
50
+ constants,
51
+ OPCAsyncIO,
52
+ OPCBrowser,
53
+ OPCCommon,
54
+ OPCGroupStateManager,
55
+ OPCItemIO,
56
+ OPCItemManager,
57
+ OPCItemProperties,
58
+ OPCServer,
59
+ OPCSyncIO,
60
+ dcom,
61
+ createServer
62
+ }
@@ -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 Sync IO Object
11
+ */
12
+ class OPCAsyncIO {
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.IOPCAsyncIO2_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[]} handles array of server handles
40
+ * @returns {Promise<object>}
41
+ * @opNum 0
42
+ */
43
+ async read(handles) {
44
+ if (!this._comObj) throw new Error("Not initialized");
45
+
46
+ //should return auto generated transaction id and cancel id
47
+ }
48
+
49
+ /** ??? */
50
+ async write() {
51
+ if (!this._comObj) throw new Error("Not initialized");
52
+
53
+ throw new Error("Not Implemented");
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @param {number} transactionID
59
+ * @param {number} source
60
+ * @returns {Promise<number>}
61
+ * @opNum 2
62
+ */
63
+ async refresh(transactionID, source) {
64
+ if (!this._comObj) throw new Error("Not initialized");
65
+
66
+ }
67
+
68
+ /**
69
+ *
70
+ * @param {number} cancelID
71
+ * @returns {Promise<void>}
72
+ * @opNum 3
73
+ */
74
+ async cancel(cancelID) {
75
+ if (!this._comObj) throw new Error("Not initialized");
76
+
77
+ }
78
+
79
+ /**
80
+ *
81
+ * @param {boolean} state
82
+ * @returns {Promise<void>}
83
+ * @opNum 4
84
+ */
85
+ async setEnable(state) {
86
+ if (!this._comObj) throw new Error("Not initialized");
87
+
88
+ }
89
+
90
+ /**
91
+ *
92
+ * @returns {Promise<boolean>}
93
+ * @opNum 5
94
+ */
95
+ async getEnable() {
96
+ if (!this._comObj) throw new Error("Not initialized");
97
+
98
+ }
99
+
100
+ }
101
+
102
+ module.exports = OPCAsyncIO;