OPC UA Server

Hi all,

I wonder have anyone of you connect VC to a custom-made OPC UA Server. I’ve tried to connect it with a dummy OPC UA server but the connection failed. I made sure the server is up and running, and the server can be connected using UaExpert. Is this approach a dead end or anyone has some experiences with it?

Thank you for your time and I am looking forward to hearing your idea.

Is it a secure connection?

Regards
Feature

The OPC UA client in Connectivity feature of VC requires the connected server to be standard-compliant. This includes that it has to support certain basic services and must have certain valid data model for the “Server” object.

Some OPC UA server libraries will just create and “empty” server by default, which is not standard compliant and thus connecting to it is not supported.

Check the VC application log file for any more detailed errors, or ask VC customer support for more info.

Hi,

Thank you very much for your input. I wonder if VC has a model OPC UA server or any documentations or templates lying around? It would really helpful for me and my learning curve.

BR,
Duc Pham

You can get full data model and address space specifications from the OPC Foundation’s GitHub:

Does your OPC UA server library have capability to load those NodesSet2 files?

The Schema folder seems to contain the full OPC UA standardized model and the others are additions by different companion specifications. The full model is very large and VC doesn’t make use of anything in the Types hierarchy, for example.

I think the free edition of Prosys simulation server has the full model which you can then browse with the Server’s GUI directly to understand it better.

Hello
I have been looking trough the thread that you posted as well as the git pages.
Being a novice in this area it is hard for me to really see what a server needs to have in terms of lines of code to be standard-compliant. The link to OPC-foundation git contains a lot of information and before i stat reading trough this im wondering:
Do you know anyone that more in detail can define what is needed for the server to be standard-compliant?

Im using this library in github where i rewrite the code to fit my purpose and has worked pretty well for me thus far.

What would be missing to make this example standard compliant?

// David

Hi @Dauken

The connection test may fail in VC but you can still connect to your server.

Here’s a simple example, tested and works on Python3

import time
from opcua import ua, Server

if __name__ == "__main__":
    # setup server
    server = Server()
    server.set_endpoint("opc.tcp://localhost:4840")

    '''
    server.set_security_policy([
      ua.SecurityPolicyType.NoSecurity,
      ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
      ua.SecurityPolicyType.Basic256Sha256_Sign
    ])
    '''

    # setup our own namespace, not really necessary but should as spec
    uri = "http://localhost"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our nodes
    objects = server.get_objects_node()
    print(objects)

    # populating our address space
    myobj = objects.add_object(idx, "MyObject")
    myvar = myobj.add_variable(idx, "MyVariable", 6.7)
    myvar.set_writable()    # Set MyVariable to be writable by clients

    print(server.get_namespace_array())

    # starting!
    server.start()

    try:
        # count = 0
        # while True:
        #     time.sleep(1)
        #     count += 0.1
        #     myvar.set_value(count)
        input("Press Enter to shutdown server...\n")
    finally:
        #close connection, remove subcsriptions, etc
        server.stop()

Shows up in VC like this after connecting:
image

1 Like

Thanks @jouha

I tested the example you provided, and I had a few problems. Luckily I managed to overcome these issues, and the connection to VC works!

To get the connection working, I had to do the following:

  1. Change the server port to 4841 in the script and in the connection plugin
  2. Cannot test the connection. It always fails
  3. Click the Apply button in the bottom right corner despite the test failing
  4. Activate the connection
  5. Refresh the server variable list


Thanks a lot!

Thanks for all the help guys!
So in conclusion, the only thing that i needed to do was to comment away
‘’’

server.set_security_policy([

  ua.SecurityPolicyType.NoSecurity,

  ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,

  ua.SecurityPolicyType.Basic256Sha256_Sign

])

