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

volker

Supermoderator
Teammitglied
Beiträge
5.524
Punkte Reaktionen
949
Zuviel Werbung?
->Hier kostenlos registrieren
Grundsätzlich sehe ich in den Scripten keinen Fehler.
Wie oft wird das Script aufgerufen?

Problematisch sehe ich ehr das beim einlesen der Zeilenanzahl ein Bit gesetzt wird welches das 2te Script startet.
Wenn Wertänderung das Script startet wird das 2 mal ausgeführt. 0->1 und bei 1->0
Ich gehe mal davon aus, dass "DB_Skriptvariablen_Taktzeitarchiv_umkopieren" auf Aktualisierung ständig Fortlaufend steht.
Ich würde das 2.te Script ehr über ein call Script2 im ersten Script starten.

Dein Script 2 wird gestartet wird bevor Script 1 fertig ist und reit sich in den Stapel ein (2 mal)
Und mit dem Rücksetzen von SmartTags("DB_Skript_Skript_Archiv") = False wird Script 1 erneut aufgerufen wegen Wertänderung

Den 2.ten Aufruf kannst du so verhindern.
Naja, verhindern nicht aber das Script wird sofort wieder verlassen.
Wirklich verhindern kannst du das wenn du ein Byte oder Int benutzt und das Script bei Grenzwert überschritten anstößt.
Das generiert aber eine Systemmeldung. Ich verwende eigentlich nur diese Variante. Scheiß auf die Meldung.
Code:
If SmartTags("DB_Skript_Skript_Archiv") = False then
    exit sub
end if

Das gleiche bei Script 2
Code:
if not "DB_Skriptvariablen_Taktzeitarchiv_umkopieren" then 'so spart du dir das = true/false
    exit sub
end if

Warum steht dort eine 9 und nicht 9999?
Code:
'Kontrolle ob beschriebene Zeilenzahl größer 9999 ist. Wenn ja, dann umkopieren
If Zeilenanzahl > 9 Then '????????????????
'Taktzeitarchiv umkopieren
'    SmartTags("DB_Skriptvariablen_Taktzeitarchiv_umkopieren") = True
    call Script2
'----------------------- oder so ----------------------------------
  Quelle = "\Storage Card SD\Taktzeitarchiv\Archiv.csv"
  Ziel = "\Storage Card SD\Sicherung_Taktzeitarchiv\"
  If fs.dir(Ziel) = "" Then
    fs.mkdir(Ziel)
  End If
  fs.filecopy Quelle , Ziel & "Taktzeitarchiv" & "_"  & DD & "_" & MM & "_" & JJJJ & "_" & HH & "_" & Min & "_" & Sek & ".csv"         
  fs.kill Quelle
  Set fs = Nothing
  Set fso = Nothing
End If
Ich würde die paar Zeilen für das umkopieren direkt in Script1 einbetten

Beim erzeugen der Datei verwendest du auch den Modus 8 (also anhängen).
Das Funktioniert. Besser wäre Modus 2 (erstellen).
Damit schlägst du sogar 2 Fliegen mit einer Klappe. Denn dann kannst du dir das löschen der alten Datei (kill) sparen.
Ob das einen Unterschied in der Laufzeit oder so macht weiß ich nicht.

Das erzeugen der Datei, danach das Schließen und erneute öffnen zum Anhängen sehe ich unproblematisch.
Das mache ich auch so und hatte noch nie Probleme damit.

EDIT:
PN/DP war etwas schneller mit dem abschicken während ich noch an der Antwort gearbeitet habe.
 
Zuletzt bearbeitet:

PN/DP

User des Jahres 2011-2013; 2015-2017; 2020-2021
Beiträge
18.455
Punkte Reaktionen
5.490
Code:
if not "DB_Skriptvariablen_Taktzeitarchiv_umkopieren" then 'so spart du dir das = true/false
    exit sub
