# VBA-Excel-OPC



## KNEFI (20 Januar 2009)

Hi Leute !!!
Ich würde mich über hilfe von euch freuen...

Ich versuche gerade Variablen eines Wincc OPC servers in Excel einzulesen. Soweit so gut mit dem Skript das ich habe klappt das auch ganz gut..Nun möchte ich aber nicht nur eine sondern mehrere Variablen darstellen. Dazu müsste ich das beiliegende Skript verändern..komme damit aber nich wirklich zurecht...
(mit nur eine der Variablen kein Problem)
bitte teilt mir die veränderungen die ich machen muss mit..

mfg KNEFI


----------



## Guido (21 Januar 2009)

Hallo,

ich habe mir deinen Code mal angesehen und würde folgendes vorschlagen:


```
[COLOR=navy]Sub[/COLOR] StartClient()
[COLOR=darkgreen]'On Error GoTo ErrorHandler[/COLOR] 
[COLOR=darkgreen]'----------- We freely can choose a ClientHandle and GroupName[/COLOR]
    ClientHandles(1) = 1
    groupname = "OPC_data"
[COLOR=darkgreen]'----------- Get the ItemID from cell "A1"[/COLOR]
[COLOR=darkgreen]'PC name wird jetzt in VBA-Skript hinterlegt[/COLOR]
    NodeName = "Hier der pc name" [COLOR=darkgreen]'----Range("A1").Value[/COLOR]
    ItemIDs(1) = "actual_weight" [COLOR=darkgreen]'----Range("A2").Value[/COLOR]
    ItemIDs(2) = "weight_shift_1"   [COLOR=darkgreen]'// Hier sind die zwei variablen die ich auslesen möchte[/COLOR]
    [COLOR=darkgreen]'----------- Get an instance of the OPC-Server[/COLOR]
    [COLOR=navy]Set[/COLOR] MyOPCServer = [COLOR=navy]New[/COLOR] OPCServer
    MyOPCServer.Connect ServerName, NodeName
    [COLOR=navy]Set[/COLOR] MyOPCGroupColl = MyOPCServer.OPCGroups
    [COLOR=darkgreen]'----------- Set the default active state for adding groups[/COLOR]
    MyOPCGroupColl.DefaultGroupIsActive = [COLOR=navy]True[/COLOR]
    [COLOR=darkgreen]'----------- Add our group to the Collection[/COLOR]
    [COLOR=navy]Set[/COLOR] MyOPCGroup = MyOPCGroupColl.Add(groupname)
    [COLOR=navy]Set[/COLOR] MyOPCItemColl = MyOPCGroup.OPCItems
    [COLOR=darkgreen]'----------- Add one item, ServerHandles are returned[/COLOR]
    MyOPCItemColl.AddItems 1, ItemIDs[COLOR=red](1)[/COLOR], ClientHandles, ServerHandles, Errors
    [COLOR=red]MyOPCItemColl.AddItems 2, ItemIDs(2), ClientHandles, ServerHandles, Errors[/COLOR]
    [COLOR=darkgreen]'----------- A group that is subscribed receives asynchronous notifications[/COLOR]
    MyOPCGroup.IsSubscribed = [COLOR=navy]True[/COLOR]
[COLOR=navy]Exit Sub[/COLOR]
    ErrorHandler:
         MsgBox "Error: " & Err.Description, vbCritical, "ERROR"
[COLOR=navy]End Sub[/COLOR]
```
 
Meine Änderungen habe ich hier mal rot markiert....
Beim ersten 'AddItems' fehlt meiner Meinung nach der Index => (1) <=
ItemIDs ist als Gruppe mit zwei Elementen deklariert! (siehe => Dim ItemIDs(2) As String)
Die ItemIDs können nur fehlerfrei bearbeitet werden, wenn der Index richtig angegeben wird.
Eigentlich müsste hier schon eine Fehlermeldung kommen, dass das Element nicht vorhanden ist...oder so ähnlich...
Genaueres würde man sehen wenn der ErrorHandler aktiviert wäre.

Die zweite Zeile dient dazu der Collection 'MyOPCItemColl' eine weitere Variable hinzuzufügen.
Für jeden weiteren Wert, der in Excel angezeigt werden soll, muss einen zusätzliche AddItems-Zeile eingefügt werden.
Natürlich muss die Gruppe ItemIDs auch die richtige Anzahl Elemente enthalten. zb. Dim ItemIDs(10) As String
Und jedes Element muss mit 'ItemIDs(3) = "weight_shift_2"' usw. beschrieben sein.

