Problem Overview
Engineers integrating Siemens S7-1500 (and S7-300/1200) PLCs with Node-RED using the oriolrius/node-red-contrib-s7 package frequently encounter two distinct symptoms after modifying data blocks in TIA Portal:
- Modified starting values declared on static DB tags do not appear in the Node-RED S7 In node payload after a project download.
- Reading an address that does not correspond to a defined variable in the DB still returns an integer-like value (a "ghost read") rather than a quality error.
Both behaviors are rooted in the S7-1500 runtime model and the way the S7 protocol exposes process memory. The issues are not bugs in Node-RED or the S7 node; they reflect a misunderstanding of what "starting value" means on a Siemens PLC and what the S7 node is doing on the wire.
Root Cause: Starting Value vs. Actual Value
In TIA Portal V15–V19, every static tag in a global or instance data block carries three distinct attributes:
| Attribute | Where it lives | When it is used |
|---|---|---|
| Start value | Offline DB snapshot loaded to the CPU's load memory | On DB initialization (cold restart, STOP→RUN, download with reinitialization) |
| Monitor value | Online view in TIA Portal / HMI | Current snapshot of the process image |
| Actual value | CPU work memory (retain or non-retain) | Continuously used by the user program; read by Node-RED |
When you change the Start value in the TIA Portal project and perform a Download to device, the S7-1500 CPU (firmware V2.5 and later, including V3.x for S7-1500/S7-1500T) does not automatically overwrite the actual value of existing tags. The download is a delta load: the new initial values sit in load memory waiting for the next DB initialization event. This is documented in the Siemens Industry Online Support KB article on DB download behavior.
Consequence: Node-RED, which talks to the CPU via S7 communication (PUT/GET or optimized DB read services), reads the actual value, not the start value. The actual value remains the value the user program (or a previous online write) last placed there.
Root Cause: Ghost Reads on Undefined Addresses
The S7 protocol is a memory-mapped read interface. A read request at offset 8.0 of DB1 returns the four bytes that happen to occupy that location in the CPU's work memory at the moment the read is serviced. The S7-1500 CPU does not perform a symbol lookup or a "is this variable defined?" check; it just hands the bytes back.
On an S7-1500 with an optimized DB, the compiler is free to reorder and pack variables. If a variable was removed or never declared, the bytes that remain may be:
- Remnants of a previous symbol that was deleted (still physically in the work memory region).
- The result of the wear-leveling allocation that the S7-1500 memory manager performs internally for non-retentive data.
- Simply zero, or simply a pattern from a previously active program scan.
On an S7-300, the same effect is more pronounced because classic (non-optimized) DBs use fixed offsets that survive symbol deletion. The PLC keeps the bytes; only the symbol table entry is gone. This is also the reason users on S7-300 sometimes see a value of 2.1019476964872256e-44 when reading a REAL at an offset that contains garbage bytes — the IEEE 754 decoder happily interprets any 4 bytes as a float. See the Node-RED Discourse: S7-300 REAL abnormal read for a worked example.
S7-1500 Download Semantics That Affect Node-RED
For S7-1500 CPUs (6ES751x, 6ES752x, ET 200SP CPU, and the S7-1500T motion controller family) running firmware V2.5 or higher, the download behavior depends on the DB attribute "Retain", the download with consistency check setting, and whether the CPU is in RUN during the download.
| DB Attribute / Action | Effect on Start Value | Effect on Actual Value |
|---|---|---|
| Download to target device, RUN mode, no reinit | Stored in load memory, not yet applied | Preserved |
| Download to target device, RUN mode, with "Reinitialize DB" checked | Applied immediately for affected DB | Overwritten with start value (retain tags preserved) |
| STOP → RUN transition (cold restart, MRES) | Applied | Overwritten for non-retain tags; preserved for retain tags |
| Online "Initialize DB" command (right-click DB in project tree) | Applied | Reset to start value |
To force a TIA Portal download that applies new start values without stopping the PLC, right-click the DB → Download to device → Software (only changed blocks), and on the "Consistent download" dialog check "Reinitialize DBs". The S7-1500 will then write the start value into the actual value of every non-retain tag, which Node-RED will pick up on its next poll cycle.
Node-RED S7 Node Configuration
The oriolrius/node-red-contrib-s7 node uses a payload schema of {variable, address, type} for legacy S7-300 reads and the typed address object for S7-1500 optimized access. A minimal read configuration looks like:
[
{
"variable": "test",
"address": "DB1",
"type": "INT",
"offset": 0
},
{
"variable": "test2",
"address": "DB1",
"type": "INT",
"offset": 2
}
]
Two common configuration mistakes produce the exact symptoms described in the source thread:
-
Duplicate address entries. Two entries both pointing at
DB1, INT, offset 0will return identical values, and the second variable name acts only as a label. Always assign non-overlapping offsets:0,2,4, etc., becauseINTis 16 bits (2 bytes) and S7 memory is byte-addressable. - No symbol binding. The S7 node does not look up the variable name against the PLC symbol table; it only sends the offset to the CPU. If the offset in Node-RED does not match the offset that TIA Portal assigned to the tag, you will read whatever bytes happen to be at that physical offset.
Step-by-Step Resolution
Step 1: Verify the S7 Node Reads the Correct Symbol
In TIA Portal, open the DB in "Open in read-only mode" while online (right-click DB → "Open online"). The Monitor column shows the actual value the CPU currently holds, and the Offset column (in the "Details" view) shows the byte offset the compiler assigned. Cross-check this offset with the value configured in the S7 node. The two must match exactly.
Step 2: Reinitialize the DB After Editing Start Values
When the goal is to make a new start value visible in Node-RED, choose one of the following methods:
| Method | Procedure | Downtime |
|---|---|---|
| Online DB reinit (preferred) | TIA Portal → right-click DB → "Download to device" → check "Reinitialize DBs" | None on S7-1500; CPU stays in RUN, retain data preserved |
| PLC restart (cold) | Switch CPU from RUN to STOP, then back to RUN, or perform MRES | Process downtime; all non-retain actual values reset |
| Online modify actual value | In the DB's online view, click the monitor cell of the tag and type the new value, confirm with Enter | None; this writes the actual value directly |
Step 3: Fix Duplicate or Mis-Aligned Address Entries
In the S7 In node configuration, ensure every {variable, address, type, offset} triple has a unique combination. For multi-word data types use proper strides:
INT → 2 bytes, increment offset by 2
DINT → 4 bytes, increment offset by 4
REAL → 4 bytes, increment offset by 4
BOOL → 1 bit, format: offset = byte.bytebit (e.g. 4.0 for byte 4, bit 0)
For BOOL reads in the oriolrius S7 node, the address string format is DB1,X4.0 for a bit at byte 4, bit 0. Mismatches between bit and byte access in optimized DBs can also produce "ghost" reads of 0 or 1.
Step 4: Validate Against Symbol Table
Export the PLC symbol table from TIA Portal (PLC → "Export to text file") and compare it against the S7 node configuration in Node-RED. The exported text file lists every DB number, byte offset, bit offset, and data type. Any address in the S7 node that does not appear in this file is reading unallocated memory.
Verification Procedure
- Place a
debugnode connected to the S7 In node and deploy. - In TIA Portal, open the target DB online and change the monitor value of a known tag (right-click → "Modify" → enter new value → Apply).
- Within one Node-RED poll cycle (default 1000 ms for the oriolrius S7 node, configurable via the
cycleparameter), the debug pane should show the new value. - Change the Start value of the same tag in the offline project, download with "Reinitialize DBs" checked, and verify the value flips to the start value in the Node-RED debug output.
- Delete the S7 In node's entry for one variable, then re-add an entry pointing at an unused offset. Confirm that the value returned is
undefined,0, or noise (and not a quality error in every S7 node version — the oriolrius node historically returns a "Failure (Bad values)" debug message in such cases; documented in the node-red-contrib-s7 GitHub README).
Edge Case: REAL Type Decoding on S7-300
The S7-300 stores REAL values in IEEE 754 single-precision format (32 bits, big-endian byte order). If the S7 node is configured to read a 4-byte REAL from an offset where the underlying memory is actually an INT (2 bytes) followed by two bytes of unrelated data, the result will be an exotic float such as 2.1019476964872256e-44 — the IEEE 754 representation of 0x00000041. The fix is to align the S7 node's declared type with the TIA Portal data type exactly. A common variant of this error appears on LOGO! 8 controllers when an analog input occupies two 16-bit words but is read as a single 32-bit value; see the Node-RED Discourse: S7 node analog output problem for a field case.
Edge Case: Optimized vs. Non-Optimized DBs
On S7-1500, the default for new DBs is "Optimized block access". With optimized access enabled, byte offsets in the S7 node will not match the symbolic offsets shown in TIA Portal — the compiler reorders the layout. The S7 node typically still works because the PUT/GET or S7 communication path resolves symbolic names, but if the Node-RED side uses raw offset reads, disable optimization in the DB properties ("Attributes" tab → uncheck "Optimized block access"). For S7-300, optimization does not exist; offsets are always the literal declaration order.
Edge Case: Retain and Non-Retain Tag Behavior
When a DB is reinitialized and a tag is marked "Set in IDB" with retain, the start value is written only on cold restart, not on RUN-mode DB reinit. This is intentional: the retain mechanism is designed to survive power cycles. If Node-RED reads a retain tag whose start value was changed in TIA Portal but the PLC was not power-cycled, the previous actual value persists. To force a refresh, either power-cycle the PLC, or remove the retain attribute, download, and set it again.
Troubleshooting Matrix
| Symptom | Likely Root Cause | Corrective Action |
|---|---|---|
| Node-RED always returns the same value despite TIA Portal change | Start value changed; actual value not yet updated | Right-click DB → Download to device → "Reinitialize DBs" |
| Two Node-RED variables always show identical values | Both addresses point to the same offset (e.g., DB1,INT,0) | Use unique offsets; verify stride for INT (2), DINT (4), REAL (4) |
| Node-RED returns a value for a variable that does not exist in TIA | S7 protocol returns whatever bytes occupy the offset; PLC does not validate symbol existence | Remove the entry, or declare the symbol in the DB |
REAL values are decoded as 2.1e-44 or NaN |
Offset/type mismatch; garbage bytes interpreted as IEEE 754 | Match type/offset to TIA declaration; check byte order |
| Bool read always returns 0 or 1 regardless of state | Bit address format wrong (e.g., 4 instead of 4.0) | Use DB1,X4.0 notation for bits |
| Retain tag retains old value after start value change | Retain mechanism suppresses reinit on RUN | Power-cycle PLC, or temporarily clear retain attribute |
| S7 In node prints "Failure (Bad values)" in debug | Offset/area mismatch (e.g., reading DB1 from an input area), or CPU in STOP | Verify CPU is in RUN; verify address is in DB area, not input/output |
Performance and Polling Considerations
On S7-1500 CPUs, the S7 communication path (PUT/GET and the S7 node's optimized read services) is rate-limited by the configured S7 connection resources. The default allows up to 16 simultaneous S7 connections. The oriolrius S7 In node typically establishes a single connection per configured address block and polls at the configured cycle interval (default 1000 ms). For 50+ tags, batch them into a contiguous read of the DB's working range — the S7 node's address object with length set to the full DB size is more efficient than 50 individual tag reads, and reduces the chance of catching the DB mid-update with mixed-cycle garbage reads. Document the polling pattern in the Node-RED flow's description so future maintainers can correlate the visible values with the PLC scan.
Security and Access Rights
The S7 node reads require the PLC's PUT/GET access to be enabled for the appropriate connection. On S7-1500, this is under PLC Properties → Protection & Security → Connection mechanisms → "Permit access with PUT/GET communication from remote partner". Without this, the S7 In node will fail to connect or return a security error. If the PLC is behind a Siemens SCALANCE firewall, port 102/TCP must be open and the firewall's deep-packet-inspection profile for S7 must allow the read functions used by the node. Production environments with safety-integrated CPUs (S7-1500F) may require the safety program to be unlocked before any read can complete — refer to the Siemens Industry Online Support portal for safety-mode read access restrictions.
FAQ
Why does my S7-1500 starting value change in TIA Portal not appear in Node-RED?
The start value is loaded to load memory but is not written to the actual value until the DB is reinitialized. Either download the DB with "Reinitialize DBs" checked (RUN-safe on S7-1500) or perform a STOP→RUN transition. Node-RED reads the actual value, not the start value.
Is the S7 In node supposed to return a value for a variable that does not exist in TIA Portal?
Yes — the S7 protocol is memory-mapped, not symbol-aware. The CPU returns whatever bytes occupy the requested offset. The Node-RED S7 node cannot tell that the variable is undefined. Only declare addresses in the S7 node that match declared tags in the DB; the oriolrius node will print "Failure (Bad values)" only on hard mismatches such as reading outside the DB.
How do I read a BOOL from a Siemens S7 PLC in Node-RED?
Use the bit address format DB<number>,X<byte>.<bit>, e.g., DB1,X4.0 for a boolean at byte 4, bit 0. The S7 In node expects the type to be set to BOOL and the offset to be the byte offset; the bit is encoded in the address string. Mismatches produce constant 0 or 1 readings.
Why do my S7-300 REAL values come out as exotic numbers like 2.1e-44?
The 4 bytes at that offset are being interpreted as an IEEE 754 float but do not actually represent a REAL — typically the offset is misaligned, or the source variable is an INT or DWORD. Match the Node-RED type and offset to the TIA Portal declaration exactly. S7-300 stores REAL as 32-bit big-endian IEEE 754.
How can I trigger a notification in Node-RED if a sensor value has not changed for X hours?
Use a Node-RED function node that captures the last-changed timestamp of the S7 In node's payload and compares it to Date.now() in a flow-level inject node scheduled at the desired check interval. The same pattern is used in home automation setups; reference implementations exist in the Home Assistant community and can be adapted to industrial S7 tags.