Auto: s7-f — Optimized DB / S7Plus decision (Track 1+3 docs-only)

Closes #304
This commit is contained in:
Joseph Doherty
2026-04-26 11:22:40 -04:00
parent 26708b6609
commit b217ca61ce
3 changed files with 252 additions and 2 deletions

View File

@@ -1,5 +1,190 @@
# Siemens SIMATIC S7 (S7-1200 / S7-1500 / S7-300 / S7-400 / ET 200SP) — Modbus TCP quirks
> **Read first: [Optimized DB constraint (S7Plus)](#optimized-db-constraint-s7plus).**
> S7netplus, the wire library this driver is built on, speaks classic S7comm
> only — it cannot read Optimized-block-access DBs on S7-1200 / S7-1500. That
> is the default in TIA Portal V14+ for new projects. If you skip the section
> below, every absolute-offset read against a freshly-created S7-1500 project
> will return `BadDeviceFailure`.
## Optimized DB constraint (S7Plus)
### Symptom
Against a default new S7-1500 TIA Portal project, an absolute-offset read like
`DB1.DBW0` issued by the OtOpcUa S7 driver returns `BadDeviceFailure` (the
S7netplus `PlcException` surfaces as `ErrorCode.WrongVarFormat` /
`ErrorCode.ReadData` depending on firmware revision). No bytes are returned;
the read never reaches the user data; the failure is identical whether
PUT/GET is enabled or not.
### Why
The OtOpcUa S7 driver is built on
[**S7netplus**](https://github.com/S7NetPlus/s7netplus), which implements
**classic S7comm** only — the protocol historically used by S7-300 / S7-400
and the legacy "compatibility" path on S7-1200 / S7-1500. Classic S7comm
addresses DB contents by **absolute byte offset**: `DB1.DBW0` literally means
"give me 2 bytes starting at byte 0 of DB number 1". This works as long as
the byte offsets in the program match the byte offsets on the wire.
S7-1200 V4 and S7-1500 introduced **Optimized block access**. When checked,
the TIA Portal compiler is free to **reorder DB members**, insert padding for
alignment, and store members in CPU-internal memory that the absolute-offset
read protocol cannot reach. There are no fixed byte offsets to address — the
only way to read an Optimized DB is by **symbolic name**, which requires
**S7Plus** (the post-2014 protocol Siemens uses for TIA-Portal-aware tooling
and OPC UA gateways).
S7Plus is undocumented by Siemens. A community Wireshark dissector exists
(`s7comm-plus`), but no production-ready open-source library implements the
write/subscribe surface end-to-end. **S7netplus does not, and is not on a
roadmap to, support S7Plus.** Snap7 v2 / Snap7Net and the various Sharp7
forks are also classic-S7comm-only.
### Default to know about
In **TIA Portal V14 and newer, "Optimized block access" is checked by default
on every newly-created DB**. A customer who clicks "Add new block → Data
block → OK" on a fresh S7-1500 project gets an Optimized DB. The driver
cannot read it.
### Supported workarounds
The OtOpcUa project supports two workarounds. Pick one per deployment.
#### Track 1 — Disable Optimized block access in TIA Portal
Per DB the driver reads:
1. In TIA Portal, open the project tree → `<PLC>`**Program blocks**
right-click the DB → **Properties**.
2. In the **Attributes** tab, **uncheck "Optimized block access"**.
3. **Compile** the program.
4. **Download** to the PLC (download the changed block; the CPU will go into
STOP if the DB layout changed and download-without-reinitialize is
refused — schedule a maintenance window).
After this, `DB1.DBW0` and friends address absolute byte offsets again and
the OtOpcUa S7 driver reads through unmodified.
**Trade-off:** Optimized DBs are slightly faster for *the PLC program
itself* to access (better alignment, sometimes better cache behaviour) and
let the compiler add/remove DB members without renumbering offsets in user
code. Disabling Optimized access trades a tiny amount of CPU-side
performance and a layout-stability guarantee for absolute-offset wire
addressability. For DBs that exist only as a Modbus / S7comm gateway buffer
(common pattern), there is no real downside.
This is the same prerequisite called out in
["Optimized block access — must be off"](#optimized-block-access--must-be-off)
and ["Address / DB Mapping → MB_HOLD_REG"](#address--db-mapping) for the
Modbus-TCP path; the constraint is the same and stems from the same
absolute-offset-only assumption.
#### Track 3 — Bridge via the OpcUaClient driver against the CPU's onboard OPC UA server
S7-1500 firmware **V2.5 and later** ship with an **integrated OPC UA
server** running on the CPU's PROFINET port (default port 4840). Once
enabled in TIA Portal it exposes the entire symbol table — including
Optimized DBs — through standard OPC UA, by symbolic name. There is no S7
protocol involved at all from the OtOpcUa side.
Configure the bridge once:
1. **TIA Portal side**:
- Open the CPU's properties → **OPC UA****General** → check
**Activate OPC UA server**.
- Set the server port (default 4840) and security policy. For a quick
bring-up, allow `None` + `UserName` and create a server certificate;
for production, use Basic256Sha256 with a CA-issued cert.
- Under **OPC UA****Server interfaces**, expose the symbols/tags the
OtOpcUa side should see. (Whole-symbol-table exposure works; a
curated server interface is more secure and faster.)
- Compile and download.
- Note: this requires a **runtime OPC UA license on the CPU**
(Siemens SIMATIC NET OPC UA server license, typically activated via
SIMATIC SUM). The license is per CPU, not per client.
2. **OtOpcUa side** — register an `OpcUaClient` driver instance pointing
at the CPU. Minimal `DriverConfig` JSON:
```json
{
"Driver": "OpcUaClient",
"Name": "PLC1500_Onboard",
"Options": {
"EndpointUrl": "opc.tcp://10.0.0.42:4840",
"SecurityMode": "SignAndEncrypt",
"SecurityPolicy": "Basic256Sha256",
"UserName": "OtOpcUa",
"Password": "<from secret store>",
"WatchModelChanges": true
}
}
```
The driver handles browse, read, write, and subscriptions through the
CPU's symbolic name space. Optimized DBs Just Work — the CPU resolves
names internally, so the wire never sees a byte offset.
See [`docs/drivers/OpcUaClient.md`](../drivers/OpcUaClient.md) for the full
configuration surface (reverse connect, model-change re-import, failover,
aggregate functions, redundancy via `ServerUriArray`, etc.).
**When to use Track 3 over Track 1**:
- The DB layout is owned by an upstream Siemens engineering team that won't
disable Optimized access (legitimate concern: shared-DB constraints,
compile-time member-renumbering, application notes that mandate optimized
blocks).
- The customer already licenses OPC UA on the CPU.
- Symbolic addressing is preferred end-to-end (no byte-offset bookkeeping
in the OtOpcUa tag list; tags survive DB-member additions).
- S7-300 / S7-400 are out of scope on this CPU (the onboard OPC UA server
is S7-1500 V2.5+ only — see V2.5 firmware change list).
**When to use Track 1 over Track 3**:
- The CPU is S7-1200 (no onboard OPC UA server even on the V4 firmware
line) or older S7-1500 firmware (< V2.5).
- The customer won't pay for the SIMATIC NET OPC UA server license on the
CPU.
- The DBs in question exist purely as gateway buffers and have no
significant CPU-program access pattern that would benefit from
Optimized access.
### Track 2 — out of scope
For completeness, the **Track 2** option that was evaluated and rejected:
migrate the OtOpcUa S7 driver off S7netplus to a library that speaks
S7Plus. The candidates were:
- **Snap7 v2 / Snap7Net** — classic S7comm only. Same Optimized-DB
limitation. Not a step forward.
- **Sharp7 community forks** — partial S7-1200 / S7-1500 PUT/GET semantics
but still classic-S7comm wire format. Not a step forward.
- **Custom S7Plus implementation** — possible in principle (the Wireshark
`s7comm-plus` dissector covers the wire format), but estimated **≥4
weeks** of engineering for a minimal read/write/subscribe surface, plus
ongoing maintenance every time Siemens revs the protocol version
(which they do silently with each TIA Portal release).
**Track 2 is not on the OtOpcUa roadmap** unless a specific customer funds
the engineering and ongoing maintenance. Track 1 + Track 3 together cover
every shipping S7 deployment we have visibility into.
### Pre-flight diagnostics
The driver does not currently auto-detect Optimized DBs from the
`BadDeviceFailure` shape (the same error code is returned for "DB doesn't
exist", "DB exists but is too short", etc.). On first encounter of a
device-failure error, check the suspect DB's properties in TIA Portal
**before** chasing wire-level theories. The auto-detect would require an
SZL probe or a symbolic round-trip; tracked but not a v2 deliverable.
---
Siemens S7 PLCs do *not* speak Modbus TCP natively at the OS/firmware level. Every
S7 Modbus-TCP-server deployment is either (a) the **`MB_SERVER`** library block
running on the CPU's PROFINET port (S7-1200 / S7-1500 / CPU 1510SP-series
@@ -1030,7 +1215,11 @@ addresses by absolute offset, including UDT-typed DBs.
If a customer can't disable Optimized access (e.g., shared-DB constraints),
the workaround is to expose the UDT through the symbolic-tag path once that
ships — not in PR-S7-D2.
ships — not in PR-S7-D2. See
[Optimized DB constraint (S7Plus)](#optimized-db-constraint-s7plus) at the
top of this document for the project-wide decision (Track 1 disable in TIA
Portal, or Track 3 bridge via the OpcUaClient driver against the CPU's
onboard OPC UA server).
### Validation