#TIA Openness #TypeScript #S7-1500 #Code Generation #Automation

Typsicherheit im Schaltschrank: Aus TIA-Portal-XML vollautomatisch TypeScript generieren

Wie Sie S7-1500 Datenbausteine und UDTs per TIA Openness exportieren und in compile-time TypeScript Interfaces konvertieren, um Runtime-Bugs bei der Inbetriebnahme zu eliminieren.

BG
Boris Kotov • Solutions Architect
• 8 Min. Lesezeit

Jeder Inbetriebnehmer kennt diesen Moment: Die Anlage steht auf der Baustelle, der Testlauf beginnt – und das HMI stürzt ab oder zeigt Phantasiewerte an. Die Ursache nach stundenlangem Wireshark- und Tracing-Aufwand? Ein banaler Tippfehler in einem Variablenstring: DB10.MotorCurret statt DB10.MotorCurrent.

In traditionellen SPS-Programmiersprachen (SCL, KOP, FUP) sorgt der Compiler für absolute Typsicherheit. Doch an der Schnittstelle zur Web-Visualisierung (WinCC Unified, Node-RED, Custom Web Controls) reißt diese Sicherheitskette traditionell ab.

In diesem Beitrag zeigen wir, wie Sie die TIA Openness XML-Schnittstelle nutzen, um SPS-Datenbausteine (DBs) und User Defined Data Types (UDTs) vollautomatisch in typsichere TypeScript-Definitionen zu kompilieren.


1. Der Status Quo: Die Typlücke zwischen SPS und Web

Traditionell wird in HMI-Skripten mit magischen Zeichenketten gearbeitet:

// Ungetypt und fehleranfällig:
const speed = Tags("DB_Drive_Axis1.ActualSpeed").Read(); 
// Kein Compiler warnt Sie, wenn 'ActualSpeed' in der SPS in 'ActSpeed' umbenannt wurde!

Bei hunderten Datenpunkten pro Maschine führt jede Refaktorisierung im TIA Portal zu einem unkalkulierbaren Fehlerrisiko auf der Baustelle.


2. Der Rohstoff: TIA Portal SimaticML / Openness XML

Wenn Sie im TIA Portal einen Datenbaustein oder UDT als XML exportieren (manuell oder via TIA Portal Openness API), erhalten Sie eine strukturierte Definition:

<?xml version="1.0" encoding="utf-8"?>
<Document>
  <Engineering version="V19" />
  <SW.Blocks.GlobalDB ID="0">
    <AttributeList>
      <Name>DB_Drive_Axis1</Name>
      <Number>10</Number>
    </AttributeList>
    <ObjectList>
      <MultilingualText ID="1" CompositionName="Comment" />
      <SW.Blocks.CompileUnit ID="2" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource>
            <!-- Member Definitionen -->
          </NetworkSource>
        </AttributeList>
      </SW.Blocks.CompileUnit>
      <Member Name="ControlWord" Datatype="Word" Remanence="NonRetain" />
      <Member Name="SetSpeedRPM" Datatype="Real" Remanence="Retain" />
      <Member Name="ActualCurrentAmps" Datatype="Real" Remanence="NonRetain" />
      <Member Name="StatusRunning" Datatype="Bool" Remanence="NonRetain" />
      <Member Name="FaultCode" Datatype="DInt" Remanence="NonRetain" />
    </ObjectList>
  </SW.Blocks.GlobalDB>
</Document>

3. Die Typ-Mapping-Engine (AST-Generator)

Wir mappen die Siemens S7-Datentypen auf primitive TypeScript-Typen:

Siemens S7 DatentypTypeScript TypValidierung / Range
Boolbooleantrue | false
Byte, Word, DWordnumberHexadezimal / Bitmasken
SInt, Int, DIntnumberInteger Bounds
Real, LRealnumberIEEE 754 Float
String, WStringstringUTF-8 / UTF-16
DTL, Date_And_TimeDate | stringISO-8601 Timestamp
UDT_<Name>Custom InterfaceVerschachteltes Interface

Die Node.js Transformations-Pipeline

