mirror of
https://github.com/FreeOpcUa/opcua-asyncio
synced 2025-10-29 17:07:18 +08:00
parent
5b4bf6961b
commit
e09c160192
|
|
@ -2,6 +2,8 @@
|
|||
High level method related functions
|
||||
"""
|
||||
|
||||
from asyncio import iscoroutinefunction
|
||||
|
||||
from asyncua import ua
|
||||
|
||||
|
||||
|
|
@ -67,14 +69,32 @@ def uamethod(func):
|
|||
Method decorator to automatically convert
|
||||
arguments and output to and from variants
|
||||
"""
|
||||
def wrapper(parent, *args):
|
||||
|
||||
if iscoroutinefunction(func):
|
||||
async def wrapper(parent, *args):
|
||||
func_args = _format_call_inputs(parent, *args)
|
||||
result = await func(*func_args)
|
||||
return _format_call_outputs(result)
|
||||
|
||||
else:
|
||||
def wrapper(parent, *args):
|
||||
func_args = _format_call_inputs(parent, *args)
|
||||
result = func(*func_args)
|
||||
return _format_call_outputs(result)
|
||||
return wrapper
|
||||
|
||||
|
||||
def _format_call_inputs(parent, *args):
|
||||
if isinstance(parent, ua.NodeId):
|
||||
result = func(parent, *[arg.Value for arg in args])
|
||||
return (parent, *[arg.Value for arg in args])
|
||||
else:
|
||||
self = parent
|
||||
parent = args[0]
|
||||
args = args[1:]
|
||||
result = func(self, parent, *[arg.Value for arg in args])
|
||||
return (self, parent, *[arg.Value for arg in args])
|
||||
|
||||
|
||||
def _format_call_outputs(result):
|
||||
if result is None:
|
||||
return []
|
||||
elif isinstance(result, ua.CallMethodResult):
|
||||
|
|
@ -86,7 +106,6 @@ def uamethod(func):
|
|||
return to_variant(*result)
|
||||
else:
|
||||
return to_variant(result)
|
||||
return wrapper
|
||||
|
||||
|
||||
def to_variant(*args):
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import pickle
|
|||
import shelve
|
||||
import logging
|
||||
import collections
|
||||
from asyncio import iscoroutinefunction
|
||||
from datetime import datetime
|
||||
|
||||
from asyncua import ua
|
||||
|
|
@ -454,10 +455,10 @@ class MethodService:
|
|||
async def call(self, methods):
|
||||
results = []
|
||||
for method in methods:
|
||||
results.append(self._call(method))
|
||||
results.append(await self._call(method))
|
||||
return results
|
||||
|
||||
def _call(self, method):
|
||||
async def _call(self, method):
|
||||
self.logger.info("Calling: %s", method)
|
||||
res = ua.CallMethodResult()
|
||||
if method.ObjectId not in self._aspace or method.MethodId not in self._aspace:
|
||||
|
|
@ -468,7 +469,10 @@ class MethodService:
|
|||
res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNothingToDo)
|
||||
else:
|
||||
try:
|
||||
result = node.call(method.ObjectId, *method.InputArguments)
|
||||
if iscoroutinefunction(node.call):
|
||||
result = await node.call(method.ObjectId, *method.InputArguments)
|
||||
else:
|
||||
result = node.call(method.ObjectId, *method.InputArguments)
|
||||
if isinstance(result, ua.CallMethodResult):
|
||||
res = result
|
||||
elif isinstance(result, ua.StatusCode):
|
||||
|
|
|
|||
|
|
@ -1,75 +1,83 @@
|
|||
import sys
|
||||
sys.path.insert(0, "..")
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
try:
|
||||
from IPython import embed
|
||||
except ImportError:
|
||||
import code
|
||||
|
||||
def embed():
|
||||
vars = globals()
|
||||
vars.update(locals())
|
||||
shell = code.InteractiveConsole(vars)
|
||||
shell.interact()
|
||||
|
||||
|
||||
from asyncua import ua, uamethod, Server
|
||||
|
||||
|
||||
# method to be exposed through server
|
||||
def func(parent, variant):
|
||||
print("func method call with parameters: ", variant.Value)
|
||||
ret = False
|
||||
if variant.Value % 2 == 0:
|
||||
ret = True
|
||||
return [ua.Variant(ret, ua.VariantType.Boolean)]
|
||||
|
||||
|
||||
# method to be exposed through server
|
||||
async def func_async(parent, variant):
|
||||
if variant.Value % 2 == 0:
|
||||
print("Sleeping asynchronously for 1 second")
|
||||
await asyncio.sleep(1)
|
||||
else:
|
||||
print("Not sleeping!")
|
||||
|
||||
|
||||
# method to be exposed through server
|
||||
# uses a decorator to automatically convert to and from variants
|
||||
|
||||
|
||||
@uamethod
|
||||
def multiply(parent, x, y):
|
||||
print("multiply method call with parameters: ", x, y)
|
||||
return x * y
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@uamethod
|
||||
async def multiply_async(parent, x, y):
|
||||
sleep_time = x * y
|
||||
print(f"Sleeping asynchronously for {x * y} seconds")
|
||||
await asyncio.sleep(sleep_time)
|
||||
|
||||
|
||||
async def main():
|
||||
# optional: setup logging
|
||||
logging.basicConfig(level=logging.WARN)
|
||||
#logger = logging.getLogger("asyncua.address_space")
|
||||
# logger = logging.getLogger("asyncua.address_space")
|
||||
# logger.setLevel(logging.DEBUG)
|
||||
#logger = logging.getLogger("asyncua.internal_server")
|
||||
# logger = logging.getLogger("asyncua.internal_server")
|
||||
# logger.setLevel(logging.DEBUG)
|
||||
#logger = logging.getLogger("asyncua.binary_server_asyncio")
|
||||
# logger = logging.getLogger("asyncua.binary_server_asyncio")
|
||||
# logger.setLevel(logging.DEBUG)
|
||||
#logger = logging.getLogger("asyncua.uaprocessor")
|
||||
# logger = logging.getLogger("asyncua.uaprocessor")
|
||||
# logger.setLevel(logging.DEBUG)
|
||||
#logger = logging.getLogger("asyncua.subscription_service")
|
||||
# logger = logging.getLogger("asyncua.subscription_service")
|
||||
# logger.setLevel(logging.DEBUG)
|
||||
|
||||
# now setup our server
|
||||
server = Server()
|
||||
#server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
|
||||
await server.init()
|
||||
# server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
|
||||
server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
|
||||
server.set_server_name("FreeOpcUa Example Server")
|
||||
|
||||
# setup our own namespace
|
||||
uri = "http://examples.freeopcua.github.io"
|
||||
idx = server.register_namespace(uri)
|
||||
idx = await server.register_namespace(uri)
|
||||
|
||||
# get Objects node, this is where we should put our custom stuff
|
||||
objects = server.get_objects_node()
|
||||
|
||||
# populating our address space
|
||||
myfolder = objects.add_folder(idx, "myEmptyFolder")
|
||||
myobj = objects.add_object(idx, "MyObject")
|
||||
myvar = myobj.add_variable(idx, "MyVariable", 6.7)
|
||||
myvar.set_writable() # Set MyVariable to be writable by clients
|
||||
myarrayvar = myobj.add_variable(idx, "myarrayvar", [6.7, 7.9])
|
||||
myarrayvar = myobj.add_variable(idx, "myStronglytTypedVariable", ua.Variant([], ua.VariantType.UInt32))
|
||||
myprop = myobj.add_property(idx, "myproperty", "I am a property")
|
||||
mymethod = myobj.add_method(idx, "mymethod", func, [ua.VariantType.Int64], [ua.VariantType.Boolean])
|
||||
await objects.add_folder(idx, "myEmptyFolder")
|
||||
myobj = await objects.add_object(idx, "MyObject")
|
||||
myvar = await myobj.add_variable(idx, "MyVariable", 6.7)
|
||||
await myvar.set_writable() # Set MyVariable to be writable by clients
|
||||
myarrayvar = await myobj.add_variable(idx, "myarrayvar", [6.7, 7.9])
|
||||
await myobj.add_variable(
|
||||
idx, "myStronglytTypedVariable", ua.Variant([], ua.VariantType.UInt32)
|
||||
)
|
||||
await myobj.add_property(idx, "myproperty", "I am a property")
|
||||
await myobj.add_method(idx, "mymethod", func, [ua.VariantType.Int64], [ua.VariantType.Boolean])
|
||||
|
||||
inargx = ua.Argument()
|
||||
inargx.Name = "x"
|
||||
|
|
@ -90,13 +98,17 @@ if __name__ == "__main__":
|
|||
outarg.ArrayDimensions = []
|
||||
outarg.Description = ua.LocalizedText("Multiplication result")
|
||||
|
||||
multiply_node = myobj.add_method(idx, "multiply", multiply, [inargx, inargy], [outarg])
|
||||
await myobj.add_method(idx, "multiply", multiply, [inargx, inargy], [outarg])
|
||||
await myobj.add_method(idx, "multiply_async", multiply_async, [inargx, inargy], [])
|
||||
await myobj.add_method(idx, "func_async", func_async, [ua.VariantType.Int64], [])
|
||||
|
||||
# starting!
|
||||
server.start()
|
||||
print("Available loggers are: ", logging.Logger.manager.loggerDict.keys())
|
||||
try:
|
||||
async with server:
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
embed()
|
||||
finally:
|
||||
server.stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
loop = asyncio.get_event_loop()
|
||||
# loop.set_debug(True)
|
||||
loop.run_until_complete(main())
|
||||
loop.close()
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ client side since we have been carefull to have the exact
|
|||
same api on server and client side
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from asyncua import ua, uamethod, Node
|
||||
from asyncua.common import ua_utils
|
||||
from asyncua.common.methods import call_method_full
|
||||
|
|
@ -80,6 +82,15 @@ async def add_server_methods(srv):
|
|||
[ua.VariantType.Int64, ua.VariantType.Int64, ua.VariantType.Int64]
|
||||
)
|
||||
|
||||
@uamethod
|
||||
async def func6(parent):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
o = srv.get_objects_node()
|
||||
await o.add_method(
|
||||
ua.NodeId("ServerMethodAsync", 2), ua.QualifiedName('ServerMethodAsync', 2), func6, [], []
|
||||
)
|
||||
|
||||
|
||||
async def test_find_servers(opc):
|
||||
servers = await opc.opc.find_servers()
|
||||
|
|
@ -618,6 +629,13 @@ async def test_method_none(opc):
|
|||
assert [] == result.OutputArguments
|
||||
|
||||
|
||||
async def test_method_async(opc):
|
||||
o = opc.opc.get_objects_node()
|
||||
m = await o.get_child("2:ServerMethodAsync")
|
||||
await o.call_method(m)
|
||||
await call_method_full(o, m)
|
||||
|
||||
|
||||
async def test_add_nodes(opc):
|
||||
objects = opc.opc.get_objects_node()
|
||||
f = await objects.add_folder(3, 'MyFolder')
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user