Skip to content

Commit

Permalink
finish client implementation for custom structures
Browse files Browse the repository at this point in the history
  • Loading branch information
oroulet committed Mar 19, 2017
1 parent ede59f4 commit 1671288
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 240 deletions.
31 changes: 24 additions & 7 deletions opcua/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,21 +551,38 @@ def register_namespace(self, uri):
ns_node.set_value(uries)
return len(uries) - 1

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

for node in nodes:
xml = node.get_value()
gen = StructGenerator(xml, name)
xml = xml.decode("utf-8")
#with open("titi.xml", "w") as f:
#f.write(xml)
name = "structures_" + node.get_browse_name().Name
gen = StructGenerator()
gen.make_model_from_string(xml)
structs_dict = gen.save_and_import(name + ".py")
# register classes
for desc in node.get_children_descriptions():
if desc.BrowseName.Name in structs_dict:
self.logger.info("registring new structure: %: %s", desc.NodeId, desc.BrowseName.Name)
ua.extension_object_classes[desc.NodeId] = structs_dict[desc.BrowseName.Name]
ua.extension_object_ids[desc.BrowseName.Name] = desc.NodeId




1 change: 1 addition & 0 deletions opcua/common/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ def __init__(self, server):
self.variable_types = Node(server, ObjectIds.VariableTypesFolder)
self.object_types = Node(server, ObjectIds.ObjectTypesFolder)
self.namespace_array = Node(server, ObjectIds.Server_NamespaceArray)
self.opc_binary = Node(server, ObjectIds.OPCBinarySchema_TypeSystem)
43 changes: 28 additions & 15 deletions opcua/common/structures_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
for custom structures
"""

import os
import importlib

from lxml import objectify


Expand Down Expand Up @@ -123,15 +126,19 @@ def __init__(self, name):


class StructGenerator(object):
def __init__(self, path, output):
self.path = path
self.output = output
def __init__(self):
self.model = []
self._file = None

def _make_model(self):
obj = objectify.parse(self.path)
def make_model_from_string(self, xml):
obj = objectify.fromstring(xml)
self._make_model(obj)

def make_model_from_file(self, path):
obj = objectify.parse(path)
root = obj.getroot()
self._make_model(root)

def _make_model(self, root):
for child in root.iter("{*}StructuredType"):
struct = Struct(child.get("Name"))
array = False
Expand All @@ -152,23 +159,29 @@ def _make_model(self):
struct.fields.append(field)
self.model.append(struct)

def run(self):
self._make_model()
self._file = open(self.output, "wt")
self._make_header()
def save_to_file(self, path):
_file = open(path, "wt")
self._make_header(_file)
for struct in self.model:
self._file.write(struct.get_code())
self._file.close()
_file.write(struct.get_code())
_file.close()

def save_and_import(self, path):
self.save_to_file(path)
name = os.path.basename(path)
name = os.path.splitext(name)[0]
mymodule = importlib.import_module(name)
mydict = {struct.name: getattr(mymodule, struct.name) for struct in self.model}
return mydict

def get_structures(self):
self._make_model()
ld = {}
for struct in self.model:
exec(struct.get_code(), ld)
return ld

def _make_header(self):
self._file.write("""
def _make_header(self, _file):
_file.write("""
'''
THIS FILE IS AUTOGENERATED, DO NOT EDIT!!!
'''
Expand Down
Loading

0 comments on commit 1671288

Please sign in to comment.