Mit einem schlanken Node.js-Skript parsen wir das SimaticML-XML:

// typegen.ts
import { XMLParser } from 'fast-xml-parser';
import * as fs from 'fs';

const typeMap: Record<string, string> = {
  'Bool': 'boolean',
  'Real': 'number',
  'LReal': 'number',
  'Int': 'number',
  'DInt': 'number',
  'Word': 'number',
  'String': 'string',
};

export function generateTypeScriptFromS7Xml(xmlContent: string): string {
  const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_' });
  const doc = parser.parse(xmlContent);
  
  const dbName = doc.Document['SW.Blocks.GlobalDB'].AttributeList.Name;
  const members = doc.Document['SW.Blocks.GlobalDB'].ObjectList.Member;

  let tsOutput = `/**\n * Automatisch generiert aus TIA Portal DB: ${dbName}\n */\n`;
  tsOutput += `export interface S7_${dbName} {\n`;

  for (const m of (Array.isArray(members) ? members : [members])) {
    const propName = m['@_Name'];
    const s7Type = m['@_Datatype'];
    const tsType = typeMap[s7Type] || 'unknown';
    tsOutput += `  /** S7-Typ: ${s7Type} */\n`;
    tsOutput += `  ${propName}: ${tsType};\n`;
  }

  tsOutput += `}\n`;
  return tsOutput;
}

Das Ergebnis ist ein sauberes, compile-time geprüftes Interface:

/**
 * Automatisch generiert aus TIA Portal DB: DB_Drive_Axis1
 */
export interface S7_DB_Drive_Axis1 {
  /** S7-Typ: Word */
  ControlWord: number;
  /** S7-Typ: Real */
  SetSpeedRPM: number;
  /** S7-Typ: Real */
  ActualCurrentAmps: number;
  /** S7-Typ: Bool */
  StatusRunning: boolean;
  /** S7-Typ: DInt */
  FaultCode: number;
}

4. Typsicherer HMI-Zugriff mit Proxy-Pattern

Mit TypeScript Generics können wir nun einen typsicheren Wrapper um die Siemens Tags() API bauen:

export class TypedPlcClient<TDB extends object> {
  constructor(private dbPrefix: string) {}

  public read<K extends keyof TDB>(tag: K): Promise<TDB[K]> {
    const fullPath = `${this.dbPrefix}.${String(tag)}`;
    return (Tags(fullPath) as any).Read();
  }

  public write<K extends keyof TDB>(tag: K, value: TDB[K]): Promise<void> {
    const fullPath = `${this.dbPrefix}.${String(tag)}`;
    return (Tags(fullPath) as any).Write(value);
  }
}

// Verwendung im Custom Web Control:
const axis1 = new TypedPlcClient<S7_DB_Drive_Axis1>('DB_Drive_Axis1');

// VOLLSTÄNDIGE AUTOVERVOLLSTÄNDIGUNG IM EDITOR!
await axis1.write('SetSpeedRPM', 1450.0); // ✅ Gültig

// @ts-expect-error - Compile-Fehler: 'MotorCurret' existiert nicht!
await axis1.write('MotorCurret', 12); 

// @ts-expect-error - Compile-Fehler: 'StatusRunning' erwartet boolean, nicht number!
await axis1.write('StatusRunning', 123);

Fazit: Null Inbetriebnahme-Fehler an der Tag-Schnittstelle

Indem Sie TIA Portal XML-Exporte als Single Source of Truth in Ihren Frontend-Build einbinden, machen Sie Tippfehler und Typinkompatibilitäten unmöglich. Was früher erst im Schaltschrank beim Testlauf auffiel, schlägt nun direkt beim npm run build fehl.

In CWC Studio Pro ist dieser TypeGen-Generator als Drag & Drop-Modul integriert.

Engineering • Architektur • Beratung

Planen Sie ein WinCC Unified Projekt oder eine HMI-Modernisierung?

Ob Migration bestehender VBScripts, Entwicklung individueller Custom Web Controls oder Performance-Optimierung: Sprechen Sie direkt mit Boris Kotov über Ihr Vorhaben.