Commit 962ab91c authored by Andrew's avatar Andrew Committed by ORD

Improve instantiate when parent has string node id + small fixes (#342)

* Improve instantiate when parent has string node id

* Make String node id instantiation more clear

* Fix string to value for boolean

Can't use bool(string); will always return true
Make string to UA ints more readable

* Ignore XML Extensions tag

Other modelers make this XML element which contains a model and hash
from the generation tool

* Add test for instaniate with String NodeIds

* Handle import of Null values
parent 466e159e
......@@ -13,7 +13,7 @@ def instantiate(parent, node_type, nodeid=None, bname=None, idx=0):
"""
instantiate a node type under a parent node.
nodeid and browse name of new node can be specified, or just namespace index
If they exists children of the node type, such as components, variables and
If they exists children of the node type, such as components, variables and
properties are also instantiated
"""
rdesc = _rdesc_from_node(parent, node_type)
......@@ -23,7 +23,7 @@ def instantiate(parent, node_type, nodeid=None, bname=None, idx=0):
if bname is None:
bname = rdesc.BrowseName
elif isinstance(bname, str):
bname = ua.QualifiedName.from_string(bname)
bname = ua.QualifiedName.from_string(bname)
nodeids = _instantiate_node(parent.server, parent.nodeid, rdesc, nodeid, bname)
return [Node(parent.server, nid) for nid in nodeids]
......@@ -53,7 +53,7 @@ def _instantiate_node(server, parentid, rdesc, nodeid, bname, recursive=True):
elif rdesc.NodeClass in (ua.NodeClass.Variable, ua.NodeClass.VariableType):
addnode.NodeClass = ua.NodeClass.Variable
_read_and_copy_attrs(node_type, ua.VariableAttributes(), addnode)
_read_and_copy_attrs(node_type, ua.VariableAttributes(), addnode)
elif rdesc.NodeClass in (ua.NodeClass.Method,):
addnode.NodeClass = ua.NodeClass.Method
_read_and_copy_attrs(node_type, ua.MethodAttributes(), addnode)
......@@ -63,7 +63,7 @@ def _instantiate_node(server, parentid, rdesc, nodeid, bname, recursive=True):
res = server.add_nodes([addnode])[0]
added_nodes = [res.AddedNodeId]
if recursive:
parents = ua_utils.get_node_supertypes(node_type, includeitself=True)
node = Node(server, res.AddedNodeId)
......@@ -71,10 +71,15 @@ def _instantiate_node(server, parentid, rdesc, nodeid, bname, recursive=True):
descs = parent.get_children_descriptions(includesubtypes=False)
for c_rdesc in descs:
# skip items that already exists, prefer the 'lowest' one in object hierarchy
if not ua_utils.is_child_present(node, c_rdesc.BrowseName):
nodeids = _instantiate_node(server, res.AddedNodeId, c_rdesc, nodeid=ua.NodeId(namespaceidx=res.AddedNodeId.NamespaceIndex), bname=c_rdesc.BrowseName)
if not ua_utils.is_child_present(node, c_rdesc.BrowseName):
# if root node being instantiated has a String NodeId, create the children with a String NodeId
if res.AddedNodeId.NodeIdType is ua.NodeIdType.String:
inst_nodeid = res.AddedNodeId.Identifier + "." + c_rdesc.BrowseName.Name
nodeids = _instantiate_node(server, res.AddedNodeId, c_rdesc, nodeid=ua.NodeId(identifier=inst_nodeid, namespaceidx=res.AddedNodeId.NamespaceIndex), bname=c_rdesc.BrowseName)
else:
nodeids = _instantiate_node(server, res.AddedNodeId, c_rdesc, nodeid=ua.NodeId(namespaceidx=res.AddedNodeId.NamespaceIndex), bname=c_rdesc.BrowseName)
added_nodes.extend(nodeids)
return added_nodes
......@@ -74,8 +74,13 @@ def string_to_val(string, vtype):
if vtype == ua.VariantType.Null:
val = None
elif vtype == ua.VariantType.Boolean:
val = bool(string)
elif 4 <= vtype.value < 9:
if string in ("True", "true", "on", "On", "1"):
val = True
else:
val = False
elif vtype in (ua.VariantType.Int16, ua.VariantType.Int32, ua.VariantType.Int64):
val = int(string)
elif vtype in (ua.VariantType.UInt16, ua.VariantType.UInt32, ua.VariantType.UInt64):
val = int(string)
elif vtype in (ua.VariantType.Float, ua.VariantType.Double):
val = float(string)
......
......@@ -136,7 +136,7 @@ class XMLParser(object):
nodes = []
for child in self.root:
tag = self._retag.match(child.tag).groups()[1]
if tag not in ["Aliases", "NamespaceUris"]:
if tag not in ["Aliases", "NamespaceUris", "Extensions"]: # these XML tags don't contain nodes
node = self._parse_node(tag, child)
nodes.append(node)
return nodes
......@@ -208,7 +208,10 @@ class XMLParser(object):
def _parse_value(self, val_el, obj):
child_el = val_el.find(".//") # should be only one child
ntag = self._retag.match(child_el.tag).groups()[1]
if child_el is not None:
ntag = self._retag.match(child_el.tag).groups()[1]
else:
ntag = "Null"
obj.valuetype = ntag
if ntag in ("Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64"):
......@@ -242,6 +245,8 @@ class XMLParser(object):
obj.value = self._parse_list(child_el)
elif ntag == "ExtensionObject":
obj.value = self._parse_ext_obj(child_el)
elif ntag == "Null":
obj.value = None
else:
self.logger.warning("Parsing value of type '%s' not implemented", ntag)
......
......@@ -607,8 +607,29 @@ class CommonTests(object):
prop1 = mydevicederived.get_child(["0:sensorx_id"])
var1 = mydevicederived.get_child(["0:childparam"])
var_parent = mydevicederived.get_child(["0:sensor"])
prop_parent = mydevicederived.get_child(["0:sensor_id"])
prop_parent = mydevicederived.get_child(["0:sensor_id"])
def test_instantiate_string_nodeid(self):
# Create device type
dev_t = self.opc.nodes.base_object_type.add_object_type(0, "MyDevice2")
v_t = dev_t.add_variable(0, "sensor", 1.0)
p_t = dev_t.add_property(0, "sensor_id", "0340")
ctrl_t = dev_t.add_object(0, "controller")
prop_t = ctrl_t.add_property(0, "state", "Running")
# instanciate device
nodes = instantiate(self.opc.nodes.objects, dev_t, nodeid=ua.NodeId("InstDevice", 2, ua.NodeIdType.String), bname="2:InstDevice")
mydevice = nodes[0]
self.assertEqual(mydevice.get_node_class(), ua.NodeClass.Object)
self.assertEqual(mydevice.get_type_definition(), dev_t.nodeid)
obj = mydevice.get_child(["0:controller"])
obj_nodeid_ident = obj.nodeid.Identifier
prop = mydevice.get_child(["0:controller", "0:state"])
self.assertEqual(obj_nodeid_ident, "InstDevice.controller")
self.assertEqual(prop.get_type_definition().Identifier, ua.ObjectIds.PropertyType)
self.assertEqual(prop.get_value(), "Running")
self.assertNotEqual(prop.nodeid, prop_t.nodeid)
def test_variable_with_datatype(self):
v1 = self.opc.nodes.objects.add_variable(3, 'VariableEnumType1', ua.ApplicationType.ClientAndServer, datatype=ua.NodeId(ua.ObjectIds.ApplicationType))
......
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