@amigo9090/ih-libiec61850-node 1.0.25 → 1.0.27

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.
@@ -21,27 +21,28 @@ const client = new MmsClient((event, data) => {
21
21
  });
22
22
  });
23
23
 
24
- // Чтение датасетов напрямую без промисов
25
- console.log('Reading datasets...');
26
- dataSets.forEach(ds => {
27
- console.log(`- ${ds.reference}`);
28
- client.readDataSetValues(ds.reference);
29
- });
24
+ // Чтение датасетов
25
+ console.log('Reading datasets in batch...');
26
+ const dataSetRefs = dataSets.map(ds => ds.reference);
27
+ client.readDataSetValues(dataSetRefs);
28
+
29
+ // Чтение одиночного DataSet:
30
+ // client.readDataSetValues('WAGO61850ServerDevice/LLN0.DataSet01');
30
31
 
31
- // Чтение данных
32
+ // Пакетное чтение данных
32
33
  console.log('Reading data...');
33
34
  const dataRefs = [
34
35
  'WAGO61850ServerDevice/XCBR1.Pos.stVal',
35
36
  'WAGO61850ServerDevice/GGIO1.Ind.stVal',
36
- 'WAGO61850ServerDevice/CALH1.GrAlm.stVal'
37
+ 'WAGO61850ServerDevice/CALH1.GrAlm.stVal'
37
38
  ];
38
- dataRefs.forEach(ref => client.readData(ref));
39
+ client.readData(dataRefs);
39
40
 
40
41
  // Включение отчётов
41
42
  const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
42
43
  const dataSetRef = 'WAGO61850ServerDevice/LLN0.DataSet01';
43
44
  console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
44
- client.enableReporting(rcbRef, dataSetRef);
45
+ client.enableReporting(rcbRef, dataSetRef);
45
46
  })
46
47
  .catch(err => console.error('Error browsing data model:', err.message));
47
48
  }
@@ -54,7 +55,18 @@ const client = new MmsClient((event, data) => {
54
55
  } else if (data.event === 'dataModel') {
55
56
  console.log(`Data Model received: ${util.inspect(data.dataModel, { depth: null })}`);
56
57
  } else if (data.event === 'dataSet') {
57
- console.log(`DataSet received for ${data.dataSetRef}: ${util.inspect(data.value, { depth: null })}`);
58
+ // Одиночный DataSet (обратная совместимость)
59
+ console.log(`DataSet received for ${data.datasetRef}: ${util.inspect(data.value, { depth: null })}`);
60
+ } else if (data.event === 'multipleDataSets') {
61
+ // Множественные DataSet
62
+ console.log(`Multiple DataSets received for ${util.inspect(data.datasetRefs, { depth: null })}:`);
63
+ data.values.forEach((value, index) => {
64
+ if (value.isValid !== false) {
65
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Value: ${util.inspect(value, { depth: null })}`);
66
+ } else {
67
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Error: ${value.errorReason}`);
68
+ }
69
+ });
58
70
  } else if (data.event === 'report') {
59
71
  console.log(`Report received for ${data.rcbRef} (rptId: ${data.rptId}):`);
60
72
  if (data.timestamp) {
@@ -65,6 +77,15 @@ const client = new MmsClient((event, data) => {
65
77
  console.log(` Value[${index}]: ${util.inspect(value, { depth: null })}, Reason: ${data.reasonsForInclusion[index]}`);
66
78
  }
67
79
  });
80
+ } else if (data.event === 'batchData') {
81
+ console.log(`Batch Data received for ${util.inspect(data.dataRefs, { depth: null })}:`);
82
+ data.values.forEach((result, index) => {
83
+ if (result.isValid) {
84
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Value: ${util.inspect(result.value, { depth: null })}`);
85
+ } else {
86
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Error: ${result.errorReason}`);
87
+ }
88
+ });
68
89
  } else {
69
90
  console.log(`Data received for ${data.dataRef || 'undefined'}: ${util.inspect(data.value, { depth: null })}`);
70
91
  }
@@ -86,8 +107,18 @@ const client = new MmsClient((event, data) => {
86
107
  console.log(`Reporting enabled for ${data.rcbRef}`);
87
108
  } else if (data.event === 'reportingDisabled') {
88
109
  console.log(`Reporting disabled for ${data.rcbRef}`);
110
+ } else if (data.event === 'dataSetCreated') {
111
+ console.log(`DataSet created: ${data.datasetRef}`);
112
+ } else if (data.event === 'dataSetDeleted') {
113
+ console.log(`DataSet deleted: ${data.datasetRef}`);
114
+ } else if (data.event === 'stateChanged') {
115
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
89
116
  }
90
117
  }
