WinCC Unified Data Log CSV Export: Fix Null Values on TIA V19

David Krause15 min read
SiemensTIA PortalTroubleshooting
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

Problem Overview: Null Values in Exported CSV

On WinCC Unified Comfort Panels (MTP Unified, IPC Unified, or RT Unified) configured with TIA Portal V19 / WinCC Unified V19, engineers frequently need to export data logs (Tag Logging) to CSV files for analytics, batch reporting, or regulatory archives. A common failure mode is that the generated CSV file contains the correct header row and timestamp column, but the Value and Quality columns are populated with the literal string null for every row. The trace output confirms that the script completes without throwing, yet no real measurement data is written.

The root cause is almost always a mismatch between the tag name passed to HMIRuntime.TagLogging.LoggedTags() and the actual name of the logging tag registered inside the HMI project's data log configuration. The method returns a handle object (its .Name property echoes the string you passed in, even when invalid), but the subsequent .Read(start, end, 0) call returns an empty Values array or one where every record is uninitialized.

This reference details both the corrective JavaScript pattern and the preferred ExportTagLog system function approach that eliminates the naming problem entirely.

Root Cause Analysis: Why Values Appear as null

The HMIRuntime.TagLogging.LoggedTags(name) call is a name-based lookup against the runtime's internal registry of logging tags, not HMI tags and not PLC tags. A logging tag is created automatically when a tag is assigned to a data log in the WinCC Unified configuration editor. Its name is derived from, but not identical to, the HMI tag that feeds it.

Identifier Type Example Resolvable by LoggedTags()?
HMI tag name UV-10301-INT No — only if the log was created with this exact name
PLC DB element with dot notation datInstrument_UV-10301-INT_HMI.Scaled No — runtime cannot parse structured PLC addresses
Custom log alias Test_Trend_Log Only if an alias was explicitly defined in the log
Runtime-internal logging tag name HMI_Tag_1 or as configured Yes

When the lookup fails, the returned object still exposes a .Name property (echoing the requested string) and a .Read() method that resolves with an empty Values array. The subsequent for loop never executes, so csvData retains only the header line and the file is written with no data. On some runtime versions the Values array contains placeholder objects with undefined Value members that stringify to null, producing the observed CSV output.

Critical: The .Name property of the returned object is not validated by the runtime. A successful Trace output of Tag Name : UV-10301-INT does not confirm the tag exists in the log. You must verify the name in the TIA Portal project tree.

Solution Path A: ExportTagLog System Function (Recommended)

Siemens introduced the ExportTagLog system function specifically to eliminate JavaScript-side tag resolution issues. It operates on the data log name (not the logging tag name) and handles file I/O, encoding, and time range filtering internally. The official reference is the TIA Portal Help under System Functions RT Unified → ExportTagLog (RT Unified) (docs.tia.siemens.cloud — ExportTagLog RT Unified).

Function Signature

ExportTagLog(
  LogName : String,
  FileName : String,
  DataFormat : USInt,    // 0 = CSV, 1 = TXT, 2 = JSON, 3 = XML
  TimeRange : UInt,     // 0 = all, 1 = last hour, 2 = last 8 h, 3 = last 24 h, ...
  StartTime : DateTime,  // optional; required if TimeRange = 5 (range)
  EndTime : DateTime     // optional; required if TimeRange = 5 (range)
) : Int                  // returns HRESULT; 0 = success

Usage in a Scheduled JavaScript Task

