TIA VB CSV. Datei auf Storage Card anlegen (Datenlogger)

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Zuviel Werbung?
->Hier kostenlos registrieren
Guten Morgen,

ich bin gerade dabei, Taktzeiten einer Anlage nach jedem fertigen Bauteil in eine csv. Datei auf der Storage Card zu schreiben.
Da ich in Sachen Skripten auch recht neu unterwegs bin, habe ich natürlich die ein oder andere Stolperfalle, bei der ich aktuell nicht weiter komme.

Funktion soll folgendermaßen sein.
- Nach auslösen des Skriptes wird überprüft, ob die Karte gesteckt ist (Funktioniert)
- Wenn die Datei dann auf der Karte noch nicht existiert, wird sie angelegt (Taktzeitarchiv\Archiv.csv) und die Kopfzeile wird mit den entsprechenden Beschriftungen gefüllt (Funktioniert)
- Wenn ich 10000 Taktzeiten abgespeichert habe, will ich die Datei in einen Ordner "Taktzeitarchiv_Sicherung" verschieben, die Datei mit dem aktuellen Tagesstempel versehen und die "alte Datei im Ordner (Taktzeiten\Archiv.csv.) löschen. (Funktioniert)

Jetzt das Problem.
Ich bekomme es nicht hin, die CSV. Datei wieder mit den Kopfdaten zu erstellen, da der Ordner (Taktzeitarchiv) ja noch da ist und nur die CSV darin gelöscht ist.
Ich habe zwei Skripte draus gemacht.


Skript Archiv erstellen und befüllen
Code:
Sub Archiv()
'Skript dient dazu, Taktzeiten in eine .CSV Datei zu speichern



'Variablen definieren
Dim f, fs, fso, Datei, Pfad, Artikel, Solltaktzeit, Isttaktzeit
Dim DD, MM, JJJJ, HH, Min, Sek               
Dim DD_HV, MM_HV, JJJJ_HV, HH_HV, Min_HV, Sek_HV    'Hilfsvariablen für Datum / Uhrzeit
Dim strDatum, strUhrzeit                            'Hilfsvariablen für Stringzusammensetzung Datum / Uhrzeit
Dim strName                                            'Hilfsvariable für Dateiname

'Variablen vorbelegen
Artikel = SmartTags("Test_Artikel")                        'SmartTags("DB_Akt_Daten_Daten_Wkz-Name")
DD = Day(Now)
MM = Month(Now)
JJJJ = Year(Now)
HH = Hour(Now)
Min = Minute(Now)
Sek = Second(Now)
Solltaktzeit = SmartTags("Test_Soll")                                                    'SmartTags("Taktzeiten_Taktzeit_Soll")
Isttaktzeit = SmartTags("Test_Ist")                                                        'SmartTags("Taktzeiten_Taktzeit_1_Real")
strName = DD & "." & MM & "." & JJJJ & "/" & HH & ":" & Min & ":" & Sek                    'Datum und Uhrzeit als Text in Dateinamen anfügen

'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"


'Objekt für das Filehandling erstellen
Set fs = CreateObject("filectl.filesystem")
Set f= CreateObject("filectl.file")
Set fso = CreateObject("filectl.filesystem")


