Commit f4a5dc52 authored by Christian Bergmiller's avatar Christian Bergmiller

cleanup

parent 053cf74f
master 3.13 3.9 312 AndreasHeine-patch-1 AndreasHeine-patch-2 AndreasHeine-patch-2-1 AndreasHeine-patch-3 AndreasHeine-patch-4 AndreasHeine-patch-create_custom_type AndreasHeine-patch-sql-history-emitting-node-is-not-the-source ISSUE_Template_bugs_workover JoeyFaulkner-bugfix/server_memory_leak Patch-missing-awaits Roles-and-Permissions-todo ZuZuD-invalid_signature add-example-for-extobj-as-method-arg add-typecheck-buildinfo add_object-instantiate-optionals add_typecheck_for_VariantType adim array array2 asyncua backport backports berg bname browse browse-multiple-nodes browse-multiple-nodes-1 bts bug builtin check ci ci2 ci3 clb clb2 clean converted-to-asyncio/asyncua csub dataclass debug dependabot/github_actions/astral-sh/setup-uv-5 dependabot/github_actions/pypa/gh-action-pypi-publish-1.12.4 dependabot/submodules/nodeset-dee1991 disconnect dos dvfix elleven enum fff fix fix3 fix_28 fix_40 fix_49 fix_59 fix_60_aiosqlite fix_71 fix_74 fix_issue_40 fix_xmlimporter_random_order fixes flake frozen github-actions hack hang hist idname ipython limits log meth method methods mult my2 newspec nikola_enumstring_support noargs nobsd noget noloop none pool prevent-instantiation-of-abstract-types prosys pypy pyth read_attr reconnect refactor_imports refactor_subscription reffix relative release rename revert rtfd ruff sampling-interval-default-value schroeder--patch-1 session set set_result sigmunau-master struct104 sub subscrition_#39 swamper123-patch-1 sync-api sync2 sync3 syncwork sz test_rewrite testing tests timeout timing tl tmp token tokenid tools typecheck typing ua_client_refactoring uaerr upd update utc utf wait 0.9.14 0.9.7 0.9.6 0.9.5 0.9.4 0.9.3 0.9.2 0.9.1 0.9.0 0.8.4 0.8.3 0.8.2 0.8.1 0.8.0 0.6.1 0.6.0 0.5.1 0.5.0 v1.05a1 v1.1.5 v1.1.4 v1.1.3 v1.1.2 v1.1.1 v1.1.0 v1.0.6 v1.0.5 v1.0.5a3 v1.0.5.a2 v1.0.5a1 v1.0.4 v1.0.3 v1.0.2 v1.0.1 v1.0.0 v0.9.98 v0.9.97 v0.9.96 v0.9.95 v0.9.94 v0.9.93 v0.9.92 v0.9.91 v0.9.90 v0.9.12 v0.9.11 v0.9.10 v0.9.9 v0.9.8
No related merge requests found
import os
os.environ['PYOPCUA_NO_TYPO_CHECK'] = 'True'
import asyncio
import logging
from opcua import Client, Node, ua
logging.basicConfig(level=logging.INFO)
......
import os
#os.environ['PYOPCUA_NO_TYPO_CHECK'] = 'True'
import asyncio
import logging
from opcua import Client, Node, ua
logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger('opcua')
async def browse_nodes(node: Node):
"""
Build a nested node tree dict by recursion (filtered by OPC UA objects and variables).
......@@ -28,7 +23,7 @@ async def browse_nodes(node: Node):
try:
var_type = (await node.get_data_type_as_variant_type()).value
except ua.UaError:
_logger.warning('Node Variable Type coudl not be determined for %r', node)
_logger.warning('Node Variable Type could not be determined for %r', node)
var_type = None
return {
'id': node.nodeid.to_string(),
......@@ -40,9 +35,9 @@ async def browse_nodes(node: Node):
async def task(loop):
# url = 'opc.tcp://192.168.2.213:4840'
url = 'opc.tcp://192.168.2.213:4840'
# url = 'opc.tcp://localhost:4840/freeopcua/server/'
url = 'opc.tcp://commsvr.com:51234/UA/CAS_UA_Server'
# url = 'opc.tcp://commsvr.com:51234/UA/CAS_UA_Server'
try:
async with Client(url=url) as client:
# Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
......
......@@ -77,6 +77,7 @@ class Client(object):
"""
Find endpoint with required security mode and policy URI
"""
_logger.info('find_endpoint %r %r %r', endpoints, security_mode, policy_uri)
for ep in endpoints:
if (ep.EndpointUrl.startswith(ua.OPC_TCP_SCHEME) and
ep.SecurityMode == security_mode and
......@@ -527,6 +528,7 @@ class Client(object):
def import_xml(self, path=None, xmlstring=None):
"""
Import nodes defined in xml
COROUTINE
"""
importer = XmlImporter(self)
return importer.import_xml(path, xmlstring)
......
......@@ -247,6 +247,7 @@ class Node:
attributeid is a member of ua.AttributeIds
datavalue is a ua.DataValue object
"""
_logger.info('Node set_attribute %r %r %r', self, attributeid, datavalue)
attr = ua.WriteValue()
attr.NodeId = self.nodeid
attr.AttributeId = attributeid
......@@ -619,7 +620,7 @@ class Node:
results = await self.server.add_references(params)
_check_results(results, len(params))
def set_modelling_rule(self, mandatory):
async def set_modelling_rule(self, mandatory):
"""
Add a modelling rule reference to Node.
When creating a new object type, its variable and child nodes will not
......
......@@ -26,14 +26,14 @@ class XmlImporter(object):
self.aliases = {}
self.refs = None
def _map_namespaces(self, namespaces_uris):
async def _map_namespaces(self, namespaces_uris):
"""
creates a mapping between the namespaces in the xml file and in the server.
if not present the namespace is registered.
"""
namespaces = {}
for ns_index, ns_uri in enumerate(namespaces_uris):
ns_server_index = self.server.register_namespace(ns_uri)
ns_server_index = await self.server.register_namespace(ns_uri)
namespaces[ns_index + 1] = ns_server_index
return namespaces
......@@ -46,14 +46,14 @@ class XmlImporter(object):
aliases_mapped[alias] = self.to_nodeid(node_id)
return aliases_mapped
def import_xml(self, xmlpath=None, xmlstring=None):
async def import_xml(self, xmlpath=None, xmlstring=None):
"""
import xml and return added nodes
"""
self.logger.info("Importing XML file %s", xmlpath)
self.parser = xmlparser.XMLParser(xmlpath, xmlstring)
self.namespaces = self._map_namespaces(self.parser.get_used_namespaces())
self.namespaces = await self._map_namespaces(self.parser.get_used_namespaces())
self.aliases = self._map_aliases(self.parser.get_aliases())
self.refs = []
......@@ -64,49 +64,50 @@ class XmlImporter(object):
nodes = []
for nodedata in nodes_parsed: # self.parser:
try:
node = self._add_node_data(nodedata)
node = await self._add_node_data(nodedata)
except Exception:
self.logger.warning("failure adding node %s", nodedata)
raise
nodes.append(node)
self.refs, remaining_refs = [], self.refs
self._add_references(remaining_refs)
await self._add_references(remaining_refs)
if len(self.refs) != 0:
self.logger.warning("The following references could not be imported and are probaly broken: %s", self.refs)
return nodes
def _add_node_data(self, nodedata):
async def _add_node_data(self, nodedata):
if nodedata.nodetype == 'UAObject':
node = self.add_object(nodedata)
node = await self.add_object(nodedata)
elif nodedata.nodetype == 'UAObjectType':
node = self.add_object_type(nodedata)
node = await self.add_object_type(nodedata)
elif nodedata.nodetype == 'UAVariable':
node = self.add_variable(nodedata)
node = await self.add_variable(nodedata)
elif nodedata.nodetype == 'UAVariableType':
node = self.add_variable_type(nodedata)
node = await self.add_variable_type(nodedata)
elif nodedata.nodetype == 'UAReferenceType':
node = self.add_reference_type(nodedata)
node = await self.add_reference_type(nodedata)
elif nodedata.nodetype == 'UADataType':
node = self.add_datatype(nodedata)
node = await self.add_datatype(nodedata)
elif nodedata.nodetype == 'UAMethod':
node = self.add_method(nodedata)
node = await self.add_method(nodedata)
else:
self.logger.warning("Not implemented node type: %s ", nodedata.nodetype)
raise ValueError(f"Not implemented node type: {nodedata.nodetype} ")
return node
def _add_node(self, node):
"""COROUTINE"""
if isinstance(self.server, opcua.server.server.Server):
return self.server.iserver.isession.add_nodes([node])
else:
return self.server.uaclient.add_nodes([node])
def _add_references(self, refs):
async def _add_references(self, refs):
if isinstance(self.server, opcua.server.server.Server):
res = self.server.iserver.isession.add_references(refs)
res = await self.server.iserver.isession.add_references(refs)
else:
res = self.server.uaclient.add_references(refs)
res = await self.server.uaclient.add_references(refs)
for sc, ref in zip(res, refs):
if not sc.is_good():
......@@ -170,7 +171,7 @@ class XmlImporter(object):
def to_nodeid(self, nodeid):
return self._migrate_ns(self._to_nodeid(nodeid))
def add_object(self, obj):
async def add_object(self, obj):
node = self._get_node(obj)
attrs = ua.ObjectAttributes()
if obj.desc:
......@@ -178,12 +179,12 @@ class XmlImporter(object):
attrs.DisplayName = ua.LocalizedText(obj.displayname)
attrs.EventNotifier = obj.eventnotifier
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def add_object_type(self, obj):
async def add_object_type(self, obj):
node = self._get_node(obj)
attrs = ua.ObjectTypeAttributes()
if obj.desc:
......@@ -191,12 +192,12 @@ class XmlImporter(object):
attrs.DisplayName = ua.LocalizedText(obj.displayname)
attrs.IsAbstract = obj.abstract
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def add_variable(self, obj):
async def add_variable(self, obj):
node = self._get_node(obj)
attrs = ua.VariableAttributes()
if obj.desc:
......@@ -216,14 +217,14 @@ class XmlImporter(object):
if obj.dimensions:
attrs.ArrayDimensions = obj.dimensions
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def _get_ext_class(self, name):
if hasattr(ua, name):
return getattr(ua, name)
return getattr(ua, name)
elif name in self.aliases.keys():
nodeid = self.aliases[name]
class_type = ua.uatypes.get_extensionobject_class_type(nodeid)
......@@ -319,7 +320,7 @@ class XmlImporter(object):
else:
return ua.Variant(obj.value, getattr(ua.VariantType, obj.valuetype))
def add_variable_type(self, obj):
async def add_variable_type(self, obj):
node = self._get_node(obj)
attrs = ua.VariableTypeAttributes()
if obj.desc:
......@@ -336,11 +337,11 @@ class XmlImporter(object):
attrs.ArrayDimensions = obj.dimensions
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def add_method(self, obj):
async def add_method(self, obj):
node = self._get_node(obj)
attrs = ua.MethodAttributes()
if obj.desc:
......@@ -355,12 +356,12 @@ class XmlImporter(object):
if obj.dimensions:
attrs.ArrayDimensions = obj.dimensions
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def add_reference_type(self, obj):
async def add_reference_type(self, obj):
node = self._get_node(obj)
attrs = ua.ReferenceTypeAttributes()
if obj.desc:
......@@ -373,12 +374,12 @@ class XmlImporter(object):
if obj.symmetric:
attrs.Symmetric = obj.symmetric
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def add_datatype(self, obj):
async def add_datatype(self, obj):
node = self._get_node(obj)
attrs = ua.DataTypeAttributes()
if obj.desc:
......@@ -387,12 +388,12 @@ class XmlImporter(object):
if obj.abstract:
attrs.IsAbstract = obj.abstract
node.NodeAttributes = attrs
res = self._add_node(node)
self._add_refs(obj)
res = await self._add_node(node)
await self._add_refs(obj)
res[0].StatusCode.check()
return res[0].AddedNodeId
def _add_refs(self, obj):
async def _add_refs(self, obj):
if not obj.refs:
return
refs = []
......@@ -404,7 +405,7 @@ class XmlImporter(object):
ref.TargetNodeClass = ua.NodeClass.DataType
ref.TargetNodeId = self.to_nodeid(data.target)
refs.append(ref)
self._add_references(refs)
await self._add_references(refs)
def _sort_nodes_by_parentid(self, ndatas):
"""
......
import pickle
import shelve
import asyncio
import logging
import collections
from threading import RLock
from datetime import datetime
from opcua import ua
from opcua.server.users import User
_logger = logging.getLogger(__name__)
class AttributeValue(object):
......
......@@ -91,13 +91,19 @@ class Server:
self.private_key = None
self._policies = []
self.nodes = Shortcuts(self.iserver.isession)
self._security_policy = ["Basic256_Sign", "Basic256_SignAndEncrypt"]
self._security_policy = [
ua.SecurityPolicyType.NoSecurity,
ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt,
ua.SecurityPolicyType.Basic128Rsa15_Sign,
ua.SecurityPolicyType.Basic256_SignAndEncrypt,
ua.SecurityPolicyType.Basic256_Sign
]
self._policyIDs = ["Anonymous", "Basic256", "Basic128", "Username"]
async def init(self, shelf_file=None):
await self.iserver.init(shelf_file)
# setup some expected values
self.set_application_uri(self._application_uri)
await self.set_application_uri(self._application_uri)
sa_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_ServerArray))
await sa_node.set_value([self._application_uri])
status_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_ServerStatus))
......@@ -136,7 +142,7 @@ class Server:
"""
self.iserver.disabled_clock = val
def set_application_uri(self, uri):
async def set_application_uri(self, uri):
"""
Set application/server URI.
This uri is supposed to be unique. If you intent to register
......@@ -250,46 +256,51 @@ class Server:
async def _setup_server_nodes(self):
# to be called just before starting server since it needs all parameters to be setup
if "None" in self._security_policy:
if ua.SecurityPolicyType.NoSecurity in self._security_policy:
self._set_endpoints()
self._policies = [ua.SecurityPolicyFactory()]
if (len(self._security_policy) > 1) and self.private_key:
if self._security_policy != [ua.SecurityPolicyType.NoSecurity]:
if not (self.certificate and self.private_key):
self.logger.warning("Endpoints other than open requested but private key and certificate are not set.")
return
if ua.SecurityPolicyType.NoSecurity in self._security_policy:
self.logger.warning(
"Creating an open endpoint to the server, although encrypted endpoints are enabled.")
if self.certificate and self.private_key:
if "Basic128Rsa15_SignAndEncrypt" in self._security_policy:
if ua.SecurityPolicyType.Basic128Rsa15_SignAndEncrypt in self._security_policy:
self._set_endpoints(security_policies.SecurityPolicyBasic128Rsa15,
ua.MessageSecurityMode.SignAndEncrypt)
ua.MessageSecurityMode.SignAndEncrypt)
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic128Rsa15,
ua.MessageSecurityMode.SignAndEncrypt,
self.certificate,
self.private_key)
)
if "Basic128Rsa15_Sign" in self._security_policy:
ua.MessageSecurityMode.SignAndEncrypt,
self.certificate,
self.private_key)
)
if ua.SecurityPolicyType.Basic128Rsa15_Sign in self._security_policy:
self._set_endpoints(security_policies.SecurityPolicyBasic128Rsa15,
ua.MessageSecurityMode.Sign)
ua.MessageSecurityMode.Sign)
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic128Rsa15,
ua.MessageSecurityMode.Sign,
self.certificate,
self.private_key)
)
if "Basic256_SignAndEncrypt" in self._security_policy:
ua.MessageSecurityMode.Sign,
self.certificate,
self.private_key)
)
if ua.SecurityPolicyType.Basic256_SignAndEncrypt in self._security_policy:
self._set_endpoints(security_policies.SecurityPolicyBasic256,
ua.MessageSecurityMode.SignAndEncrypt)
ua.MessageSecurityMode.SignAndEncrypt)
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic256,
ua.MessageSecurityMode.SignAndEncrypt,
self.certificate,
self.private_key)
)
if "Basic256_Sign" in self._security_policy:
ua.MessageSecurityMode.SignAndEncrypt,
self.certificate,
self.private_key)
)
if ua.SecurityPolicyType.Basic256_Sign in self._security_policy:
self._set_endpoints(security_policies.SecurityPolicyBasic256,
ua.MessageSecurityMode.Sign)
ua.MessageSecurityMode.Sign)
self._policies.append(ua.SecurityPolicyFactory(security_policies.SecurityPolicyBasic256,
ua.MessageSecurityMode.Sign,
self.certificate,
self.private_key)
)
ua.MessageSecurityMode.Sign,
self.certificate,
self.private_key)
)
def _set_endpoints(self, policy=ua.SecurityPolicy, mode=ua.MessageSecurityMode.None_):
idtokens = []
......@@ -503,12 +514,12 @@ class Server:
await custom_t.add_method(idx, method[0], method[1], method[2], method[3])
return custom_t
def import_xml(self, path=None, xmlstring=None):
async def import_xml(self, path=None, xmlstring=None):
"""
Import nodes defined in xml
"""
importer = XmlImporter(self)
return importer.import_xml(path, xmlstring)
return await importer.import_xml(path, xmlstring)
def export_xml(self, nodes, path):
"""
......
......@@ -468,7 +468,7 @@ def uaclient():
sys.exit(0)
def uaserver():
async def uaserver():
parser = argparse.ArgumentParser(description="Run an example OPC-UA server. By importing xml definition and using uawrite command line, it is even possible to expose real data using this server")
# we setup a server, this is a bit different from other tool so we do not reuse common arguments
parser.add_argument("-u",
......@@ -506,15 +506,16 @@ def uaserver():
logging.basicConfig(format="%(levelname)s: %(message)s", level=getattr(logging, args.loglevel))
server = Server()
await server.init()
server.set_endpoint(args.url)
if args.certificate:
server.load_certificate(args.certificate)
await server.load_certificate(args.certificate)
if args.private_key:
server.load_private_key(args.private_key)
await server.load_private_key(args.private_key)
server.disable_clock(args.disable_clock)
server.set_server_name("FreeOpcUa Example Server")
if args.xml:
server.import_xml(args.xml)
await server.import_xml(args.xml)
if args.populate:
@uamethod
def multiply(parent, x, y):
......@@ -522,7 +523,7 @@ def uaserver():
return x * y
uri = "http://examples.freeopcua.github.io"
idx = server.register_namespace(uri)
idx = await server.register_namespace(uri)
objects = server.get_objects_node()
myobj = objects.add_object(idx, "MyObject")
mywritablevar = myobj.add_variable(idx, "MyWritableVariable", 6.7)
......@@ -532,7 +533,7 @@ def uaserver():
myprop = myobj.add_property(idx, "MyProperty", "I am a property")
mymethod = myobj.add_method(idx, "MyMethod", multiply, [ua.VariantType.Double, ua.VariantType.Int64], [ua.VariantType.Double])
server.start()
await server.start()
try:
if args.shell:
embed()
......@@ -547,7 +548,7 @@ def uaserver():
while True:
time.sleep(1)
finally:
server.stop()
await server.stop()
sys.exit(0)
......
......@@ -6,15 +6,14 @@ from opcua import Client
from opcua import Server
from opcua import ua
from .tests_subscriptions import SubscriptionTests
from .tests_common import CommonTests, add_server_methods
from .tests_xml import XmlTests
from .tests_common import add_server_methods
from .tests_enum_struct import add_server_custom_enum_struct
port_num1 = 48510
_logger = logging.getLogger(__name__)
pytestmark = pytest.mark.asyncio
@pytest.fixture()
async def admin_client():
# start admin client
......
......@@ -47,7 +47,7 @@ async def discovery_server():
# start our own server
srv = Server()
await srv.init()
srv.set_application_uri('urn:freeopcua:python:discovery')
await srv.set_application_uri('urn:freeopcua:python:discovery')
srv.set_endpoint(f'opc.tcp://127.0.0.1:{port_discovery}')
await srv.start()
yield srv
......
......@@ -35,7 +35,7 @@ class ExampleStruct(uatypes.FrozenClass):
async def add_server_custom_enum_struct(server: Server):
# import some nodes from xml
server.import_xml("tests/enum_struct_test_nodes.xml")
await server.import_xml("tests/enum_struct_test_nodes.xml")
ns = await server.get_namespace_index('http://yourorganisation.org/struct_enum_example/')
uatypes.register_extension_object('ExampleStruct', ua.NodeId(5001, ns), ExampleStruct)
val = ua.ExampleStruct()
......
......@@ -2,10 +2,14 @@
import sys
import os
import asyncio
import logging
logging.basicConfig(level=logging.DEBUG)
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
from opcua.tools import uaserver
if __name__ == "__main__":
uaserver()
loop = asyncio.get_event_loop()
loop.run_until_complete(uaserver())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment