Skip to main content

IEC 60870-5-104

The Zeus IEC104 module targets power telecontrol, energy gateway, and station data acquisition scenarios. The built-in path covers the common master-side workflow: STARTDT, general interrogation, single commands, and normalized, scaled, and short-float measured/setpoint values. The link layer implements IEC 60870-5-104 t1/t2/t3 timers and the k/w window: t1 waits for I/U acknowledgements, t2 bounds S-format acknowledgements, and t3 sends TESTFR act after idle.

Install​

dotnet add package Zeus.Communications
dotnet add package Zeus.Protocols.Iec104

IEC104 usually runs over TCP. For hardware-free testing, start with a virtual station:

var options = new Iec104Options { CommonAddress = 7 };
var memory = new Iec104StationMemory();
memory.SetSinglePoint(1, true);
memory.SetScaled(100, 253);
memory.SetShortFloat(200, 25.3);

await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("iec-link", new Iec104SlaveResponder(options, memory));
builder.AddIec104("station", "iec-link", options);
});

await app.StartAsync();
var station = app.Devices.Get<Iec104Device>("station");
var values = await station.InterrogateAsync();

For a real gateway, switch only the channel:

builder.AddTcpClient("iec-link", "192.168.1.20", 2404);
builder.AddIec104("station", "iec-link", new Iec104Options { CommonAddress = 7 });

Point Polling​

builder.AddAcquisition(TimeSpan.FromMilliseconds(1000));
builder.AddIec104(
"station",
"iec-link",
new Iec104Options { CommonAddress = 7 },
points: map => map
.SinglePoint("running", 1)
.Scaled("temperature", 100, scale: 0.1)
.ShortFloat("pressure", 200));

The acquisition loop runs general interrogation and publishes matching IOAs to the point table. A Scaled point with scale: 0.1 publishes wire value 253 as engineering value 25.3.

Write-Back​

builder.AddIec104(
"station",
"iec-link",
new Iec104Options { CommonAddress = 7 },
points: map => map
.SinglePoint("remoteSwitch", 1).Writable("remoteSwitch")
.Scaled("setpoint", 100, scale: 0.1).Writable("setpoint"));

await app.Points.WriteAsync("remoteSwitch", true);
await app.Points.WriteAsync("setpoint", 18.6);

SinglePoint uses a single command. Normalized, Scaled, and ShortFloat use matching setpoint commands. Points with scale are converted back to wire values before write-back.

JSON Configuration​

{
"channels": [
{
"name": "iec-link",
"type": "tcp",
"options": {
"host": "192.168.1.20",
"port": 2404
}
}
],
"devices": [
{
"name": "station",
"channel": "iec-link",
"type": "iec104",
"options": {
"commonAddress": 7,
"t1Milliseconds": 15000,
"t2Milliseconds": 10000,
"t3Milliseconds": 20000,
"maxUnacknowledgedIFrames": 12,
"acknowledgeWindow": 8
},
"points": [
{
"name": "running",
"options": {
"address": 1,
"dataType": "single-point"
}
},
{
"name": "temperature",
"options": {
"address": 100,
"dataType": "scaled",
"scale": 0.1
}
},
{
"name": "pressure",
"options": {
"address": 200,
"dataType": "short-float"
}
}
]
}
]
}

Virtual station configuration:

{
"name": "iec-link",
"type": "virtual",
"options": {
"responder": "iec104",
"commonAddress": 7
}
}

Supported Types​

TypeDirectionZeus Type
M_SP_NA_1 / C_SC_NA_1Poll / writeSinglePoint
M_ME_NA_1 / C_SE_NA_1Poll / writeNormalized
M_ME_NB_1 / C_SE_NB_1Poll / writeScaled
M_ME_NC_1 / C_SE_NC_1Poll / writeShortFloat

Link-layer timers default to the annex values: t1=15s, t2=10s, t3=20s, k=12, w=8. Set t3Milliseconds to 0 to disable TESTFR when using a virtual station. A t1 timeout resets sequence numbers and requires STARTDT again.

For timestamped ASDUs, double commands, file transfer, or balanced-mode extensions, inspect the actual peer frames with channel tracing before extending Zeus.Protocols.Iec104.