Probier das mal aus und melde dich nochmal....

Gruss
Guido


----------



## KNEFI (21 Januar 2009)

HI Guido!
danke für deine Hillfe.
Habe deine Vorschläge umgesetzt aber nun sagt der kompiler 
zu der rot markierten stellen deiner änderung.

"Fehler beim Kompilieren:
Unverträgliche Typatenfeld oder benutzerdefinierter Typ erwartet"

Test:
"MyOPCitemcoll.additems 2, ItemIDs, Client Handles.............

wenn ich dort die nummerierung wegnehme kommt der fehler:

"Laufzeitfehler 9:
Index außerhalb des gültigen Bereiches"

und zwar bei der eigentlichen ausgabe der Variablen
"Range ("B4").Value= Cstr(ItemValues(2))

Vielleicht haste ja noch ne idee??? ich werde es auch weiter ausprobieren.....:-D


----------



## Guido (21 Januar 2009)

Hallo,

hast du noch den original Code in dem nur eine Variable gelesen und angezeigt wird?
Mich würde mal interessieren wie das vor deinen Änderungen aussah....

Vielleicht kannst du ja mal den Original-Code hier rein kopieren....

Gruss
Guido


----------



## KNEFI (21 Januar 2009)

Hi Guido!
ich habe hier jetzt das original skript eingefügt.
hier müssen noch der pc name und der variablenname von excel aus eingefügt werden. das hatte ich ja schon geändert.
ziel ist es einfach variablen aus dem server in excel sichtbar zumachen.


----------



## Guido (22 Januar 2009)

Hallo,

ich habe mir die beiden Versionen nochmals angeschaut und möchte dich bitten vielleicht mal folgendes zu probieren?
Kopier die zwei Zeilen in das 'MyOPCGroup_DataChange'...


```
Private Sub MyOPCGroup_DataChange(ByVal TransactionID As Long, ByVal NumItems As Long, ClientHandles() As Long, ItemValues() As Variant, Qualities() As Long, TimeStamps() As Date)
    [COLOR=red]Stop[/COLOR]
[COLOR=red]    Debug.Print NumItems[/COLOR]
    '----------- Set the spreadsheet cell values to the values read
    Range("B2").Value = CStr(ItemValues(1))
    Range("C2").Value = Hex(Qualities(1))
    Range("D2").Value = CStr(TimeStamps(1))
End Sub
```
Dann ändere mal den Wert der erste Variablen in deinem OPC, damit das DataChange-Ereigniss ausgelöst wird.
Der VBA-Kompiler wird dann auf dem Stop-Befehl stehen bleiben.
Mit der F8-Taste kannst du dann einen Schritt weitergehen und wirst den Wert in 'NumItems' sehen können.
Wenn ich nicht ganz daneben liege, müsste in 'NumItems' die Nummer des Wertes stehen welcher sich geändert hat.
Wenn du den zweiten Wert im OPC änderst, müsste in 'NumItems' "2" stehen.
Vorraussetzung ist natürlich dass du die oben beschriebene Erweiterung noch im Code drin hast....

Wenn meine Vermutung sich bestätigt, und 'NumItems' enthält die Nummer der Wertes welcher
sich geändert hat, könntest du vielleicht noch folgendes machen:


```
Private Sub MyOPCGroup_DataChange(ByVal TransactionID As Long, ByVal NumItems As Long, ClientHandles() As Long, ItemValues() As Variant, Qualities() As Long, TimeStamps() As Date)
[COLOR=red] Select Case NumItems[/COLOR]
[COLOR=red]     Case 1[/COLOR]
[COLOR=red]         Range("B2").Value = CStr(ItemValues(1))[/COLOR]
[COLOR=red]     Case 2[/COLOR]
[COLOR=red]         Range("B4").Value = CStr(ItemValues(1))[/COLOR]
[COLOR=red] End Select[/COLOR]
    '----------- Set the spreadsheet cell values to the values read
[COLOR=red] 'Range("B2").Value = CStr(ItemValues(1))[/COLOR]
    Range("C2").Value = Hex(Qualities(1))
    Range("D2").Value = CStr(TimeStamps(1))
End Sub
```
 