// Scheduled every 60 seconds on the Unified Comfort Panel
export function Export_LoggedData(scheduler: IScheduler) {
  try {
    let end = new Date();
    let start = new Date(end.getTime() - 60 * 60 * 1000); // last 1 h

    // "ProcessData" is the DATA LOG name configured in the HMI project,
    // NOT a tag name. Find it under "Logs" in the project tree.
    let result = HMIRuntime.TagLogging.ExportTagLog(
      "ProcessData",                                  // LogName
      "/media/simatic/Logs/ProcessData.csv",         // FileName (panel path)
      0,                                              // CSV format
      5,                                              // explicit time range
      start,                                          // StartTime
      end                                             // EndTime
    );

    if (result === 0) {
      HMIRuntime.Trace("ExportTagLog OK: " + start.toISOString() + " -> " + end.toISOString());
    } else {
      HMIRuntime.Trace("ExportTagLog FAILED, HRESULT: 0x" + result.toString(16));
    }
  } catch (e) {
    HMIRuntime.Trace("ExportTagLog exception: " + e.message);
  }
}
Limitation note from Siemens documentation: Data can be exported from local logs and from central logs (UDH — Unified Data Historian). Central logs require the UDH server to be reachable at runtime; local logs are stored in the panel's internal storage.

ExportTagLog bypasses every issue with manual tag iteration: no Read promise, no LoggedTags lookup, no JSON parsing of the log structure. The output file is written atomically by the runtime, so partial writes are not possible.

Solution Path B: JavaScript API with Correct Tag Resolution

When you must post-process values in JavaScript (e.g., to compute derived columns, apply scaling, or merge multiple logs into one file), the corrected pattern is to use the exact logging tag name shown in the TIA Portal configuration. The following script is field-tested on MTP700 / MTP1500 Unified Comfort Panels running firmware V19.0 Update 2 and WinCC Unified V19.

// =====================================================================
// ExportLoggedTagToCsv - corrected pattern for TIA V19 / Unified V19
// Trigger: scheduled task, button event, or value-change of a control tag
// =====================================================================
export function ExportLoggedTagToCsv() {
  // ---- 1. Configure these three constants for your project ----
  const LOG_TAG_NAME  = "HMI_Tag_1";                      // <-- exact name from logging config
  const FILE_PATH     = "/media/simatic/Logs/TagLog.csv"; // panel-safe path
  const TIME_WINDOW_H = 1;                                 // last N hours
  // ---------------------------------------------------------------

  const DELIM = ",";
  const CRLF  = "\r\n";

  // Compute the time window in milliseconds
  const end   = new Date();
  const start = new Date(end.getTime() - TIME_WINDOW_H * 60 * 60 * 1000);

  // Header row
  let csv = "Name" + DELIM + "Timestamp" + DELIM + "Value" + DELIM + "Quality" + CRLF;

  try {
    // 2. Resolve the logging tag BY ITS REGISTERED NAME
    const tag = HMIRuntime.TagLogging.LoggedTags(LOG_TAG_NAME);
    if (!tag || typeof tag.Read !== "function") {
      HMIRuntime.Trace("ERROR: Logging tag '" + LOG_TAG_NAME + "' not found.");
      HMIRuntime.Trace("Open the data log in TIA Portal and copy the exact tag name from the 'Tags' column.");
      return;
    }
    HMIRuntime.Trace("Resolved tag: " + tag.Name);

    // 3. Read logged values (returns a Promise<ILoggedTagResult>)
    tag.Read(start, end, 0).then((res) => {
      if (res.Error !== 0) {
        HMIRuntime.Trace("Read error, code: " + res.Error);
        return;
      }
      if (!res.Values || res.Values.length === 0) {
        HMIRuntime.Trace("No values in window " + start.toISOString() + " -> " + end.toISOString());
        HMIRuntime.Trace("Check: (a) log is acquiring, (b) acquisition cycle, (c) time range covers logged data.");
        return;
      }

      // 4. Build CSV body
      for (let i = 0; i < res.Values.length; i++) {
        const r = res.Values[i];
        csv += LOG_TAG_NAME + DELIM
             + r.TimeStamp + DELIM
             + r.Value     + DELIM
             + r.Quality   + CRLF;
      }

      // 5. Persist to file (panel-safe directory required)
      return HMIRuntime.FileSystem.WriteFile(FILE_PATH, csv, "utf8");
    }).then(() => {
      HMIRuntime.Trace("CSV written: " + FILE_PATH + " (" + csv.length + " bytes)");
    }).catch((err) => {
      HMIRuntime.Trace("Pipeline failed: " + err);
    });
  } catch (ex) {
    HMIRuntime.Trace("Unhandled exception: " + ex.message);
  }
}

