Skip to content

Siemens S7 (SIMATIC)

The WattWächter Plus connects directly to a SIMATIC S7-1200 or S7-1500 through its Modbus TCP server. All you need is the MB_CLIENT instruction from the TIA Portal library — no add-on module, no CP.

First things first: the address conversion

MB_CLIENT does not expect a protocol address at MB_DATA_ADDR — it expects a Modicon reference, and converts it before sending. Entering the addresses from the register map unchanged reads a completely different location and returns empty registers. See Converting addresses.


Prerequisites

  • WattWächter Plus with firmware 1.2.0 or newer (for values as Real: 1.2.1 or newer)
  • Modbus TCP enabled on the WattWächter — web interface → SettingsModbus TCPEnable Modbus TCP serverSave. Other ways under Modbus TCP → Enabling
  • S7-1200 or S7-1500 with an on-board PROFINET interface on the same network
  • TIA Portal with the MB_CLIENT instruction (Communication → Others → MODBUS TCP)
  • A static IP address for the WattWächter — via a DHCP reservation in your router or configured on the device. How to find the current IP is described in the FAQ

The Miniserver caveat applies here too

The S7 does not resolve mDNS/.local names. The connection parameters need the IP address, not wattwaechter-XXXXXXXXXXXX.local.


Converting addresses

Every address in our documentation is a protocol address — the number that travels in the Modbus frame. MB_DATA_ADDR takes a Modicon reference instead and subtracts from it:

Entry at MB_DATA_ADDR Protocol address sent Function code at MB_MODE = 0
40001 … 49999 entry − 40001 0x03 Read Holding Registers
400001 … 465535 entry − 400001 0x03 Read Holding Registers

The range 40001–49999 therefore only reaches protocol address 9998 — it is unusable for the WattWächter's registers. The only rule that applies is:

MB_DATA_ADDR = protocol address + 400001
What Protocol address MB_DATA_ADDR
SunSpec ID "SunS" 40000 440001
Model 203, start 40070 440071
Total active power W 40088 440089
Import TotWhImp 40116 440117
Model 213, total active power W 40205 440206

Self-test first, everything else after

Start small: MB_DATA_ADDR = 440001, MB_DATA_LEN = 2. The two words must hold 21365 and 28243 — that is the SunSpec ID "SunS" at protocol address 40000. If it arrives, your addressing is correct and you can widen to the full block. If it does not, the conversion is at fault, not the device.


Step 1 — Create the connection parameters

Create a data block holding a variable of system data type TCON_IP_v4 (e.g. DB12, variable CONNECT). It describes the TCP connection to the WattWächter:

Field Value Note
InterfaceId hardware identifier of the PROFINET interface Device configuration → Properties → Hardware identifier
ID freely chosen, 14095 unique across the project; several MB_CLIENT calls sharing an ID share one connection
ConnectionType 16#0B TCP/IPv4
ActiveEstablishment TRUE the CPU opens the connection
RemoteAddress.ADDR the WattWächter's IP, e.g. 192.168.178.106 four individual bytes
RemotePort 502 or the alternative port from the device settings
LocalPort 0 assigned by the CPU

Step 2 — Create the data block for the registers

Create a second data block for the registers you read, e.g. DB11 with a variable Data of type Array[0..106] of Int — 107 registers is exactly the Model 203 block.

Turn off optimized block access

MB_DATA_PTR needs an ANY/pointer expression such as P#DB11.DBX0.0. That can only be formed on a data block without optimized block access.

Right-click the DB → PropertiesAttributesclear the Optimized block access checkbox. The block view then shows an Offset column with 0.0, 2.0, 4.0 … — that is how you know it worked.


Step 3 — Call MB_CLIENT

Call MB_CLIENT from the cyclic program (e.g. in OB1) and parameterise it like this:

Parameter Value Meaning
REQ clock memory bit or your own timing starts a request; edge-triggered
DISCONNECT FALSE open the connection and keep it
MB_MODE 0 read
MB_DATA_ADDR 440071 protocol address 40070 — see Converting addresses
MB_DATA_LEN 107 number of registers, 125 at most
MB_DATA_PTR P#DB11.DBX0.0 destination area from step 2
CONNECT P#DB12.DBX0.0 connection parameters from step 1

Outputs: DONE, BUSY, ERROR, STATUS.

Keep EN enabled, pulse REQ

MB_CLIENT must be processed in every scan cycle until DONE or ERROR is set. A request is started via REQ, not via EN. If the enable input drops in between, BUSY stays set, DONE never arrives, and the data block stays empty.