Es würde mich mal interssieren was dabei rauskommt.....


Gruss
Guido


----------



## KNEFI (22 Januar 2009)

Hi!!
Ich habe deine idee nochman getestet bei diesem stop debug befehl zeigt er mir immer die 1 an. Ich bekomme ihn nich dazu sich zu ändern.
Aber da ich ja gestern fleißig war habe ich das Skript geändert. (siehe anhang. Die änderung der Variablen kommt nun auf knopfdruck und wird nich ständig aktualisiert.
Es funktioniert super habe nur noch ein paar fragen bzw problemchen.

1. Ich kann nur die Parameterwerte von Wincc als Variable in Excel angeben und nich die OPC Variable? Also "Waage" statt "actual_Weight"
(siehe bild anhang) als Quality code dieser Variablen haut er mir           immer " 4c " rein und prozesswert 0.
Status in excel bei der OPC vari is "20" 
Bei dem ersten meiner programme konnte ich noch die richtige OPC Vari angeben.??? Wo liegt der fehler.

2. Die Zeitstempel funktion sie geht in meinem programm immer eine stunde vor?? Sommer/winterzeit??? Wie kann ich sie anpassen??

3. Meine feststellung nach einigen stunden:
Die Variablen die ich in Excel anzeigen möchte müssen in WinCC auf einem Bild sein. Sonst zeigt er mir sie nicht. Das verstehe ich nich so ganz aber damit könnte ich leben. vllt haste ja ne erklärung????

vielen dank für deine mühen....
mfg Knefi


----------



## Guido (22 Januar 2009)

Hallo,



> 1. Ich kann nur die Parameterwerte von Wincc als Variable in Excel angeben und nich die OPC Variable?
> Bei dem ersten meiner programme konnte ich noch die richtige OPC Vari angeben.??? Wo liegt der fehler?


 

```
[FONT=Courier New]'Act_Cell ist die Starzeile = 1 + 4 = 5[/FONT]
[FONT=Courier New]'das lesen der Variablen beginnt in Zeile 5[/FONT]
[FONT=Courier New]For i = 1 To Max_Items[/FONT]
[FONT=Courier New] Act_Cell = i + Cell_Offset[/FONT]
[FONT=Courier New] ClientHandles(i) = i[/FONT]
[FONT=Courier New][COLOR=red] ItemIDs(i) = Range("A" & Act_Cell).Value[/COLOR][/FONT]
[FONT=Courier New]Next i[/FONT]
```


```
ItemIDs(1) = "actual_weight" [COLOR=darkgreen]'----Range("A2").Value[/COLOR]
```
Das liegt daran das in der Schleife jetzt die Variablen-Namen aus den Excelzellen A5 bis A8 übernommen werden.
Vorher wurden die Variablen-Namen im VBA-Code direkt geschrieben.



> 2. Die Zeitstempel funktion sie geht in meinem programm immer eine stunde vor?? Sommer/winterzeit??? Wie kann ich sie anpassen??


Entweder du suchst die Stelle von der das Datum/Uhrzeit geliefert wird und stellst es um.
Oder du machst in der folgenden Schleife ein kleine Änderung...

```
[FONT=Courier New]For i = 1 To NumItems[/FONT]
[FONT=Courier New] k = Cell_Offset + i[/FONT]
[FONT=Courier New] Range("B" & k).Value = CStr(ItemValues(i))[/FONT]
[FONT=Courier New] Range("C" & k).Value = Hex(Qualities(i))[/FONT]
[FONT=Courier New] Range("D" & k).Value = CStr(TimeStamps(i)[COLOR=red]-3600[/COLOR])[/FONT]
[FONT=Courier New]Next i[/FONT]
```
Ich habe hier jetzt einfach mal "-3600" gemacht falls der TimeStamp in Sekunden-Format vorliegt.
Ich gehe aber davon aus dass das Date-Format verwendet wird.
Hier ist es aber auch möglich eine Stunde vom Wert abzuziehen bevor er in Excel geschrieben wird.
Die VB-Funktion 'CDate' kann hier vielleicht hilfreich sein.... 



> 3. Meine feststellung nach einigen stunden:
> Die Variablen die ich in Excel anzeigen möchte müssen in WinCC auf einem Bild sein.
> Sonst zeigt er mir sie nicht.


Falls du mit 'nicht anzeigen' meinst das der Wert nicht aktualisiert wird kann das folgende Ursache haben.
Es kann sein dass das der OPC nur Werte aktualisiert die von WinCC gebraucht und angezeigt werden.
Andere Variabeln bleiben möglicherweise auf '0'.....

Gruss
Guido


----------



## KNEFI (22 Januar 2009)

hi!

zu 1:
Ich sehe da eigentlich für meine verhältnisse keinen unterschied ob ich die varible "actual_weight" von der Excel oberfläche oder direkt im Skript eintrage. Biste sicher das es daran liegt?? das würde a irgenwie keinen sinn ergeben oder?
(Habe dank siemens und co die suche nach jedem sinn aufgebeben bin froh wenn es mal läuft..haha)

zu 2.
Also ich kann mit der zb von dir eingetragenen zahl den Wert verändern. aber ich finde nicht den richtigen Wert da ich mit dieser eingabe von         -3600 die anzeige von vorher
(22.01.2009 12:44:26)
und nach der eingabe der Zahl
(16.03.1999 12:45:09)
Also das Datum ändert sich möchte eigenlich nur eine Stunde vor auf 13:45 uhr.
habe nichts zur timestamp formatierung gefunden. 
Wenn ich wüsste wo er(timestamp) diese zeit wegbekommt wäre das auch nich schlecht das sollte sich ja irgendwie automatisch umschalten. Ich kann ja nich immer im sommer und winter zum Kunden und diese zeiten umstellen.Ich dachte er würde die aktuelle Computer Zeit verwenden aber dem ist ja scheinbar nicht so.

vllt kanste mir da nochma helfen?
oder vllt sogar meine funktionen mit der cdate-funktion abändern wenn das die bessere lösung ist.

zu 3. 
Excel löscht mir die Wert anzeige und schreibt zum status 20 rein das datum bleibt natürlich da und passt sich an. Wenn die abgefragte Variable (zb Ausgabefeld in Wincc) nicht auf der Wincc oberfläche ist.
ich kann mir dabei helfen indem ich das entsprechende feld in ein bild kopiere das immer auf dem desktop ist und dann unsichtbar mache oder verstecke. das Problem ergibt sich dann wenn es dann doch mal mehrer Variablen werden sollen.
Das finde ich wenn es so ist wie ich es momentan sehe wäre das ein manko.
Bei größeren Datenmängen möchten wir dann eh auf das siemens eigene produkt "databridge" zurückgreifen.

danke für deine Hilfe

mfg Knefi


----------



## Guido (22 Januar 2009)

HI,

Für die Zeit-Korrektur kannst du mal folgendes machen:

```
[FONT=Courier New]Range("D" & k).Value = CStr(TimeStamps(i) + CDate(0.041666))[/FONT]
```
Indem du den Wert "0,041666" zu TimeStamps hinzuaddierst wird die Zeit um 1 Stunde vorgesetzt.
Habe das mit VisualBasic6 auf meinem Rechner ausprobiert... und hat auch funktioniert.... 
Hatte mit 3600 wohl etwas übers Ziel hinaus geschossen....ca. 10 Jahre...nicht schlecht  

Sorry dass ich mich so kurz fasse, aber zu den Punkten 1 und 3 kann ich nichts wirklich konstruktives mehr sagen....

Gruss
Guido


----------



## KNEFI (23 Januar 2009)

Hi nochmal!

zu meinen ersten Punkt:
Ich hab das nochmal ausprobiert und habe die Variablen nicht über excel sondern im Skript direkt eingetragen. Und es will trotzdem nich funktionieren. Das muss an irgendeiner Verbindungs einstellung zum OPCServer liegen im Excel skript. Weil der erste versuch funktioniert ja wie gesagt mit den OPC variablen. ?????

zu 2 
Ich habe deine änderung ausprobiert und sie funktioniert gut. ich konnte die fehlende stunde dazu addieren.



> Wenn ich wüsste wo er(timestamp) diese zeit wegbekommt wäre das auch nich schlecht das sollte sich ja irgendwie automatisch umschalten. Ich kann ja nich immer im sommer und winter zum Kunden und diese zeiten umstellen.Ich dachte er würde die aktuelle Computer Zeit verwenden aber dem ist ja scheinbar nicht so.


Aber das alte problem der Zeitumstellung besteht ja weiterhin.

Danke für deine super hilfen......

mfg Knefi


----------

