Wie VBA Scripte mit der S7 verbinden

tommylik

Level-2
Beiträge
115
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen,

Habe derzeit ein S7-Projekt auf einer 416F-3 laufen.
Programmerstellung wird mit der 5.6 gemacht.
Die Visualisierung wird mit Zenon von Copa-Data dargestellt.
Es gibt 12 Triggersignale im S7 Programm die jeweils ein VBA Script in Zenon auslöst.
Die Scripte kopieren Daten zu verschiedenen Zeitpunkte auf den Server.
Eigentlich eine gute Idee funktioniert auch ist aber nicht 100% tauglich für die Produktion wegen der möglichen mehrfachen aufrufen pro Zyklus.
Es wurden auch schon Verriegelungen bedacht, das die Scripte nacheinander abgearbeitet werden.
Damit die Visu nicht sporadisch blockiert wird.
Das Problem ist die RT von Zenon, die unterstützt keine Multiinstanzen das mehrere Scripte parallel laufen können.

Meine Frage an Euch mit welcher anderen externen Software (WinCC ist keine Option)
die ich mit der S7 verbinden kann, VBA unterstützt und auch unterstützt das mehrere Scripte gleichzeitig ausgeführt werden
könnte ich das umsetzen?

Für Eure Ideen vielen Dank im voraus.

Mfg Tommylik
 
Muss denn definitiv zum Zeitpunkt des Triggersignals geschrieben werden? Falls nein und die Trigger nicht zu oft kommen könntest Du ja die Trigger in ein Array schreiben und in ZenOn dies Element für Element abarbeiten lassen und immer wenn ein Element TRUE ist wird das entsprechende Script abgearbeitet und dann geht es weiter, allerdings müsstest Du Dir dann noch ein Handshake Verfahren ausdenken, damit ein Script nicht mehrfach ausgeführt wird weil der Trigger vielleicht noch anliegt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Oliver,

Vielen Dank für deine Antwort.

Wäre besser damit die RT bis zum nächsten anderem Triggersignal wieder frei ist.
Es kann ja auch vorkommen das mehrere Triggersignale gleichzeitig anstehen.
Das habe ich schon so verriegelt das ein Signal nach dem anderen abgearbeitet wird.
Es ist auch schon bedacht das wenn ein Script ausgeführt wird das das Triggersignal am Ende des Scriptes auf 0 gesetzt wird.
Somit kann der Trigger nicht mehr anliegen.
Mein Problem ist eigentlich mehr das die RT blockiert werden könnte weil halt die Scripte erst fertig sein müssen.
Einige Scripte brauchen länger weil die zu kopieren Daten höher sind.

Wenn die Scripte gleichzeitig laufen könnten wäre auch die RT nicht belegt. Wie Multi-Instanz.


Vielen Dank nochmal für deine Hilfe

Mfg Tommylik
 