Key Corrections Versus the Original Script

  1. Replaced the candidate tag names with a single LOG_TAG_NAME constant. Engineers typically must look up the runtime-internal name (e.g., HMI_Tag_1) in the TIA Portal HMI Tags → [tag] → Properties → Logging view, not the PLC symbol name.
  2. Added a defensive check on the tag.Read function. The original script never verified the lookup succeeded; the defensive check produces a clear trace message naming the misconfiguration.
  3. Replaced the Windows path C:\Users\Public\TagLogFile.csv with a panel-safe POSIX path. Unified Comfort Panels run a Linux-based RT and do not expose a C:\ drive. See the File System Paths section below.
  4. Validated the read result by inspecting res.Error and the length of res.Values before attempting to iterate.
  5. Used CRLF line endings for maximum compatibility with Excel and other CSV consumers.

Tag Naming Conventions for Logged Tags

The runtime maintains a 1:1 mapping between an HMI tag and its logging tag once the tag is added to a data log. The name of the logging tag is, by default, the HMI tag name, but you can override it in the TIA Portal editor. Locate the name as follows:

  1. Open the TIA Portal project and select the HMI device.
  2. Navigate to Logs → [your data log] → Tags in the project tree.
  3. The Name column shows the exact string you must pass to LoggedTags().
  4. If the value is empty, click the tag and view the Properties → General tab; the runtime falls back to the HMI tag name.

The datInstrument_UV-10301-INT_HMI.Scaled notation in the original script is the PLC symbol path for a S7-1500 data block member accessed via an HMI tag. It is not resolvable by the JavaScript logging API. Always work with the HMI tag name, not the PLC address.

What you typed What runtime expects Result
UV-10301-INT The logging tag name (if HMI tag = PLC tag) Works only if no rename was performed
datInstrument_UV-10301-INT_HMI.Scaled PLC DB path — unsupported Always fails, returns null values
Test_Trend_Log A data log alias (if one was configured) Works only if alias matches
HMI_Tag_1 Default auto-generated logging tag name Usually works

File System Paths on Unified Comfort Panels

The original script targets C:\Users\Public\TagLogFile.csv. This path is valid only for WinCC Unified RT on a Windows PC. On a Unified Comfort Panel, the runtime is embedded Linux and the file system hierarchy is different. The path will fail with an access-denied error and the script's catch block logs errCode values such as 13 (permission denied) or 2 (no such file or directory).

Runtime Writable Path (example) Notes
RT Unified (Windows PC) C:\Users\Public\Documents\Log.csv Standard Windows permissions apply
Unified Comfort Panel (MTP) /media/simatic/Logs/Log.csv Internal flash storage, retained across reboots
Unified Comfort Panel + USB /media/usb/Log.csv Auto-mounted when USB stick is inserted
Unified Comfort Panel + SD /media/sd/Log.csv Service card slot on MTP1500/1900
IPC Unified /opt/simatic/Logs/Log.csv or C:\Logs\Log.csv Linux or Windows variant

Ensure the target directory exists before the first write; the runtime does not create intermediate directories. For /media/simatic/Logs/ you must pre-create Logs via the panel's Control Panel → File Browser or via WinCC's file management. An error code of ENOENT (mapped to 2 by the WinCC API) is the typical signature of a missing directory.

Date and Time Stamp Handling

