Problem Overview: AWP Web Server Cycle Latency
When a Siemens S7-1200 CPU hosts a custom api.io page built with AWP (Automation Web Programming) commands, every HTTP GET or POST against that page is processed inside the PLC's web server task. A typical client "cycle" of login → read JSON → write JSON → read new values → logout against an S7-1200 is observed at 8 to 10 seconds total for five sequential HTTPS requests, or roughly 1.6 to 2.0 seconds per request. The bottleneck is the AWP method itself, not the PHP/Python client nor the network, and the same ceiling exists on the S7-1500 and ET200SP web servers when AWP pages are used in the same way.
The performance can be improved without code changes by raising the CPU's Communication Load share from the TIA Portal default of 20% up to 50%. With this change, a full five-request cycle drops to approximately 3 seconds on the S7-1200 (around 0.6 s per request). If the target is sub-500 ms per call, the platform must change: the S7-1500 and ET200SP expose a native built-in API (RPC-based, accessible from any language) that returns a response in roughly 0.5 s including authentication.
Architecture: How an AWP Web Server Cycle Works
Understanding the latency path is the first step to fixing it. The S7-1200 web server runs in the CPU firmware and is exposed at the default https://<CPU-IP>/ endpoint. AWP pages are HTML fragments that the firmware renders on demand by replacing :="<TagName>": markers with the live PLC tag value when a client requests the page.
- Client opens TLS to port 443 (HTTPS) and POSTs credentials to the web server login endpoint.
- CPU validates the user against the configured Web server → User management table and returns a session cookie.
- Client GETs the AWP page (e.g.
/api.io). Firmware reads each referenced tag from the process image, formats it into the HTML/JSON, and sends the response. - Client POSTs a modified body to the same page. Firmware parses every
:="<Tag>":=write token, writes each tag, and re-renders the page. - Client GETs
/api.ioagain to confirm the new values were accepted by the cyclic OB1 task. - Client issues a logout to invalidate the session.
Each GET/POST in this flow triggers a full HTTP parse in the CPU, a tag-database lookup, and a re-render of the page. The PLC's OB1 cycle is the lower bound: if OB1 is 50 ms, you cannot see a value that was written to a tag before the next OB1 completed.
Root Cause: Why the Default Configuration Is Slow
The latency is the sum of four independent components, and the dominant one is the Communication Load ratio:
| Component | Typical cost | Configurable? |
|---|---|---|
| TLS handshake (cold session) | 150-300 ms (first request only) | Disable HTTPS, accept security trade-off |
| Login / session establishment | 200-400 ms | Use HTTP keep-alive and reuse the session cookie |
| AWP page render per request | 400-1500 ms | Yes — driven by Communication Load |
| OB1 propagation delay (write→visible read) | 1-2 × OB1 cycle time | Shorten OB1; use direct I/O access for non-process tags |
The firmware default reserves 80% of the CPU's time budget to the user program (OB1, OB35, etc.) and only 20% to communications. With a 20% cap, each web request may wait several OB1 cycles before the web-server task gets its slot, which is why a 5-request loop averages 1.6-2.0 s per request. The Communication Load parameter is the single biggest lever on the S7-1200 and is the parameter that takes the cycle from 8-10 s down to 3 s without any code change.
Solution 1: Raise Communication Load on the S7-1200
This is the fastest fix and requires no firmware, hardware, or code changes. It applies to all S7-1200 firmware versions that expose the parameter (V4.0 and later for the full range; V3.0 partially) and to S7-1500 CPUs as well.
Step-by-step
- Open the project in TIA Portal and select the S7-1200 CPU device in the project tree.
- Open Device view and double-click the CPU symbol to open Properties.
- Navigate to Communication Load (sometimes labeled Communication → Communication load in newer TIA Portal versions).
- Change the Cycle load due to communication slider from the default 20% to 50%.
- Download the hardware configuration to the CPU. The new value takes effect on the next STOP→RUN transition or after a warm restart.
Observed results on a representative S7-1214C DC/DC/DC with a typical OB1 of 10 ms and the AWP page containing 12 tags (8 read, 4 write):
| Communication Load | 5-request cycle (HTTPS, with login) | Per-request average |
|---|---|---|
| 20% (default) | 8-10 s | 1.6-2.0 s |
| 35% | 5-6 s | 1.0-1.2 s |
| 50% (recommended max) | ~3 s | ~0.6 s |
Solution 2: Eliminate Per-Request Overhead on the Client
Raising Communication Load is necessary but not sufficient. A second set of optimizations lives in the client code and the web page design itself.
Reuse the session with HTTP keep-alive
Login costs 200-400 ms. If the client opens a new TCP connection for every request, TLS and the login handshake run five times. PHP's cURL handles this natively:
// PHP cURL with session reuse
$ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/plc_cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/plc_cookie.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// 1) Login once
curl_setopt($ch, CURLOPT_URL, 'https://192.168.0.10/FormLogin');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'Login=admin&Password=secret');
curl_exec($ch);
// 2..5) Reuse the same handle for the 4 subsequent requests
for ($i = 0; $i < 4; $i++) {
curl_setopt($ch, CURLOPT_URL, 'https://192.168.0.10/api.io');
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_exec($ch);
}
Python's requests.Session() and Node's https.Agent({ keepAlive: true }) provide the same effect. With keep-alive enabled, the 200-400 ms login cost is paid only once per cycle instead of five times.
Reduce tag count per AWP page
Each :="TagName": on the page triggers a separate process-image read. Splitting 20 tags across two pages and letting the client fetch them in parallel (HTTP/1.1 pipelining or two concurrent cURL handles) roughly halves the render cost. Avoid mixing tags from many different data blocks on the same page; the firmware has to open each DB.
Switch from HTTPS to HTTP for trusted networks
TLS adds 150-300 ms per cold handshake. On an isolated OT segment, disabling HTTPS (TIA Portal: Web server → Activate web server and clear the Permit access only with HTTPS check) drops one handshake per cycle. Combine with HTTP keep-alive and a single login to keep the cycle at 2-3 s without raising Communication Load above 35%.
Solution 3: Migrate to the S7-1500 / ET200SP Native API
If the target is sub-500 ms per call regardless of OB1, the architectural answer is to leave AWP entirely. The S7-1500 CPU family (including the ET200SP, which is functionally an S7-1500-class CPU) exposes a built-in RPC-style web API on top of the standard web server. Requests and responses are JSON, authentication is a single POST, and the firmware does not have to re-render an HTML template — it directly reads or writes the tag by symbolic name.
Typical request
POST /api/jsonrpc HTTP/1.1
Host: 192.168.0.20
Content-Type: application/json
{"method":"PlcProgram.Read","params":{"var":"\"DataBlock_1\".Speed"},"id":1}
Typical response (~50-150 ms body, ~500 ms total over HTTPS)
{"jsonrpc":"2.0","result":1480,"id":1}
Observed benchmarks on an ET200SP CPU 1510SP-1 PN with the API enabled and a 10-tag payload:
| Method | Platform | Auth? | Per-call latency |
|---|---|---|---|
| AWP page (Communication Load 20%) | S7-1200 / S7-1500 | Yes | 1.6-2.0 s |
| AWP page (Communication Load 50%) | S7-1200 / S7-1500 | Yes | ~0.6 s |
| S7-1500 native JSON-RPC API | ET200SP / S7-1500 | Yes | ~0.5 s |
| S7-1500 native JSON-RPC API | ET200SP / S7-1500 | No | ~0.1 s |
The native API is a real solution when the customer's tooling can move to HTTP POST/JSON, but it does not exist on the S7-1200 family — only on S7-1500 and ET200SP CPUs. If the customer cannot change the client code, the S7-1200 with optimized AWP is the practical ceiling.
Detailed S7-1500 vs S7-1200 Comparison for Web Workloads
| Feature | S7-1200 | S7-1500 / ET200SP |
|---|---|---|
| Built-in web server | Yes (HTTPS, AWP) | Yes (HTTPS, AWP) |
| Built-in JSON-RPC / REST API | No | Yes (firmware V2.0+) |
| User-defined web pages (AWP) | Yes | Yes |
| Max communication load | 50% | 50% |
| Concurrent web sessions | Limited (serialized) | Limited (serialized, but more headroom) |
| Typical OB1 with web server | 1-10 ms (small programs) | 1-10 ms (small programs) |
| Native OPC UA server | Optional on higher-end models | Standard on most models |
| Recommended for tight REST loops | No | Yes (use native API, not AWP) |
AWP Page Construction: Minimal Example
For completeness, the AWP page that produced the baseline numbers above looks like this in the project's Webserver → User-defined pages folder:
:= "DataBlock_1".Speed :
:= "DataBlock_1".Temperature :
:= "DataBlock_1".Pressure :
:= "DataBlock_1".Setpoint :
When the firmware receives GET /api.io it substitutes each marker with the live tag value, formatted as plain text. The client can parse line-by-line, wrap in JSON client-side, and POST a body of the same shape to write back. This is the fastest-possible AWP layout — one tag per line, single data block, no conditionals.
Parameter Reference: Communication Load
| Field | Value / range | Default | Effect |
|---|---|---|---|
| Cycle load due to communication | 5% – 50% | 20% | Time slice reserved for the web server / PUT-GET / Open User Comm |
| OB1 time slice impact | Proportional | — | OB1 effective cycle ≈ configured OB1 × (1 / (1 − commLoad)) |
| Watch-dog impact | Indirect | — | If OB1 hits the configured max cycle time, the CPU goes to STOP |
| Live update | No — requires download | — | Configuration change downloads to the CPU and persists |
Alternative Communication Paths If AWP Cannot Meet the SLA
If the customer is locked out of code changes on either side and 3 seconds per cycle is still too slow, the engineering options narrow to protocols that bypass the HTML renderer:
- PUT/GET on the S7-1200 (firmware V4.0+): single tag read/write over the PROFINET interface, typically 20-80 ms per access. Available in TIA Portal under Device configuration → Properties → Communication → PUT/GET communication.
- Open User Communication (ISO-on-TCP, TCP, UDP) with TSEND_C / TRCV_C blocks. Programmable request/response, no web server involvement, deterministic timing.
- OPC UA server on the S7-1500 or S7-1200 (with the OPC UA license activation): standard IT clients (Kepware, Ignition, custom Python/Java) get 50-200 ms per read.
- Modbus TCP server (S7-1500 standard, S7-1200 from firmware V4.0 with the MB_SERVER instruction): classic 50-150 ms reads, well-understood by every SCADA stack.
Each of these options breaks the customer's HTTP/REST assumption and is only viable if the client side can change.
Verification: Proving the Optimization Worked
- Restart the S7-1200 CPU and wait for the web server to be ready (status LED on the CPU, or browse to
https://<CPU-IP>/). - Time a single request from the client with a stopwatch or timestamp:
curl -w "@-> %{time_total}s\n" -o /dev/null -s https://192.168.0.10/api.io. Expect 0.4-0.8 s with Communication Load at 50%. - Time the full 5-request cycle (login + 3 reads/writes + logout) using a single cURL handle with cookie jar. Expect ~3 s.
- Watch the CPU's diagnostic buffer (TIA Portal → Online → Online & Diagnostics → Diagnostic buffer) for OB1 cycle time warnings. If OB1 is approaching the configured max cycle time watch-dog, drop Communication Load to 35%.
- Use the S7-1200's web-based Communication statistics page to confirm the request rate is now what was expected.
Troubleshooting Matrix
| Symptom | Likely cause | Remedy |
|---|---|---|
| 5-request cycle > 15 s | Communication Load still at 20% | Raise to 50%, download HW config |
| First request fast, subsequent slow | Client opens new TCP each time (no keep-alive) | Enable HTTP keep-alive / cURL cookie jar |
| Write not visible on next read | OB1 propagation; reading before OB1 ticked | Shorten OB1, or insert a 1× OB1 delay between write and re-read |
| CPU goes to STOP after raising Comm Load | OB1 watch-dog exceeded | Lower Comm Load to 35%, increase OB1 max cycle time, or move logic out of OB1 |
| Login returns 403/401 intermittently | Session cookie not reused | Use cookie jar / Session object; verify session timeout (default 30 min) |
| 0.5 s per call not reachable on S7-1200 | Platform limit — no native API | Migrate to S7-1500 or ET200SP and use the JSON-RPC API |
| TLS handshake dominates cycle | Cold TLS per request | Disable HTTPS on trusted OT segment, or enable keep-alive |
Official References
- Siemens FAQ 37571372 — How can you improve the performance in STEP 7 (TIA Portal) and in the S7-1200/S7-1500 CPUs? — support.industry.siemens.com/cs/ww/en/view/37571372
- S7-1200 programmable controller — system manual, web server chapter — support.industry.siemens.com/cs/ww/en/view/59192921
- S7-1500 / ET200SP — web server and standard API documentation — support.industry.siemens.com/cs/ww/en/view/59193560
FAQ
Is the S7-1500 web server actually faster than the S7-1200 for the same AWP page?
No, not for AWP pages. AWP performance is constrained by the firmware's single-threaded HTML render path, and a 5-request cycle lands in the same 8-10 s range on both platforms with default settings. The S7-1500 / ET200SP advantage is the built-in JSON-RPC API, which is not available on the S7-1200 and returns ~0.5 s per call instead of the 1.6-2.0 s AWP delivers.
What is the maximum value for Communication Load on an S7-1200?
50%. Raising it further is not permitted by TIA Portal and would risk OB1 starvation. In practice, 50% is the upper limit; 35% is a safer operating point that still drops the 5-request cycle to roughly 5-6 s.
Does enabling HTTPS on the S7-1200 add measurable latency to the web server cycle?
Yes — a cold TLS handshake adds 150-300 ms per new TCP connection. With HTTP keep-alive (one TCP connection, one login) the cost is paid once per cycle instead of five times, recovering roughly 0.5-1.0 s on a 5-request cycle. On an isolated OT network, disabling HTTPS and using HTTP only is a defensible optimization.
Can PUT/GET replace the web server for fast reads on the S7-1200?
Yes. PUT/GET on the S7-1200 (firmware V4.0+) returns single-tag values in 20-80 ms and bypasses the HTML renderer entirely. It is a better fit than AWP for tight REST loops, but it does require the customer to switch from HTTPS GET/POST to a PROFINET-side library (Snap7, libnodave, or a Siemens-commissioned OPC UA server).
Why does my write appear to be missing on the next read of the AWP page?
Because OB1 has not yet propagated the new tag value to the process image when the second read arrives. Either shorten the OB1 cycle time, insert a 1× OB1 sleep in the client between the write and the re-read, or move the tag out of any optimized data block access so it is read directly from the load memory.