118
+
119
+ if (event === 'conn' && data.event === 'stateChanged') {
120
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
121
+ }
91
122
  });
92
123
 
93
124
  async function main() {
@@ -102,12 +133,12 @@ async function main() {
102
133
  reconnectDelay: 2
103
134
  });
104
135
  await sleep(5000);
105
- // Выполнение операции управления
106
- //console.log('And now we try do control operation!!!!!!!!!!!!!!!...');
107
- //client.controlObject("WAGO61850ServerDevice/XCBR1.Pos", true);
136
+
137
+ // console.log('And now we try do control operation!!!!!!!!!!!!!!!...');
138
+ // client.controlObject("WAGO61850ServerDevice/XCBR1.Pos", true);
108
139
 
109
140
  // Дополнительное ожидание для обработки операции управления
110
- //await sleep(5000);
141
+ // await sleep(5000);
111
142
 
112
143
  // Ожидание обработки данных и отчетов
113
144
  console.log('Waiting for data and reports...');
@@ -116,7 +147,7 @@ async function main() {
116
147
  // Отключение отчетов
117
148
  const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
118
149
  console.log(`Disabling reporting for ${rcbRef}`);
119
- client.disableReporting(rcbRef);
150
+ client.disableReporting(rcbRef);
120
151
 
121
152
  console.log('Client status:', client.getStatus());
122
153
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amigo9090/ih-libiec61850-node",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Node.js addon for IEC 61850 client (MMS, GOOSE) using libiec61850",
5
5
  "main": "index.js",
6
6
  "keywords": [
package/readme.md CHANGED
@@ -48,38 +48,143 @@ A cross-platform Node.js native addon for the **IEC 61850 protocol**, enabling s
48
48
 
49
49
  ## 📖 Usage
50
50
 
51
+
51
52
  Below is an example of using `ih-lib61850-node` to establish an IEC 61850 connection and handle GOOSE and MMS messages:
52
53
 
53
54
  ```javascript
54
- const { IEC61850Client } = require('@amigo9090/ih-libiec61850-node');
55
-
56
- // Initialize an IEC 61850 client
57
- const client = new IEC61850Client({
58
- host: '192.168.0.1',
59
- port: 102,
60
- // Additional configuration parameters
61
- });
62
-
63
- // Connect to the server
64
- client.connect();
65
-
66
- // Subscribe to GOOSE messages
67
- client.subscribeGOOSE('domain', 'gooseId', (message) => {
68
- console.log('Received GOOSE message:', message);
69
- });
70
-
71
- // Send an MMS request
72
- client.sendMMSRequest('domain', 'itemId', (response) => {
73
- console.log('MMS response:', response);
55
+ const { MmsClient } = require('@amigo9090/ih-libiec61850-node');
56
+ const util = require('util');
57
+
58
+ const client = new MmsClient((event, data) => {
59
+ console.log(`Event: ${event}, Data: ${util.inspect(data, { depth: null })}`);
60
+
61
+ if (event === 'conn' && data.event === 'opened') {
62
+ console.log('Connection opened, browsing data model...');
63
+ client.browseDataModel()
64
+ .then(dataModel => {
65
+ console.log('Data Model:', util.inspect(dataModel, { depth: null }));
66
+
67
+ // Extracting links to datasets
68
+ const dataSets = [];
69
+ dataModel.forEach(ld => {
70
+ ld.logicalNodes.forEach(ln => {
71
+ ln.dataSets.forEach(ds => {
72
+ console.log(`Found dataset: ${ds.reference}`);
73
+ dataSets.push(ds);
74
+ });
75
+ });
76
+ });
77
+
78
+ // Reading datasets directly without promises
79
+ console.log('Reading datasets...');
80
+ dataSets.forEach(ds => {
81
+ console.log(`- ${ds.reference}`);
82
+ client.readDataSetValues(ds.reference);
83
+ });
84
+
85
+ // Reading data
86
+ console.log('Reading data...');
87
+ const dataRefs = [
88
+ 'WAGO61850ServerDevice/XCBR1.Pos.stVal',
89
+ 'WAGO61850ServerDevice/GGIO1.Ind.stVal',
90
+ 'WAGO61850ServerDevice/CALH1.GrAlm.stVal'
91
+ ];
92
+ dataRefs.forEach(ref => client.readData(ref));
93
+
94
+ // Enabling reporting
95
+ const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
96
+ const dataSetRef = 'WAGO61850ServerDevice/LLN0.DataSet01';
97
+ console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
98
+ client.enableReporting(rcbRef, dataSetRef);
99
+ })
100
+ .catch(err => console.error('Error browsing data model:', err.message));
101
+ }
102
+
103
+ if (event === 'data' && data.type === 'data') {
104
+ if (data.event === 'logicalDevices') {
105
+ console.log(`Logical Devices received: ${util.inspect(data.logicalDevices, { depth: null })}`);
106
+ } else if (data.event === 'dataSetDirectory') {
107
+ console.log(`DataSet Directory for ${data.logicalNodeRef}: ${util.inspect(data.dataSets, { depth: null })}`);
108
+ } else if (data.event === 'dataModel') {
109
+ console.log(`Data Model received: ${util.inspect(data.dataModel, { depth: null })}`);
110
+ } else if (data.event === 'dataSet') {
111
+ console.log(`DataSet received for ${data.dataSetRef}: ${util.inspect(data.value, { depth: null })}`);
112
+ } else if (data.event === 'report') {
113
+ console.log(`Report received for ${data.rcbRef} (rptId: ${data.rptId}):`);
114
+ if (data.timestamp) {
115
+ console.log(` Timestamp: ${data.timestamp}`);
116
+ }
117
+ data.values.forEach((value, index) => {
118
+ if (data.reasonsForInclusion[index] !== 0) {
119
+ console.log(` Value[${index}]: ${util.inspect(value, { depth: null })}, Reason: ${data.reasonsForInclusion[index]}`);
120
+ }
121
+ });
122
+ } else {
123
+ console.log(`Data received for ${data.dataRef || 'undefined'}: ${util.inspect(data.value, { depth: null })}`);
124
+ }
125
+ }
126
+
127
+ if (event === 'data' && data.type === 'error') {
128
+ console.error(`Error received: ${data.reason}`);
129
+ }
130
+
131
+ if (event === 'conn' && data.event === 'reconnecting') {
132
+ console.error(`Reconnection failed: ${data.reason}`);
133
+ if (data.reason.includes('attempt 3')) {
134
+ throw new Error('Max reconnection attempts reached');
135
+ }
136
+ }
137
+
138
+ if (event === 'data' && data.type === 'control') {
139
+ if (data.event === 'reportingEnabled') {
140
+ console.log(`Reporting enabled for ${data.rcbRef}`);
141
+ } else if (data.event === 'reportingDisabled') {
142
+ console.log(`Reporting disabled for ${data.rcbRef}`);
143
+ }
144
+ }
74
145
  });
75
146
 
76
- // Handle events
77
- client.on('event', (event) => {
78
- console.log('Event:', event);
79
- });
147
+ async function main() {
148
+ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
149
+
150
+ try {
151
+ console.log('Starting client...');
152
+ await client.connect({
153
+ ip: '192.168.0.1',
154
+ port: 102,
155
+ clientID: 'mms_client1',
156
+ reconnectDelay: 2
157
+ });
158
+ await sleep(5000);
159
+
160
+ // Perform control operation
161
+ console.log('Try to do control operation...');
162
+ client.controlObject("IEC61850ServerDevice/XCBR1.Pos", true);
163
+
164
+ // Waiting for data and reports
165
+ console.log('Waiting for data and reports...');
166
+ await sleep(30000);
167
+
168
+ // Disabling reporting
169
+ const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
170
+ console.log(`Disabling reporting for ${rcbRef}`);
171
+ client.disableReporting(rcbRef);
172
+
173
+ console.log('Client status:', client.getStatus());
174
+
175
+ console.log('Closing client...');
176
+ await client.close();
177
+ console.log('Client closed.');
178
+ } catch (err) {
179
+ console.error('Main error:', err.message);
180
+ await client.close().catch(e => console.error('Close error:', e.message));
181
+ }
182
+ }
183
+
184
+ main().catch(err => console.error('Fatal error:', err.message));
80
185
  ```
81
186
 
82
- 📚 **Additional Examples**: Examples for all supported functionalities are available in the [`examples/` directory](https://github.com/intrahouseio/ih-lib61850-node/tree/main/examples). These demonstrate various configurations and use cases for substation automation.
187
+ 📚 **Additional Examples**: Examples for all supported functionalities are available in the [`examples/` directory](https://github.com/intrahouseio/ih-lib61850-node/examples). These demonstrate various configurations and use cases for substation automation.
83
188
 
84
189
  ---
85
190