WinCC VB Skript zum auslesen einer CSV und schreiben in einen DB

Amkonianer

Level-1
Beiträge
24
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusamen,

ich habe folgende Aufgabenstellung:
Ich muss Änderungen die im Einrichtbetrieb vorgenommen wurden in einer CSV abspeichern um diese exportieren zu können und gleichzeitig im Tabellenformat auf einem Siemens IPC, wo Runtime Advanced läuft, anzeigen lassen.

Im Einsatz habe ich eine S7-1500 1512-2 PN und einen IPC C377E mit Windows 10 Enterprise 2016 LTSB.

Was ich bisher habe & meine Idee:
Das schreiben in die CSV funktioniert schon mal. Das lesen funktioniert teilweise. Die "Tabelle" im HMI besteht aus mehreren E/A-Feldern, wo ich insgesamt 10 Datensätze anzeigen lasse, wobei hier die nächsten Datensätze dann mit einem Button "<" und ">" geladen werden sollten. Ich habe mir 2 Datenbausteine angelegt. Einmal einen wo ich 1000 Datensätze aus der CSV auslese und in DB (Array 0..999 of Struct, die jeweils 4 Strings enthalten) zwischenspeichere und einen anderen DB der mit Daten gefüttert werden die dann in den E/A-Feldern angezeigt werden.

Wenn die Pfeiltasten gedrückt werden, sollte einfach der Index des Arrays erhöht werden, von wo die Daten des 1. DB's in den 2. DB geschrieben werden.

VB-Skript zum lesen der Daten aus der CSV:
Code:
Sub ReadFile()Dim fso, datei, textfile, x, name, stringliste
Set fso = CreateObject("Scripting.FileSystemObject")
 
datei="D:\Files\Schmiermittel.csv"


Set fso = CreateObject("Scripting.FileSystemObject")
 
    Set textfile = fso.OpenTextFile(datei, 1)
    x = 0
    Do While textfile.AtEndOfStream <> True
        name = textfile.ReadLine
        stringliste = Split(name, ";")
        
        SmartTags("Logbuch_Tabelle_DB_Tabelle_Einträge{"&x&"}_DateTime") = stringliste(0)
        SmartTags("Logbuch_Tabelle_DB_Tabelle_Einträge{"&x&"}_Artikelbeschreibung") = stringliste(1)
        SmartTags("Logbuch_Tabelle_DB_Tabelle_Einträge{"&x&"}_Aenderung") = stringliste(2)
        SmartTags("Logbuch_Tabelle_DB_Tabelle_Einträge{"&x&"}_AltNeuWert") = stringliste(3)     
        x = x + 1
    Loop    
    textfile.Close
End Sub

