S7 Web Server Momentary Push Button: HTML5 AJAX Guide

David Krause13 min read
SiemensTIA PortalTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Building a Momentary HTML Push Button for the S7-1200/1500 Web Server

Standard HTML form submissions cannot deliver a true "press-and-hold" (momentary) behavior on a Siemens SIMATIC S7 CPU web server because every <input type="submit"> triggers a full HTTP POST, page reload, and a single value write that the browser retains until the next submit. This reference shows how to replace the static AWP form with an HTML5 event-driven button that writes 1 on mousedown and 0 on mouseup using JavaScript and XMLHttpRequest (AJAX) against the S7 web server's CGI write interface. The article covers AWP variable declaration, TIA Portal web server configuration, working HTML5/JavaScript code, browser-side debounce, S7-1200 versus S7-1500 firmware differences, and the GOT/PLCSim alternatives that engineers use when the web server is unavailable.

1. Why Standard AWP Forms Cannot Be Momentary

The Siemens S7 web server exposes the Automation Web Programming (AWP) command set for user-defined pages. A typical "Motor ON / Motor OFF" pair uses the following pattern from the SIMATIC S7-1200 Programmable Controller Web Server Function Manual:

<!-- AWP_In_Variable Name='"webdata".Motor_Start' -->
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Motor Start</title>
</head>
<body>
<form method="post" action="">
  <input type="submit" value="Motor ON" class="inputbutton">
  <input type="hidden" name='"webdata".Motor_Start' value="1">
</form>
<form method="post" action="">
  <input type="submit" value="Motor OFF" class="inputbutton">
  <input type="hidden" name='"webdata".Motor_Start' value="0">
</form>
</body>
</html>

Each form posts a single value and reloads the page. The CPU never receives a "release" event because the browser is stateless between submits, and the page that comes back already contains the value just written. This is the architectural constraint that prevents a true momentary control using vanilla HTML forms. A "toggle" attempt with two hidden inputs in the same form is even worse - HTML forms submit all named fields, but the order is undefined and the page only reflects the last parsed assignment.

Design constraint: The S7 web server responds to HTTP POST, not to a persistent socket. A momentary button must therefore issue two separate POSTs (one for 1, one for 0) from client-side JavaScript rather than rely on a single form submission.

2. Prerequisites

Item Requirement
CPU S7-1200 (any) or S7-1500 (any), firmware as listed below
S7-1200 firmware V4.0 or later (AWP user-defined pages supported from V4.0). V4.4+ recommended for TLS and improved HTML handling
S7-1500 firmware V1.8 or later; V2.9+ recommended for full JavaScript / AJAX tolerance
Engineering tool TIA Portal V16 or later (V17/V18 recommended)
Web server Enabled in Device Configuration > Web server; "Enable user-defined web pages" must be checked
Access level The PLC tag used as the button state must permit write access from the web server (tag must be in DB "webdata" or marked accessible from HMI/OPC UA with write permission)
User authorization A user with "Write to PLC" right in the web server user list; the default "admin" account or a custom user with write privilege
Browser Any HTML5-compliant browser (Chrome 90+, Firefox 90+, Edge 90+). Touch devices work via pointerdown / pointerup
Network CPU and browser on same subnet, or routed through VPN; port 80 (HTTP) or 443 (HTTPS) reachable

3. Enabling the Web Server and Declaring AWP Variables

  1. In TIA Portal, open the CPU device configuration and select Web server from the navigation tree.
  2. Check Enable Web server. Check Enable user-defined web pages and enter the HTML application name (for example MotorControl). The HTML source must be placed in the project under CPU > Web application > [name] > htm.
  3. Add a data block named webdata (case-sensitive - the AWP engine references the DB by this name). Inside it declare a static tag of BOOL type named Motor_Start with the default value false.
  4. In the user-defined web page source, declare the variable as an AWP_In_Variable at the very top of the file (this statement must appear before any HTML body content):
    <!-- AWP_In_Variable Name='"webdata".Motor_Start' -->
  5. Compile the project and download hardware and software to the CPU. The web server then becomes available at http://<cpu-ip>/awp/MotorControl/<pagename>.html.
AWP name format: The string passed to Name= must match the symbolic PLC name, including the DB name in double quotes. TIA Portal normally formats the reference as "webdata".Motor_Start. If the AWP declaration is missing, the page loads but the form fields are not bound to the PLC tag.

