Commit 16acc718 authored by Denis Štogl's avatar Denis Štogl

Merge branch 'master' into event_proposal

parents 49c07a7d 305c006f
......@@ -25,7 +25,7 @@ if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
#client = Client("opc.tcp://localhost:53530/OPCUA/SimulationServer/")
client = Client("opc.tcp://olivier:olivierpass@localhost:53530/OPCUA/SimulationServer/")
client.set_security_string("Basic256,SignAndEncrypt,example-certificate.der,example-private-key.pem")
client.set_security_string("Basic256,SignAndEncrypt,certificate-example.der,private-key-example.pem")
try:
client.connect()
root = client.get_root_node()
......
......@@ -98,6 +98,13 @@ class Client(object):
self._session_counter = 1
self.keepalive = None
def __enter__(self):
self.connect()
return self
def __exit__(self):
self.disconnect()
@staticmethod
def find_endpoint(endpoints, security_mode, policy_uri):
"""
......
......@@ -37,7 +37,7 @@ def create_folder(parent, *args):
or namespace index, name
"""
nodeid, qname = _parse_add_args(*args)
return node.Node(parent.server, _create_folder(parent.server, parent.nodeid, nodeid, qname))
return node.Node(parent.server, _create_object(parent.server, parent.nodeid, nodeid, qname, ua.ObjectIds.FolderType))
def create_object(parent, *args):
......@@ -47,7 +47,7 @@ def create_object(parent, *args):
or namespace index, name
"""
nodeid, qname = _parse_add_args(*args)
return node.Node(parent.server, _create_object(parent.server, parent.nodeid, nodeid, qname))
return node.Node(parent.server, _create_object(parent.server, parent.nodeid, nodeid, qname, ua.ObjectIds.BaseObjectType))
def create_property(parent, *args):
......@@ -91,7 +91,7 @@ def create_method(parent, *args):
outputs = args[4]
else:
outputs = []
return _create_method(parent, nodeid, qname, callback, inputs, outputs)
return node.Node(parent.server, _create_method(parent, nodeid, qname, callback, inputs, outputs))
def create_subtype(parent, *args):
......@@ -177,7 +177,7 @@ def _create_method(parent, nodeid, qname, callback, inputs, outputs):
addnode.BrowseName = qname
addnode.NodeClass = ua.NodeClass.Method
addnode.ParentNodeId = parent.nodeid
addnode.ReferenceTypeId = ua.NodeId.from_string("i=47")
addnode.ReferenceTypeId = ua.NodeId(ua.ObjectIds.HasComponent)
#node.TypeDefinition = ua.NodeId(ua.ObjectIds.BaseObjectType)
attrs = ua.MethodAttributes()
attrs.Description = ua.LocalizedText(qname.Name)
......
......@@ -242,12 +242,7 @@ class Node(object):
HasNotifier = 48
HasOrderedComponent = 49
"""
references = self.get_children_descriptions(refs, nodeclassmask)
nodes = []
for desc in references:
node = Node(self.server, desc.NodeId)
nodes.append(node)
return nodes
return self.get_referenced_nodes(refs, ua.BrowseDirection.Forward, nodeclassmask)
def get_properties(self):
"""
......@@ -257,11 +252,19 @@ class Node(object):
return self.get_children(refs=ua.ObjectIds.HasProperty, nodeclassmask=ua.NodeClass.Variable)
def get_children_descriptions(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
return self.get_references(refs, ua.BrowseDirection.Forward, nodeclassmask, includesubtypes)
def get_references(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
"""
return all attributes of child nodes as UA BrowseResult structs
returns references of the node based on specific filter defined with:
refs = ObjectId of the Reference
direction = Browse direction for references
nodeclassmask = filter nodes based on specific class
includesubtypes = If true subtypes of the reference (ref) are also included
"""
desc = ua.BrowseDescription()
desc.BrowseDirection = ua.BrowseDirection.Forward
desc.BrowseDirection = direction
desc.ReferenceTypeId = ua.TwoByteNodeId(refs)
desc.IncludeSubtypes = includesubtypes
desc.NodeClassMask = nodeclassmask
......@@ -274,6 +277,36 @@ class Node(object):
results = self.server.browse(params)
return results[0].References
def get_referenced_nodes(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
"""
returns referenced nodes based on specific filter
Paramters are the same as for get_references
"""
references = self.get_references(refs, direction, nodeclassmask, includesubtypes)
nodes = []
for desc in references:
node = Node(self.server, desc.NodeId)
nodes.append(node)
return nodes
def get_type_definition(self):
"""
returns type definition of the node.
"""
references = self.get_references(refs=ua.ObjectIds.HasTypeDefinition, direction=ua.BrowseDirection.Forward)
if len(references) == 0:
return ua.ObjectIds.BaseObjectType
return references[0].NodeId.Identifier
def get_parent(self):
"""
returns parent of the node.
"""
refs = self.get_references(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse)
return Node(self.server, refs[0].NodeId)
def get_child(self, path):
"""
get a child specified by its path from this node.
......
......@@ -108,7 +108,8 @@ class ViewService(object):
"""
if ref1.Identifier == ref2.Identifier:
return True
if not subtypes and ref2.Identifier == ua.ObjectIds.HasSubtype:
#TODO: Please check the changes here
elif not subtypes:
return False
oktypes = self._get_sub_ref(ref1)
return ref2 in oktypes
......@@ -117,7 +118,7 @@ class ViewService(object):
res = []
nodedata = self._aspace[ref]
for ref in nodedata.references:
if ref.ReferenceTypeId.Identifier == ua.ObjectIds.HasSubtype:
if ref.ReferenceTypeId.Identifier == ua.ObjectIds.HasSubtype and ref.IsForward:
res.append(ref.NodeId)
res += self._get_sub_ref(ref.NodeId)
return res
......@@ -127,6 +128,8 @@ class ViewService(object):
return True
if desc == ua.BrowseDirection.Forward and isforward:
return True
if desc == ua.BrowseDirection.Inverse and not isforward:
return True
return False
def translate_browsepaths_to_nodeids(self, browsepaths):
......@@ -215,35 +218,51 @@ class NodeManagementService(object):
# add requested attrs
self._add_nodeattributes(item.NodeAttributes, nodedata)
if not item.ParentNodeId.is_null():
desc = ua.ReferenceDescription()
desc.ReferenceTypeId = item.ReferenceTypeId
desc.NodeId = nodedata.nodeid
desc.NodeClass = item.NodeClass
desc.BrowseName = item.BrowseName
desc.DisplayName = ua.LocalizedText(item.BrowseName.Name)
desc.TypeDefinition = item.TypeDefinition
desc.IsForward = True
self._aspace[item.ParentNodeId].references.append(desc)
# now add our node to db
self._aspace[nodedata.nodeid] = nodedata
if not item.ParentNodeId.is_null():
self._add_ref_from_parent(nodedata, item)
self._add_ref_to_parent(nodedata, item, user)
# add type definition
if item.TypeDefinition != ua.NodeId():
addref = ua.AddReferencesItem()
addref.SourceNodeId = nodedata.nodeid
addref.IsForward = True
addref.ReferenceTypeId = ua.NodeId(ua.ObjectIds.HasTypeDefinition)
addref.TargetNodeId = item.TypeDefinition
addref.TargetNodeClass = ua.NodeClass.DataType
self._add_reference(addref, user)
self._add_type_definition(nodedata, item, user)
result.StatusCode = ua.StatusCode()
result.AddedNodeId = nodedata.nodeid
return result
def _add_ref_from_parent(self, nodedata, item):
desc = ua.ReferenceDescription()
desc.ReferenceTypeId = item.ReferenceTypeId
desc.NodeId = nodedata.nodeid
desc.NodeClass = item.NodeClass
desc.BrowseName = item.BrowseName
desc.DisplayName = ua.LocalizedText(item.BrowseName.Name)
desc.TypeDefinition = item.TypeDefinition
desc.IsForward = True
self._aspace[item.ParentNodeId].references.append(desc)
def _add_ref_to_parent(self, nodedata, item, user):
addref = ua.AddReferencesItem()
addref.ReferenceTypeId = item.ReferenceTypeId
addref.SourceNodeId = nodedata.nodeid
addref.TargetNodeId = item.ParentNodeId
addref.TargetNodeClass = self._aspace[item.ParentNodeId].attributes[ua.AttributeIds.NodeClass].value.Value.Value
addref.IsForward = False
self._add_reference(addref, user)
def _add_type_definition(self, nodedata, item, user):
addref = ua.AddReferencesItem()
addref.SourceNodeId = nodedata.nodeid
addref.IsForward = True
addref.ReferenceTypeId = ua.NodeId(ua.ObjectIds.HasTypeDefinition)
addref.TargetNodeId = item.TypeDefinition
addref.TargetNodeClass = ua.NodeClass.DataType
self._add_reference(addref, user)
def delete_nodes(self, deletenodeitems, user=User.Admin):
results = []
for item in deletenodeitems:
......
......@@ -81,6 +81,13 @@ class Server(object):
sa_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_ServerArray))
sa_node.set_value([self.application_uri])
def __enter__(self):
self.start()
return self
def __exit__(self):
self.stop()
def load_certificate(self, path):
"""
load server certificate from file, either pem or der
......
......@@ -642,7 +642,7 @@ class QualifiedName(FrozenClass):
A string qualified with a namespace index.
'''
def __init__(self, name="", namespaceidx=0):
def __init__(self, name=None, namespaceidx=0):
if not isinstance(namespaceidx, int):
raise UaError("namespaceidx must be an int")
self.NamespaceIndex = namespaceidx
......@@ -696,14 +696,14 @@ class LocalizedText(FrozenClass):
A string qualified with a namespace index.
'''
def __init__(self, text=""):
def __init__(self, text=None):
self.Encoding = 0
self.Text = text
if isinstance(self.Text, unicode):
self.Text = self.Text.encode('utf-8')
if self.Text:
self.Encoding |= (1 << 1)
self.Locale = b''
self.Locale = None
self._freeze = True
def to_binary(self):
......
......@@ -106,8 +106,6 @@ class MySubHandlerCounter():
self.event_count += 1
class CommonTests(object):
'''
......@@ -222,14 +220,42 @@ class CommonTests(object):
self.assertTrue(prop2 in props)
self.assertFalse(var in props)
self.assertFalse(folder in props)
self.assertFalse(obj2 in props)
all_vars = obj.get_children(nodeclassmask=ua.NodeClass.Variable)
self.assertTrue(prop in all_vars)
self.assertTrue(var in all_vars)
self.assertFalse(folder in props)
self.assertFalse(obj2 in props)
all_objs = obj.get_children(nodeclassmask=ua.NodeClass.Object)
self.assertTrue(folder in all_objs)
self.assertTrue(obj2 in all_objs)
self.assertFalse(var in all_objs)
def test_browse_references(self):
objects = self.opc.get_objects_node()
folder = objects.add_folder(4, "folder")
childs = objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(folder in childs)
childs = objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Both, includesubtypes=False)
self.assertTrue(folder in childs)
childs = objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertFalse(folder in childs)
parents = folder.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(objects in parents)
parents = folder.get_referenced_nodes(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertFalse(objects in parents)
parents = folder.get_referenced_nodes(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse, includesubtypes=True)
self.assertTrue(objects in parents)
parent = folder.get_parent()
self.assertEqual(parent, objects)
def test_browsename_with_spaces(self):
o = self.opc.get_objects_node()
v = o.add_variable(3, 'BNVariable with spaces and %&+?/', 1.3)
......@@ -831,14 +857,57 @@ class CommonTests(object):
def test_add_nodes(self):
objects = self.opc.get_objects_node()
f = objects.add_folder(3, 'MyFolder')
child = objects.get_child("3:MyFolder")
self.assertEqual(child, f)
o = f.add_object(3, 'MyObject')
child = f.get_child("3:MyObject")
self.assertEqual(child, o)
v = f.add_variable(3, 'MyVariable', 6)
child = f.get_child("3:MyVariable")
self.assertEqual(child, v)
p = f.add_property(3, 'MyProperty', 10)
child = f.get_child("3:MyProperty")
self.assertEqual(child, p)
childs = f.get_children()
self.assertTrue(o in childs)
self.assertTrue(v in childs)
self.assertTrue(p in childs)
def test_references_for_added_nodes(self):
objects = self.opc.get_objects_node()
o = objects.add_object(3, 'MyObject')
nodes = objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(o in nodes)
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(objects in nodes)
self.assertEqual(o.get_parent(), objects)
self.assertEqual(o.get_type_definition(), ua.ObjectIds.BaseObjectType)
o2 = o.add_object(3, 'MySecondObject')
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(o2 in nodes)
nodes = o2.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(o in nodes)
self.assertEqual(o2.get_parent(), o)
self.assertEqual(o2.get_type_definition(), ua.ObjectIds.BaseObjectType)
v = o.add_variable(3, 'MyVariable', 6)
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(v in nodes)
nodes = v.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(o in nodes)
self.assertEqual(v.get_parent(), o)
self.assertEqual(v.get_type_definition(), ua.ObjectIds.BaseDataVariableType)
p = o.add_property(3, 'MyProperty', 2)
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.HasProperty, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(p in nodes)
nodes = p.get_referenced_nodes(refs=ua.ObjectIds.HasProperty, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(o in nodes)
self.assertEqual(p.get_parent(), o)
self.assertEqual(p.get_type_definition(), ua.ObjectIds.PropertyType)
def test_get_endpoints(self):
endpoints = self.opc.get_endpoints()
self.assertTrue(len(endpoints) > 0)
self.assertTrue(endpoints[0].EndpointUrl.startswith("opc.tcp://"))
......@@ -7,6 +7,7 @@ import opcua
from opcua import Server
from opcua import Client
from opcua import ua
from opcua import uamethod
port_num = 485140
......@@ -137,6 +138,27 @@ class TestServer(unittest.TestCase, CommonTests):
var.set_value(3.0)
self.srv.iserver.disable_history(var)
def test_references_for_added_nodes_method(self):
objects = self.opc.get_objects_node()
o = objects.add_object(3, 'MyObject')
nodes = objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(o in nodes)
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(objects in nodes)
self.assertEqual(o.get_parent(), objects)
self.assertEqual(o.get_type_definition(), ua.ObjectIds.BaseObjectType)
@uamethod
def callback(parent):
return
m = o.add_method(3, 'MyMethod', callback)
nodes = o.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Forward, includesubtypes=False)
self.assertTrue(m in nodes)
nodes = m.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
self.assertTrue(o in nodes)
self.assertEqual(m.get_parent(), o)
# This should work for following BaseEvent tests to work (maybe to write it a bit differentlly since they are not independent)
def test_get_event_from_node_BaseEvent(self):
ev = opcua.common.event.get_event_from_node(opcua.Node(self.opc.iserver.isession, ua.NodeId(ua.ObjectIds.BaseEventType)))
......@@ -152,7 +174,6 @@ class TestServer(unittest.TestCase, CommonTests):
properties = event.get_properties()
self.assertIsNot(properties, None)
def test_get_event_from_node_CustomEvent(self):
ev = opcua.common.event.get_event_from_node(opcua.Node(self.opc.iserver.isession, ua.NodeId(ua.ObjectIds.AuditEventType)))
check_base_event(self, ev)
......@@ -241,7 +262,6 @@ class TestServer(unittest.TestCase, CommonTests):
#sub.unsubscribe(handle)
#sub.delete()
def check_eventgenerator_BaseEvent(test, evgen):
test.assertIsNot(evgen, None) # we did not receive event generator
test.assertIs(evgen.isession, test.opc.iserver.isession)
......
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