SCL-Code zum befüllen des 2. DB's:
Code:
IF "Logbuch_Tabelle_Anzeige_DB".Temp_zaehlen_plus OR "Logbuch_Tabelle_Anzeige_DB".Temp_zaehlen_minus THEN    FOR #x := 0 TO 9 BY 1 DO
        "Logbuch_Tabelle_Anzeige_DB".Tabelle.Einträge[#x].DateTime := "Logbuch_Tabelle_DB".Tabelle.Einträge["Logbuch_Tabelle_Anzeige_DB".y].DateTime;
        "Logbuch_Tabelle_Anzeige_DB".Tabelle.Einträge[#x].Artikelbeschreibung := "Logbuch_Tabelle_DB".Tabelle.Einträge["Logbuch_Tabelle_Anzeige_DB".y].Artikelbeschreibung;
        "Logbuch_Tabelle_Anzeige_DB".Tabelle.Einträge[#x].Aenderung := "Logbuch_Tabelle_DB".Tabelle.Einträge["Logbuch_Tabelle_Anzeige_DB".y].Aenderung;
        "Logbuch_Tabelle_Anzeige_DB".Tabelle.Einträge[#x].AltNeuWert := "Logbuch_Tabelle_DB".Tabelle.Einträge["Logbuch_Tabelle_Anzeige_DB".y].AltNeuWert;
        "Logbuch_Tabelle_Anzeige_DB".y := "Logbuch_Tabelle_Anzeige_DB".y + 1;
    END_FOR;
    "Logbuch_Tabelle_Anzeige_DB".Temp_zaehlen_plus := FALSE;
    "Logbuch_Tabelle_Anzeige_DB".Temp_zaehlen_minus := FALSE;
END_IF;

Wobei hier "y" der Index-Wert des Arrays im 1. DB ist, von wo an gelesen und geladen werden sollte.

Mein Problem:
Die Daten werden zwar aus der CSV, gelesen, aber nur die ersten 10 Einträge, mehr befinden sich dann nicht in meinem 1. DB. Und die ganze Sache kommt mir ziemlich langsam vor und als ob das VB-Skript nicht immer ausgeführt wird.

Jemand eine Idee, woran das liegen könnte, dass nicht alle Daten von der CSV geladen werden? Und warum das ganze so träge bzw. das VB-Skript nicht richtig ausgeführt werden könnte?
 
Frage dazu :
Wann wird denn dein Script ausgeführt (also welches Ereignis ist der Trigger) ?

Bemerkung dazu :
Da du in deinem VBS-Script indiziert arbeitest (du verwendest im Tagnamen das x) mußt du sicherstellen, dass diese Variablen zwischen Visu und SPS überhaupt aktualisiert werden.
Weiterhin mußt du auch sicherstellen, dass der so entstehenden Tagname auch wirklich GENAU identisch mit dem in deiner Variablentabelle ist - eigentlich wird hier ein String übergeben.

Weitere Frage :
Wie langsam ist "ziemlich langsam" ? Beachte bitte, dass du immer dein komplettes File einliest ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Larry,

danke erstmal für deine Hilfe.
Zur 1. Frage:
Ich habe mir einen Button mit "Daten laden" erstellt wo das Skript dann aufgerufen wird.

Zur Bemerkung:
Habe meinen Fehler gefunden. Die restlichen Smarttag Variablen waren nicht in den HMI-Variablen, sondern nur die vom Eintrag 0-9. Jetzt werden auch alle Einträge geladen.
Das Problem was ich nur jetzt habe, ich habe jetzt über 4000 HMI-Variablen :rolleyes:

Irgend einen Tipp wie man das anders lösen könnte, bzw. eine ganz andere Methode um Daten in einer CSV zu speichern und als HMI Tabelle darzustellen?

Ich hätte schon überlegt eine HTML-Datei erzeugen zu lassen mit einem Skript und diese dann einfach in einen HTML Browser anzeigen zu lassen am HMI.

LG Steini
 
Ich frage mal anders :
Wieviele Datensätze zeigst du denn auf einmal an ? Ich nehme mal an, dass deine Tabelle in der HMI z.B. 10 Datensätze anzeigt und du eine Art Blätternfunktion hast, die dir dann dir weiteren Daten hervorholt ...?
Wenn ja ... warum lädst du dann nicht einfach nur die Daten aus der CSV, die du wirklich anzeigen willst ? Das wäre vom Script ein bißchen komplizierter - aber durchaus umsetzbar.

Gruß
Larry
 
Richtig, so habe ich es gemacht. Aber ich habe mich jetzt für eine andere Methode und meiner Meinung nach ressourcenschonendere Methode entschieden.
Es sollten nämlich nicht nur Änderungen so angezeigt werden, Qualitätstabellen etc. Ich wollte mir eben alle Datensätze in einen DB laden und von dort dann immer die 10 in einen anderen DB schreiben, die ich anzeigen lassen wollte.

Aber ich habe es jetzt wie folgt gelöst:
Ich schreibe die Daten in eine CSV, die man dann per USB auch abspeichern kann um sie am Büroplatz angucken zu können. Dann habe ich mir ein VB Skript gebastelt, das die CSV ausliest und pro Datensatz einen Tabelleneintrag in einer HTML Datei erzeugt. Diese HTML lasse ich dann einfach am HMI mit dem integrierten Webbrowser anzeigen. Das ganze noch ein bischen mid CSS verschönern fertig ist es.

Code:
Sub WriteHTMLFile()Dim fso, datei, textfile, fso2, datei2, textfile2, text, stringliste


Set fso = CreateObject("Scripting.FileSystemObject")
Set fso2 = CreateObject("Scripting.FileSystemObject")
datei = "D:\Files\Daten.html"
datei2 = "D:\Files\Schmiermittel.csv"


Set textfile = fso.CreateTextFile(datei, True)
Set textfile2 = fso2.OpenTextFile(datei2, 1)


textfile.WriteLine "<!DOCTYPE html>"
textfile.WriteLine "<html lang='de'>"
textfile.WriteLine "<head>"
textfile.WriteLine "<meta charset='utf-8'/>"
textfile.WriteLine "<meta name='viewport' content='width=device-width, initial-scale=1.0'/>"
textfile.WriteLine "<title>Titel</title>"
textfile.WriteLine "</head>"
textfile.WriteLine "<body>"
textfile.WriteLine "<h1>Einfache Tabelle</h1>"
textfile.WriteLine "<table>"
textfile.WriteLine "<tr>"
textfile.WriteLine "<th>Datum</th><th>Auftragsnummer</th><th>Änderung</th><th>Alt & Neu </th>"


Do While textfile2.AtEndOfStream <> True
	text = textfile2.ReadLine
	stringliste = Split(text, ";")
	
	textfile.WriteLine "<tr>"
	textfile.WriteLine "<td>"&stringliste(0)&"</td>"
	textfile.WriteLine "<td>"&stringliste(1)&"</td>"
	textfile.WriteLine "<td>"&stringliste(2)&"</td>"
	textfile.WriteLine "<td>"&stringliste(3)&"</td>"
	textfile.WriteLine "</tr>"		
Loop
	textfile2.Close
	
	textfile.WriteLine "</table>
	textfile.WriteLine "</body>"
	textfile.WriteLine "</html>"
	textfile.Close		
End Sub

LG Steini
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Warum willst Du (bis zu) 1000 Datensätze komplett in die SPS lesen und in der SPS 10 Datensätze umkopieren, nur um 10 Datensätze am HMI anzuzeigen? Das könntest Du rein im HMI machen mit internen HMI-Variablen (ohne Steuerungsanbindung).

Wenn Du die Datensätze wirklich in die SPS lesen mußt, dann bekommst Du die nur mit einem Handshake (am besten als Rezeptur) sicher in die SPS geladen. So einfach wie Du das in Deinem Skript gemacht hast, bist Du nicht sicher, wann alle Variablenwerte in der SPS angekommen sind. Du brauchst noch ein Handshake oder eine Prüfsumme "über alles".
Suchbegriff für TIA-Hilfe und hier im Forum: "SetDataRecordTagsToPLC", schau mal hier

Das Variablen-Aktualisierungs-Problem besteht auch (und da noch gravierender) beim Einlesen von PLC-Variablen ins HMI, z.B. für das Schreiben der Werte in csv-Dateien. Suchbegriff "GetDataRecordTagsFromPLC"

Nur HMI-intern (ohne Umweg über SPS): Anstatt 4000 einzelnen HMI-Variablen könntest Du 4 Arrays nehmen.
z.B. HMI-Variable "Logbuch_Tabelle_DateTime" : Array [0..999] of DateTime : <interne Variable>
(allerdings weiß ich nicht, ob in TIA HMI mittlerweile "Array of WString" können)

Weiteres:
Du solltest beim Einlesen der CSV-Datei das x überwachen und die Schleife abbrechen wenn zu viele Zeilen in der Datei sind.
Nach dem Split solltest Du mit Ubound(stringliste) checken, ob in der eingelesenen Zeile auch wirklich 4 Werte drin waren.

Code:
    Do Until textfile.AtEndOfStream
        name = textfile.ReadLine
        stringliste = Split(name, ";")
        If UBound(stringliste) <> 3 Then
            ShowSystemAlarm "Fehler beim Einlesen csv-Datei in Zeile " & x + 1
            Exit Do
        Else
            SmartTags("Logbuch_Tabelle_DateTime")(x)            = stringliste(0)
            SmartTags("Logbuch_Tabelle_Artikelbeschreibung")(x) = stringliste(1)
            SmartTags("Logbuch_Tabelle_Aenderung")(x)           = stringliste(2)
            SmartTags("Logbuch_Tabelle_AltNeuWert")(x)          = stringliste(3)
        End If

        x = x + 1
        If x >= 1000 Then Exit Do
    Loop

Harald
 
Vielen Dank erstmal für die Hilfe.

Ich habe das Problem jetzt wie folgt gelöst:
Beim erstellen der CSV bzw. schreiben in die CSV überprüfe ich erst wie viele Zeilen schon enthalten sind. Wenn mehr als 1000 Zeilen enthalten sind, schreibe ich die Datei als "Backup" weg und erstelle eine neue CSV wo ich wieder reinschreibenen kann.
Code:
Dim fso,datum,zeit,datei,textfile1, x, backupfile, backuppath, headers 
Set fso = CreateObject("Scripting.FileSystemObject")
 
datei= "D:\Files\Kunde\CSV\Logbuch.csv"
backuppath = "D:\Files\Kunde\CSV\Altdaten"
backupfile = backuppath & "\Logbuch_Alt_" & Date & ".csv"
headers = "Datum/Uhrzeit;Auftragsnummer;Art der Aenderung; Alter Wert/Neuer Wert"
 
If Not fso.FileExists (datei) Then 
    Set textfile1 = fso.CreateTextFile(datei, True)
    textfile1.WriteLine headers
    'textfile1.WriteLine 'Werte die vom DB kommen
    textfile1.Close
End If
 
If fso.FileExists (datei) Then 
    Set textfile1 = fso.OpenTextFile(datei, 1)
    textfile1.ReadAll
    If textfile1.Line >= 1000 Then
		textfile1.Close
		If fso.FolderExists(backuppath)Then
			fso.CopyFile datei, backupfile
		Else
			fso.CreateFolder(backuppath)
		End If
		fso.CopyFile datei, backupfile
		fso.DeleteFile datei
		Set textfile1 = fso.CreateTextFile(datei, True)
		textfile1.Close	
		Set textfile1 = fso.OpenTextFile(datei, 8)
		textfile1.WriteLine headers
	End If
	'textfile1.WriteLine 'Werte die vom DB kommen
    textfile1.Close
End If

Wenn ich dann die HTML erzeuge überprüfe ich noch ob alle Einträge richtig sind wie Harald es geschrieben hat:
Code:
Dim fso, datei, textfile, fso2, datei2, textfile2, text, stringliste, x

Set fso = CreateObject("Scripting.FileSystemObject")
Set fso2 = CreateObject("Scripting.FileSystemObject")
datei = "D:\Files\Kunde\HTML\Logbuch.html"
datei2 = "D:\Files\Kunde\CSV\Logbuch.csv"


Set textfile2 = fso2.OpenTextFile(datei2, 1)
Set textfile = fso.CreateTextFile(datei, True)


textfile.WriteLine "<!DOCTYPE html>"
textfile.WriteLine "<html lang=""de"">"
textfile.WriteLine "<head>"
textfile.WriteLine "<style>"
textfile.WriteLine "table{ border-collapse: collapse; border: none; font-size: 14pt; font-family: arial; background-color: white; min-width: 100%; }"
textfile.WriteLine "td, th { text-align: left; padding: 15px; border: 1px solid black; }"
textfile.WriteLine "</style>"
textfile.WriteLine "<meta charset=""utf-8""/>"
textfile.WriteLine "<meta name=""viewport"" content=""width=device-width, initial-scale=1.0""/>"
textfile.WriteLine "<title>Titel</title>"
textfile.WriteLine "</head>"
textfile.WriteLine "<body>"
textfile.WriteLine "<table>"
textfile.WriteLine "<tr>"


x = 0
Do Until textfile2.AtEndOfStream
	text = textfile2.ReadLine
	stringliste = Split(text, ";")
	If UBound(stringliste) <> 3 Then
		ShowSystemAlarm "Fehler beim Einlesen der Logbuch.csv in Zeile " & x + 1
		Exit Do
	Else
		textfile.WriteLine "<tr>"
		textfile.WriteLine "<td>"&stringliste(0)&"</td>"
		textfile.WriteLine "<td>"&stringliste(1)&"</td>"
		textfile.WriteLine "<td>"&stringliste(2)&"</td>"
		textfile.WriteLine "<td>"&stringliste(3)&"</td>"
		textfile.WriteLine "</tr>"
	End If
		x = x + 1
		'If x >= 1000 Then Exit Do
Loop


	textfile2.Close	
	textfile.WriteLine "</table>"
	textfile.WriteLine "</body>"
	textfile.WriteLine "</html>"	
	textfile.Close

Wenn ihr noch irgendwelche Tipps habt wie man das verbessern kann, dann würde ich mich darüber freuen.

Steini
 
Zurück
Oben