@amigo9090/ih-libiec61850-node 1.0.27 → 1.0.28

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');
1
+ /*const { MmsClient } = require('../build/Release/addon_iec61850');
2
2
  const util = require('util');
3
3
 
4
4
  const client = new MmsClient((event, data) => {
@@ -160,4 +160,178 @@ async function main() {
160
160
  }
161
161
  }
162
162
 
163
+ main().catch(err => console.error('Fatal error:', err.message));*/
164
+
165
+ const { MmsClient } = require('../build/Release/addon_iec61850');
166
+ const util = require('util');
167
+
168
+ const client = new MmsClient((event, data) => {
169
+ console.log(`Event: ${event}, Data: ${util.inspect(data, { depth: null })}`);
170
+
171
+ if (event === 'conn' && data.event === 'opened') {
172
+ console.log('Connection opened, browsing data model...');
173
+ // Запускаем асинхронную логику после открытия соединения
174
+ handleConnectionOpened();
175
+ }
176
+
177
+ if (event === 'data' && data.type === 'data') {
178
+ if (data.event === 'logicalDevices') {
179
+ console.log(`Logical Devices received: ${util.inspect(data.logicalDevices, { depth: null })}`);
180
+ } else if (data.event === 'dataSetDirectory') {
181
+ console.log(`DataSet Directory for ${data.logicalNodeRef}: ${util.inspect(data.dataSets, { depth: null })}`);
182
+ } else if (data.event === 'dataModel') {
183
+ console.log(`Data Model received: ${util.inspect(data.dataModel, { depth: null })}`);
184
+ } else if (data.event === 'dataSet') {
185
+ console.log(`DataSet received for ${data.datasetRef}: ${util.inspect(data.value, { depth: null })}`);
186
+ } else if (data.event === 'multipleDataSets') {
187
+ console.log(`Multiple DataSets received for ${util.inspect(data.datasetRefs, { depth: null })}:`);
188
+ data.values.forEach((value, index) => {
189
+ if (value.isValid !== false) {
190
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Value: ${util.inspect(value, { depth: null })}`);
191
+ } else {
192
+ console.log(` DataSet[${index}]: ${data.datasetRefs[index]}, Error: ${value.errorReason}`);
193
+ }
194
+ });
195
+ } else if (data.event === 'report') {
196
+ console.log(`Report received for ${data.rcbRef} (rptId: ${data.rptId}):`);
197
+ if (data.timestamp) {
198
+ console.log(` Timestamp: ${data.timestamp}`);
199
+ }
200
+ data.values.forEach((value, index) => {
201
+ if (data.reasonsForInclusion[index] !== 0) {
202
+ console.log(` Value[${index}]: ${util.inspect(value, { depth: null })}, Reason: ${data.reasonsForInclusion[index]}`);
203
+ }
204
+ });
205
+ } else if (data.event === 'batchData') {
206
+ console.log(`Batch Data received for ${util.inspect(data.dataRefs, { depth: null })}:`);
207
+ data.values.forEach((result, index) => {
208
+ if (result.isValid) {
209
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Value: ${util.inspect(result.value, { depth: null })}`);
210
+ } else {
211
+ console.log(` dataRef[${index}]: ${data.dataRefs[index]}, Error: ${result.errorReason}`);
212
+ }
213
+ });
214
+ } else {
215
+ console.log(`Data received for ${data.dataRef || 'undefined'}: ${util.inspect(data.value, { depth: null })}`);
216
+ }
217
+ }
218
+
219
+ if (event === 'data' && data.type === 'error') {
220
+ console.error(`Error received: ${data.reason}`);
221
+ }
222
+
223
+ if (event === 'conn' && data.event === 'reconnecting') {
224
+ console.error(`Reconnection failed: ${data.reason}`);
225
+ if (data.reason.includes('attempt 3')) {
226
+ throw new Error('Max reconnection attempts reached');
227
+ }
228
+ }
229
+
230
+ if (event === 'data' && data.type === 'control') {
231
+ if (data.event === 'reportingEnabled') {
232
+ console.log(`Reporting enabled for ${data.rcbRef}`);
233
+ } else if (data.event === 'reportingDisabled') {
234
+ console.log(`Reporting disabled for ${data.rcbRef}`);
235
+ } else if (data.event === 'dataSetCreated') {
236
+ console.log(`DataSet created: ${data.datasetRef}`);
237
+ } else if (data.event === 'dataSetDeleted') {
238
+ console.log(`DataSet deleted: ${data.datasetRef}`);
239
+ } else if (data.event === 'stateChanged') {
240
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
241
+ }
242
+ }
243
+
244
+ if (event === 'conn' && data.event === 'stateChanged') {
245
+ console.log(`Connection state changed: ${data.state}, isConnected: ${data.isConnected}`);
246
+ }
247
+ });
248
+
249
+ // Вспомогательная функция сна
250
+ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
251
+
252
+ // Основная асинхронная функция обработки после открытия соединения
253
+ async function handleConnectionOpened() {
254
+ try {
255
+ // Просмотр модели данных
256
+ const dataModel = await client.browseDataModel();
257
+ console.log('Data Model:', util.inspect(dataModel, { depth: null }));
258
+
259
+ // Извлечение всех датасетов
260
+ const dataSets = [];
261
+ dataModel.forEach(ld => {
262
+ ld.logicalNodes.forEach(ln => {
263
+ ln.dataSets.forEach(ds => {
264
+ console.log(`Found dataset: ${ds.reference}`);
265
+ dataSets.push(ds);
266
+ });
267
+ });
268
+ });
269
+
270
+ // Пакетное чтение датасетов
271
+ if (dataSets.length > 0) {
272
+ console.log('Reading datasets in batch...');
273
+ const dataSetRefs = dataSets.map(ds => ds.reference);
274
+ await client.readDataSetValues(dataSetRefs);
275
+ }
276
+
277
+ // Пакетное чтение отдельных значений
278
+ console.log('Reading data...');
279
+ const dataRefs = [
280
+ 'WAGO61850ServerDevice/XCBR1.Pos.stVal',
281
+ 'WAGO61850ServerDevice/GGIO1.Ind.stVal',
282
+ 'WAGO61850ServerDevice/CALH1.GrAlm.stVal'
283
+ ];
284
+ await client.readData(dataRefs);
285
+
286
+ // Включение отчётности
287
+ const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
288
+ const dataSetRef = 'WAGO61850ServerDevice/LLN0.DataSet01';
289
+ console.log(`Enabling reporting for ${rcbRef} with dataset ${dataSetRef}`);
290
+ await client.enableReporting(rcbRef, dataSetRef);
291
+
292
+ } catch (err) {
293
+ console.error('Error in handleConnectionOpened:', err.message);
294
+ }
295
+ }
296
+
297
+ // Главная функция
298
+ async function main() {
299
+ try {
300
+ console.log('Starting client...');
301
+ await client.connect({
302
+ ip: '192.168.0.102',
303
+ port: 102,
304
+ clientID: 'mms_client1',
305
+ reconnectDelay: 2
306
+ });
307
+
308
+ // Ждём открытия соединения (событие будет обработано в колбэке)
309
+ await sleep(5000);
310
+
311
+ // Опционально: управление (раскомментируй при необходимости)
312
+ // console.log('Performing control operation...');
313
+ // await client.controlObject("WAGO61850ServerDevice/XCBR1.Pos", true);
314
+ // await sleep(5000);
315
+
316
+ // Ожидание данных и отчётов
317
+ console.log('Waiting for data and reports...');
318
+ await sleep(30000);
319
+
320
+ // Отключение отчётов
321
+ const rcbRef = 'WAGO61850ServerDevice/LLN0.RP.ReportBlock0101';
322
+ console.log(`Disabling reporting for ${rcbRef}`);
323
+ await client.disableReporting(rcbRef);
324
+
325
+ console.log('Client status:', client.getStatus());
326
+ console.log('Closing client...');
327
+ await client.close();
328
+ console.log('Client closed.');
329
+
330
+ } catch (err) {
331
+ console.error('Main error:', err.message);
332
+ await client.close().catch(e => console.error('Close error:', e.message));
333
+ }
334
+ }
335
+
336
+ // Запуск
163
337
  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.27",
3
+ "version": "1.0.28",
4
4
  "description": "Node.js addon for IEC 61850 client (MMS, GOOSE) using libiec61850",
5
5
  "main": "index.js",
6
6
  "keywords": [