end if
Ich bin zwar auch kein Freund von unnötigen expliziten Vergleichen von BOOL-Werten mit True/False, aber bei VBS (automatische Datentyp-Wahl!) und speziell im Zusammenhang mit Siemens WinCC flexible/TIA hatte ich schon Konstrukte, wo die automatische Datentypwahl zu falscher/ungewollter VBS-Übersetzung geführt hat und wo man dann tatsächlich If SmartTags("hmivar") = False then schreiben musste. Deshalb habe ich mir angewöhnt, in VBS im Zweifelsfall auf True/False zu vergleichen.

Harald
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Wie schon geschrieben, würde ich aber das Skript Archiv_Kopieren_Loeschen() gar nicht über eine Wertänderung aufrufen, sondern das erste Skript kann dieses Skript direkt aufrufen.

Hallo Harald,
genau so habe ich das jetzt gelöst und die Überlast ist weg.


Ebenso die bisher "umständliche" Vorgehensweise, was die Erzeugung des Datums und der Uhrzeit betrifft.

Das "On Error Resume Next" habe ich auch in den Skripten eingefügt.

Jetzt läuft es auf jedenfall ohne Probleme durch und meldet auch kein "Überlast Skript".

Warum steht dort eine 9 und nicht 9999?
@ Volker: Das war nur zum testen :) . Später kommt die 9999 da rein.

Dazu hätte ich noch eine Frage. Könnte es Laufzeit-Probleme geben, wenn so viele Zeilen gezählt werden müssen bei jedem Skriptdurchlauf?

Gruß Willi
 

Heinileini

Well-known member
Beiträge
4.984
Punkte Reaktionen
1.066
Dazu hätte ich noch eine Frage. Könnte es Laufzeit-Probleme geben, wenn so viele Zeilen gezählt werden müssen bei jedem Skriptdurchlauf?
Grundsätzlich: JA.
Deinen Umweg über die Zählerei finde ich recht "unschön". Wenn Du wirklich die ZeilenNr benötigst, würde ich sie mit in die csv-Datei mogeln.
Ich habe aber nicht wirklich verstanden, warum sie überhaupt relevant für Dich bzw. den Auswerter der csv-Datei sein soll.
Steuerungs-intern müsstest Du doch einen Zähler aufbauen können, der unabhängig von der bereits in die csv-Datei geschriebenen Anzahl Sätze arbeiten kann und ggfs - falls überhaupt nötig - einmalig am Anfang (was auch immer das sein mag) Deiner SchreibAktionen synchronisiert werden kann. Diese Zählerei vor dem Schreiben jeder einzelnen Zeile in die Datei zu wiederholen, finde ich schon recht abenteuerlich.
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Zuviel Werbung?
->Hier kostenlos registrieren
Grundsätzlich: JA.
Deinen Umweg über die Zählerei finde ich recht "unschön". Wenn Du wirklich die ZeilenNr benötigst, würde ich sie mit in die csv-Datei mogeln.
Ich habe aber nicht wirklich verstanden, warum sie überhaupt relevant für Dich bzw. den Auswerter der csv-Datei sein soll.
Steuerungs-intern müsstest Du doch einen Zähler aufbauen können, der unabhängig von der bereits in die csv-Datei geschriebenen Anzahl Sätze arbeiten kann und ggfs - falls überhaupt nötig - einmalig am Anfang (was auch immer das sein mag) Deiner SchreibAktionen synchronisiert werden kann. Diese Zählerei vor dem Schreiben jeder einzelnen Zeile in die Datei zu wiederholen, finde ich schon recht abenteuerlich.

Hallo Heinileini,

ich dachte es mir schon. Dann gehe ich den Weg anders.
Dann würde ich doch in der SPS mit zählen und bei erreichen der gewünschten Zahl, ein Bit setzen.
Dieses könnte ich ja ruhig bei jedem Skriptdurchlauf auf True abfragen. Wenn es dann True ist, kopiere ich um. Andernfalls überspringt er es halt.


Gruß Willi
 

Heinileini

Well-known member
Beiträge
4.984
Punkte Reaktionen
1.066
Da fällt mir gerade etwas anderes ein.
Die Anzahl Zeichen pro geschriebener Zeile ist konstant? Und es gibt eine Möglichkeit, die Länge der Datei abzufragen?
Dann könntest Du daraus die Anzahl Sätze in der Datei berechnen.

