@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.
- package/examples/index_iec61850_client2.js +47 -16
- package/package.json +1 -1
- package/readme.md +130 -25
|
@@ -21,27 +21,28 @@ const client = new MmsClient((event, data) => {
|
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
// Чтение датасетов
|
|
25
|
-
console.log('Reading datasets...');
|
|
26
|
-
dataSets.
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
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 {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const client = new
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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/
|
|
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
|
|