Overview
End-of-cycle report printing on a Siemens Unified Comfort Panel such as the MTP700 running WinCC Unified V18 requires bridging three subsystems: the WinCC Unified report engine, the on-device CUPS (Common UNIX Printing System) spool, and the panel's JavaScript runtime that orchestrates the workflow. The WinCC Unified JavaScript object model does not expose a CUPS binding, so the print submission has to be delegated to the standard lp command (or a headless LibreOffice invocation) launched through the StartProgram runtime method. This reference documents a field-proven configuration: trigger the report at cycle end, locate the timestamped PDF on the local file system, push it to a pre-provisioned CUPS queue, and raise a WinCC alarm if the job never reaches the printer.
Cups() wrapper or call cups.printFile() from a Unified script will fail at parse time. Treat the lp binary as the only supported bridge to the print spool.Prerequisites
| Item | Specification | Notes |
|---|---|---|
| HMI hardware | SIMATIC MTP700 (Unified Comfort) | 6AV2 128-3GB06-0AX0 or equivalent 7" generation |
| HMI firmware / runtime | WinCC Unified V18 (TIA Portal V18) | Runtime version must match engineering build |
| PLC | SIMATIC S7-1200 (CPU 1214C / 1215C / 1217C) | Any firmware V4.x that pairs with TIA V18 |
| Printer | Brother HLL8260CDW (or HLL5100DN) – factory-provisioned on the Unified image | Custom drivers are not installable on the panel; pick a model from the Siemens-approved peripheral list |
| Spooler | CUPS pre-installed on the Unified Linux base | Visible in the HMI Control Panel → Printers |
| Office pipeline | LibreOffice headless on the HMI image (optional path) | Required only if the report is generated as .xlsx / .ods
|
| Network | Printer reachable on the panel's plant network (static IP recommended) | DHCP leases that change break the CUPS queue |
Confirm TIA Portal V18 and the Unified runtime update are both on the same service pack. Mixing, for example, TIA V18 Update 2 with runtime V18 GA has been observed to break the StartProgram permission profile.
CUPS Architecture and Queue Provisioning
CUPS on the Unified Comfort Panel behaves exactly like a Linux desktop install: a local daemon (cupsd) listens on the loopback socket, queues are defined in /etc/cups/printers.conf, and jobs are submitted through the lp / lpr binaries. The crucial difference is that the panel image ships with a whitelist of printer models. Adding an arbitrary driver is not supported; the printer must appear in the HMI's Control Panel → Printers → Add dialog. The Brother HLL8260CDW and HLL5100DN are two of the pre-validated models and are reliable choices for production cells.
Once a printer is added, capture the exact queue name – CUPS is case-sensitive and the queue name embedded in scripts must match byte-for-byte. The fastest way to confirm the queue name from the HMI desktop is:
- Open Control Panel → Printers.
- Right-click the Brother device and select Properties.
- Copy the Queue Name field (for example
HLL8260CDWorHLL5100DN). - Validate by running
lpstat -p -dfrom a shell; the queue should appear in the output.
For more details on the lp command options, refer to the CUPS lp man page and the CUPS documentation set.
Triggering Report Generation at Cycle End
Reports in WinCC Unified are template-driven objects that render to .pdf (and optionally .xlsx) on a schedule or on demand. For a deterministic cycle-end trigger, configure the report with the Event-based output mode and bind a PLC tag (for example "DB_Cycle.CycleDone") as the trigger bit. The Siemens Industry Online Support portal hosts the TIA Portal V18 help package, which documents the report configuration tree under Reports → Output → Trigger.
Configure the report's storage path on the panel's local file system – for example:
/media/simatic/report_archive/
The default naming pattern appends a timestamp. A typical filename rendered at the end of cycle 4729 is:
Report_CycleSummary_20240118_143207_4729.pdf
Note the underscore separators – they are what the JavaScript parser relies on to extract the cycle number and the wall-clock time.
Resolving the Timestamped PDF Path
The JSOM exposes the local file system through HMIRuntime.FileSystem. Use readdir against the report directory, sort by modified descending, and pick the most recent PDF. A robust pattern that handles the race between report write and read is to wait until the file size is stable across two consecutive samples (an unlocked PDF is still growing during the render phase).
// Locate the newest PDF in the report directory
const dir = "/media/simatic/report_archive";
const items = HMIRuntime.FileSystem.readdir(dir);
let newest = null;
let newestMtime = 0;
for (const f of items) {
if (!f.toLowerCase().endsWith(".pdf")) continue;
const full = `${dir}/${f}`;
const st = HMIRuntime.FileSystem.stat(full);
if (st.mtimeMs > newestMtime) {
newestMtime = st.mtimeMs;
newest = full;
}
}
if (!newest) {
HMIRuntime.Tags.SysFct.SetTagValue("Print_Alarm", true);
HMIRuntime.Trace("Report lookup failed: no PDF in " + dir);
return;
}
For deterministic lookup (useful when the report name includes the cycle number passed from the PLC), parse the filename and match on a regex:
const cycle = HMIRuntime.Tags.SysFct.GetTagValue("DB_Cycle.CurrentCycle");
const re = new RegExp(`CycleSummary_.*_${cycle}\.pdf$`);
const match = items.find(f => re.test(f));
Invoking lp via StartProgram
StartProgram is the only public JSOM entry point that can spawn a child process from a Unified runtime script. The signature is:
HMIRuntime.StartProgram(
program: string, // absolute path or command in PATH
args: string, // single command-line string
mode: number, // 0 = wait for completion, 1 = detached
timeout: number // ms; 0 = no timeout
);
The job-blocking mode (mode = 0) returns a numeric status that maps to the lp exit code. CUPS returns 0 on a successful enqueue and a non-zero value if the queue is paused, the printer is offline, or the file is unreadable. Capture that return code and route it to a tag that the alarm logic will read.
// Submit the PDF to the CUPS queue
const printer = "HLL8260CDW"; // MUST match the CUPS queue name
const title = `Cycle_${cycle}_Report`;
const cmd = `/usr/bin/lp`;
const args = `-d ${printer} -t "${title}" -n 1 "${newest}"`;
let rc;
try {
rc = HMIRuntime.StartProgram(cmd, args, 0, 15000);
} catch (e) {
HMIRuntime.Trace("StartProgram threw: " + e);
rc = -1;
}
HMIRuntime.Tags.SysFct.SetTagValue("Print_RC", rc);
if (rc !== 0) {
HMIRuntime.Tags.SysFct.SetTagValue("Print_Alarm", true);
HMIRuntime.Trace(`lp failed rc=${rc} file=${newest}`);
}
Relevant lp options to consider:
| Option | Meaning | When to use |
|---|---|---|
-d <queue> |
Destination queue | Always required; value is the CUPS queue name |
-n <count> |
Number of copies | Production reports are usually 1; shop-floor travelers may need 2–3 |
-t <title> |
Job title shown in the queue | Embed cycle ID for traceability |
-o sides=two-sided-long-edge |
Duplex | Required for ISO 9001 traveler documents |
-o media=A4 |
Force paper size | Prevents tray-fallback surprises |
-o job-priority=100 |
Priority (1–100) | Bump alarm reports above routine logs |
Alternative Path: LibreOffice Headless Print
When the report template is bound to an Excel-style layout (multi-sheet .xlsx) and the destination printer's driver does not consume the raw file well, route the document through soffice in headless mode. The command line is:
soffice --headless --norestore --nologo \
--convert-to pdf:"calc_pdf_Export" \
--outdir /tmp /media/simatic/report_archive/Report.xlsx
Then submit the intermediate PDF to lp as shown above. The whole pipeline can be wrapped in a single shell script invoked from StartProgram:
/usr/bin/sh /home/admin/scripts/print_report.sh "${newest}" "${printer}"
Headless soffice does not display the LibreOffice splash on the HMI screen, which is essential for an operator-facing panel. It does, however, hold a license lockfile at ~/.config/libreoffice; if two reports fire in the same second the second invocation will block. Add a 250 ms sleep between calls or queue them through a single at job.
Alarm Handling for Print Failures
Three independent failure modes must surface as discrete alarms so that maintenance can route to the right discipline (network, mechanical, or software):
| Failure | Detection | Alarm tag | Recommended priority |
|---|---|---|---|
| Report file not found |
readdir returned no PDF within 30 s of trigger |
Alarm_Print_NoFile |
Warning |
| CUPS enqueue rejected |
lp returned non-zero exit code |
Alarm_Print_Queue |
Warning |
| Job stuck in queue | Queue depth > 0 with no progress for > 60 s (lpstat -o cross-check) |
Alarm_Print_Stuck |
Error |
| Printer hardware fault (paper, toner, offline) | CUPS printer-state-reasons flag |
Alarm_Print_Hardware |
Error |
A polled watchdog tag named Print_Heartbeat should be set to true on every successful print and auto-cleared by an external timer after 120 s. If a follow-up print never toggles the heartbeat, an Inactive alarm fires, which catches the silent case where the report job completes but the operator never sees the printed sheet.
For an additional layer of robustness, schedule a cron-driven shell job on the panel that runs lpstat -p HLL8260CDW -o every 30 seconds, parses the state, and writes the result back to a WinCC tag via the SIMATIC Runtime ODK interface – this is a heavier integration and is only justified on high-reliability lines.
Verification Procedure
-
Static check: from the HMI desktop, run
lpstat -p -d. The Brother queue should be listed as idle and marked as the default destination. -
Manual smoke test: open a terminal and execute
lp -d HLL8260CDW /media/simatic/report_archive/<any>.pdf. The printer must produce one page within five seconds. -
Script-level test: trigger the report from the HMI's Report control manually and confirm the job title appears in
lpq. -
Alarm test: power-cycle the printer, retrigger a report, and confirm
Alarm_Print_Queueraises within the script timeout (15 s). -
End-to-end test: run a full S7-1200 cycle, verify the PDF appears in the archive directory, the printer emits a sheet, and the
Print_Heartbeattag toggles totruein TIA's online tag view. -
Long-run soak: repeat step 5 for 100 consecutive cycles. Inspect CUPS
access_logfor repeated printer-error entries that would indicate an intermittent queue or driver issue.
Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic | Corrective action |
|---|---|---|---|
| Script never fires | Event-bound report trigger bit never sets | Watch DB_Cycle.CycleDone in TIA online |
Verify the PLC code raises the bit for at least one scan after the cycle ends |
StartProgram throws permission error |
Unified runtime user lacks lp exec rights |
Check audit.log for denied execve
|
Re-image the panel with the Siemens "Print Server" option enabled in ProSave |
| Job sits in queue, never prints | Printer offline or IP changed | lpstat -p HLL8260CDW -l |
Assign a static IP on the printer and re-ping from the panel |
| PDF prints as blank pages | File was still being written when lp opened it |
Compare file size between two polls 2 s apart | Add the size-stability guard shown in the Resolving the Timestamped PDF Path section |
| Garbled characters in printed text | Embedded font missing on the HMI image | Open the PDF in the on-device viewer | Switch the report template to a font that ships with the panel (Liberation Sans, DejaVu Sans) |
| Alarms raise but no actual failure | False positive from StartProgram timeout on a slow first print |
Compare Print_RC tag value to lp exit codes |
Increase the StartProgram timeout to 30 000 ms for the first job after a long idle |
| Only the first cycle of the shift prints | CUPS queue paused after a recoverable error and never resumed |
cupsenable HLL8260CDW output |
Add cupsenable to a startup script or invoke it from the alarm-clear handler |
Limitations and Field Notes
-
No direct CUPS binding. The Unified JavaScript object model exposes neither the CUPS spooler nor the
lpbinary. All print submissions must go throughStartProgramand rely on the operating system's PATH resolution. - Whitelisted printers only. Custom PPDs and third-party drivers cannot be added to a Unified Comfort Panel. Pick a printer from the Siemens-approved peripheral list; the Brother HLL8260CDW and HLL5100DN are confirmed to work in production.
- Filename parsing brittleness. The default timestamp format includes a seconds field. If your cycle time is shorter than one second (rare on a discrete line but possible in test rigs), consider switching the report to millisecond precision and updating the regex accordingly.
-
Locale on the HMI.
lpwill print date and number formats using the panel's locale. A European panel printing English reports will invert commas and dots on number fields. Set the report template to a fixed-culture format string before relying on printed numeric values. -
Security.
StartProgramruns with the Unified runtime user's privileges. Do not pass untrusted cycle IDs or filenames into theargsstring without sanitization – a malformed cycle tag containing a shell metacharacter will be executed. Use a strict regex whitelist on the cycle number and the filename before composingargs. -
Audit trail. The
access_logunder/var/log/cups/is the canonical record of every job. Mirror it to a network share for compliance with FDA 21 CFR Part 11 or similar regulated environments.
FAQ
Does WinCC Unified V18 expose a CUPS object in the JavaScript API?
No. The JSOM does not include a CUPS class, and there is no public roadmap item to add one. The supported bridge is the HMIRuntime.StartProgram method calling the lp binary directly.
Which printers are validated for use with an MTP700 Unified Comfort Panel?
Only models that appear in the HMI's Control Panel → Printers → Add dialog can be added, because custom drivers cannot be installed. The Brother HLL8260CDW and HLL5100DN are field-validated monochrome/color laser options that print correctly via CUPS out of the box.
How do I select the most recent timestamped PDF after a report runs?
Use HMIRuntime.FileSystem.readdir on the report directory, filter for .pdf, and pick the entry with the highest mtime. For deterministic matching when the cycle number is known, parse the filename with a regex like CycleSummary_.*_<cycle>\.pdf$. Always confirm the file size is stable across two polls to avoid reading a half-rendered PDF.
Why does my lp call return non-zero even though the page eventually prints?
The most common cause is an insufficient StartProgram timeout. The first job after a long idle triggers a CUPS warm-up that can exceed 15 s. Increase the timeout argument to 30 000 ms, or split the call into an enqueue (fast) and a watchdog that polls lpstat separately.
Can I print an Excel-style report directly without converting to PDF first?
Yes – use LibreOffice in headless mode: soffice --headless --convert-to pdf:"calc_pdf_Export" --outdir /tmp <xlsx>, then submit the resulting PDF to lp. Wrap both steps in a shell script invoked from StartProgram to keep the script body short and to avoid the LibreOffice single-instance lockfile.