Commit ac15d133 authored by Olivier R-D's avatar Olivier R-D

add high level namespace api, set server namespace array

parent ef58b9d6
...@@ -214,6 +214,15 @@ class Client(object): ...@@ -214,6 +214,15 @@ class Client(object):
params.Priority = 0 params.Priority = 0
return Subscription(self.bclient, params, handler) return Subscription(self.bclient, params, handler)
def get_namespace_array(self):
ns_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
return ns_node.get_value()
def get_namespace_index(self, uri):
uries = self.get_namespace_array()
return uries.index(uri)
...@@ -46,6 +46,9 @@ class InternalServer(object): ...@@ -46,6 +46,9 @@ class InternalServer(object):
self._stopev = False self._stopev = False
self._timer = None self._timer = None
self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime)) self.current_time_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
uries = ["http://opcfoundation.org/UA/"]
ns_node = Node(self.isession, ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
ns_node.set_value(uries)
def start(self): def start(self):
self.logger.info("starting internal server") self.logger.info("starting internal server")
......
...@@ -7,8 +7,8 @@ import opcua.uaprotocol as ua ...@@ -7,8 +7,8 @@ import opcua.uaprotocol as ua
class Node(object): class Node(object):
""" """
High level node object, to access node attribute High level node object, to access node attribute,
and browse address space browse and populate address space
""" """
def __init__(self, server, nodeid): def __init__(self, server, nodeid):
self.server = server self.server = server
...@@ -28,19 +28,27 @@ class Node(object): ...@@ -28,19 +28,27 @@ class Node(object):
return "Node({})".format(self.nodeid) return "Node({})".format(self.nodeid)
__repr__ = __str__ __repr__ = __str__
def get_name(self): def get_browse_name(self):
result = self.get_attribute(ua.AttributeIds.BrowseName) result = self.get_attribute(ua.AttributeIds.BrowseName)
return result.Value return result.Value
def get_value(self): def get_display_name(self):
result = self.get_attribute(ua.AttributeIds.Value) result = self.get_attribute(ua.AttributeIds.DisplayName)
return result.Value return result.Value
def _value(self): def get_value(self):
"""
Get value of a node. Only variables(properties) have values.
An exception will be generated for other node types.
"""
result = self.get_attribute(ua.AttributeIds.Value) result = self.get_attribute(ua.AttributeIds.Value)
return result.Value return result.Value
def set_value(self, value, varianttype=None): def set_value(self, value, varianttype=None):
"""
Set value of a node. Only variables(properties) have values.
An exception will be generated for other node types.
"""
variant = None variant = None
if type(value) == ua.Variant: if type(value) == ua.Variant:
variant = value variant = value
...@@ -49,6 +57,9 @@ class Node(object): ...@@ -49,6 +57,9 @@ class Node(object):
self.set_attribute(ua.AttributeIds.Value, ua.DataValue(variant)) self.set_attribute(ua.AttributeIds.Value, ua.DataValue(variant))
def set_attribute(self, attributeid, datavalue): def set_attribute(self, attributeid, datavalue):
"""
Set an attribute of a node
"""
attr = ua.WriteValue() attr = ua.WriteValue()
attr.NodeId = self.nodeid attr.NodeId = self.nodeid
attr.AttributeId = attributeid attr.AttributeId = attributeid
...@@ -59,6 +70,9 @@ class Node(object): ...@@ -59,6 +70,9 @@ class Node(object):
result[0].check() result[0].check()
def get_attribute(self, attr): def get_attribute(self, attr):
"""
Get an attribute of a node
"""
rv = ua.ReadValueId() rv = ua.ReadValueId()
rv.NodeId = self.nodeid rv.NodeId = self.nodeid
rv.AttributeId = attr rv.AttributeId = attr
...@@ -68,10 +82,31 @@ class Node(object): ...@@ -68,10 +82,31 @@ class Node(object):
result[0].StatusCode.check() result[0].StatusCode.check()
return result[0].Value return result[0].Value
def get_children(self): def get_children(self, refs=ua.ObjectIds.HierarchicalReferences):
"""
Get all children of a node. By default hierarchical references are returnes.
Other types may be given:
References = 31
NonHierarchicalReferences = 32
HierarchicalReferences = 33
HasChild = 34
Organizes = 35
HasEventSource = 36
HasModellingRule = 37
HasEncoding = 38
HasDescription = 39
HasTypeDefinition = 40
GeneratesEvent = 41
Aggregates = 44
HasSubtype = 45
HasProperty = 46
HasComponent = 47
HasNotifier = 48
HasOrderedComponent = 49
"""
desc = ua.BrowseDescription() desc = ua.BrowseDescription()
desc.BrowseDirection = ua.BrowseDirection.Forward desc.BrowseDirection = ua.BrowseDirection.Forward
desc.ReferenceTypeId = ua.TwoByteNodeId(ua.ObjectIds.References) desc.ReferenceTypeId = ua.TwoByteNodeId(refs)
desc.IncludeSubtypes = True desc.IncludeSubtypes = True
desc.NodeClassMask = ua.NodeClass.Unspecified desc.NodeClassMask = ua.NodeClass.Unspecified
desc.ResultMask = ua.BrowseResultMask.None_ desc.ResultMask = ua.BrowseResultMask.None_
...@@ -87,6 +122,14 @@ class Node(object): ...@@ -87,6 +122,14 @@ class Node(object):
return nodes return nodes
def get_child(self, path): def get_child(self, path):
"""
get a child specified by its path from this node.
A path might be:
* a string representing a qualified name.
* a qualified name
* a list of string
* a list of qualified names
"""
if type(path) not in (list, tuple): if type(path) not in (list, tuple):
path = [path] path = [path]
rpath = ua.RelativePath() rpath = ua.RelativePath()
...@@ -138,6 +181,8 @@ class Node(object): ...@@ -138,6 +181,8 @@ class Node(object):
def add_object(self, *args): def add_object(self, *args):
""" """
create a child node object create a child node object
arguments are nodeid, browsename
or namespace index, name
""" """
nodeid, qname = self._parse_add_args(*args) nodeid, qname = self._parse_add_args(*args)
return self._add_object(nodeid, qname) return self._add_object(nodeid, qname)
...@@ -210,7 +255,36 @@ class Node(object): ...@@ -210,7 +255,36 @@ class Node(object):
results = self.server.add_nodes([node]) results = self.server.add_nodes([node])
results[0].StatusCode.check() results[0].StatusCode.check()
return Node(self.server, nodeid) return Node(self.server, nodeid)
def add_method(self, *args):
"""
create a child method object
"""
nodeid, qname = self._parse_add_args(*args)
return self._add_object(nodeid, qname)
def _add_method(self, nodeid, qname):
node = ua.AddNodesItem()
node.RequestedNewNodeId = nodeid
node.BrowseName = qname
node.NodeClass = ua.NodeClass.Object
node.ParentNodeId = self.nodeid
node.ReferenceTypeId = ua.NodeId.from_string("i=35")
node.TypeDefinition = ua.NodeId(ua.ObjectIds.BaseObjectType)
attrs = ua.MethodAttributes()
attrs.Description = ua.LocalizedText(qname.Name)
attrs.DisplayName = ua.LocalizedText(qname.Name)
attrs.WriteMask = 0
attrs.UserWriteMask = 0
self.Executable = True
self.UserExecutable = True
node.NodeAttributes = attrs
results = self.server.add_nodes([node])
results[0].StatusCode.check()
return Node(self.server, nodeid)
def _vtype_to_uatype(self, vtype): def _vtype_to_uatype(self, vtype):
return eval("ua.NodeId(ua.ObjectIds.{})".format(vtype.name)) return eval("ua.NodeId(ua.ObjectIds.{})".format(vtype.name))
......
...@@ -30,8 +30,14 @@ class Server(object): ...@@ -30,8 +30,14 @@ class Server(object):
def set_endpoint(self, url): def set_endpoint(self, url):
self.endpoint = urlparse(url) self.endpoint = urlparse(url)
def _set_endpoints(self): def _setup_server_nodes(self):
#to be called just before starting server since it needs all parameters to be setup #to be called just before starting server since it needs all parameters to be setup
self._set_endpoints()
self.register_namespace(self.server_uri)
sa_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_ServerArray))
sa_node.set_value([self.server_uri])
def _set_endpoints(self):
idtoken = ua.UserTokenPolicy() idtoken = ua.UserTokenPolicy()
idtoken.PolicyId = 'anonymous' idtoken.PolicyId = 'anonymous'
idtoken.TokenType = ua.UserTokenType.Anonymous idtoken.TokenType = ua.UserTokenType.Anonymous
...@@ -58,7 +64,7 @@ class Server(object): ...@@ -58,7 +64,7 @@ class Server(object):
def start(self): def start(self):
self.iserver.start() self.iserver.start()
self._set_endpoints() self._setup_server_nodes()
self.bserver = BinaryServer(self.iserver, self.endpoint.hostname, self.endpoint.port) self.bserver = BinaryServer(self.iserver, self.endpoint.hostname, self.endpoint.port)
self.bserver.start() self.bserver.start()
...@@ -94,6 +100,21 @@ class Server(object): ...@@ -94,6 +100,21 @@ class Server(object):
params.Priority = 0 params.Priority = 0
return Subscription(self.iserver.isession, params, handler) return Subscription(self.iserver.isession, params, handler)
def get_namespace_array(self):
ns_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
return ns_node.get_value()
def register_namespace(self, uri):
ns_node = self.get_node(ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
uries = ns_node.get_value()
uries.append(uri)
ns_node.set_value(uries)
return (len(uries)-1)
def get_namespace_index(self, uri):
uries = self.get_namespace_array()
return uries.index(uri)
......
...@@ -185,13 +185,13 @@ class CommonTests(object): ...@@ -185,13 +185,13 @@ class CommonTests(object):
def test_root(self): def test_root(self):
root = self.opc.get_root_node() root = self.opc.get_root_node()
self.assertEqual(ua.QualifiedName('Root', 0), root.get_name()) self.assertEqual(ua.QualifiedName('Root', 0), root.get_browse_name())
nid = ua.NodeId(84, 0) nid = ua.NodeId(84, 0)
self.assertEqual(nid, root.nodeid) self.assertEqual(nid, root.nodeid)
def test_objects(self): def test_objects(self):
objects = self.opc.get_objects_node() objects = self.opc.get_objects_node()
self.assertEqual(ua.QualifiedName('Objects', 0), objects.get_name()) self.assertEqual(ua.QualifiedName('Objects', 0), objects.get_browse_name())
nid = ua.NodeId(85, 0) nid = ua.NodeId(85, 0)
self.assertEqual(nid, objects.nodeid) self.assertEqual(nid, objects.nodeid)
...@@ -242,13 +242,13 @@ class CommonTests(object): ...@@ -242,13 +242,13 @@ class CommonTests(object):
#sub.delete() #sub.delete()
#def test_get_NamespaceIndex(self): #def test_get_browse_namespaceIndex(self):
#idx = self.opc.get_NamespaceIndex('http://freeua.github.io') #idx = self.opc.get_browse_namespaceIndex('http://freeua.github.io')
#self.assertEqual(idx, 1) #self.assertEqual(idx, 1)
#def test_use_namespace(self): #def test_use_namespace(self):
#root = self.opc.get_root_node() #root = self.opc.get_root_node()
#idx = self.opc.get_NamespaceIndex('http://freeua.github.io') #idx = self.opc.get_browse_namespaceIndex('http://freeua.github.io')
#o = root.add_object(idx, 'test_namespace') #o = root.add_object(idx, 'test_namespace')
#self.assertEqual(idx, o.nodeid.NamespaceIndex) #self.assertEqual(idx, o.nodeid.NamespaceIndex)
#o2 = root.get_child('{}:test_namespace'.format(idx)) #o2 = root.get_child('{}:test_namespace'.format(idx))
...@@ -286,7 +286,7 @@ class CommonTests(object): ...@@ -286,7 +286,7 @@ class CommonTests(object):
nid = ua.NodeId(888, 3) nid = ua.NodeId(888, 3)
qn = ua.QualifiedName('numericnodefromstring', 3) qn = ua.QualifiedName('numericnodefromstring', 3)
self.assertEqual(nid, v.nodeid) self.assertEqual(nid, v.nodeid)
self.assertEqual(qn, v.get_name()) self.assertEqual(qn, v.get_browse_name())
def test_add_string_variable(self): def test_add_string_variable(self):
objects = self.opc.get_objects_node() objects = self.opc.get_objects_node()
...@@ -294,7 +294,7 @@ class CommonTests(object): ...@@ -294,7 +294,7 @@ class CommonTests(object):
nid = ua.NodeId('stringid', 3) nid = ua.NodeId('stringid', 3)
qn = ua.QualifiedName('stringnodefromstring', 3) qn = ua.QualifiedName('stringnodefromstring', 3)
self.assertEqual(nid, v.nodeid) self.assertEqual(nid, v.nodeid)
self.assertEqual(qn, v.get_name()) self.assertEqual(qn, v.get_browse_name())
def test_add_string_array_variable(self): def test_add_string_array_variable(self):
objects = self.opc.get_objects_node() objects = self.opc.get_objects_node()
...@@ -302,7 +302,7 @@ class CommonTests(object): ...@@ -302,7 +302,7 @@ class CommonTests(object):
nid = ua.NodeId('stringarrayid', 3) nid = ua.NodeId('stringarrayid', 3)
qn = ua.QualifiedName('stringarray', 9) qn = ua.QualifiedName('stringarray', 9)
self.assertEqual(nid, v.nodeid) self.assertEqual(nid, v.nodeid)
self.assertEqual(qn, v.get_name()) self.assertEqual(qn, v.get_browse_name())
val = v.get_value() val = v.get_value()
self.assertEqual(['l', 'b'], val) self.assertEqual(['l', 'b'], val)
...@@ -312,7 +312,7 @@ class CommonTests(object): ...@@ -312,7 +312,7 @@ class CommonTests(object):
qn = ua.QualifiedName('AddNodeVar1', 3) qn = ua.QualifiedName('AddNodeVar1', 3)
v1 = objects.add_variable(nid, qn, 0) v1 = objects.add_variable(nid, qn, 0)
self.assertEqual(nid, v1.nodeid) self.assertEqual(nid, v1.nodeid)
self.assertEqual(qn, v1.get_name()) self.assertEqual(qn, v1.get_browse_name())
def test_add_string_node(self): def test_add_string_node(self):
objects = self.opc.get_objects_node() objects = self.opc.get_objects_node()
...@@ -320,7 +320,7 @@ class CommonTests(object): ...@@ -320,7 +320,7 @@ class CommonTests(object):
nid = ua.NodeId('AddNodeVar2Id', 3) nid = ua.NodeId('AddNodeVar2Id', 3)
v2 = objects.add_variable(nid, qn, 0) v2 = objects.add_variable(nid, qn, 0)
self.assertEqual(nid, v2.nodeid) self.assertEqual(nid, v2.nodeid)
self.assertEqual(qn, v2.get_name()) self.assertEqual(qn, v2.get_browse_name())
def test_add_find_node_(self): def test_add_find_node_(self):
objects = self.opc.get_objects_node() objects = self.opc.get_objects_node()
...@@ -341,7 +341,7 @@ class CommonTests(object): ...@@ -341,7 +341,7 @@ class CommonTests(object):
nid = ua.NodeId(102, 2) nid = ua.NodeId(102, 2)
self.assertEqual(o.nodeid, nid) self.assertEqual(o.nodeid, nid)
qn = ua.QualifiedName('AddReadObject', 2) qn = ua.QualifiedName('AddReadObject', 2)
self.assertEqual(o.get_name(), qn) self.assertEqual(o.get_browse_name(), qn)
def test_simple_value(self): def test_simple_value(self):
o = self.opc.get_objects_node() o = self.opc.get_objects_node()
...@@ -438,6 +438,13 @@ class CommonTests(object): ...@@ -438,6 +438,13 @@ class CommonTests(object):
sub.unsubscribe(handle) sub.unsubscribe(handle)
sub.delete() sub.delete()
def test_use_namespace(self):
idx = self.opc.get_namespace_index("urn:freeopcua:python:server")
self.assertEqual(idx, 1)
root = self.opc.get_root_node()
myvar = root.add_variable(idx, 'var_in_custom_namespace', [5])
myid = myvar.nodeid
self.assertEqual(idx, myid.NamespaceIndex)
...@@ -501,7 +508,7 @@ class TestClient(unittest.TestCase, CommonTests): ...@@ -501,7 +508,7 @@ class TestClient(unittest.TestCase, CommonTests):
# new one before this one is really stopped # new one before this one is really stopped
self.srv.join() self.srv.join()
"""
class TestServer(unittest.TestCase, CommonTests): class TestServer(unittest.TestCase, CommonTests):
''' '''
...@@ -527,11 +534,11 @@ class TestServer(unittest.TestCase, CommonTests): ...@@ -527,11 +534,11 @@ class TestServer(unittest.TestCase, CommonTests):
self.assertTrue(v in childs) self.assertTrue(v in childs)
self.assertTrue(p in childs) self.assertTrue(p in childs)
'''
def test_register_namespace(self): def test_register_namespace(self):
uri = 'http://mycustom.Namespace.com' uri = 'http://mycustom.Namespace.com'
idx1 = self.opc.register_namespace(uri) idx1 = self.opc.register_namespace(uri)
idx2 = self.opc.get_NamespaceIndex(uri) idx2 = self.opc.get_namespace_index(uri)
self.assertEqual(idx1, idx2) self.assertEqual(idx1, idx2)
def test_register_use_namespace(self): def test_register_use_namespace(self):
...@@ -541,9 +548,8 @@ class TestServer(unittest.TestCase, CommonTests): ...@@ -541,9 +548,8 @@ class TestServer(unittest.TestCase, CommonTests):
myvar = root.add_variable(idx, 'var_in_custom_namespace', [5]) myvar = root.add_variable(idx, 'var_in_custom_namespace', [5])
myid = myvar.nodeid myid = myvar.nodeid
self.assertEqual(idx, myid.NamespaceIndex) self.assertEqual(idx, myid.NamespaceIndex)
#self.assertEqual(uri, myid.Namespace_uri) #FIXME: should return uri!!!
'''
"""
......
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