Oder aber:
Nicht um die genaue Anzahl Sätze kümmern, sondern die csv-Datei bis zu einer gewissen Länge anwachsen lassen, um dann eine neue Datei anzulegen?
 
Zuletzt bearbeitet:
OP
P

Platinum

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

Die Anzahl kann Variieren. Ich habe es jetzt so gelöst, das es in der SPS gezählt wird. Nach erreichen der gewünschten Anzahl setze ich mir ein Bit. Dieses wird im Skript abgefragt. Ist das Bit True, rufe ich das Skript zum umkopieren direkt in dem Skript wo es archiviert wird auf. Das läuft jedenfalls jetzt ohne Fehler sauber durch.

Eine Frage noch. Ich bin im nächsten Step ein Logbuch am erstellen, welches bestimmte Werte, die geändert wurden ebenfalls in eine csv Speichern soll.
Nach dem Neustart des Panels (TP1200 Comfort), schreibt er "Skriptfehler Logbuch - 2147024809 no screen item index 0" in die Systemmeldungen.
(Habe das On Error Resume Next implementiert).
Ich habe einen Startbildschirm, da ist kein Element drin, nur ein Bild.
Frage ist, warum stößt das Skript überhaupt an beim Neustart des Panels?

Gruß Willi

Edit:

Hier auch gerne der Skriptcode mal

Code:
Sub Logbuch(ByRef Input)
'Skript dient dazu, ausgewählte Werte/Funktionen in einem Logbuch
'auf Änderungen zu erfassen und abzuspeichern


'Variablen definieren
Dim t, s
Dim strName
Dim Objekt, ObjektName, VAR_Objekt, ObjElement, Bildname, StartbildName
Dim f, fs, fso
Dim WkzName
Dim AlterWert, NeuerWert
Dim Pfad, Datei


On Error Resume Next

'Aktives Bild und Objekt bestimmen
Set ObjElement = HmiRuntime.ActiveScreen.ActiveScreenItem    'Aktives Element
Bildname = ObjElement.Parent.ObjectName        'Bildname
VAR_Objekt = ObjElement.ObjectName        'Objektname

'Objekt definieren
Set Objekt = HmiRuntime.Screens(Bildname).ScreenItems(VAR_Objekt)

'Variablen vorbesetzen
WkzName = SmartTags("DB_Akt_Daten_Daten_Wkz-Name")
NeuerWert = Input
t = Now
strName = Year(t) & "." & Right("0" & Month(t), 2) & "." & Right("0" & Day(t), 2) & "_" _
  & Right("0" & Hour(t), 2) & ":" & Right("0" & Minute(t), 2) & ":" & Right("0" & Second(t), 2)


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

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


'Kontrolle ob MMC Karte gesteckt ist
If fso.Dir("\Storage Card SD\") = "" Then     
    ShowSystemAlarm "SD Karte ist nicht gesteckt, daher kann Logbucheintrag nicht gespeichert werden"
Exit Sub
End If


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

If Err.Number <> 0 Then
    ShowSystemAlarm "Skriptfehler Logbuch" & Err.Number & " " & Err.Description
    Err.Clear
    Exit Sub
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" & ";" & "Bildname" & ";" & "Objektname" & ";" & "Alter Wert" & ";" & "Neuer Wert" & ";"
    f.close
End If

If Err.Number <> 0 Then
    ShowSystemAlarm "Skriptfehler Archiv" & Err.Number & " " & Err.Description
    Err.Clear
    Exit Sub
End If


'Pfad und Datei öffnen und beschreiben, danach wieder schließen   
f.open Pfad + Datei, 8        '8 = Daten anhängen
f.LinePrint strName & ";" & WkzName & ";" & Bildname & ";" & ObjektName & ";" & AlterWert & ";" & NeuerWert & ";"
f.close

If Err.Number <> 0 Then
    ShowSystemAlarm "Skriptfehler Archiv" & Err.Number & " " & Err.Description
    Err.Clear
    Exit Sub
End If


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

PN/DP

User des Jahres 2011-2013; 2015-2017; 2020-2021
Beiträge
18.455
Punkte Reaktionen
5.490
Wird das Skript vielleicht auch bei "Wertänderung" einer Variable aufgerufen?

Harald
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.141
Punkte Reaktionen
2.737
... wir wissen ja nicht genau, wie Siemens intern so tickt ... prinzipiell kann dieses Ereignis ggf. auch durch das Initialisieren des Bildes beim Neustart erzeugt werden ...
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Zuviel Werbung?
->Hier kostenlos registrieren
Du könntest ja in dem Script abfragen ob der ActiveScreen deinem gewünschten Bild überhaupt entspricht ...
Hallo Larry,

das hatte ich so schon mal drin, fand es aber unschön und hatte gehofft eine bessere Lösung zu finden.
... wir wissen ja nicht genau, wie Siemens intern so tickt
Das ist das Problem :)