'Kontrolle ob MMC Karte gesteckt ist
If fso.Dir("\Storage Card SD\") = "" Then     
    ShowSystemAlarm "SD Karte ist nicht gesteckt, daher Abbruch der Datenübertragung"
Else     
    
      
'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If


f.open Pfad
If f.dir(Datei) = "" Then
    f.mkdir(Datei)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
Else
    f.close
End If


'Kontrolle ob Tag < 10 ist. Wenn ja, dann eine 0 vor die Zahl hängen
If DD < 10 Then
    DD_HV = CStr("0" & DD)
Else
    DD_HV = CStr(DD)
End If

'Kontrolle ob Monat < 10 ist. Wenn ja, dann eine 0 vor die Zahl hängen
If MM < 10 Then
    MM_HV = CStr("0" & MM)
Else
    MM_HV = CStr(MM)
End If

'Kontrolle ob Stunde < 10 ist. Wenn ja, dann eine 0 vor die Zahl hängen
If HH < 10 Then
    HH_HV = CStr("0" & HH)
Else
    HH_HV = CStr(HH)
End If

'Kontrolle ob Minute < 10 ist. Wenn ja, dann eine 0 vor die Zahl hängen
If Min < 10 Then
    Min_HV = CStr("0" & Min)
Else
    Min_HV = CStr(Min)
End If

'Kontrolle ob Sekunde < 10 ist. Wenn ja, dann eine 0 vor die Zahl hängen
If Sek < 10 Then
    Sek_HV = CStr("0" & Sek)
Else
    Sek_HV = CStr(Sek)
End If

'String für Datum zusammensetzen
strDatum = DD_HV & "." & MM_HV & "." & JJJJ
strUhrzeit = HH_HV & ":" & Min_HV & ":" & Sek_HV

'Zeile nur beschreiben, wenn Skriptbit auf True ist
If SmartTags("DB_Skript_Skript_Archiv") = True Then
    
'Pfad und datei öffnen und beschreiben, danach wieder schließen   
f.open Pfad + Datei, 8        '8 = Daten anhängen
f.LinePrint strDatum & ";" & strUhrzeit & ";" & Artikel & ";" & Solltaktzeit & ";" & Isttaktzeit & ";"
f.close

Else SmartTags("DB_Skript_Skript_Archiv") = False
    
End If
End If

 
'Filehandling zurücksetzen
Set fs = Nothing
Set f = Nothing
Set fso = Nothing

'Skriptvariable zurücksetzen
SmartTags("DB_Skript_Skript_Archiv") = False
End Sub

und Skript Datei verschieben und löschen

Code:
Sub Archiv_Kopieren_Loeschen()
'Tip:
'Skript dient dazu eine .CSV Datei in einen anderen Ordner zu kopieren und die aktuelle Datei zu löschen




'Variablen definieren
Dim fs, fso, Quelle, Quelle_Ordner, Ziel
Dim DD, MM, JJJJ, HH, Min, Sek   

'Quell- und Zielpfad festlegen
'Pfad und Datei festlegen
Quelle = "\Storage Card SD\Taktzeitarchiv\Archiv.csv"
'Quelle_Ordner = "\Storage Card SD\Taktzeitarchiv"
Ziel = "\Storage Card SD\Sicherung_Taktzeitarchiv\"
'On Error Resume Next
Set fs = CreateObject("filectl.filesystem")
Set fso = CreateObject("filectl.filesystem")

DD = Day(Now)
MM = Month(Now)
JJJJ = Year(Now)
HH = Hour(Now)
Min = Minute(Now)
Sek = Second(Now)

'Kontrolle ob MMC Karte gesteckt ist
If fso.Dir("\Storage Card SD\") = "" Then     
    ShowSystemAlarm "SD Karte ist nicht gesteckt, daher Abbruch der Datenübertragung"
Else


'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Ziel) = "" Then
    fs.mkdir(Ziel)
End If



fs.filecopy Quelle , Ziel & DD & "_" & MM & "_" & JJJJ & "_" & HH & "_" & Min & "_" & Sek & ".csv"           
fs.kill Quelle
'fs.kill Quelle_Ordner
End If

Set fs = Nothing
Set fso = Nothing



End Sub

Das er die CSV nicht anlegt, liegt meines erachtens daran, das im ersten Skript, wo kontrolliert wird das die Datei nicht vorhanden wird, ein Fehler ist. Ich denke weil es den Ordner "Taktzeitarchiv" ja noch gibt.
Wie kann ich es schaffen nur abzufragen, ob die Datei in dem Ordner fehlt?

Danke für eure Hilfe

Gruß Willi
 

faust

Well-known member
Beiträge
493
Punkte Reaktionen
116
Zuviel Werbung?
->Hier kostenlos registrieren
Guten Morgen Willi,

eine grundsätzliche Problemlösung wäre, dass du eigene Fehlerbehandlungsroutinen implementierst.

Aktuell würde dein Script ja bei jedem Fehler unmittelbar "aussteigen".
Setzt du jedoch an den Script-Anfang ein "On Error Resume Next" und fragst nach jedem relevanten Befehl das Error-Objekt "Err" ab (z.B. mit "If Err.Number > 0 Then ..."), dann kannst du sogar gezielt auf einzelne Problemszenarien reagieren und -wichtig- das Script läuft auf jeden Fall bis zum Ende durch.


Gruß, Fred
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.143
Punkte Reaktionen
2.738
du überprüfst doch an dieser Stelle ob das Verzeichnis vorhanden ist :
Code:
'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If
gleichzeitig erstellst du dann auch die Datei.
Das würde ich so nicht machen und damit wäre dein Problem dann auch gelöst :
Du solltest überprüfen, ob das Verzeichnis existiert und wenn nicht dann NUR das Verzeichnis erstellen.
Danach überprüfst du, ob die Datei existiert und wenn nicht dann die erstellen (also deinen Block in 2 Prüfungen aufsplitten).
Nun würde nach dem Löschen und dann Wieder-Aufruf das Verzeichnis nicht erstellt werden (weil ja schon vorhanden), die Datei dann aber erstellt werden (weil ja nun nicht mehr vorhanden)

Gruß
Larry
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Hallo faust,

dieses "On Error Resume Next" bewirkt bei einem Laufzeitfehler, das der Code danach trotzdem ausgeführt wird?

Sprich also wäre ein Ansatz so:

Code:
'Scriptanfang
On Error Resume Next



'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If Err.Number = 0 Then
If fs.dir(Ziel) = "" Then
    fs.mkdir(Ziel)
End If
End If

Wird dann der Laufzeitfehler auch im Panel dann angezeigt? Über Systemmeldungen o.ä.?

Gruß Willi
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Zuviel Werbung?
->Hier kostenlos registrieren
Das würde ich so nicht machen und damit wäre dein Problem dann auch gelöst :
Du solltest überprüfen, ob das Verzeichnis existiert und wenn nicht dann NUR das Verzeichnis erstellen.
Danach überprüfst du, ob die Datei existiert und wenn nicht dann die erstellen (also deinen Block in 2 Prüfungen aufsplitten).
Nun würde nach dem Löschen und dann Wieder-Aufruf das Verzeichnis nicht erstellt werden (weil ja schon vorhanden), die Datei dann aber erstellt werden (weil ja nun nicht mehr vorhanden)
Hallo Larry,

so ähnlich habe ich mir das auch gedacht. Aber wie mache ich die Abfrage auf NUR die Datei?
Muss ich dann im Skript abfragen (Pfad +Datei)?

Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"

'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If
 

JSEngineering

Well-known member
Beiträge
1.442
Punkte Reaktionen
407
Hallo faust,

dieses "On Error Resume Next" bewirkt bei einem Laufzeitfehler, das der Code danach trotzdem ausgeführt wird?

Sprich also wäre ein Ansatz so:

Code:
'Scriptanfang
On Error Resume Next



'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If Err.Number = 0 Then
If fs.dir(Ziel) = "" Then
    fs.mkdir(Ziel)
End If
End If

Wird dann der Laufzeitfehler auch im Panel dann angezeigt? Über Systemmeldungen o.ä.?

Gruß Willi

Moin Willi,

On Error Resume Next bewirkt nur, daß das Skript nicht abgebrochen wird.
Nach möglichen Fehlerstellen mußt Du dann selbst auswerten, ob ein Fehler aufgetreten ist.
Hier mal eine kleine Doku: https://docs.microsoft.com/de-de/do...guage-reference/statements/on-error-statement

Demgemäß mußt Du auch selber für eine Ausgabe des Fehlers sorgen.
 

JSEngineering

Well-known member
Beiträge
1.442
Punkte Reaktionen
407
Hallo Larry,

so ähnlich habe ich mir das auch gedacht. Aber wie mache ich die Abfrage auf NUR die Datei?
Muss ich dann im Skript abfragen (Pfad +Datei)?

Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"

'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If
Versuche mal die Methode FileExists auf dem fs-Objekt.
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Im Prinzip JA, aber nicht vergessen, dass zwischen Pfad und Datei auch wirklich ein (=1) blackslash ('\') stehen muss.

Hab ich versucht. Irgendwas stört Tia an der Zeile noch. Beim übersetzen ist auch immer alles gut.

Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"

'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
'    f.open Pfad + Datei, 8
'    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If

'Kontrolle ob CSV.Datei vorhanden. Wenn nicht, dann CSV.Datei erstellen
If f.dir(Pfad = 1\ Datei) = "" Then
    f.mkdir(Pfad + Datei)
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
End If
 

JSEngineering

Well-known member
Beiträge
1.442
Punkte Reaktionen
407
'Kontrolle ob CSV.Datei vorhanden. Wenn nicht, dann CSV.Datei erstellen
If f.dir(Pfad = 1\ Datei) = "" Then
f.mkdir(Pfad + Datei)
f.open Pfad + Datei, 8
f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
End If[/CODE]

Was soll "Pfad = 1\ Datei" bewirken?
Was soll "f.mkdir(Pfad + Datei)" machen? Dir ist bewußt, daß MKDIR = "Make Directory" bedeutet? Damit kannst Du also keine Datei erstellen. Eine Datei wird in der Regel durch's Öffnen mit Schreibrechten erstellt.
 

Heinileini

Well-known member
Beiträge
5.041
Punkte Reaktionen
1.074
Zuviel Werbung?
->Hier kostenlos registrieren
Was soll "Pfad = 1\ Datei" bewirken?
Das war ein Missverständnis!
Ich wollte nur darauf hinweisen, dass zwischen der Pfad-Angabe und dem DateiNamen (genau) 1 backslash stehen muss.
Mal ist dieses Zeichen ohnehin am Ende der Pfad-Angabe vorhanden (obwohl es eigentlich nicht dazu gehört) und mal nicht.
Das führt leicht dazu, dass es in dem zusammengesetzten String mal fehlt oder doppelt vorhanden ist. Folglich: Kontrollieren!
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.143
Punkte Reaktionen
2.738
Ich würde es ungefähr so machen (ohne Gewähr da gerade keine SW zur Hand) :
Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"

'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
End If

'Kontrolle ob CSV.Datei vorhanden. Wenn nicht, dann CSV.Datei erstellen
If not fs.FileExists(Pfad + Datei)  Then
    fs.open Pfad + Datei, 8
    fs.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    fs.close
End If
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Ich würde es ungefähr so machen (ohne Gewähr da gerade keine SW zur Hand) :
Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"

'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
End If

'Kontrolle ob CSV.Datei vorhanden. Wenn nicht, dann CSV.Datei erstellen
If not fs.FileExists(Pfad + Datei)  Then
    fs.open Pfad + Datei, 8
    fs.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    fs.close
End If

Hallo Larry,

Objekt unterstützt diese Eigenschaft oder Methode nicht
Das fs.FileExists meckert Tia an.
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
ich habe nicht richtig geschaut welche Objekte du wie verwendest ...
Vielleicht schaust du aber mal hier : FileExists
Dort wird dasselbe Problem behandelt ...
Ich habe es gelöst bekommen.
Folgendermaßen:

Code:
'Pfad und Datei festlegen
Pfad = "Storage Card SD\Taktzeitarchiv\"
Datei = "Archiv.csv"


'Objekt für das Filehandling erstellen
Set fs = CreateObject("filectl.filesystem")
Set f= CreateObject("filectl.file")
Set fso = CreateObject("filectl.FileSystem")


'Kontrolle ob MMC Karte gesteckt ist
If fso.Dir("\Storage Card SD\") = "" Then     
    ShowSystemAlarm "SD Karte ist nicht gesteckt, daher Abbruch der Datenübertragung"
Else     
    
      
'Kontrolle ob Verzeichnis vorhanden. Wenn nicht, dann Verzeichnis erstellen
If fs.dir(Pfad) = "" Then
    fs.mkdir(Pfad)
    f.close
End If

'Kontrolle ob CSV.Datei vorhanden. Wenn nicht, dann CSV.Datei erstellen
If fs.dir(Pfad + Datei) = "" Then
    f.open Pfad + Datei, 8
    f.LinePrint "Datum" & ";" & "Uhrzeit" & ";" & "Artikel" & ";" & "Solltaktzeit" & ";" & "Isttaktzeit" & ";"
    f.close
End If

Es macht auf jedenfall jetzt was es soll.
Muss jetzt nur das Fehlerhandling noch einbinden.
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Hallo zusammen,

ich habe die Archiv Funktion erfolgreich umgesetzt.
Jetzt geht es darum, nach einer bestimmten Anzahl an Einträgen, die Datei zu verschieben. Aktuell lasse ich einen Zähler in der SPS mit laufen und nach erreichen der Sollvorgabe, stoße ich ein Skript zum weg kopieren der vollen csv.Datei und anlegen einer neuen csv. Datei.

Klappt auch alles.
Gibt es dennoch eine Möglichkeit die aktuelle Zeilennummer, die man zuletzt beschrieben hat in der csv. Datei herauszulesen?

Danke und Gruß
Willi
 

Heinileini

Well-known member
Beiträge
5.041
Punkte Reaktionen
1.074
Zuviel Werbung?
->Hier kostenlos registrieren
Gibt es dennoch eine Möglichkeit die aktuelle Zeilennummer, die man zuletzt beschrieben hat in der csv. Datei herauszulesen?
:unsure: Was meinst Du damit? Die ZeilenNr wird doch normalerweise nicht in die csv-Datei geschrieben.
Wozu brauchst Du die ZeilenNr? Um zu kontrollieren, ob zwischen den Sätzen der verschobenen und der aktuellen Datei eine Lücke klafft, also Sätze fehlen/verloren gegangen sind?
Du könntest in der Tabelle eine Spalte für die ZeilenNr anfügen.
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
:unsure: Was meinst Du damit? Die ZeilenNr wird doch normalerweise nicht in die csv-Datei geschrieben.
Wozu brauchst Du die ZeilenNr? Um zu kontrollieren, ob zwischen den Sätzen der verschobenen und der aktuellen Datei eine Lücke klafft, also Sätze fehlen/verloren gegangen sind?
Du könntest in der Tabelle eine Spalte für die ZeilenNr anfügen.
Hallo Heinileini,

Also, ich hänge ja nach jeder Runde die aktuelle Zeit eine Zeile unter dem letzten Eintrag an.

Wenn ich jetzt z.B. 1000 Taktzeiten archiviert habe, will ich die Datei speichern und eine neue anlegen. Das klappt ja soweit.
Aber, der Zähler ist aktuell in der SPS.
Ich dachte, wenn ich jetzt bei jedem Durchlauf des Skriptes die Nummer der Zeilen (Die Zeilennummer aus Excel) auslesen könnte wo ich gerade abspeichere, dann wüsste ich ja, wann ich die Zeile 1000 beschreibe.

Die würde ich dann noch beschreiben und im Anschluss direkt das speichern anstoßen (wäre dann halt außerhalb der SPS), was ich in dem Falle schöner finden würde.

Danke
Willi
 

Heinileini

Well-known member
Beiträge
5.041
Punkte Reaktionen
1.074
Das habe ich leider immer noch nicht verstanden.
Nach jeder Runde heisst nach jedem Satz oder nach jedem Block von 1000 Sätzen?
Wo hängst Du die aktuelle Zeit eine Zeile nach dem letzten Eintrag an? In der Tabelle in der SPS oder in der csv-Datei?
Deinen Satz verstehe ich jetzt so, dass Du nach jedem "Tabellen"-Satz, den Du in die csv schreibst einen weiteren Satz schreibst, der nur die aktuelle Zeit enthält.

Ich hoffe, mein Verständnis ist richtig, dass Du die csv-Datei mit der SPS/HMI erzeugst und in Excel einlesen willst?
 
Oben