in order to test this you will need the freeopcua library. I want to offer the user a list of methods available on the server. The user can detect which methods exist. (through an enum)
All these functions have a variable amount of input args and output args.
now with freeopcua you call a method like
node.call_method("2:myMethod1", 1,2,3,4)
However what I have available is [1,2,3,4]. (is thats the user input I get) Would there be a way to parse this so it fits as myMethod arguments?
Minimal code to run the issue (not at all my code but it will give the idea of where I want to go:
myServer.py: (Only needed to have the methods no issue in here)
from opcua import Server, ua, uamethod
from enum import Enum
class methods(Enum):
add = "add"
multi = "more"
person = "notInt"
class myServer(Server):
def __init__(self):
Server.__init__(self)
self.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
self.set_server_name("FreeOpcUa Example Server")
uri = "http://examples.freeopcua.github.io"
self.idx = self.register_namespace(uri)
# Automatically creates server methods of the methods I promise to offer
for mymethod in methods:
args = self.methodCreator(mymethod)
args[1]
self.nodes.objects.add_method(args[0], args[1], args[2], args[3], args[4])
self.start()
def methodCreator(self, method_type):
inargs = None
outargs = None
method = None
if method_type == methods.add:
inargs = []
inarg = ua.Argument()
inarg.Name = "first_number"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "second_number"
inargs.append(inarg)
method = self.multi
return [2, method_type.value, method, inargs, outargs]
elif method_type == methods.multi:
inargs = []
inarg = ua.Argument()
inarg.Name = "first_number"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "second_number"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "third_number"
inargs.append(inarg)
method = self.add
return [2, method_type.value, method, inargs, outargs]
elif method_type == methods.person:
inargs = []
inarg = ua.Argument()
inarg.Name = "Name"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "Age"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "Surname"
inargs.append(inarg)
inarg = ua.Argument()
inarg.Name = "Job"
inargs.append(inarg)
method = self.person
return [2, method_type.value, method, inargs, outargs]
@uamethod
def add(self, parent, x, y):
print(x+y)
@uamethod
def multi(self, parentm, x, y, z):
print(x*y*z)
@uamethod
def person(self, parent, name, age, surname, job):
print("I'm %s %s I'm %s years old and I do %s" % (name, surname, age, job))
Now the file it's all about:
myClient.py
from stack.server import myServer, methods
from opcua import Client
class myClient(Client):
def call_functions(self):
print("Implemented methods:")
values = []
for method in methods:
print(method.value)
values.append(method.value)
#In my real code I check input but here I'll trust the user
method = input("Select a method please: \n")
objects = self.nodes.objects
inarguments = objects.get_child(["2:" + method, "0:InputArguments"]).get_value()
inargs = []
for argument in inarguments:
inargs.append(input("%s: " % argument.Name))
# I disabled some methods to make sure I just need to show one case
if method == 'notInt':
print("Desired")
objects.call_method("2:" + method, inargs[0], inargs[1], inargs[2], inargs[3])
print("error")
objects.call_method("2:" + method, inargs) # This is the line that wont work
server = myServer()
with myClient("opc.tcp://localhost:4840/freeopcua/server/") as client:
client.call_functions()
server.stop()
So when I want to call the method generic like:
objects.call_method("2:" + method, inargs)
Which for 'notInt' would have the desired output as if I did:
objects.call_method("2:" + method, inargs[0], inargs[1], inargs[2], inargs[3])
Is there a way in python to get this parsed from array to list of input args seperated by ,? So that I can keep my generic way to call each method? Or in freeopcua is there a way to get the desired affect (keep in mind that I use the argument names to ask the user for his input so just making it take a list as input wont be a sollution)
I've searched a bit. And yesterday at a meeting with some friends I discussed the issue. They made a point about *args and that I should investigate if that path works. And it does. To solve my issue I only had to add an * in front of my list of client responses and it just as promised in the shared link unboxes it and sends it to the server as being all individual arguments instead of 1 list object. My search keywords were wrong the other day. Anyway resolved by just doing this in de myClient.py
Now all I need to do is remove the enum so the client asks this to the server and then I have a client that is generic for whatever function I add to my opcua-server my client code will be able to ask which are available, choose one and ask for the arguments without needing additional code. Gotta love python!