4. Static Reference: AWP Forms for Latched Control

For applications where a latched start/stop is sufficient, the two-button form posted earlier is the canonical Siemens example and is documented in section 11.3 of the S7-1200 Web Server Function Manual. A variant that toggles a single bit uses a checkbox:

<!-- AWP_In_Variable Name='"webdata".Motor_Start' -->
<form method="post" action="">
  <input type="checkbox" name='"webdata".Motor_Start' value="1"> Start
  <input type="submit" value="Apply">
</form>

When the user checks the box and clicks Apply, the form POSTs "webdata".Motor_Start=1. Unchecking sends =0 after the next Apply. None of these produce press-and-hold semantics - they always require a second user action (clicking Apply) to send the second value.

5. Momentary Control Using HTML5, JavaScript and AJAX

To write 1 while a button is depressed and 0 on release, the page must issue two POSTs without a page reload. The mechanism is straightforward: bind pointerdown (or mousedown) and pointerup (or mouseup) handlers to a <button> element and use the fetch() API or XMLHttpRequest to POST a application/x-www-form-urlencoded body to the current URL with the variable name/value pair. The S7 web server accepts the same body format that an HTML form would produce.

5.1 Complete Working HTML5 Page

<!-- AWP_In_Variable Name='"webdata".Motor_Start' -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Motor Start (Momentary)</title>
<style>
  body { font-family: Segoe UI, sans-serif; background: #1e1e1e; color: #eee; }
  .pb { width: 160px; height: 80px; font-size: 18px;
        background: #444; color: #fff; border: 2px solid #888;
        border-radius: 8px; user-select: none; cursor: pointer; }
  .pb.pressed { background: #c33; border-color: #f55; }
  .status { margin-top: 16px; font-size: 14px; }
</style>
</head>
<body>
  <h2>Motor Start - Press and Hold</h2>
  <button id="pb" class="pb" type="button">MOTOR</button>
  <div class="status" id="status">Tag: ?</div>

  <script>
    const TAG = '"webdata".Motor_Start';
    const URL = window.location.href.split('?')[0]; // strip any query string
    const pb   = document.getElementById('pb');
    const stat = document.getElementById('status');

    function writeTag(val) {
      // Use sendBeacon on release so the request is sent even if the page
      // is being closed; use fetch on press for full control.
      const body = encodeURIComponent(TAG) + '=' + val;
      if (val === '0' && navigator.sendBeacon) {
        navigator.sendBeacon(URL, new Blob([body],
          {type: 'application/x-www-form-urlencoded'}));
      } else {
        fetch(URL, {
          method: 'POST',
          headers: {'Content-Type': 'application/x-www-form-urlencoded'},
          body: body,
          credentials: 'include'
        }).then(r => {
          stat.textContent = 'Tag write HTTP ' + r.status;
        }).catch(err => {
          stat.textContent = 'Error: ' + err;
        });
      }
    }

    pb.addEventListener('pointerdown',  e => { e.preventDefault();
                                              pb.classList.add('pressed');
                                              writeTag('1'); });
    pb.addEventListener('pointerup',    e => { e.preventDefault();
                                              pb.classList.remove('pressed');
                                              writeTag('0'); });
    pb.addEventListener('pointercancel',    () => {
                                              pb.classList.remove('pressed');
                                              writeTag('0'); });
    pb.addEventListener('pointerleave',     () => {
                                              pb.classList.remove('pressed');
                                              writeTag('0'); });
    // Keyboard support: SPACE while focused = momentary
    pb.addEventListener('keydown', e => {
      if ((e.key === ' ' || e.code === 'Space') && !e.repeat) {
        pb.classList.add('pressed'); writeTag('1');
      }
    });
    pb.addEventListener('keyup', e => {
      if (e.key === ' ' || e.code === 'Space') {
        pb.classList.remove('pressed'); writeTag('0');
      }
    });
  </script>
</body>
</html>

5.2 Why This Works

  • The pointerdown/pointerup events cover mouse, touch, and pen input uniformly. mousedown/mouseup are acceptable for desktop-only deployments.
  • The POST body uses the same name=value encoding as a real HTML form, so the S7 web server's AWP handler binds the value to the declared webdata.Motor_Start tag.
  • Using the same URL as the page (no separate endpoint) means the page re-renders after the POST, which is the natural AWP behavior; on pointerup the page is replaced and the user can press again.
  • navigator.sendBeacon on release ensures the final 0 write is delivered even if the user is closing the tab or the connection is slow.
  • Including credentials: 'include' makes the browser send the basic-auth cookies of the web server session, which is required for the write to be authorized.

6. S7-1200 vs S7-1500: JavaScript Tolerance Differences

Feature S7-1200 (FW 4.x) S7-1500 (FW 1.8+)
User-defined web pages Yes (from V4.0) Yes
AWP_In_Variable write Yes via form POST Yes
HTML5 / JS / AJAX scripts referenced in page Limited - the S7-1200 only serves the page; JavaScript runs in the browser, not in the CPU. AJAX requests to the same page work, but the S7-1200 web server can be slow to answer a second POST if the first is still being processed. Fully supported - S7-1500 web server (FW 2.0+) answers concurrent POSTs from AJAX more reliably and has higher connection limits
TLS / HTTPS Available V4.4+ Available all firmware
Concurrent HTTP connections ~4 ~8 (FW 2.9: 16+)
Recommended for momentary button Acceptable, expect ~150-300 ms round-trip per write Preferred; round-trip typically <80 ms on LAN
JavaScript itself runs in the browser, never in the CPU. Both S7-1200 and S7-1500 are equal in that respect. The performance difference comes from how quickly the CPU's web server answers a second POST while still serving the same page.

7. PLC-Side Handling of the Momentary Tag

The web server writes the tag in DB webdata exactly as an HMI would. In the OB1 or a cyclic OB, your application logic should treat the rising edge of webdata.Motor_Start as the start command and the falling edge as the stop command, the same way you would treat a physical push button wired to a digital input. A safe pattern is:

// SCL (TIA Portal) - momentary start/stop with edge detection
IF "webdata".Motor_Start" THEN        // tag is 1 while button is held
    "Motor".StartCmd := TRUE;
ELSE
    "Motor".StartCmd := FALSE;
END_IF;

// Optional: heartbeat watchdog - clear StartCmd if webdata is stuck at 1
// for more than e.g. 5 seconds (operator may have walked away)
"webdata".Motor_Start_Watchdog(IN := "webdata".Motor_Start",
                                PT := T#5s);
IF "webdata".Motor_Start_Watchdog.Q THEN
    "Motor".StartCmd := FALSE;
END_IF;

For a jog-style output (drive runs only while button is held), wire the tag directly to the drive enable input and add a hardware/software interlock in the safety circuit. The web page must not bypass the safety chain.

8. Security Considerations

  • Enable HTTPS and disable HTTP in the web server configuration. The S7-1200 supports self-signed certificates; load a CA-signed certificate on production systems to suppress browser warnings.
  • Create a dedicated web user with the minimum required right (write to webdata only). Do not reuse the PLC's "admin" account.
  • Add IP-based access restrictions in the CPU's firewall (S7-1500) or in the network infrastructure. See the SIMATIC Security Concept.
  • Add CSRF mitigation: the AWP POST is authenticated by the basic-auth cookie, which is sent automatically. For higher assurance, include a per-session token in a hidden field and validate it in the PLC.
  • Confirm the operator's expectation: a momentary web button that controls a hazardous actuator is generally not acceptable under functional-safety standards. For SIL-rated controls, use a hardwired E-stop and a safety PLC.

9. Verification and Test Procedure

  1. Open the user-defined page in a browser, e.g. http://<cpu-ip>/awp/MotorControl/motor.html. Log in with a user that has write rights.
  2. Open the TIA Portal online watch table for DB webdata and observe the Motor_Start tag.
  3. Click and hold the button. The tag should change to TRUE within ~100 ms on an S7-1500 (LAN) and ~250 ms on an S7-1200. The button CSS class should change to .pressed for visual feedback.
  4. Release the button. The tag must drop to FALSE. The page may visibly refresh, but the release POST should be sent via sendBeacon immediately before navigation.
  5. Run a network capture (Wireshark) on the CPU port to confirm exactly two POSTs per click: one with body "webdata".Motor_Start=1 and one with =0.
  6. Test on a touch device. Tap and hold; release. The pointer* events handle touch identically to mouse.
  7. Test keyboard operation: TAB to focus the button, then hold SPACE. The tag should toggle 1/0 with the key state.
  8. Stress test: rapid click sequence (10 presses in 2 seconds). The CPU should not drop a release POST; if it does, increase the S7-1500 maximum web connections in the device configuration or move to a dedicated HMI panel.

10. Troubleshooting Matrix

Symptom Likely Cause Corrective Action
Tag never goes to 1 when button pressed AWP_In_Variable declaration missing or tag name typo Verify the <!-- AWP_In_Variable ... --> is the first line of the page and that the name exactly matches the symbolic PLC name
Tag sticks at 1 after release Release POST never sent (page navigation interrupts fetch) Use navigator.sendBeacon for the release write, as in the sample above
HTTP 401 on every POST User lacks write rights, or session cookie not sent Confirm the user has "Write to PLC" in the web server user list; add credentials: 'include' in fetch options
HTTP 403 / 302 to login CSRF or session timeout Re-login; for production, extend session in web server config or implement a token
No visible response in browser Browser blocks mixed content (HTTPS page calling HTTP POST or vice versa) Use a single protocol end-to-end
Tag toggles randomly Multiple event handlers bound; pointerdown fires twice on touch Call e.preventDefault() in handlers; ensure handlers are bound only once
S7-1200 extremely slow to respond CPU under heavy load or too many simultaneous connections Reduce polling; use S7-1500 for high-frequency control
Touch device never sees pointerup Finger drifts off button; pointerleave never fires Add pointercancel handler and a global document.pointerup that always writes 0

11. Alternative Platforms and When to Use Them

The S7 web server is appropriate for low-frequency, local operator panels and for prototypes. For real production HMI, Siemens recommends either a SIMATIC HMI Panel (Unified Comfort or Basic) programmed in TIA Portal with WinCC, or a SCADA system such as WinCC Professional / WinCC OA. Both deliver robust, deterministic momentary controls without requiring the user to write JavaScript. A custom HTML page should be used only when:

  • The CPU is the only device available (no panel budget).
  • The control is non-safety and rate-limited (operator acknowledgements, slow jogging).
  • The deployment is a local maintenance interface, not a primary operator panel.

For development without a physical CPU, use S7-PLCSIM (V16+) which emulates the web server and accepts the same AJAX POSTs, allowing the entire HTML5 page to be tested in a browser before hardware is available.

12. Reference: AWP Commands Used in This Page

Command Syntax Purpose
AWP_In_Variable <!-- AWP_In_Variable Name='"db".tag' --> Declare a variable whose value can be written from the web page via HTTP POST
AWP_Out_Variable <!-- AWP_Out_Variable Name='"db".tag' --> Declare a variable that can be read into the page (substituted into the HTML)
AWP_Enum_Def <!-- AWP_Enum_Def Name="State" Values="0:OFF,1:ON" --> Map integer values to display strings for combo boxes
AWP_Start_Form / AWP_End_Form HTML form block Mark the form whose fields are bound to the declared variables

Complete reference: SIMATIC S7-1200 Programmable Controller - Web Server Function Manual (entry ID 59192925) and S7-1500 Web Server Function Manual (entry ID 59193592).

Can the S7-1200 web server run JavaScript?

JavaScript always runs in the browser, never inside the S7-1200. The CPU only serves the HTML file and answers POSTs. The S7-1200 supports HTML5 pages with AJAX, but it is slower than the S7-1500 and limits concurrent connections to about 4, so for high-frequency momentary control prefer the S7-1500.

Why does the tag stay at 1 after I release the button?

The release POST is lost because the browser begins navigating to the new page (returned by the press POST) and cancels the pending fetch. Use navigator.sendBeacon for the release write, or use two distinct page endpoints so the press and release POSTs do not collide with a navigation.

What HTTP status does the S7 web server return for a successful tag write?

A successful write returns HTTP 200 and the rendered page. A failed authentication returns 401, a missing or wrong tag returns 404, and an AWP parse error returns 500. Watch the network tab in the browser to confirm a 200 on every press and release.

Do I need a specific firmware version for AJAX support?

No firmware requirement is unique to AJAX because the S7 web server has always accepted standard application/x-www-form-urlencoded POSTs. However, S7-1200 firmware V4.4 and S7-1500 firmware V2.9 add connection-handling and TLS improvements that improve reliability of high-frequency AJAX calls.

Can I bind the same momentary button to a safety function?

No. The S7 web server is not a safety-rated interface, has no deterministic response time, and is exposed to the same IT attack surface as any other web service. SIL-rated emergency stop and enable controls must remain hardwired to a safety input module (F-CPU) and a certified E-stop device.

Back to blog