A polling cycle of 5 s for power values and 30 s for meter readings is a good starting point — the same cycles the Loxone templates use.


Step 4 — Extract the values from the block

Reading 107 registers from MB_DATA_ADDR = 440071 puts protocol address 40070 into Data[0]. A register's index is therefore protocol address − 40070:

Value Protocol address Index in DB11.Data Type Scale factor
Total active power W 40088 [18] Int [22] (W_SF)
Power L1 / L2 / L3 40089–40091 [19] / [20] / [21] Int [22] (W_SF)
Total current A 40072 [2] Int [6] (A_SF)
Current L1 / L2 / L3 40073–40075 [3] / [4] / [5] Int [6] (A_SF)
Voltage LN (average) 40077 [7] Int [15] (V_SF)
Voltage L1 / L2 / L3 40078–40080 [8] / [9] / [10] Int [15] (V_SF)
Line frequency Hz 40086 [16] Int [17] (Hz_SF)
Export TotWhExp 40108–40109 [38] + [39] 2 × Int [54] (TotWh_SF)
Import TotWhImp 40116–40117 [46] + [47] 2 × Int [54] (TotWh_SF)

Scaling. Model 203 transmits integers; the real value is raw × 10^SF. The factors live in the same block and come along with the read — take them from the register rather than hard-coding them. That keeps the program correct across firmware updates too. With W_SF = 1, a raw value of 217 means 2170 W.

32-bit values. The energy counters occupy two registers, high word first. In SCL:

"DB11".Import_Wh := UINT_TO_UDINT("DB11".Data[46]) * 65536
                  + UINT_TO_UDINT("DB11".Data[47]);

Values not delivered. A register holding -32768 (0x8000) means your smart meter does not provide that value — it is the SunSpec sentinel for not implemented. Which registers are currently valid is shown by the status endpoint.


Values as Real (firmware 1.2.1 and newer)

From firmware 1.2.1 the WattWächter additionally serves the same measurements as float32 in Model 213 — with no scale factors. For the S7 that is the data type Real, and no reordering is needed: Modbus transmits the high word first, which is exactly how the S7 stores a Real.

Value Protocol address MB_DATA_ADDR MB_DATA_LEN
Total active power W 40205 440206 2
Power L1 / L2 / L3 40207 / 40209 / 40211 440208 / 440210 / 440212 2 each
Export TotWhExp 40237 440238 2
Import TotWhImp 40245 440246 2

A DB with Array[0..n] of Real is enough as the destination — the registers you read are then available directly as floating-point values, with no SF register and no power of ten.

Model 213 does not fit into one request

The block spans 126 registers, but Modbus allows at most 125 per read request. So read the values you need individually (2 registers each) instead of fetching the block in one go.

Values not delivered are NaN

Fields your meter does not send hold NaN instead of a number. A Real holding NaN makes arithmetic operations return ENO = FALSE. The exceptions are W, TotWhExp and TotWhImp — those start out at 0.


Troubleshooting

All registers stay at 0

By far the most common cause: the address conversion. With MB_DATA_ADDR set to 40071 instead of 440071, the S7 sends protocol address 70 — there is nothing there on the WattWächter, and the device answers with Modbus exception 02.

Run the self-test with 440001 and length 2. And make ERROR and STATUS latch in a watch table — both are set for a single scan cycle and are otherwise never visible. A STATUS starting with 16#838 means the WattWächter answered the request with a Modbus exception.

BUSY stays set, DONE never arrives

Is MB_CLIENT really processed every scan cycle? A dropping enable input leaves the request hanging. REQ is the start signal; EN must stay asserted throughout.

Values like 16#700116#7006 at STATUS are not errors but intermediate states during processing.

MB_DATA_PTR cannot be entered

The destination block still has optimized block access. Clear the checkbox in the block properties — see step 2.

The connection never comes up
  • Is Modbus enabled on the WattWächter? Check /api/v1/modbus/statusenabled: true, running: true.
  • Does RemoteAddress hold an IP address and not a .local name?
  • Is RemotePort correct (default 502) and ActiveEstablishment = TRUE?
  • The WattWächter allows at most 2 concurrent Modbus connections. If a test with modpoll, Home Assistant or Loxone is still running, close that one first.
  • Is the ID in TCON_IP_v4 unique across the project?
Values are off by a factor of 10

The Model 203 scale factor is missing or hard-coded. W_SF changed from 0 to 1 with firmware 1.2.0. Read the factor from the SF register along with the data instead of storing it in the program — or switch to Model 213, which needs no factors at all.

More points in the Modbus TCP troubleshooting section.