'''

just out of curiosity, is it possible to use uamethods in VC somehow ? i have yet to come up with any examples on exactly how to construct an experiment where uamethods are used in conjunction with VC but i have some ideas.

I will probably start a new thread if i run into problems here anyway

//David

uamethods cannot be used with the OPC UA connection plugin in VC. for example, it does not have the functionality that UAExpert has to execute methods.

Hello,

I have a project where I do to realize a server python who connect with the OPC UA of Visual Components. In my project I hava a electronic card who I coded in Arduino for send data of movements as joysticks, buttons or commutators. 2 buttons are for the creation of errors in Visual as the position of a box on a pallet incorrectly or a speed of a conveyor too slow or too fast as second error. One over button run the simulation and stop that and the last pause the simulation and run after pause.
One joystick is for the speed of the conveyor and the one other is for the deplacement of a robot arm Visual Components. One commutator is for three speeds define for conveyor (slow,normal,fast). The other commutator is for the selection of robot axes to be moved (RY,RX,RY2). I finished the partie Arduino but it’s the transmission in Python where I’m blocked and after to send to Visual because I begin on Visual Components and I don’t understand completly how use the Connectivity.

One person can help me please ?
Thanks for your attention and comprehension.

Cordialy,
Jérémie

You have a OPC UA server running in a Python, which needs to connect to the OPC UA client in Visual Components. Can you connect? Does the server structure appear in the Create Variable Pairs editor in VC for the server connection? See the above examples on what others had to do for the connection to work.

You want to pair variables from the server with variables in your simulation, e.g. layout of components in 3D world. And then what: Are the simulation variables such as signal or property supposed to call functions when their values change? I ask because it is not clear if you want a component script to start and stop simulation or if you plan on using .NET API.

Yes I managed to connect to my Python server already thanks to the help from this forum and the support from Visual Components. Yes my structure appear in the Create Variable Pairs editor in VC. I just want to call my functions using my electronic card to trigger the signals I created on VC with their codes. For example on VC I have codes which modify the speed of the conveyor using signals. I will therefore want to connect my server variable to this signla so when I press my button I activate the signal which changes the speed. Then by using the joystick on my card I call a function of my server which modifies the speed of the conveyor. However I’m a bit lost in creating the server with Python and VC and that’s why I ask for your help please. I’m not sure how the .NET API works yet. So I will want to use a component script that would start and stop the simulation.

Not sure if you solved it already but you only need to for example create a bool variable on your server and a bool signal in one of you components. Under Connectivity on server to simulation right click and choose add variable or something. Then you click on the bool signal and bool variable and bind them.

Now if the variable changes on the server so does the one in the simulation.
The code for a server is written above.

Hello,

I have coded a server OPC UA to connect to Visual Components.

import time
import json
from opcua import ua, Server


if __name__ == "__main__":
    # setup server
    server = Server()
    server.set_endpoint("opc.tcp://localhost:4841")

    '''
    server.set_security_policy([
      ua.SecurityPolicyType.NoSecurity,
      ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
      ua.SecurityPolicyType.Basic256Sha256_Sign
    ])
    '''
    OFFSET_JOYSTICK = 50

    # setup our own namespace, not really necessary but should as spec
    uri = "http://localhost"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our nodes
    objects = server.get_objects_node()
    print(objects)

    # populating our address space
    MyObjects = objects.add_object(idx, "MyObjects")
    button3 = MyObjects.add_variable(idx,"button3",int(0))
    button4 = MyObjects.add_variable(idx,"button4",int(0))
    joy2_x = MyObjects.add_variable(idx,"joy2_x",int(512))
    joy2_y = MyObjects.add_variable(idx,"joy2_y",int(512))
    Selecteur = MyObjects.add_variable(idx,"selecteur",int(0))

    # starting!
    server.start()

    while True:

        with open("boutons.json") as p:
            boutons = json.load(p)
            print(boutons)
            print(boutons['boutons'])

        if button3 == 1:
            ButtonSignal = True
            button3.set_writable()
        else:
            ButtonSignal = False
            button3.set_writable()

        if button4 == 1:
            for i in range(1,4):
                if i == 1:
                    SlowSpeed = True
                    FastSpeed = False
                    StartStopSpeed = False
                    button4.set_writable()
                if i == 2:
                    SlowSpeed = False
                    StartStopSpeed = False
                    FastSpeed = True
                    button4.set_writable()
                if i == 3:
                    FastSpeed = False
                    SlowSpeed = False
                    StartStopSpeed = True
                    button4.set_writable()

        if button4 == 0:
            SlowSpeed = False
            FastSpeed = False
            StartStopSpeed = False
            button4.set_writable()

        with open("selecteur.json") as f:
            selecteur = json.load(f)
            print(selecteur)
            print(selecteur['selecteur'])

        if selecteur == 1:
            Vitesse_lente = True
            Selecteur.set_writable(selecteur)
            with open("joystick.json") as o:
                joystick =json.load(o)
                print(joystick)
                print(joystick['joystick'])
            if joy2_x < (512 - OFFSET_JOYSTICK) and joy2_y < (512 - OFFSET_JOYSTICK):
                joy2_x.set_writable()
                joy2_y.set_writable()
                Vitesse_lente = 300

        if selecteur == 2:
            Vitesse_normale = True
            Selecteur.set_writable(selecteur)
            with open("joystick.json") as l:
                joystick = json.load(l)
                print(joystick)
                print(joystick['joystick'])
            if joy2_x == 512 and joy2_y == 512:
                joy2_x.set_writable()
                joy2_y.set_writable()
                Vitesse_normale = 500

        if selecteur == 3:
            Vitesse_rapide = True
            Selecteur.set_writable(selecteur)
            with open("joystick.json") as r:
                joystick = json.load(r)
                print(joystick)
                print(joystick['joystick'])
            if joy2_x > (512 + OFFSET_JOYSTICK) and joy2_y > (512 + OFFSET_JOYSTICK):
                joy2_x.set_writable()
                joy2_y.set_writable()
                Vitesse_rapide = 700

        # Set MyVariable to be writable by clients  

        print(server.get_namespace_array())

        try:
            # count = 0
            # while True:
            #     time.sleep(1)
            #     count += 0.1
            #     myvar.set_value(count)
            input("Press Enter to shutdown server...\n")
        finally:
            # close connection, remove subcsriptions, etc
            server.stop()

In this server I want to recover the data json who are sent and after write this data to Visual Components. But in Visual Components after connection and execution I see this error.

image

Hello Deros,

Being a novice in this field, I wonder how to extract data using python opc ua from Visual Comp model.
Using this code were you able to store data in json format ??
if yes can you share your approach. I think i am walking with a similar approach and got stuck in data storing.

Thanks in Advance

Hello,

In this code with arduino card I create differents files json (bouton3,bouton4,selecteur,joystick) and open this for write diferents values which are sended to arduino card to json.

import serial
import time
import json


ser = serial.Serial('COM5', 115200)
ser.timeout = 0.5  # valeur en secondes
ser.reset_input_buffer()  # flushInput est dépréciée depuis PySerial 3.0
ser.reset_output_buffer()  # idem pour flushOutput

etape = 0


while True:
    try:
        msg_recu = ser.readline().decode('utf8').rstrip().lower()  # réception puis décodage puis retrait des '\r\n' (avec rstrip()) puis mise en minuscule)
    except serial.SerialTimeoutException:
        print("Erreur: Sortie par Timeout de lecture")
        print(f"Pas de message reçu dans l'intervalle de temps indiqué ({ser.timeout}s)")
        break
    except serial.SerialException:
        print("Erreur: Erreur d'E/S du port série")
        break
    else:
        print((msg_recu))
        if msg_recu.startswith("bouton3"):
            etape = 1
        if msg_recu.startswith("bouton4"):
            etape = 2
        elif msg_recu.startswith("selecteur"):
            etape = 10
        elif msg_recu.startswith("joystick"):
            etape = 20
        elif msg_recu == '':  # on passe ici si la chaine est vide (correspond à un changement de type de message)
            etape = 0  # ça évite de le tester à chaque type de message
        elif etape == 1:
            # on passe ici si on a eu le message "boutons poussoirs" et que l'on a reçu le 1er message suivant
            bouton3 = str(msg_recu)
            dictionnaire ={"bouton3": bouton3}
            with open("bouton3.json", "w", encoding='utf-8') as l:
                json.dump(dictionnaire, l)
        elif etape == 2:
            bouton4 = str(msg_recu)
            dictio = {"bouton4":bouton4}
            with open("bouton4.json","w", encoding= 'utf-8') as j:
                json.dump(dictio,j)
        elif etape == 10:
            # on passe ici si on a eu le message "sélecteur" et une des valeurs
            selecteur = int(msg_recu)
            dico ={"selecteur": selecteur }
            with open("selecteur.json", "w", encoding='utf-8') as p:
                json.dump(dico, p)
            # on traite la valeur reçue
        elif etape == 20:
            # on passe ici si on a eu le message "joystick" et une des valeurs
            joystick = float(msg_recu)
            my_dictionnaire ={"joystick": joystick}
            with open("joystick.json","w",encoding= 'utf-8') as f:
                json.dump(my_dictionnaire,f)

ser.close()

In this second code I want to load values of my arduino card to exceute differents actions in logiciel in depending on the value but on the Visual Components side it didn’t work and the values ​​weren’t updating correctly so I stopped the project.

import time
import json
from opcua import ua, Server


if __name__ == "__main__":
    # setup server
    server = Server()
    server.set_endpoint("opc.tcp://localhost:4841")

    '''
    server.set_security_policy([
      ua.SecurityPolicyType.NoSecurity,
      ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
      ua.SecurityPolicyType.Basic256Sha256_Sign
    ])
    '''
    OFFSET_JOYSTICK = 50

    # setup our own namespace, not really necessary but should as spec
    uri = "http://localhost"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our nodes
    objects = server.get_objects_node()
    print(objects)

    # populating our address space
    MyObjects = objects.add_object(idx, "MyObjects")
    button3 = MyObjects.add_variable(idx,"button3",int())
    button4 = MyObjects.add_variable(idx,"button4",int())
    joyst = MyObjects.add_variable(idx,"joyst",int())
    select = MyObjects.add_variable(idx, "selector", int())

    # starting!
    server.start()

    while True:

        with open ("bouton3.json") as k:
            bouton3 = json.load(k)
            #print(bouton3)
            #print(bouton3['bouton3'])

        if bouton3 == 1:
            ButtonSignal = True
            button3.set_value(1)
        else:
            ButtonSignal = False
            button3.set_value(0)

        with open("bouton4.json") as p:
            bouton4 = json.load(p)
            #print(bouton4)
            #print(bouton4['bouton4'])

        if bouton4 == 1:
            for i in range(1,4):
                if i == 1:
                    SlowSpeed = True
                    FastSpeed = False
                    StartStopSpeed = False
                    button4.set_value(1)
                if i == 2:
                    SlowSpeed = False
                    StartStopSpeed = False
                    FastSpeed = True
                    button4.set_value(1)
                if i == 3:
                    FastSpeed = False
                    SlowSpeed = False
                    StartStopSpeed = True
                    button4.set_value(1)

        if bouton4 == 0:
            SlowSpeed = False
            FastSpeed = False
            StartStopSpeed = False
            button4.set_value(0)

        with open("selecteur.json") as f:
            selecteur = json.load(f)
            #print(selecteur)
            #print(selecteur['selecteur'])

        if selecteur == 1:
            Vitesse_lente = True
            select.set_value(1)
            with open("joystick.json") as o:
                joystick = json.load(o)
                #print(joystick)
                #print(joystick['joystick'])

            if joystick >= 0 and joystick < 512:
                joyst.set_value(joystick)
                low_vitesse = 399 - 10
            if joystick == 512:
                joyst.set_value(joystick)
                low_vitesse = 399
            elif joystick > 512:
                joyst.set_value(joystick)
                low_vitesse = 200 + 10

        if selecteur == 2:
            Vitesse_normale = True
            select.set_value(2)
            with open("joystick.json") as l:
                joystick = json.load(l)
                #print(joystick)
                #print(joystick['joystick'])

            if joystick >= 0 and joystick < 512:
                joyst.set_value(joystick)
                normal_vitesse = 599 - 10
            elif joystick == 512:
                joyst.set_value(joystick)
                normal_vitesse = 599
            elif joystick > 512:
                joyst.set_value(joystick)
                normal_vitesse = 400 + 10

        if selecteur == 3:
            Vitesse_rapide = True
            select.set_value(3)
            with open("joystick.json") as r:
                joystick = json.load(r)
                #print(joystick)
                #print(joystick['joystick'])

            if joystick >= 0 and joystick < 512:
                joyst.set_value(joystick)
                fast_vitesse = 799 - 10
            elif joystick == 512:
                joyst.set_value(joystick)
                fast_vitesse = 799
            elif joystick > 512:
                joyst.set_value(joystick)
                fast_vitesse = 600 + 10

        # Set MyVariable to be writable by clients

        print(server.get_namespace_array())

        try:
            # count = 0
            # while True:
            #     time.sleep(1)
            #     count += 0.1
            #     myvar.set_value(count)
            input("Press Enter to shutdown server...\n")
        finally:
            # close connection, remove subcsriptions, etc
            server.stop()