Skip to content

Commit 1671288

Browse files
committed
finish client implementation for custom structures
1 parent ede59f4 commit 1671288

6 files changed

Lines changed: 279 additions & 240 deletions

File tree

opcua/client/client.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -551,21 +551,38 @@ def register_namespace(self, uri):
551551
ns_node.set_value(uries)
552552
return len(uries) - 1
553553

554-
def import_structures(self, nodes=None):
554+
def import_and_register_structures(self, nodes=None):
555555
"""
556556
Download xml from given variable node defining custom structures.
557-
If no node is given, attemps to import variables from
557+
If no no node is given, attemps to import variables from all nodes under
558+
"0:OPC Binary"
559+
the code is generated and imported on the fly. If you know the structures
560+
are not going to be modified it is safer to copy the generated files
561+
and include them in you code
558562
"""
559-
if not nodes:
563+
if nodes is None:
560564
nodes = []
561-
opc_bin = self.nodes.base_data_type.get_child("0:OPC Binary")
562-
for desc in opc_bin.get_children_descriptions():
563-
if desc.BrowseName != ua.QualifiedName("opc.Ua"):
565+
for desc in self.nodes.opc_binary.get_children_descriptions():
566+
if desc.BrowseName != ua.QualifiedName("Opc.Ua"):
564567
nodes.append(self.get_node(desc.NodeId))
568+
self.logger.info("Importing structures from nodes: %s", nodes)
565569

566570
for node in nodes:
567571
xml = node.get_value()
568-
gen = StructGenerator(xml, name)
572+
xml = xml.decode("utf-8")
573+
#with open("titi.xml", "w") as f:
574+
#f.write(xml)
575+
name = "structures_" + node.get_browse_name().Name
576+
gen = StructGenerator()
577+
gen.make_model_from_string(xml)
578+
structs_dict = gen.save_and_import(name + ".py")
579+
# register classes
580+
for desc in node.get_children_descriptions():
581+
if desc.BrowseName.Name in structs_dict:
582+
self.logger.info("registring new structure: %: %s", desc.NodeId, desc.BrowseName.Name)
583+
ua.extension_object_classes[desc.NodeId] = structs_dict[desc.BrowseName.Name]
584+
ua.extension_object_ids[desc.BrowseName.Name] = desc.NodeId
585+
569586

570587

571588

opcua/common/shortcuts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ def __init__(self, server):
2424
self.variable_types = Node(server, ObjectIds.VariableTypesFolder)
2525
self.object_types = Node(server, ObjectIds.ObjectTypesFolder)
2626
self.namespace_array = Node(server, ObjectIds.Server_NamespaceArray)
27+
self.opc_binary = Node(server, ObjectIds.OPCBinarySchema_TypeSystem)

opcua/common/structures_generator.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
for custom structures
55
"""
66

7+
import os
8+
import importlib
9+
710
from lxml import objectify
811

912

@@ -123,15 +126,19 @@ def __init__(self, name):
123126

124127

125128
class StructGenerator(object):
126-
def __init__(self, path, output):
127-
self.path = path
128-
self.output = output
129+
def __init__(self):
129130
self.model = []
130-
self._file = None
131131

132-
def _make_model(self):
133-
obj = objectify.parse(self.path)
132+
def make_model_from_string(self, xml):
133+
obj = objectify.fromstring(xml)
134+
self._make_model(obj)
135+
136+
def make_model_from_file(self, path):
137+
obj = objectify.parse(path)
134138
root = obj.getroot()
139+
self._make_model(root)
140+
141+
def _make_model(self, root):
135142
for child in root.iter("{*}StructuredType"):
136143
struct = Struct(child.get("Name"))
137144
array = False
@@ -152,23 +159,29 @@ def _make_model(self):
152159
struct.fields.append(field)
153160
self.model.append(struct)
154161

155-
def run(self):
156-
self._make_model()
157-
self._file = open(self.output, "wt")
158-
self._make_header()
162+
def save_to_file(self, path):
163+
_file = open(path, "wt")
164+
self._make_header(_file)
159165
for struct in self.model:
160-
self._file.write(struct.get_code())
161-
self._file.close()
166+
_file.write(struct.get_code())
167+
_file.close()
168+
169+
def save_and_import(self, path):
170+
self.save_to_file(path)
171+
name = os.path.basename(path)
172+
name = os.path.splitext(name)[0]
173+
mymodule = importlib.import_module(name)
174+
mydict = {struct.name: getattr(mymodule, struct.name) for struct in self.model}
175+
return mydict
162176

163177
def get_structures(self):
164-
self._make_model()
165178
ld = {}
166179
for struct in self.model:
167180
exec(struct.get_code(), ld)
168181
return ld
169182

170-
def _make_header(self):
171-
self._file.write("""
183+
def _make_header(self, _file):
184+
_file.write("""
172185
'''
173186
THIS FILE IS AUTOGENERATED, DO NOT EDIT!!!
174187
'''

0 commit comments

Comments
 (0)