Skip to main content

Siemens S7

The S7 module supports Siemens S7 TCP, also known as ISO-on-TCP with Read Var / Write Var. It covers DB, I, Q, and M areas for Bool, Byte, Word, DWord, Int, DInt, and Real, plus point acquisition, write-back, and virtual PLC simulation.

Install

dotnet add package Zeus.Communications
dotnet add package Zeus.Protocols.S7

Connect to a Real PLC

S7 TCP commonly uses port 102.

await using var app = ZeusHost.Create(builder =>
{
builder.AddTcpClient("plc-link", "192.168.1.10", 102);
builder.AddSiemensS7("plc", "plc-link", new S7Options
{
Rack = 0,
Slot = 1
});
});

await app.StartAsync();

var plc = app.Devices.Get<S7Device>("plc");
var temperature = await plc.ReadRealAsync(S7Area.DataBlock, byteOffset: 0, dbNumber: 1);
await plc.WriteIntAsync(S7Area.DataBlock, byteOffset: 4, value: 120, dbNumber: 1);
var running = await plc.ReadBoolAsync(S7Area.Merkers, byteOffset: 10, bitOffset: 0);

S7-300/400 often use slot 2; S7-1200/1500 projects often use slot 1. Set rack/slot explicitly when the default does not match the PLC.

Common Types

var dbBytes = await plc.ReadDataBlockBytesAsync(dbNumber: 1, byteOffset: 0, length: 8);
await plc.WriteDataBlockBytesAsync(dbNumber: 1, byteOffset: 20, values: [1, 2, 3, 4]);

var word = await plc.ReadWordAsync(S7Area.DataBlock, 0, dbNumber: 1);
var dint = await plc.ReadDIntAsync(S7Area.DataBlock, 4, dbNumber: 1);
var real = await plc.ReadRealAsync(S7Area.DataBlock, 8, dbNumber: 1);
var bit = await plc.ReadBoolAsync(S7Area.DataBlock, 12, 3, dbNumber: 1);

await plc.WriteWordAsync(S7Area.Merkers, 0, 1234);
await plc.WriteBoolAsync(S7Area.Outputs, 2, 1, true);

S7 multi-byte values use PLC-style big-endian encoding. Bool uses byte offset plus bit offset, so DB1.DBX12.3 maps to area: db, db: 1, address: 12, and bit: 3.

Points and Write-Back

await using var app = ZeusHost.Create(builder =>
{
builder.AddTcpClient("plc-link", "192.168.1.10", 102);
builder.AddSiemensS7("plc", "plc-link", points: map => map
.DbReal("temperature", dbNumber: 1, byteOffset: 0)
.DbInt("setpoint", dbNumber: 1, byteOffset: 4, scale: 0.1).Writable("setpoint")
.MarkerBool("running", byteOffset: 10, bitOffset: 0).Writable("running"));
});

await app.StartAsync();

var temperature = app.Points.Get<float>("temperature");
await app.Points.WriteAsync("setpoint", 12.3);
await app.Points.WriteAsync("running", true);

scale is for integer engineering values. Writing 12.3 with scale: 0.1 writes raw 123 to DB1.DBW4.

Virtual PLC

var memory = new S7SlaveMemory();
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("plc-link", new S7SlaveResponder(memory));
builder.AddSiemensS7("plc", "plc-link");
});

Run sample: samples/Zeus.Samples.Console.S7.

JSON Configuration

{
"channels": [
{ "name": "plc-link", "type": "tcp", "host": "192.168.1.10", "port": 102 }
],
"devices": [
{
"name": "plc",
"channel": "plc-link",
"type": "siemens-s7",
"rack": 0,
"slot": 1,
"points": [
{ "name": "temperature", "area": "db", "db": 1, "address": 0, "dataType": "real" },
{ "name": "setpoint", "area": "db", "db": 1, "address": 4, "dataType": "int", "scale": 0.1, "writable": true },
{ "name": "running", "area": "m", "address": 10, "bit": 0, "dataType": "bool", "writable": true }
]
}
]
}

Virtual channel:

{ "name": "plc-link", "type": "virtual", "responder": "s7" }

Common Issues

SymptomCommon causeFix
TimeoutIP, port 102, rack/slot, or PLC access setting is wrongVerify with S7SlaveResponder, then check PLC settings
DB value is wrongOffset, type, or optimized access mismatchConfirm absolute DB addresses in TIA Portal
Bool point is wrongBit offset missing or wrongaddress is byte offset; bit is 0-7
Input-area write failsI area is read-only input imageWrite Q, M, or DB areas

Next: Mitsubishi MC or Modbus.