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 → Settings → Modbus TCP → Enable Modbus TCP server → Save. 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_CLIENTinstruction (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, 1 … 4095 |
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 → Properties → Attributes → clear 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#7001 … 16#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/status→enabled: true,running: true. - Does
RemoteAddresshold an IP address and not a.localname? - Is
RemotePortcorrect (default502) andActiveEstablishment = 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
IDinTCON_IP_v4unique 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.