Zuletzt bearbeitet:
@Tommy:
Wenn hier wirklich VBA deine Basis ist dann wird es schwierig. Vielleicht könnte man etwas raten wenn wir den Code deiner Routine sehen können. Aber generell solltest du da eher Richtung .Net gehen (also z.B. VB.Net). Hier könntest du schon erreichen, dass deine Visu selbst responsibel bleibt (und das heißt nicht zwangsläufig, dass du Tasks oder Backgroundworker programmieren müßtest ...

Gruß
Larry
 
Hallo Larry,

Vielen Dank für deine Antwort.

Also VBA ist meine Basis aber Zenon kann auch über Projekt Add-Ins VB.net oder C#.
Aber laut dem Copa-Data Support würde mir VB.net oder C# auch nicht helfen da die RT das Problem ist.
Egal wie ich es umsetzte die RT kann nur ein Script nach dem anderen abarbeiten.

Es sei denn du kennst dich mit Zenon aus und kennst ein paar Tricks.

Hier die VBA Version.

VBA_Version.JPG


Hier der Code vom Zenon Projekt.
Der ist sehr lang ich habe fast alles raus gelöscht was nicht mit dem Thema zu tun hat.
Falls etwas unlogisch sein sollte dann habe ich etwas zu viel gelöscht.


Code:
Option Explicit


' Definition der Container mit Onlinevariablen für
' jeden Zugriff auf Runtimevariablen aus dem VBA-Skript heraus.


Public WithEvents Container As OnlineVariable
Public PDE_Container As OnlineVariable


Public Sub Profinet_Init()


'##### PROFINET-DIAGNOSE INITIALISIEREN #####


Dim i As Integer
Dim Profinet As Variable


For i = 1 To 256
    PN_Container.Add "Profinet_Station[" & i & "]"
Next i
PN_Container.Add "Profinet_Device_aktiv"
PN_Container.Define


'interne Variablen für Profinet-Devicenummer initialisieren
For i = 1 To 256
    
    Set Profinet = thisProject.Variables.Item("Profinet_Station[" & i & "]")
    Profinet.Value = i


Next i


thisProject.RtFunctions.Item("fct_Profinet_Systemnummer_setzen").start


'Vorbereitung zum Anklicken einer PROFINET-Station
PN_Container.Undefine
PN_Container.Add "Profinet_Device_aktiv"
PN_Container.Define
    
End Sub




Public Sub Profinet_Detailfenster_verschieben()


'##### PROFINET-DETAILFENSTER VERSCHIEBEN #####


    Dim meinBild As DynPicture
                 
    Set meinBild = thisProject.DynPictures.Item("Profinet_Details")
        
 
    ' Positionskorrektur in x-Richtung
    If xkoord > (1280 - meinBild.Width) Then ' Falls der rechte Rand erreicht ist, das Bild an die linke Seite anheften
    
        xkoord = xkoord - meinBild.Width - breite ' x-Koordinate um Breite des Detailfensters und des Stationssymbols verschieben
        
    End If
    
    ' Positionskorrektur in y-Richtung (124 steht für die Höhe der Kopfzeile)
    If (ykoord + 124) > (1024 - meinBild.Height) Then ' Falls der untere Rand erreicht ist, das Bild entsprechne nach oben schieben
    
        ykoord = ykoord - ((thisProject.ykoord + 124) - (1024 - meinBild.Height)) ' Differenz abziehen, um Bild höher schieben
        
    End If
    
    ' Bild an neue Position verschieben
    ' wird normalerweise direkt neben rechtem Eck des Symbols geöffnet
    ' (Der Wert 124 ist die Höhe der Kopfzeile)
    
    meinBild.Move xkoord, ykoord + 124, meinBild.Width, meinBild.Height
   
End Sub


Private Sub Project_Active()


'##### STARTRUTINE DER RUNTIME #####
    
  
    Set PN_Container = thisProject.OnlineVariables.CreateOnlineVariables("profinet")
    Set STG_Container = thisProject.OnlineVariables.CreateOnlineVariables("stellgeraete")
    Set Ident_Container = thisProject.OnlineVariables.CreateOnlineVariables("ident")
    Set Typ_Container = thisProject.OnlineVariables.CreateOnlineVariables("typverwaltung")
    Set Schrauber_Container = thisProject.OnlineVariables.CreateOnlineVariables("schrauberkrempl")
    
   'Container mit den Variablen für die Rueckverfolgung
    Set PDE_Container = thisProject.OnlineVariables.CreateOnlineVariables("PDE")
 
    PDE_Container.Add "PDE_PraegeCode"
    PDE_Container.Add "PDE_OrdnerName"
    PDE_Container.Add "PDE_OrdnerErstellen"

    PDE_Container.Add "PDE_Bolzen10R01"
    PDE_Container.Add "PDE_MS15R01"
    PDE_Container.Add "PDE_Kamera15R01"
    PDE_Container.Add "PDE_Kelchung15R01"
    PDE_Container.Add "PDE_Bolzen15R02"
    PDE_Container.Add "PDE_Intec15R02"
    PDE_Container.Add "PDE_HWH30R01"
    PDE_Container.Add "PDE_HWH30R02"
    PDE_Container.Add "PDE_HWH40R01"
    PDE_Container.Add "PDE_HWH50R01"
    PDE_Container.Add "PDE_HWH60R01"
    PDE_Container.Add "PDE_HWH60R02"
   
    PDE_Container.Define
        
End Sub


Private Sub Project_Inactive()
    
    '##### ENDERUTINE DER RUNTIME #####
    
    On Error Resume Next
    Container.Undefine ' Online Container wieder löschen
    Debug.Print "Der Container ist undefined"
       
    PDE_Container.Undefine
    thisProject.OnlineVariables.DeleteOnlineVariables ("PDE")
   
End Sub
  


'Dateien vom Bolzen kopieren 10R01
Public Sub Bolzen_10R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


'Fehlerroutine: Datei nicht vorhanden
If oFSO.FileExists("\\TOX10R01\AppData\" & strDatei & "TOX10R01.txt") = False Then
   'File doesn't exist
thisProject.Variables.Item("PDE_10R01BolNoFile").Value = 1
Else
   'File exist
oFSO.CopyFile "\\TOX10R01\AppData\" & strDatei & "TOX10R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_Bolzen10R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub




'Dateien von der Kelchung kopieren 15R01
Public Sub Kelchung_15R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\TOX15R01\AppData\" & strDatei & "TOX15R01.txt") = False Then
   'File doesn't exist
thisProject.Variables.Item("PDE_15R01KelNoFile").Value = 1
Else
   'File exist
oFSO.CopyFile "\\TOX15R01\AppData\" & strDatei & "TOX15R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_Kelchung15R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Bolzen kopieren 15R02
Public Sub Bolzen_15R02()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


Set oFSO = CreateObject("Scripting.FileSystemObject")


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


If oFSO.FileExists("\\TOX15R02\AppData\" & strDatei & "TOX15R02.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_15R02BolNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\TOX15R02\AppData\" & strDatei & "TOX15R02.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_Bolzen15R02").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Kleben kopieren 15R02
Public Sub Intec_15R02()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\INT15R02\AppData\" & strDatei & "INT15R02.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_15R02IntNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\INT15R02\AppData\" & strDatei & "INT15R02.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_Intec15R02").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 30R01
Public Sub HWH_30R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH30R01.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_30R01HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH30R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH30R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 30R02
Public Sub HWH_30R02()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH30R02.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_30R02HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH30R02.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH30R02").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 40R01
Public Sub HWH_40R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH40R01.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_40R01HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH40R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH40R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 40R02
Public Sub HWH_40R02()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH40R02.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_40R02HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH40R02.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH40R02").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 50R01
Public Sub HWH_50R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH50R01.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_50R01HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH50R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH50R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schrauber kopieren 60R01
Public Sub Schrauber_60R01()


Dim strNr As Variant
Dim strOrdner As String
Dim oFSO As Object


strNr = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNr), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


'Fehlerroutine: Datei nicht vorhanden
If oFSO.FileExists("D:\S7_Export\Schrauber\????\*.*", "D:\S7_Export\AppData\" & strOrdner & "\") = False Then
   'File doesn't exist
thisProject.Variables.Item("PDE_60R01RexNoFile").Value = 1
Else
   'File exist
oFSO.MoveFile "D:\S7_Export\Schrauber\????\*.*", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_Schrauber60R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 60R01
Public Sub HWH_60R01()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH60R01.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_60R01HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH60R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH60R01").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub


'Dateien vom Schweißen kopieren 60R02
Public Sub HWH_60R02()


Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object


strNrO = thisProject.Variables.Item("PDE_OrdnerName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "00000000000")
strDatei = Format(CStr(strNrD), "00000000000")


Set oFSO = CreateObject("Scripting.FileSystemObject")


If oFSO.FileExists("\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH60R02.txt") = False Then
    'File doesn't exist
thisProject.Variables.Item("PDE_60R02HwHNoFile").Value = 1
Else
    'File exist
oFSO.CopyFile "\\PEGASUS\AppData\" & strOrdner & "\" & strDatei & "HWH60R02.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If


thisProject.Variables.Item("PDE_HWH60R02").Value = 0 'Tiggersignal auf 0 setzen
         
Set oFSO = Nothing


End Sub

Über Projekt Add-Ins kann man auch in VB.Net oder in C# programmieren.

VB_Net.JPG

Da hätte ich aber das Problem das ich nicht weiß wie man bei Zenon ein Add-IN integriert und wie ich die S7 Variablen in den Online Container bekomme.
Dieses Zenon Projekt ist ohne Add-IN somit konnte ich mir für VB.Net nichts aneignen.

Deswegen denke ich die ganze Zeit daran es außerhalb von Zenon umzusetzen also mit einer anderen Software die Multitasking unterstützt.

Vielen Dank nochmal für deine Hilfe.

Mfg Tommylik
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Es wäre erst einmal festzustellen, welche Aktion denn lange dauert.
Ein Umkopieren von Dateien und dann noch auf Netzwerkfreigaben könnte ein Punkt dafür sein. Vielleicht könnte das Umkopieren von einer anderen Anwendung außerhalb der Zenon Runtime vorgenommen werden. Aus deiner Runtime kopierst du die Daten nicht um, sondern teilst dieser Anwendung nur mit: bitte Datei von a nach b verschieben, dann löschen. Falls das mit dem Ablauf nicht passt, dann zumindest Dateien verschieben noch lokal, und das transferieren über Netzwerk macht dann die andere Anwendung.

Aber wie gesagt, ich würde mal in den existierenden Skripten ein Logfile mit Zeitstempeln schreiben, mit der Information wann eine Aktion gestartet und wann beendet wurde. Erst dann weißt du wo es hakt und wo es etwas zu optimieren gibt.
 
Hallo Thomas,

Vielen Dank für deine Antwort.

Gerade das umkopieren kann ich nicht mit einer anderen Anwendung machen,
weil das Triggersignal mit einem String (Prägecode) verknüpft ist.
Das Script sucht diesen String der den Anfang des Dateinamens bildet in dem angegebenen Ordner.
Die Quellen sind Netzwerkfreigaben das Ziel ist ein Ordner mit dem String als Ordnername.

Ich kenne keine andere Anwendung die ich an die S7 anbinden kann damit sie die Triggersignale und Strings empfangen kann
und dann Scripte ausführt. Zenon kann das. Aber blockiert die RT weil sie nicht Multitasking fähig ist.
Deswegen wollte ich das mit einer anderen Software machen.


@ Larry

Aber generell solltest du da eher Richtung .Net gehen (also z.B. VB.Net).

Ich habe heute nochmal mit dem Support von Zenon gesprochen.
Mit Add-In Framework ist es doch möglich da habe ich beim letzten mal etwas falsch verstanden.
Es gibt in Zenon auch ein integriertes Visual Studio (VSTA) um in C# zu programmieren. Das wäre aber das gleiche was ich jetzt schon mit VBA habe.
Das würde auch die RT blockieren.
So ein Add-In läuft in einem eigenen Thread. Das Add-In kann man in VB.Net oder in C# programmieren.


Vielen Dank noch mal für die Hilfe.

Mfg Tommylik
 
Hallo Tommylik,

die Visualisierung läuft wo? Auf einem PC oder einem Panel?

Gibt es eine Möglichkeit, die ganze Tätigkeit direkt ins Betriebssystem zu schieben? Daß Du einen parallelen Task hast, den Du a) aufrufst oder b) triggerst, so daß der betriebssystemnah die Aufgabe erledigt? Denn das OS ist ja von sich aus multitasking fähig.

Wenn Du keine direkte Möglichkeit hast, Prozesse aufzurufen, wäre aber z.B. b) das Triggern möglich. Denn aus dem Script kannst Du bestimmt Dateien schreiben. Also Dein "Kopier"-Task läuft dauerhaft im Hintergrund auf niedriger Priorität und überwacht z.B. ein Verzeichnis. Sobald Du ihn benötigst, legst Du eine Datei mit den Parametern in das Verzeichnis. Der Task liest die aus und arbeitet entsprechend die Aufgabe ab.
Das sind natürlich keine hoch-respinsiven Möglichkeiten, aber vielleicht reicht es.

Somit könnte man ggf. auch im Betriebssystem den Tasks unterschiedliche Prioritäten geben...

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

Vielen Dank für deine Antwort.

Also die Visualisierung läuft auf einem PC.

Alles was mit dem Zenon Editor erstellt wird, muss übersetzt werden und dann an die Run Time übertragen werden.
Die RT bekommt die Triggersignale von der SPS und gibt an das Betriebssystem die Aufgaben weiter die Daten zu kopieren.
Von meiner Sicht aus kann ich nichts in das Betriebssystem schieben da ich die SPS für die Triggersignale brauche
und Zenon dieses Signale empfangen kann. Das Betriebssystem kann das nicht ohne eine Software.

Ein Beispiel:

Roboter X macht einen Kleberauftrag. Dieser Kleberauftrag ist überwacht. Wenn der Roboter fertig ist wird eine Fertigmeldung gesetzt.
Mit dieser Fertigmeldung wird in der RT eine Funktion ausgelöst die das Script startet.
Das Script sorgt dafür das von einem PC die Daten abgeholt werden und auf einem Server abgelegt werden.

Also wenn jemand von Euch eine andere Software kennt, die auch Triggersignale von einer S7 empfangen kann und dann in irgendeiner Form
Windows mit teilen kann das Windows eine bestimmte Datei (String/Prägecode) von Punkt A nach B kopieren soll, wäre das super.

Vielen Dank nochmal für deine Hilfe.

Mfg Tommylik
 
Für die S7 gibt es etliche freie Bibliotheken um damit zu kommunizieren, libnodave, Snap7, und weitere, oder auch direkt fertige Module in diversen Programmiersprachen wie Python. Damit könntest du im Hintergrund ein paar Tasks aufsetzen die unabhängig von der Visualisierung das gewünschte machen könnten.

Aber in Punkto Wartbarkeit und Nachvollziehbarkeit würde es schon besser in die Visualisierung passen. Solche Skripte laufen dann gefühlt immer unter dem Radar, und werden bei einer Datensicherung auch gerne mal vergessen. Außerdem benötigst du dann zusätzliche Verbindungsressourcen in der SPS, das kann kein Problem sein, sollte man aber im Hinterkopf behalten. Außerdem möchtest du wenn deine zusätzlichen Skripte Probleme bereiten diese wohl auch in der Visualisierung zur Anzeige bringen, hier wäre dann eine weitere Schnittstelle notwendig.
 
Hallo tommylik,

ich habe bereits mehr mit ZenOn und hätte da 1-2 Vorschläge für dich. Da du hauptsächlich Werte in Dateien ablegst würde ich dir die zweite Variante empfehlen.


1. PCE (Process Control Engine), könnte dir eventuell helfen, findest du im ZenOn ebenfalls unter den Programmierschnittstellen.
Dort kannst du normalerweise mehrere Prozesse starten die dann parallel ablaufen, die Frage ist nur ob das für deinen Umfang reicht.

2. Du kannst über die Zenon.Interop.DLL mit einer normalen VB.NET Applikation direkt auf die Runtime Variablen zugreifen, mit dem vollem Umfang, also auch OnlineVariables.
Damit könntest du dir eine kleine .exe Datei bauen die du dann als Datei in ZenOn einbindest und bei dem Application.Start immer mit startest.
Auf deine laufende Runtime kannst du dich mit folgendem Code einfach verbinden:

RSUOjbCOQzAAAzAAAzAwKkxgKhAlS5Spac2YLCXmwQMwAAMwAAMwAAMDBlAVCAqEBUwAAMwAAMwAAMwAAMwsIiBVUUFqm6o6vAJPoEBGIABGIABGIABGHjoDCAqUKWLVOlDHwC0n0kcBmAABmAABmAABpYz8P8BsM62qdaEei4AAAAASUVORK5CYII=


Sobald du zur RT verbunden bist kannst du über die obZenon, die als ZenOn.Application deklariert wurde auf alle Funktionen, gleich wie im integrierten VBA, zugreifen.

So könntest du dir in der VB.NET Applikation eine TaskFactory erstellen mit der du asynchron mehrere Prozesse parallel ablaufen lassen kannst.
 

Anhänge

  • ZenOn_Externer_Zugriff.PNG
    ZenOn_Externer_Zugriff.PNG
    18 KB · Aufrufe: 18
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Thomas,

Vielen Dank für deine Antwort.

Von libnodave habe ich schon gehört in Zusammenhang mit Excel.
Aber wenn ich das so überdenke was du geschrieben hast wird es mit einer Externen Software eher komplizierter.

Ich werde mich erstmal mit deine Vorschläge genauer befassen. Mal sehen ob das mir weiterhilft.

Vielen Dank nochmal für deine Hilfe.

Mfg Tommylik
 
Hallo Rabi,

Also von PCE habe ich noch nichts gehört. Und unter der Programmierschnittstelle ist sie auch nicht mit dabei.

Also dein 2 Vorschlag hört sich gut an. Von der Zenon.Interop.DLL habe ich mal was gelesen in Zusammenhang mit Add-In Framework.
Mit kleine .exe Datei bauen hast du mir einen schönen Schrecken eingejagt.
Aber gut, was benötige ich dafür? Das geht ja bestimmt nicht mit dem Zenon Editor.
Das hört sich aus deinem Munde sehr einfach an.
Wie sieht in meinem Fall der Aufbau aus. Wo muss ich den neuen OnlineContainer erstellen wenn ich das mit VB.Net mache?
Die Variablen von der SPS und die Makros wo wird das alles neu erstellt?
Wo kommt der Code hin aus deinem Screeshot?

Fragen über Fragen.

Zur Zeit habe ich das alles im thisprojekt in VBA. Kommt deine Idee in MyWorkspace?

Screenshot 2020-12-24 133123.png
Das klingt alles sehr interessant. Da muss ich mich erstmal in VB.net einlesen. z.B was eine TaskFactory ist.
Ich beneide Euch alle die richtig Programmieren können. Bei mir ist das alles Copy and Paste.

Vielen Dank noch mal für deine Hilfe.

Mfg Tommylik
 
Hallo Rabi,

Du hast mich mit deinen Vorschlägen weitergebracht könnte aber deine Hilfe gebrauchen da du dich ja anscheinend besser mit Zenon auskennst.

Zu deiner Info PCE gab es nur bis zur Version 7.20 ich habe 7.60 und ab dieser Version kann man mit Add-In Framework arbeiten.
Laut dem Support arbeitet ein Add-In in seinem eigenen Thread und blockiert nicht die RT.

Ich habe dann mit Hilfe von

https://onlinehelp.copadata.com/help/760/addin/html/ObjectModel Help.htm

folgendes begonnen:


Code:
using System;
using System.Diagnostics;
using Scada.AddIn.Contracts;
using Scada.AddIn.Contracts.Variable;

namespace PDE
{
    /// <summary>
    /// Description of Project Service Extension.
    /// </summary>
    [AddInExtension("OnlineContainer", "Online Container erstellen")]
    public class ProjectServiceExtension : IProjectServiceExtension
    {
        #region IProjectServiceExtension implementation

        IProject PDE_Project = null;
        IOnlineVariableContainer myContainer = null;
        string onlineContainerName = "MyOnlineContainer";

        public void Start(IProject context, IBehavior behavior)
        {
            // enter your code which should be executed when starting the SCADA Runtime Service
            PDE_Project = context;

            if (PDE_Project == null)
            {
                Debug.Print("Reference to project is null.", DebugPrintStyle.Error);
                return;
            }

            string myVariableName1 = "PDE_PraegeCode";   //Stringvariable
            string myVariableName2 = "PDE_FolderName";   //Stringvariable
            string myVariableName3 = "PDE_CreateFolder"; //Boolvariable
            string myVariableName4 = "PDE_NoFolder";     //Boolvariable
            string myVariableName5 = "PDE_FileCopy";     //Boolvariable
            string myVariableName6 = "PDE_NoFile";       //Boolvariable

            if (PDE_Project.OnlineVariableContainerCollection[onlineContainerName] == null)
            {
                //create a new online Container
                myContainer = PDE_Project.OnlineVariableContainerCollection.Create(onlineContainerName);
                //add variable to the container
                myContainer.AddVariable(myVariableName1); //Stringvariable
                myContainer.AddVariable(myVariableName2); //Stringvariable
                myContainer.AddVariable(myVariableName3); //Boolvariable
                myContainer.AddVariable(myVariableName4); //Boolvariable
                myContainer.AddVariable(myVariableName5); //Boolvariable
                myContainer.AddVariable(myVariableName6); //Boolvariable

                myContainer.Changed += MyContainer_Changed;

                //activate the online container itself
                myContainer.Activate();

            }

        }


        private void MyContainer_Changed(object sender, ChangedEventArgs e)
        {
            Was kommt hier rein ?????????????????????????????????????????????????????????? 
        }

        public void Stop()
        {
            // enter your code which should be executed when stopping the SCADA Runtime Service


            myContainer.Deactivate();
            myContainer.Changed -= MyContainer_Changed;
            PDE_Project.OnlineVariableContainerCollection.Delete(this.onlineContainerName);

        }

        #endregion
    }
}

Könnte jetzt deine Hilfe gebrauchen wie ich folgende 2 Skripte mit eingebunden bekomme.
Es gibt leider keinen Converter von VBA nach C#.

Code:
Public Sub Ordner_erstellen()
'Diese Modul erstellt einen Ordner

Dim strNr As String
Dim strText As String
Dim strPfad As String
Dim strOrdner As String
Dim oFSO As Object

strNr = thisProject.Variables.Item("PDE_FolderName").Value
strText = Format(CStr(strNr), "000000000000") 'String 12 für den Ordnernamen

'Exportpfad
strPfad = "D:\S7_Export\AppData"     ' Pfad einstellen
strOrdner = strText
   
Set oFSO = CreateObject("Scripting.FileSystemObject")
        
        If oFSO.FolderExists(strPfad) Then
            If Not oFSO.FolderExists(strPfad & "\" & strOrdner) Then
                oFSO.CreateFolder (strPfad & "\" & strOrdner)
                
                'SPS Trigger rücksetzen.
                thisProject.Variables.Item("PDE_CreateFolder").Value = 0
            End If
            
        Else
        'SPS informieren wenn Exportpfad nicht vorhanden.
        thisProject.Variables.Item("PDE_NoFolder").Value = 1
        End If
        
 Set oFSO = Nothing
 
End Sub

Code:
Public Sub FileCopy()

Dim strNrO As Variant
Dim strNrD As Variant
Dim strOrdner As String
Dim strDatei As String
Dim oFSO As Object

strNrO = thisProject.Variables.Item("PDE_FolderName").Value
strNrD = thisProject.Variables.Item("PDE_PraegeCode").Value
strOrdner = Format(CStr(strNrO), "000000000000") 'String 12 für den Ordnernamen
strDatei = Format(CStr(strNrD), "00000000000")     'String 11 für den Dateinamen         

Set oFSO = CreateObject("Scripting.FileSystemObject")

'Fehlerroutine: Datei nicht vorhanden
If oFSO.FileExists("\\TOX210R01\AppData\" & strDatei & "TOX210R01.txt") = False Then
   'File doesn't exist
thisProject.Variables.Item("PDE_NoFile").Value = 1
Else
   'File exist
oFSO.CopyFile "\\TOX210R01\AppData\" & strDatei & "TOX210R01.txt", "D:\S7_Export\AppData\" & strOrdner & "\"
End If

thisProject.Variables.Item("PDE_FileCopy").Value = 0 'SPS Trigger rücksetzen.
         
Set oFSO = Nothing

End Sub

Ich hoffe du kannst mir helfen.

Mfg Tommylik
 
Zuletzt bearbeitet:
Hi, wir nutzen für solche Sqchen ebenfalls NodeRed mit den entsprechenden Nodes für S7, das klappt immer gut. Speziell für Datenbankkommunikation mit Postgresql oder MSSql gibt es gute Nodes, mit denen sich das bewerkstelligen lässt. Und natürlich auch schreiben in Textdateien ist kein Problem. Das Ganze basiert auf Node.js und wird mit JavaScript programmiert bzw. auch oft ganz ohne Code. Einfach mal anschauen. Es gibt schon einige Hersteller, die das direkt in ihre Steuerungen einbauen. Grüße Stephan
 
Hallo,

Vielen Dank für Eure Antworten und die Vorschläge mit Note Red.
Aber ich habe ja jetzt die Idee von Rabi das ich das mit der vorhandenen Software umzusetzen kann, ohne eine zusätzliche Software auf dem PC.

Aber trotzdem vielen Dank nochmal an Euch für Eure Hilfe.

Mfg Tommylik
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

über das Framework ist es natürlich noch etwas besser das ganze zu machen, ich bin noch die älteren Versionen von ZenOn gewohnt wo ich eben direkt auf den RT-Prozess zugreifen musste.

In deinem Fall würde ich dir empfehlen wenn du mit dem Samples von Copa-Data arbeitest, dafür brauchst du eben die Developer Tools die du vermutlich schon installiert hast.

Hier ansonsten die Developer-Tools:
https://marketplace.visualstudio.co...63468.COPA-DATASCADAAdd-InDeveloperToolsforVS

Und hier die AddIn-Samples:
https://github.com/COPA-DATA/AddInHowTo


Für mich sieht es so aus als ob du die Online-Container bereits richtig erstellt hast.


Code:
[COLOR=#3E3E3E][FONT=Courier]        private void MyContainer_Changed(object sender, ChangedEventArgs e)[/FONT][/COLOR]        {
            Was kommt hier rein ??????????????????????????????????????????????????????????  [COLOR=#3E3E3E][FONT=Courier]        }[/FONT][/COLOR]

Dieser Codeabschnitt ist das angemeldete Event für deine Online-Container und wird eben aufgerufen sobald sich eine Variable ändert die du dem Container zugewiesen hast.


Ich würde dir raten noch einmal mehr die Samples von Copa-Data anzusehen wie man richtig einen Container erstellt und Variablen zuweist.
Im Anhang findest du auch ein schönes Beispiel wie die TaskFactory zu verwenden ist damit eben die RT nicht gestoppt wird wenn etwas zu lange dauert.
Und genau bei der ValueSubscription im Bild würden deine Skript hineingehören, somit startest du immer sofort einen neuen Task wenn eine Variable sich ändert.
Das einzige Problem dass du haben könntest, da dort nicht auf das erfolgreiche Beenden eines Tasks gewartet wird, könntest du einen FileAccess-Error bekommen.
Aber am besten versuchst du es einfach mal ;)


Deine zwei VB Scripte schreibe ich dir so jetzt nicht um, aber ich kann die empfehlen dass du dich in das FileSystem vom C# einliest.
Eigentlich ist da nicht sehr viel dahinter und du solltest deine Scripte relativ zügig umschreiben schaffen.

Man wird eigentlich relativ schnell fündig wenn man ein bisschen danach googelt, sieht hier:
https://docs.microsoft.com/en-us/do...guide/file-system/how-to-write-to-a-text-file
 

Anhänge

  • OnlineContainer_TaskFactory.PNG
    OnlineContainer_TaskFactory.PNG
    35,8 KB · Aufrufe: 12
Hallo Rabi,

Vielen Dank für deine tolle Unterstützung.

Die Tools habe ich schon. Ich habe da noch ein paar Fragen.

Du sagst das die Skripte in die ValueSubscription gehören. Warum?

Was ist die ValueSubscription ?
Was ist Guid.NewGuid() ?

Ich dachte die Skripte gehören in das Change Event?

Code:
private void MyContainer_Changed(object sender, ChangedEventArgs e)

Vor allem was ich nicht verstehe ist das die ValueSubscription vor dem Start aufgerufen wird. Warum?

Code:
 public VariableSubscription(Action<IEnumerable<IVariable>> variableChangeReceivedAction)
        {
            _variableChangeReceivedAction = variableChangeReceivedAction;
            _containerName = "MyOnlineContainerCollection-" + Guid.NewGuid();
        }


        public void Start(IProject context, IEnumerable<string> variables)
        {
            if (_project != null || _container != null)
            {
                throw new InvalidOperationException("Cannot start a new online container again.");
            }

In dem Beispiel von dem Bild wird das BulkChanged Event genutzt was ist dieses Bulk?
Wann sollte man das nutzen?

Ich habe ja mit VBA einige Skripte erstellt. Wäre es sinnvoll für jedes Skript ein Add-In zu erstellen?
Mein Beispiel aus Post #14 ist ein Project Service Extension also läuft das Add-In immer sobald die RT gestartet wird.
In mein Fall was wäre die bessere Lösung ein Project Service Extension oder ein Project Wizard Extension?

Vielen Dank noch mal für deine Hilfe

Mfg Tommylik
 
Um das ganze etwas zu vereinfachen, könntest du nochmal jetzt deinen Code hier reinstellen? Damit ich weiß mit was wir genau arbeiten.
Wenn wir jetzt zwei Versionen haben wird es etwas schwierig dir dabei zu helfen.

Genau deine Skripte gehören in deinem _Changed Event aufgerufen damit dort dann die Datei erstellt werden kann.

Du benötigst einen Project Service Extension. Du willst ja dass es mit der RT immer mitstartet.

Du könntest dir eine eigene statische Klasse erstellen in der du alle deine Skripte einzeln verpackst.
Somit könntest du immer bei dem auslösen des Events eine gewünschte Funktion ausführen.
 
Zurück
Oben