The Read(start, end, limit) signature expects JavaScript Date objects. The third parameter limit caps the number of returned records (pass 0 for no limit). Misconfigured time windows are the second most common cause of an empty Values array:

  • Clock drift: If the panel's RTC is not synchronized, a request for "last 1 hour" can fall entirely before the first logged value. Synchronize via NTP or set the time manually in the panel's Control Panel.
  • Acquisition cycle vs. requested resolution: A log with a 10 s acquisition cycle contains one record every 10 s. If the time range covers only a few seconds, the result set may be empty.
  • Time zone: All times are interpreted in the panel's local time zone. Confirm the panel's Regional Settings → Time Zone matches the PLC's time, otherwise records may appear shifted by hours.
  • DST transitions: Ambiguous or non-existent local times during DST shifts can cause the Read call to return fewer records than expected.

For predictable exports, use UTC throughout: convert new Date() to UTC with end.toISOString() and pass explicit UTC dates to Read. The WinCC Unified runtime stores timestamps in UTC internally and converts to local time on display.

Error Handling and RTIL Trace Diagnostics

Every JavaScript call into the HMI runtime returns a trace string visible in the RTIL Trace Viewer (started from Start → Programs → Siemens Automation → RTIL Trace Viewer on the engineering station, or via the Diagnosis → Trace page on the panel's web interface). The corrected script logs at every step:

Trace String Fragment Likely Cause Corrective Action
Logging tag 'XYZ' not found Tag name mismatch Copy the exact name from Logs → [log] → Tags
Read error, code: 0x8004... Internal I/O or access error Check the log is online and acquiring
No values in window Empty time range or no data Expand range, verify log cycle, check time sync
Write failed, Error: 2 Path not found (ENOENT) Create parent directory on the panel
Write failed, Error: 13 Permission denied (EACCES) Use a writable path; avoid C:\ on panels
Write failed, Error: 28 No space left (ENOSPC) Archive or delete older log files
Pipeline failed: TypeError JavaScript type mismatch Validate tag object before calling Read

Open the RTIL Trace Viewer before triggering the export, filter by HMIRuntime.Trace messages, and capture the full sequence. If the panel is on a separate network, enable the Remote Trace connection in the panel's Control Panel and connect from the engineering station.

Step-by-Step Commissioning Procedure

  1. Configure the data log in TIA Portal. In the HMI device, Logs → Add new data log. Set the Logging method to Circular log or Segmented log depending on retention requirements. Add the HMI tags you want to log. Note the Name of each logging tag as displayed in the table.
  2. Compile and download the project to the Unified Comfort Panel. Confirm the log is acquiring by opening the panel's Logs view on the HMI and verifying a timestamp appears within one acquisition cycle.
  3. Open the JavaScript editor in TIA Portal under HMI → Scripts → [your script]. Paste the corrected script from the Solution Path B section above. Update LOG_TAG_NAME, FILE_PATH, and TIME_WINDOW_H for your project.
  4. Pre-create the target directory on the panel. Use the panel's File Browser (Control Panel) or push a directory via the TIA Portal Files editor. The runtime will not create missing parent directories.
  5. Attach the script to a trigger: a button's Click event, a scheduled task (every 60 s, every 1 h, etc.), or a value change on a control tag.
  6. Open RTIL Trace Viewer on the engineering station. Connect to the panel via its IP address. Trigger the script and observe the trace output.
  7. Retrieve the CSV file from /media/simatic/Logs/ using the panel's web interface (File Browser → Download) or via SFTP/SCP if enabled.
  8. Validate the CSV in Excel or a text editor. Confirm that the Value column contains numeric data, not null, and that timestamps are monotonically increasing.

Verification Checklist

  • ☐ RTIL trace shows Resolved tag: <name> with the correct logging tag name.
  • ☐ Trace shows CSV written: <path> (N bytes) where N > header length.
  • ☐ File exists at the configured path and is non-empty.
  • ☐ First data row contains a numeric Value and a non-zero Quality code (typically 0xC0 = Good, 0x00 = Bad).
  • ☐ Row count matches expected: duration / acquisition_cycle ± 1.
  • ☐ No null strings in the Value column.
  • ☐ Timestamps are in the expected time zone and continuous.
  • ☐ File persists across panel reboots (stored on internal flash, not RAM).

Troubleshooting Matrix

Symptom Probable Cause Diagnostic Step Fix
CSV contains only header; no data rows Empty Values array (tag not found or window empty) Check RTIL trace for No values in window or tag not found Correct the logging tag name; widen the time window
CSV contains null in every Value cell Logging tag name points to a non-existent or wrong tag Open Logs → [log] → Tags in TIA Portal Replace name with the exact registered name
WriteFile fails with code 2 Parent directory missing Browse panel file system; confirm directory exists Create the directory on the panel before first write
WriteFile fails with code 13 Using a Windows path on a Linux-based panel Inspect FILE_PATH for \ or C:\ Use POSIX paths (/media/simatic/...)
Script works on PC RT but not on panel Path and runtime behavior differ Compare path conventions; check trace on both targets Branch the path on HMIRuntime.Runtime device type if needed
Some values are present, others are null Quality = Bad for those records (PLC connection interruption) Inspect Quality column; cross-check PLC logs Improve network reliability; filter nulls if appropriate
ExportTagLog returns HRESULT <> 0 Log name, path, or time range invalid Check LogName against Logs in TIA Portal Use the data log name (e.g., ProcessData), not a tag name
CSV is empty after panel reboot File was written to RAM-backed tmpfs Inspect the storage class of the path Write to /media/simatic/ for persistence

Frequently Asked Questions

Why does HMIRuntime.TagLogging.LoggedTags("MyHmiTag") return null values when the HMI tag clearly exists in the project?

The runtime distinguishes between HMI tags and logging tags. LoggedTags() resolves a logging tag, which is created only when the HMI tag is added to a data log. The name is usually identical to the HMI tag name, but you must verify it in Logs → [log] → Tags in the TIA Portal project tree. PLC symbol names with dot notation (e.g., DB_Struct.Element) are never valid.

Can I use the same JavaScript code on a PC-based RT Unified and on a Unified Comfort Panel?

The code logic is identical, but the file path must be platform-aware. PC RT accepts Windows paths like C:\Users\Public\Log.csv; Comfort Panels require POSIX paths like /media/simatic/Logs/Log.csv. Branch the path on the runtime device type or use the panel's Control Panel → File Browser to confirm the correct location before writing.

Is ExportTagLog available in TIA Portal V17 or V18, or only V19?

ExportTagLog was introduced with WinCC Unified V17 and is available in V17, V18, V19, and V20. The signature and DataFormat values (0 = CSV, 1 = TXT, 2 = JSON, 3 = XML) have remained stable across these versions. See the official TIA Portal help at docs.tia.siemens.cloud — ExportTagLog RT Unified.

How do I find the exact name of my logging tag without compiling and downloading the project?

Open the TIA Portal project, select the HMI device, and navigate to Logs → [data log] → Tags in the project tree. The Name column lists every logging tag registered with that log. If the column is empty for a given row, the runtime falls back to the HMI tag name shown in the HMI tag column.

Why does tag.Read(start, end, 0) return fewer records than the acquisition cycle would suggest?

Most often the panel's local time zone or RTC is misaligned with the PLC, so the requested window does not overlap the logged data. Confirm the panel's time zone in Control Panel → Regional Settings, enable NTP synchronization, and verify that the time stamps on the panel match those in the PLC's online diagnostics.

Can the exported CSV include multiple tags in one file?

ExportTagLog exports the entire data log, which contains all tags assigned to it, into a single CSV with one column per tag. If you need a custom layout (merged time stamps, computed columns, etc.), use the JavaScript API and call LoggedTags("name").Read(...) once per tag, then merge the results in the for loops into a single string before writing.

What HRESULT codes does ExportTagLog return?

Common values: 0 = success; 0x80070002 = path or log not found; 0x80070005 = access denied; 0x80070070 = disk full. Always log the full Int return value in hex to HMIRuntime.Trace for post-mortem analysis.

Back to blog