@amigo9090/ih-libiec61850-node 1.0.37 → 1.0.39

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.
@@ -1,4 +1,4 @@
1
- const { MmsClient } = require('../build/Release/addon_iec61850'); //../build/Release/addon_iec61850
1
+ const { MmsClient } = require('../build/Release/addon_iec61850');
2
2
  const util = require('util');
3
3
 
4
4
  const client = new MmsClient((event, data) => {
@@ -6,7 +6,6 @@ const client = new MmsClient((event, data) => {
6
6
 
7
7
  if (event === 'conn' && data.event === 'opened') {
8
8
  console.log('Connection opened, browsing data model...');
9
- // Запускаем асинхронную логику после открытия соединения
10
9
  handleConnectionOpened();
11
10
  }
12
11
 
@@ -33,13 +32,13 @@ const client = new MmsClient((event, data) => {
33
32
  if (data.timestamp) {
34
33
  console.log(` Timestamp: ${data.timestamp}`);
35
34
  }
36
- // data.values - это объект, а не массив
37
35
  Object.entries(data.values).forEach(([ref, value], index) => {
38
36
  const reason = data.reasons[ref];
39
37
  if (reason && reason !== 0) {
40
38
  console.log(` ${ref}: ${util.inspect(value, { depth: null })}, Reason: ${reason}`);
41
39
  }
42
40
  });
41
+
43
42
  } else if (data.event === 'batchData') {
44
43
  console.log(`Batch Data received for ${util.inspect(data.dataRefs, { depth: null })}:`);
45
44
  data.values.forEach((result, index) => {
@@ -84,17 +83,13 @@ const client = new MmsClient((event, data) => {
84
83
  }
85
84
  });
86
85
 
87
- // Вспомогательная функция сна
88
86
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
89
87
 
90
- // Основная асинхронная функция обработки после открытия соединения
91
88
  async function handleConnectionOpened() {
92
89
  try {
93
- // Просмотр модели данных
94
90
  const dataModel = await client.browseDataModel();
95
91
  console.log('Data Model:', util.inspect(dataModel, { depth: null }));
96
92
 
97
- // Извлечение всех датасетов
98
93
  const dataSets = [];
99
94
  dataModel.forEach(ld => {
100
95
  ld.logicalNodes.forEach(ln => {
@@ -105,17 +100,12 @@ async function handleConnectionOpened() {
105
100
  });
106
101
  });
107
102
 
108
- // Пакетное чтение датасетов
109
- //if (dataSets.length > 0) {
110
- // console.log('Reading datasets in batch...');
111
- // const dataSetRefs = dataSets.map(ds => ds.reference);
112
- // await client.readDataSetValues(dataSetRefs);
113
- //}
114
-
115
- // Читаем все DataSet'ы одним вызовом
116
103
  console.log('\nЧтение значений DataSet...');
117
104
  const datasetRefs = dataSets.map(ds => ds.reference);
105
+ console.log('Calling readDataSetValues...');
118
106
  const readResults = await client.readDataSetValues(datasetRefs);
107
+ console.log('readDataSetValues returned');
108
+
119
109
 
120
110
  readResults.forEach((res, idx) => {
121
111
  const ds = dataSets[idx];
@@ -126,70 +116,98 @@ async function handleConnectionOpened() {
126
116
  }
127
117
 
128
118
  console.log(` Значений: ${res.count}, Удаляемые: ${res.isDeletable}`);
119
+
120
+ // Функция для рекурсивного вывода вложенных структур
121
+ const printValue = (value, indent = ' ') => {
122
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
123
+ Object.entries(value).forEach(([key, val]) => {
124
+ if (val && typeof val === 'object' && !Array.isArray(val)) {
125
+ console.log(`${indent}${key}: {`);
126
+ printValue(val, indent + ' ');
127
+ console.log(`${indent}}`);
128
+ } else if (Array.isArray(val)) {
129
+ console.log(`${indent}${key}: [`);
130
+ val.forEach((item, i) => {
131
+ console.log(`${indent} [${i}]:`);
132
+ printValue(item, indent + ' ');
133
+ });
134
+ console.log(`${indent}]`);
135
+ } else {
136
+ console.log(`${indent}${key}: ${util.inspect(val, { colors: true })}`);
137
+ }
138
+ });
139
+ } else {
140
+ console.log(`${indent}${util.inspect(value, { colors: true })}`);
141
+ }
142
+ };
143
+
129
144
  Object.entries(res.values).forEach(([ref, value]) => {
130
- console.log(` ${ref}: ${util.inspect(value, { colors: true })}`);
145
+ console.log(` ${ref}:`);
146
+ printValue(value, ' ');
131
147
  });
132
148
  });
133
149
 
134
- // Пакетное чтение отдельных значений
135
150
  console.log('Reading data...');
136
151
  const dataRefs = [
137
152
  'WAGO61850ServerDevice/XCBR1.Pos[ST]',
138
- 'WAGO61850ServerDevice/GGIO1.Ind.stVal',
153
+ 'WAGO61850ServerDevice/GGIO1.Ind1.stVal',
139
154
  'WAGO61850ServerDevice/CALH12.GrAlm.stVal'
140
155
  ];
141
156
  const readRefResult = await client.readData(dataRefs);
142
- console.log("readRefResult " + util.inspect(readRefResult));
157
+ console.log("readRefResult " + util.inspect(readRefResult, { depth: null }));
143
158
 
144
- // Включение отчётности
145
- const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
146
- const dataSetRef = 'WAGO61850ServerDevice/LLN0.DataSet01';
147
- console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
148
- await client.enableReporting(rcbRef, dataSetRef);
149
-
150
- // Включение отчётности2
151
159
  const rcbRef2 = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0201';
152
160
  const dataSetRef2 = 'WAGO61850ServerDevice/LLN0.DataSet02';
153
161
  console.log(`Enabling reporting for ${rcbRef2} with dataset ${dataSetRef2}`);
154
162
  await client.enableReporting(rcbRef2, dataSetRef2);
155
163
 
164
+ /*console.log('Reading data...');
165
+ const dataRefs = [
166
+ 'A01LD0/Q1_XCBR1.Pos[ST]',
167
+ 'A01LD0/In_GGIO1.Ind1',
168
+ 'A01LD0/CALH1.GrAlm.stVal'
169
+ ];
170
+ const readRefResult = await client.readData(dataRefs);
171
+ console.log("readRefResult " + util.inspect(readRefResult, { depth: null }));
172
+
173
+ const rcbRef = 'A01LD0/LLN0.RP.repTI1';
174
+ const dataSetRef = 'A01LD0/LLN0.TI_ASU';
175
+ console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
176
+ await client.enableReporting(rcbRef, dataSetRef);
177
+
178
+ const rcbRef2 = 'A01LD0/LLN0.BR.repTS1';
179
+ const dataSetRef2 = 'A01LD0/LLN0.TS_ASU';
180
+ console.log(`Enabling reporting for ${rcbRef2} with dataset ${dataSetRef2}`);
181
+ await client.enableReporting(rcbRef2, dataSetRef2);*/
182
+
156
183
  } catch (err) {
157
184
  console.error('Error in handleConnectionOpened:', err.message);
158
185
  }
159
186
  }
160
187
 
161
- // Главная функция
162
188
  async function main() {
163
189
  try {
164
190
  console.log('Starting client...');
165
191
  await client.connect({
166
- ip: '192.168.0.142',
192
+ ip: '192.168.0.106',
167
193
  port: 102,
168
194
  clientID: 'mms_client1',
169
- reconnectDelay: 2
195
+ reconnectDelay: 2,
196
+ //heartbeatInterval: 3000 //новый параметр - интервал эхо-запросов для поддержки соединения
170
197
  });
171
198
 
172
- // Ждём открытия соединения (событие будет обработано в колбэке)
173
199
  await sleep(5000);
174
200
 
175
- // Опционально: управление (раскомментируй при необходимости)
176
- // console.log('Performing control operation...');
177
- // await client.controlObject("WAGO61850ServerDevice/XCBR1.Pos", true);
178
- // await sleep(5000);
179
-
180
- // Ожидание данных и отчётов
181
201
  console.log('Waiting for data and reports...');
182
202
  await sleep(30000);
183
203
 
184
- // Отключение отчётов
185
- const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
204
+ /*const rcbRef = 'A01LD0/LLN0.RP.repTI1';
186
205
  console.log(`Disabling reporting for ${rcbRef}`);
187
- await client.disableReporting(rcbRef);
206
+ await client.disableReporting(rcbRef);*/
188
207
 
189
- // Отключение отчётов2
190
- const rcbRef2 = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0102';
191
- console.log(`Disabling reporting for ${rcbRef2}`);
192
- await client.disableReporting(rcbRef2);
208
+ const rcbRef2 = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0201';
209
+ console.log(`Disabling reporting for ${rcbRef2}`);
210
+ await client.disableReporting(rcbRef2);
193
211
 
194
212
  console.log('Client status:', client.getStatus());
195
213
  console.log('Closing client...');
@@ -202,5 +220,4 @@ async function main() {
202
220
  }
203
221
  }
204
222
 
205
- // Запуск
206
223
  main().catch(err => console.error('Fatal error:', err.message));
@@ -0,0 +1,229 @@
1
+ const { MmsClient } = require('../build/Release/addon_iec61850');
2
+ const util = require('util');
3
+
4
+ const client = new MmsClient((event, data) => {
5
+ console.log(`Event: ${event}, Data: ${util.inspect(data, { depth: null })}`);
6
+
7
+ if (event === 'conn' && data.event === 'opened') {
8
+ console.log('Connection opened, browsing data model...');
9
+ handleConnectionOpened();
10
+ }
11
+
12
+ if (event === 'data' && data.type === 'data') {
13
+ if (data.event === 'logicalDevices') {
14
+ console.log(`Logical Devices received: ${util.inspect(data.logicalDevices, { depth: null })}`);
15
+ } else if (data.event === 'dataSetDirectory') {
16
+ console.log(`DataSet Directory for ${data.logicalNodeRef}: ${util.inspect(data.dataSets, { depth: null })}`);
17
+ } else if (data.event === 'dataModel') {
18
+ console.log(`Data Model received: ${util.inspect(data.dataModel, { depth: null })}`);
19
+ } else if (data.event === 'dataSet') {
20
+ console.log(`DataSet received for ${data.datasetRef}: ${util.inspect(data.value, { depth: null })}`);
21
+ } else if (data.event === 'multipleDataSets') {
22
+ console.log(`Multiple DataSets received for ${util.inspect(data.datasetRefs, { depth: null })}:`);
23
+ data.values.forEach((value, index) => {
24
+ if (value.isValid !== false) {
25
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Value: ${util.inspect(value, { depth: null })}`);
26
+ } else {
27
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Error: ${value.errorReason}`);
28
+ }
29
+ });
30
+ } else if (data.event === 'report') {
31
+ console.log(`Report received for ${data.rcbRef} (rptId: ${data.rptId}):`);
32
+ if (data.timestamp) {
33
+ console.log(` Timestamp: ${data.timestamp}`);
34
+ }
35
+ Object.entries(data.values).forEach(([ref, value], index) => {
36
+ const reason = data.reasons[ref];
37
+ if (reason && reason !== 0) {
38
+ console.log(` ${ref}: ${util.inspect(value, { depth: null })}, Reason: ${reason}`);
39
+ }
40
+ });
41
+ } else if (data.event === 'batchData') {
42
+ console.log(`Batch Data received for ${util.inspect(data.dataRefs, { depth: null })}:`);
43
+ data.values.forEach((result, index) => {
44
+ if (result.isValid) {
45
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Value: ${util.inspect(result.value, { depth: null })}`);
46
+ } else {
47
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Error: ${result.errorReason}`);
48
+ }
49
+ });
50
+ } else {
51
+ console.log(`Data received for ${data.dataRef || 'undefined'}: ${util.inspect(data.value, { depth: null })}`);
52
+ }
53
+ }
54
+
55
+ if (event === 'data' && data.type === 'error') {
56
+ console.error(`Error received: ${data.reason}`);
57
+ }
58
+
59
+ if (event === 'conn' && data.event === 'reconnecting') {
60
+ console.error(`Reconnection failed: ${data.reason}`);
61
+ if (data.reason.includes('attempt 3')) {
62
+ throw new Error('Max reconnection attempts reached');
63
+ }
64
+ }
65
+
66
+ if (event === 'data' && data.type === 'control') {
67
+ if (data.event === 'reportingEnabled') {
68
+ console.log(`Reporting enabled for ${data.rcbRef}`);
69
+ } else if (data.event === 'reportingDisabled') {
70
+ console.log(`Reporting disabled for ${data.rcbRef}`);
71
+ } else if (data.event === 'dataSetCreated') {
72
+ console.log(`DataSet created: ${data.datasetRef}`);
73
+ } else if (data.event === 'dataSetDeleted') {
74
+ console.log(`DataSet deleted: ${data.datasetRef}`);
75
+ } else if (data.event === 'stateChanged') {
76
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
77
+ }
78
+ }
79
+
80
+ if (event === 'conn' && data.event === 'stateChanged') {
81
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
82
+ }
83
+ });
84
+
85
+ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
86
+
87
+ async function handleConnectionOpened() {
88
+ try {
89
+ const dataModel = await client.browseDataModel();
90
+ console.log('Data Model:', util.inspect(dataModel, { depth: null }));
91
+
92
+ const dataSets = [];
93
+ dataModel.forEach(ld => {
94
+ ld.logicalNodes.forEach(ln => {
95
+ ln.dataSets.forEach(ds => {
96
+ console.log(`Found dataset: ${ds.reference}`);
97
+ dataSets.push(ds);
98
+ });
99
+ });
100
+ });
101
+
102
+ //для теста
103
+ const dataModel2 = await client.TestDebug();
104
+
105
+ console.log('\nЧтение значений DataSet...');
106
+ const datasetRefs = dataSets.map(ds => ds.reference);
107
+ console.log('Calling readDataSetValues...');
108
+ const readResults = await client.readDataSetValues(datasetRefs);
109
+ console.log('readDataSetValues returned');
110
+
111
+
112
+ readResults.forEach((res, idx) => {
113
+ const ds = dataSets[idx];
114
+ console.log(`\nDataSet: ${res.datasetRef}`);
115
+ if (!res.isValid) {
116
+ console.error(' Ошибка:', res.errorReason);
117
+ return;
118
+ }
119
+
120
+ console.log(` Значений: ${res.count}, Удаляемые: ${res.isDeletable}`);
121
+
122
+ // Функция для рекурсивного вывода вложенных структур
123
+ const printValue = (value, indent = ' ') => {
124
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
125
+ Object.entries(value).forEach(([key, val]) => {
126
+ if (val && typeof val === 'object' && !Array.isArray(val)) {
127
+ console.log(`${indent}${key}: {`);
128
+ printValue(val, indent + ' ');
129
+ console.log(`${indent}}`);
130
+ } else if (Array.isArray(val)) {
131
+ console.log(`${indent}${key}: [`);
132
+ val.forEach((item, i) => {
133
+ console.log(`${indent} [${i}]:`);
134
+ printValue(item, indent + ' ');
135
+ });
136
+ console.log(`${indent}]`);
137
+ } else {
138
+ console.log(`${indent}${key}: ${util.inspect(val, { colors: true })}`);
139
+ }
140
+ });
141
+ } else {
142
+ console.log(`${indent}${util.inspect(value, { colors: true })}`);
143
+ }
144
+ };
145
+
146
+ Object.entries(res.values).forEach(([ref, value]) => {
147
+ console.log(` ${ref}:`);
148
+ printValue(value, ' ');
149
+ });
150
+ });
151
+
152
+ console.log('Reading data...');
153
+ const dataRefs = [
154
+ 'WAGO61850ServerDevice/XCBR1.Pos[ST]',
155
+ 'WAGO61850ServerDevice/GGIO1.Ind1.stVal',
156
+ 'WAGO61850ServerDevice/CALH12.GrAlm.stVal'
157
+ ];
158
+ const readRefResult = await client.readData(dataRefs);
159
+ console.log("readRefResult " + util.inspect(readRefResult, { depth: null }));
160
+
161
+ /*const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
162
+ const dataSetRef = 'WAGO61850ServerDevice/LLN0.DataSet01';
163
+ console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
164
+ await client.enableReporting(rcbRef, dataSetRef);*/
165
+
166
+ const rcbRef2 = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0201';
167
+ const dataSetRef2 = 'WAGO61850ServerDevice/LLN0.DataSet02';
168
+ console.log(`Enabling reporting for ${rcbRef2} with dataset ${dataSetRef2}`);
169
+ await client.enableReporting(rcbRef2, dataSetRef2);
170
+
171
+ /*console.log('Reading data...');
172
+ const dataRefs = [
173
+ 'A01LD0/Q1_XCBR1.Pos[ST]',
174
+ 'A01LD0/In_GGIO1.Ind1',
175
+ 'A01LD0/CALH1.GrAlm.stVal'
176
+ ];
177
+ const readRefResult = await client.readData(dataRefs);
178
+ console.log("readRefResult " + util.inspect(readRefResult, { depth: null }));
179
+
180
+ const rcbRef = 'A01LD0/LLN0.RP.repTI1';
181
+ const dataSetRef = 'A01LD0/LLN0.TI_ASU';
182
+ console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
183
+ await client.enableReporting(rcbRef, dataSetRef);
184
+
185
+ const rcbRef2 = 'A01LD0/LLN0.BR.repTS1';
186
+ const dataSetRef2 = 'A01LD0/LLN0.TS_ASU';
187
+ console.log(`Enabling reporting for ${rcbRef2} with dataset ${dataSetRef2}`);
188
+ await client.enableReporting(rcbRef2, dataSetRef2);*/
189
+
190
+ } catch (err) {
191
+ console.error('Error in handleConnectionOpened:', err.message);
192
+ }
193
+ }
194
+
195
+ async function main() {
196
+ try {
197
+ console.log('Starting client...');
198
+ await client.connect({
199
+ ip: '192.168.0.142',
200
+ port: 102,
201
+ clientID: 'mms_client1',
202
+ reconnectDelay: 2
203
+ });
204
+
205
+ await sleep(5000);
206
+
207
+ console.log('Waiting for data and reports...');
208
+ await sleep(15000);
209
+
210
+ /*const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
211
+ console.log(`Disabling reporting for ${rcbRef}`);
212
+ await client.disableReporting(rcbRef);*/
213
+
214
+ const rcbRef2 = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0201';
215
+ console.log(`Disabling reporting for ${rcbRef2}`);
216
+ await client.disableReporting(rcbRef2);
217
+
218
+ console.log('Client status:', client.getStatus());
219
+ console.log('Closing client...');
220
+ await client.close();
221
+ console.log('Client closed.');
222
+
223
+ } catch (err) {
224
+ console.error('Main error:', err.message);
225
+ await client.close().catch(e => console.error('Close error:', e.message));
226
+ }
227
+ }
228
+
229
+ main().catch(err => console.error('Fatal error:', err.message));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amigo9090/ih-libiec61850-node",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "Node.js addon for IEC 61850 client (MMS, GOOSE) using libiec61850",
5
5
  "main": "index.js",
6
6
  "keywords": [