6.8 KiB
otopcua-s7-cli — Siemens S7 test client
Ad-hoc probe / read / write / subscribe tool for Siemens S7-300 / S7-400 /
S7-1200 / S7-1500 (and compatible soft-PLCs) over S7comm / ISO-on-TCP port 102.
Uses the same S7Driver the OtOpcUa server does (S7.Net under the hood).
Fourth of four driver test-client CLIs.
Build + run
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli -- --help
Common flags
| Flag | Default | Purpose |
|---|---|---|
-h / --host |
required | PLC IP or hostname |
-p / --port |
102 |
ISO-on-TCP port (rarely changes) |
-c / --cpu |
S71500 |
S7200 / S7200Smart / S7300 / S7400 / S71200 / S71500 |
--rack |
0 |
Hardware rack (S7-400 distributed setups only) |
--slot |
0 |
CPU slot (S7-300 = 2, S7-400 = 2 or 3, S7-1200/1500 = 0) |
--timeout-ms |
5000 |
Per-operation timeout |
--tsap-mode |
Auto |
ISO-on-TCP connection class: Auto / Pg / Op / S7Basic / Other. Hardened S7-1500 / ET 200SP CPUs may require Op or S7Basic. See s7.md TSAP / Connection Type. |
--local-tsap |
(unset) | Optional 16-bit local TSAP override (e.g. 0x0200). Required when --tsap-mode Other; wins over class default under Pg/Op/S7Basic. |
--remote-tsap |
(unset) | Optional 16-bit remote TSAP override. Required when --tsap-mode Other; wins over class default under Pg/Op/S7Basic. |
--verbose |
off | Serilog debug output |
PUT/GET must be enabled
S7-1200 / S7-1500 ship with PUT/GET communication disabled by default.
Enable it in TIA Portal: Device config → Protection & Security → Connection
mechanisms → "Permit access with PUT/GET communication from remote partner".
Without it the CLI's first read will surface BadNotSupported.
Pre-flight PUT/GET enablement (PR-S7-C5)
The driver issues a tiny 2-byte read against Probe.ProbeAddress (default
MW0) immediately after OpenAsync and fails InitializeAsync with a
typed S7PutGetDisabledException when the PLC rejects the read with the
wire-level "function not allowed" response. The exception message names the
exact TIA Portal toggle to flip — operators see the configuration fix at
init time, not after the first per-tag read produces BadDeviceFailure.
Two opt-out knobs on the JSON Probe block:
ProbeAddress— set to""(empty string) to skip the pre-flight read entirely. Useful when no fingerprint address has been wired.SkipPreflight— set totrueto defer the check to runtime while keeping the background liveness loop. Per-tag reads still surfaceBadDeviceFailureuntil PUT/GET is enabled, but Init succeeds and the driver becomes visible in the Admin UI.
See s7.md "Pre-flight PUT/GET enablement"
for the full rationale, classifier behaviour, and the wire-level
ErrorCode matching.
S7 address grammar cheat sheet
| Form | Meaning |
|---|---|
DB1.DBW0 |
DB number 1, word offset 0 |
DB1.DBD4 |
DB number 1, dword offset 4 |
DB1.DBX2.3 |
DB number 1, byte 2, bit 3 |
DB10.STRING[0] |
DB 10 string starting at offset 0 |
M0.0 |
Merker bit 0.0 |
MW0 / MD4 |
Merker word / dword |
IW4 |
Input word 4 |
QD8 |
Output dword 8 |
Commands
probe
# S7-1500 — default probe MW0
otopcua-s7-cli probe -h 192.168.1.30
# S7-300 (slot 2)
otopcua-s7-cli probe -h 192.168.1.31 -c S7300 --slot 2 -a DB1.DBW0
read
# DB word
otopcua-s7-cli read -h 192.168.1.30 -a DB1.DBW0 -t Int16
# Float32 from DB dword
otopcua-s7-cli read -h 192.168.1.30 -a DB1.DBD4 -t Float32
# Merker bit
otopcua-s7-cli read -h 192.168.1.30 -a M0.0 -t Bool
# 80-char S7 string
otopcua-s7-cli read -h 192.168.1.30 -a DB10.STRING[0] -t String --string-length 80
write
otopcua-s7-cli write -h 192.168.1.30 -a DB1.DBW0 -t Int16 -v 42
otopcua-s7-cli write -h 192.168.1.30 -a DB1.DBD4 -t Float32 -v 3.14
otopcua-s7-cli write -h 192.168.1.30 -a M0.0 -t Bool -v true
Writes to M / Q are real — they drive the PLC program. Be careful what you flip on a running machine.
Hardened CPU — forcing OP-class TSAP
# Probe a hardened S7-1500 that rejects PG class but accepts OP.
otopcua-s7-cli probe -h 10.50.12.30 --tsap-mode Op
# Read against the same CPU.
otopcua-s7-cli read -h 10.50.12.30 --tsap-mode Op -a DB1.DBW0 -t Int16
# Manual TSAP override (e.g. site with a fixed proprietary TSAP gateway).
otopcua-s7-cli probe -h 10.50.12.30 --tsap-mode Other --local-tsap 0x4D57 --remote-tsap 0x4D58
Without --tsap-mode, the CLI uses S7netplus's CpuType-derived default (PG
class for almost everything). The same connection-refused failure shape that a
wrong --slot produces also shows up when the CPU rejects PG class — try
--tsap-mode Op first when the handshake is failing on otherwise-correct
endpoint config. See s7.md TSAP / Connection Type
for the byte table and motivation.
subscribe
otopcua-s7-cli subscribe -h 192.168.1.30 -a DB1.DBW0 -t Int16 -i 500
S7comm has no native push — the CLI polls through PollGroupEngine just like
Modbus / AB.
import-symbols
PR-S7-D1 / #299 — read a TIA
Portal CSV ("Show all tags" export) or STEP 7 Classic .AWL file and emit a
JSON tag fragment for appsettings.json, or a one-line summary. Mirrors the
AB Legacy import-rslogix CLI in shape.
# TIA Portal CSV — emit JSON fragment to stdout
otopcua-s7-cli import-symbols --file plc-export.csv --format tia
# STEP 7 Classic AWL — emit summary line
otopcua-s7-cli import-symbols --file classic.awl --format awl --emit summary
# DE-locale CSV — auto-detected; output to file
otopcua-s7-cli import-symbols `
--file plc-de.csv `
--format tia `
--emit appsettings-fragment `
--output tags.json
# Strict mode — fail-fast on the first malformed row (CI lint)
otopcua-s7-cli import-symbols --file plc.csv --format tia --strict
| Flag | Default | Purpose |
|---|---|---|
-f / --file |
required | Path to the TIA CSV or .AWL file |
--format |
tia |
tia (CSV) or awl (STEP 7 Classic) |
-d / --device |
none | Optional documentation tag (held for symmetry with import-rslogix) |
--emit |
appsettings-fragment |
appsettings-fragment (JSON) or summary (one-line counter) |
-o / --output |
stdout | Optional path; when set the JSON fragment is written there + summary line goes to stdout |
--max-rows |
unlimited | Defensive cap on rows imported |
--strict |
off | Fail-fast on the first malformed row (default permissive: skip + log) |
UDT-typed rows import as placeholder tags (data type forced to Byte); see
S7-TIA-Import.md for the full format reference,
locale auto-detection, and AWL position-based addressing rules.