• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[Python] OPCUA Copy Server

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
576
Hallo zusammen,

ich habe einen OPCUA-Server (OrigServer) zu dem ich subscriben kann. Die Daten gehören rechtlich mir / meiner Firma und wir möchten diese weiteren Menschen zur Verfügung stellen, jedoch möchten wir den Zugriff auf den eigentlichen Server (OrigServer) beschränken.

Unsere Idee: Wir haben einen Server (ServerExtern) für unsere externen Zugreifer, auf dem wir einen OPCUA Server betreiben. Dieser subscribed alle Nodes auf dem OrigServer und published sie NEU.

Da es sich dabei um einige Tausend Nodes handelt, würden wir das gerne mit einem Skript automatisieren.
Ich habe die inzwischen fleißig studiert. Ich habe auf einen Code-Schnippsel gehofft, bei dem ich einmal eine Liste aller Nodes ausgeben lassen kann und diese auf dem neuen Server "einfach" importieren.
Das scheint es nicht zu geben, oder habt ihr da etwa auf die Schnelle gefunden?

Derzeit sehe ich nur die Möglichkeit durch jede Node zu Iterieren und jeden Datentyp, Namen, Identifier usw. zu extrahieren und NEU zu erstellen. Hierfür dann noch die zugehörigen Callbacks zu registieren, damit alle Änderungen übergeben werden scheint relativ umständlich zu sein.
Geht das auch einfacher oder ist mein Ansatz hier generell umständlich und ich habe etwas übersehen?

P.S.: Externe Zugreifer sollen zwar auf dem ExternServer schreiben können, jedoch sollen diese Änderungen NICHT an OrigServer übergeben werden. An dieser Stelle soll nur eine lesende Verbindung bestehen.

Über jegliche Tipps und Hinweise bin ich glücklich!
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
576
  • Thread Starter Thread Starter
  • #2
Derzeit bin ich soweit einige Daten von einem beliebigen OPCUA-Server auszulesen. Dazu habe ich exemplarisch das folgende Skript gebaut. Ich bin mir aktuell noch nicht sicher, ob ich damit alle notwendigen Daten auslese um die Nodes in gleicher Art und Weise zu replizieren.
Insbesondere die (numerische) NodeId könnte mir Probleme bereiten. Ich überlege aktuell, ob ich diese einfach ignorieren kann und nur die allgemeine Struktur erhalten möchte.

[src=python]import logging
from opcua import Client
from opcua import Server as opcuaServer
from opcua import ua
import socket
import threading
import time

if __name__ == "__main__":
logging.basicConfig(level=logging.WARN)
address = "opc.tcp://127.0.0.1:4840"
client = Client(address)
try:
client.connect()
# Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
root = client.get_root_node()
print("Root node is: ", root)
objects = client.get_objects_node()
print("Objects node is: ", objects)

# Node objects have methods to read and write node attributes as well as browse or populate address space
children = root.get_children()
print("Children of root are: ", children)

def recursive_print_children_browse_names(c):

def recursive_var_check(variables):
for v in variables:
print("Variables:", v, "\tName:", v.get_browse_name(), "\tPath:", v.get_path(), "\tValue:", v.get_value())
new_vars = v.get_variables()
if len(new_vars) != 0:
recursive_var_check(new_vars)

for child in c:
try:
print("Childname:", child.get_browse_name())
print(child.get_description()) # LocalizedText(Encoding:2, Locale:None, Text:The browse entry point when looking for objects in the server address space.)
print(child.get_description_refs()) # []
print(child.get_node_class()) # NodeClass.Object
print(child.get_parent()) # i=84
print(child.get_path()) # [Node(TwoByteNodeId(i=84)), Node(TwoByteNodeId(i=85))]
print(child.get_properties()) # []
print(child.get_type_definition()) # TwoByteNodeId(i=61)
variables = child.get_variables()

recursive_var_check(variables)
except ua.UaStatusCodeError as e:
print("Error catched:", e)
new_childs = child.get_children()
if len(new_childs) != 0:
recursive_print_children_browse_names(new_childs)
#if len(new_childs) >=6:
# recursive_print_children_browse_names(new_childs[:6])
#else:
# recursive_print_children_browse_names(new_childs)

for child in children:
print("##")
print(dir(child))
# 'get_access_level', 'get_array_dimensions', 'get_attribute', 'get_attributes', 'get_browse_name', 'get_child', 'get_children', 'get_children_descriptions', 'get_data_type', 'get_data_type_as_variant_type', 'get_data_value', 'get_description', 'get_description_refs', 'get_display_name', 'get_encoding_refs', 'get_event_notifier', 'get_methods', 'get_node_class', 'get_parent', 'get_path', 'get_properties', 'get_referenced_nodes', 'get_references', 'get_type_definition', 'get_user_access_level', 'get_value', 'get_value_rank', 'get_variables'
# print(child.get_access_level())
# print(child.get_array_dimensions())
# print(child.get_attributes())
# print(child.get_data_type())
# print(child.get_data_type_as_variant_type())
# print(child.get_data_value())
print(child.get_description()) # LocalizedText(Encoding:2, Locale:None, Text:The browse entry point when looking for objects in the server address space.)
print(child.get_description_refs()) # []
print(child.get_node_class()) # NodeClass.Object
print(child.get_parent()) # i=84
print(child.get_path()) # [Node(TwoByteNodeId(i=84)), Node(TwoByteNodeId(i=85))]
print(child.get_properties()) # []
print(child.get_type_definition()) # TwoByteNodeId(i=61)
# print(child.get_value())

print("### Starting the recursive loop")
recursive_print_children_browse_names(children)
#recursive_print_children_browse_names([objects])

finally:
client.disconnect()
[/src]

Dieses Skript baucht ungefähr ein ganzes Jahrhundert um alle Nodes abzugreifen. Ich bin mir nicht sicher, ob das wirklich der eleganteste Weg ist.
Allerdings ist meine derzeitige Idee während ich durch die Client-Objekte iteriere, parallel neue Objekte für den Server zu erstellen, die den gleichen Namen und die gleichen Kinder haben. Zudem müsste ich auch entsprechende Callbacks definieren, sobald sich einer der Werte bei OrigServer (hier client VerbindunG) ändern, diese auch auf den neu erstellen Server zu übertragen.

Alternativ habe ich auch versucht mit export_xml und import_xml zu experimentieren. Abgesehen von langer Wartezeit und anschließenden Fehlermeldungen habe ich da bisher wenig Erfolg gehabt.
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
576
  • Thread Starter Thread Starter
  • #3
Ich habe ein paar Fortschritte in der Zwischenzeit gemacht.
Ich habe mir aktuell manuell die fehlenden Datentypen rausgesucht und erstelle diese nachträglich.
Leider scheint dabei irgendwas von mir noch zu fehlen.

Der Baum sieht anders aus, obwohl die eigentlichen Elemente anscheinend gleich sind.
Ich kopiere die Datentypen von der Simatic (Siemens) Steuerung und erstelle damit meinen OwnServer.
OwnServer.jpg Siemens_Server.jpg

Hat da jemand eine Ahnung, was ich anscheinend anders mache? Ich dachte es liegt vielleicht am Display_Name aber der scheint ja ebenfalls gleich zu sein...
 
Oben