Trotzdem Danke euch
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Du könntest ja in dem Script abfragen ob der ActiveScreen deinem gewünschten Bild überhaupt entspricht ...
Hallo Larry,

habe es jetzt wieder so umgesetzt. Wenn das Startbild Aktiv ist, dann gehe ich zum Exit Sub.
Funktioniert so auch.

Ich habe aber in dem eigentlichen Bild, wo Bsp. das E/A Feld welches ich speichern möchte drin ist, ein Problem.
Ich habe mit Eingabe abgeschlossen in einem E/A Feld das Skript ausgelöst. Klappt auch soweit. Er schreibt den Alten und neuen Wert entsprechend in die CSV.Datei.
Ich schreibe auch den Namen des Objektes mit in die CSV.Datei.
Jetzt das Problem. Ich kam erst nicht drauf, habe aber dann gesehen, das das Panel nach "Eingabe abgeschlossen" in ein anderes E/A Feld springt (welches aber kein Skript auslöst) und in der CSV.Datei dann der Name des anderen E/A Feldes eingetragen wird.

Wieso springt das Panel nach Eingabe abgeschlossen auf ein anderes E/A Feld? Hatte das schonmal jemand?

Danke und Gruß
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.141
Punkte Reaktionen
2.737
Erklären kann ich es dir nicht wirklich - ich würde sagen, dass "Eingabe abgeschlossen" den Fokus auf das nächste Element in der Rangliste (also der Numerierung) übergibt.
Ich bin jetzt gerade nicht sicher, meine aber, dass du es mit etwas Trickserei erreichen kannst, dass das letzte E/A-Feld den Fokus behält ... (über erneutes Aufrufen des Screens mit Angabe des anzuwählenden E/A-Feldes)
 
OP
P

Platinum

Well-known member
Beiträge
89
Punkte Reaktionen
3
Zuviel Werbung?
->Hier kostenlos registrieren
Erklären kann ich es dir nicht wirklich
OK.
Das Problem ist, das ich mit Eingabe abgeschlossen das Skript ausführe. Bis ich den Screen neu geöffnet habe, ist das Skript vermutlich schon lange fertig.
Hast Du sonst eine Idee wie ich den Namen abspeichern kann? Evtl. beim Aktivieren ein Skript ausführen was nur den Namen speichert?
Auch nicht die schöne Lösung :-(

Gruß
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.141
Punkte Reaktionen
2.737
Vielleicht am Start deiner Prozedur schon den Namen abspeichern - ich weiß nicht wann du es aktuell tust ...
Oder in dem Moment in dem das E/A-Feld angewählt wird ihn auf eine interne Variable schreiben ...
 

PN/DP

User des Jahres 2011-2013; 2015-2017; 2020-2021
Beiträge
18.455
Punkte Reaktionen
5.490
Bei Aktivieren des E/A-Feldes den Name in eine HMI-Variable schreiben (und ggf. auch den aktuellen Prozesswert speichern), und bei Eingabe abgeschlossen den Wert aus der HMI-Variable verwenden.

Harald
 
Oben