Diese Anleitung beschreibt das „Schritt für Schritt“-Vorgehen, um eine per RFC 1006 empfangene XML-Datei nach dem Empfang in eine Datenbank zu schreiben.
Als Datenquelle wird hierbei beispielhaft der RFC 1006 Device Plugin und als Datenziel eine lokale MySQL Datenbank verwendet.
Durch das einheitliche Interface, das CoDaBix für den Zugriff auf angebundene Geräte und Datenbanken bietet, ist dieses Vorgehen jedoch auf jede Art von Daten,
die in CoDaBix definiert sind, anwendbar.
Für die Ausführung der folgenden Schritte benötigen Sie einen Rechner (mit Windows oder Linux Betriebssystem),
auf dem Sie die erforderlichen Rechte besitzen, um Anwendungen installieren zu können.
Desweiteren ist eine Internetverbindung notwendig, um CoDaBix und die bereitgestellte Standardkonfiguration zu laden.
Die genauen Systemanforderungen an Hardware und Betriebssystemversion finden Sie hier:
Folgende CoDaBix Plugins sind erforderlich
In diesem Schritt installieren Sie CoDaBix auf Ihrem System.
Für diese Anleitung stellen wir Ihnen eine Grundkonfiguration für die Prozessdatenerfassung bereit.
auf dem Sie CoDaBix verwenden wollen.
4) Restore Backup
Enter
-Taste
Im „Nodes“ Verzeichnis wird eine Folder-Node XML
erstellt.
Dort erstellen wir folgende Nodestruktur:
TriggerNode
Steuerung
Ort
tagid
Inhalte
Info
Client Channel anlegen
Unter System
→ Devices
→ RFC-1006 Device
legen Sie einen neuen Channel mit dem Namen Channel1
und folgenden Einstellungen an.
Hier verwenden wir die localhost IP-Adresse 127.0.0.1, da ein weiterer Channel angelegt wird, welcher als Testserver dient.
Dann können Sie wie folgt vorgehen, um aus dem Rfc1006-Channel1 ein XML-Telegramm zu empfangen und dieses in die Nodes zu schreiben, welche dann wiederrum in eine Datenbank geschrieben werden können:
Stellen Sie bitte im Rfc1006-Channel im Ordner „Nodes“ den Value Type der „ReceiveBuffer“-Node von Blob auf „String“ um
Testserver Channel anlegen
Nun legen wir noch den Channel für den Testserver mit dem Namen TestServer
an.
Hier werden die LocalTSAP und RemoteTSAP vertauscht um mit dem Client kommunizieren zu können.
Stellen Sie bitte im Rfc1006-Channel im Ordner „Nodes“ den Value Type der „TransmitBuffer“-Node von Blob auf „String“ um
RFC1006 Deserialisation
Bitte beachten Sie, dass das Script als Beispiel noch nicht alle String-Werte korrekt dekodiert (z.b. wenn mit „&“ kodierte Zeichen vorkommen). Wir arbeiten jedoch aktuell an der Implementierung eines separaten XML-Plugins für CoDaBix, dass das Parsen von XML-Dateien übernimmt, sodass alle Stringwerte korrekt ausgelesen werden können.
runtime.handleAsync(async function () { const rfc1006ChannelReceiveBufferPath = "/System/Devices/RFC-1006 Device/Channels/Channel1/Nodes/ReceiveBuffer"; const rfc1006ChannelReceiveBufferNode = codabix.findNode(rfc1006ChannelReceiveBufferPath); if (!rfc1006ChannelReceiveBufferNode) throw new Error(`Could not find node '${rfc1006ChannelReceiveBufferPath}'.`); const tagBaseNodePath = "/Nodes/XML"; const triggerNodePath = tagBaseNodePath + "/TriggerNode"; const triggerNode = codabix.findNode(triggerNodePath); if (!triggerNode) throw new Error(`Could not find node '${triggerNodePath}'.`); const tagNames = ["Steuerung", "Ort", "tagid", "Inhalte", "Info"]; // Find the nodes for each tag name. const tagNodes = new Map<string, codabix.Node>(); for (let tagName of tagNames) { const nodePath = tagBaseNodePath + "/" + tagName; const node = codabix.findNode(nodePath); if (!node) throw new Error(`Could not find node '${nodePath}'.`); tagNodes.set(tagName, node); } // Reset the trigger node. void codabix.writeNodeValueAsync(triggerNode, 0); // Add a value changed event listener to the Receive Buffer. rfc1006ChannelReceiveBufferNode.addValueChangedEventListener(e => { if (typeof e.newValue.value != "string") { logger.logError(`Value Type of node '${rfc1006ChannelReceiveBufferPath}' is not 'String'!`); } else { let stringValue = e.newValue.value; // Log the received XML. logger.log("Received: " + stringValue); // Find the tags. let tags = extractTagsFromXmlString(stringValue); // Now write the tags into their corresponding nodes. codabix.scheduleCallback(() => { let valuesToWrite: { node: codabix.Node, value: string | number }[] = []; tags.forEach((value, key) => valuesToWrite.push({ node: tagNodes.get(key)!, value })); // Also, write 1 to the Trigger Node. valuesToWrite.push({ node: triggerNode, value: 1 }); // Write the values. codabix.writeNodeValuesAsync(valuesToWrite); // After writing the values, switch the trigger node back to 0. codabix.writeNodeValueAsync(triggerNode, 0); }); } }); function extractTagsFromXmlString(xmlString: string): Map<string, string> { let map = new Map<string, string>(); for (let tagName of tagNames) { // Search for the start tag. let startTag = `<${tagName}>`; let endTag = `</${tagName}>`; let startTagIndex = xmlString.indexOf(startTag); if (startTagIndex >= 0) { // OK, we found the start tag. Now search for the end tag. let endTagIndex = xmlString.indexOf(endTag, startTagIndex + startTag.length); if (endTagIndex >= 0) { // OK, we now have the value. // TODO: To get the correct string value, we would need to XML-decode the string. let content = xmlString.substring(startTagIndex + startTag.length, endTagIndex); logger.log(`Found Tag '${tagName}' with value '${content}'.`); map.set(tagName, content); } else { logger.logWarning(`Could not find start tag '${startTag}'.`); } } else { logger.logWarning(`Could not find start tag '${startTag}'.`); } } return map; } }());
(Falls ein Fehler geloggt wird, dass eine Node nicht gefunden wurde, müssen Sie ggf. den Pfad zur Node im Script-Code anpassen.)
Nun sollten auch die Werte in den zuvor erstellen Nodes stehen:
Um nun jedes Mal wenn neue Werte geschrieben wurden, die Tags in eine Datenbank zu schreiben, können Sie z.B. unser Database-Plugin verwenden. Dazu können Sie folgende Konfiguration in der XML-Konfigurationsdatei (CoDaBix.DatabasePlugin.Settings.xml) angeben:
<?xml version="1.0" encoding="utf-8" ?> <PluginSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Channels> <Channel id="ch1" active="true"> <DbConnections> <DbConnection id="con1" type="MySQL" hostname="localhost" port="3306" username="root" password="xxxxx" database="mydatabase" table="mytable" /> </DbConnections> <Triggers> <Trigger id="t1" type="edge" node="/Nodes/XML/TriggerNode" edgeValue="1" /> </Triggers> <DataSets> <DataSet id="ds1" writeDelay="1000" writeBufSize="10"> <DbConnection id="con1" /> <Trigger id="t1" /> <Nodes root="/Nodes/XML/"> <Node path="Steuerung" column="Steuerung" /> <Node path="Ort" column="Ort" /> <Node path="tagid" column="tagid" /> <Node path="Inhalte" column="Inhalte" /> <Node path="Info" column="Info" /> </Nodes> </DataSet> </DataSets> </Channel> </Channels> </PluginSettings>
Dadurch würde nun immer wenn ein neues XML-Telegramm eintrifft, dieses in die Datenbank geschrieben werden.