ua_utils.py
Go to the documentation of this file.
00001 """
00002 Usefull method and classes not belonging anywhere and depending on opcua library
00003 """
00004 
00005 from dateutil import parser
00006 from datetime import datetime
00007 from enum import Enum, IntEnum
00008 import uuid
00009 
00010 from opcua import ua
00011 from opcua.ua.uaerrors import UaError
00012 
00013 
00014 def val_to_string(val):
00015     """
00016     convert a python object or python-opcua object to a string
00017     which should be easy to understand for human
00018     easy to modify, and not too hard to parse back ....not easy
00019     meant for UI or command lines
00020 
00021     """
00022     if isinstance(val, (list, tuple)):
00023         res = []
00024         for v in val:
00025             res.append(val_to_string(v))
00026         return "[" + ", ".join(res) + "]"
00027 
00028     if hasattr(val, "to_string"):
00029         val = val.to_string()
00030     elif isinstance(val, ua.StatusCode):
00031         val = val.name
00032     elif isinstance(val, (Enum, IntEnum)):
00033         val = val.name
00034     elif isinstance(val, ua.DataValue):
00035         val = variant_to_string(val.Value)
00036     elif isinstance(val, str):
00037         pass
00038     elif isinstance(val, bytes):
00039         val = str(val)
00040     elif isinstance(val, datetime):
00041         val = val.isoformat()
00042     elif isinstance(val, (int, float)):
00043         val = str(val)
00044     else:
00045         # FIXME: Some types are probably missing!
00046         val = str(val)
00047     return val
00048 
00049 
00050 def variant_to_string(var):
00051     """
00052     convert a variant to a string which should be easy to understand for human
00053     easy to modify, and not too hard to parse back ....not easy
00054     meant for UI or command lines
00055     """
00056     return val_to_string(var.Value)
00057 
00058 
00059 def string_to_val(string, vtype):
00060     """
00061     Convert back a string to a python or python-opcua object
00062     Note: no error checking is done here, supplying null strings could raise exceptions (datetime and guid)
00063     """
00064     string = string.strip()
00065     if string.startswith("["):
00066         string = string[1:-1]
00067         var = []
00068         for s in string.split(","):
00069             s = s.strip()
00070             val = string_to_val(s, vtype)
00071             var.append(val)
00072         return var
00073 
00074     if vtype == ua.VariantType.Null:
00075         val = None
00076     elif vtype == ua.VariantType.Boolean:
00077         if string in ("True", "true", "on", "On", "1"):
00078             val = True
00079         else:
00080             val = False
00081     elif vtype in (ua.VariantType.Int16, ua.VariantType.Int32, ua.VariantType.Int64):
00082             val = int(string)
00083     elif vtype in (ua.VariantType.UInt16, ua.VariantType.UInt32, ua.VariantType.UInt64):
00084         val = int(string)
00085     elif vtype in (ua.VariantType.Float, ua.VariantType.Double):
00086         val = float(string)
00087     elif vtype in (ua.VariantType.String, ua.VariantType.XmlElement):
00088         val = string
00089     elif vtype in (ua.VariantType.SByte, ua.VariantType.ByteString):
00090         val = string.encode("utf-8")
00091     elif vtype in (ua.VariantType.NodeId, ua.VariantType.ExpandedNodeId):
00092         val = ua.NodeId.from_string(string)
00093     elif vtype == ua.VariantType.QualifiedName:
00094         val = ua.QualifiedName.from_string(string)
00095     elif vtype == ua.VariantType.DateTime:
00096         val = parser.parse(string)
00097     elif vtype == ua.VariantType.LocalizedText:
00098         val = ua.LocalizedText(string)
00099     elif vtype == ua.VariantType.StatusCode:
00100         val = ua.StatusCode(string)
00101     elif vtype == ua.VariantType.Guid:
00102         val = uuid.UUID(string)
00103     else:
00104         # FIXME: Some types are probably missing!
00105         raise NotImplementedError
00106     return val
00107 
00108 
00109 def string_to_variant(string, vtype):
00110     """
00111     convert back a string to an ua.Variant
00112     """
00113     return ua.Variant(string_to_val(string, vtype), vtype)
00114 
00115 
00116 def get_node_children(node, nodes=None):
00117     """
00118     Get recursively all children of a node
00119     """
00120     if nodes is None:
00121         nodes = [node]
00122     for child in node.get_children():
00123         nodes.append(child)
00124         get_node_children(child, nodes)
00125     return nodes
00126 
00127 
00128 def get_node_subtypes(node, nodes=None):
00129     if nodes is None:
00130         nodes = [node]
00131     for child in node.get_children(refs=ua.ObjectIds.HasSubtype):
00132         nodes.append(child)
00133         get_node_subtypes(child, nodes)
00134     return nodes
00135 
00136 
00137 def get_node_supertypes(node, includeitself=False, skipbase=True):
00138     """
00139     return get all subtype parents of node recursive
00140     :param node: can be a ua.Node or ua.NodeId
00141     :param includeitself: include also node to the list
00142     :param skipbase don't include the toplevel one
00143     :returns list of ua.Node, top parent first 
00144     """
00145     parents = []
00146     if includeitself:
00147         parents.append(node)
00148     parents.extend(_get_node_supertypes(node))
00149     if skipbase and len(parents) > 1:
00150         parents = parents[:-1]
00151 
00152     return parents
00153 
00154 
00155 def _get_node_supertypes(node):
00156     """
00157     recursive implementation of get_node_derived_from_types
00158     """
00159     basetypes = []
00160     parent = get_node_supertype(node)
00161     if parent:
00162         basetypes.append(parent)
00163         basetypes.extend(_get_node_supertypes(parent))
00164 
00165     return basetypes
00166 
00167 
00168 def get_node_supertype(node):
00169     """
00170     return node supertype or None
00171     """
00172     supertypes = node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype,
00173                                            direction=ua.BrowseDirection.Inverse,
00174                                            includesubtypes=True)
00175     if supertypes:
00176         return supertypes[0]
00177     else:
00178         return None
00179 
00180 
00181 def is_child_present(node, browsename):
00182     """
00183     return if a browsename is present a child from the provide node
00184     :param node: node wherein to find the browsename
00185     :param browsename: browsename to search
00186     :returns returne True if the browsename is present else False 
00187     """
00188     child_descs = node.get_children_descriptions()
00189     for child_desc in child_descs:
00190         if child_desc.BrowseName == browsename:
00191             return True
00192 
00193     return False
00194 
00195 
00196 def data_type_to_variant_type(dtype_node):
00197     """
00198     Given a Node datatype, find out the variant type to encode
00199     data. This is not exactly straightforward...
00200     """
00201     base = get_base_data_type(dtype_node)
00202 
00203     if base.nodeid.Identifier != 29:
00204         return ua.VariantType(base.nodeid.Identifier)
00205     else:
00206         # we have an enumeration, we need to look at child to find type
00207         descs = dtype_node.get_children_descriptions()
00208         bnames = [d.BrowseName.Name for d in descs]
00209         if "EnumStrings" in bnames:
00210             return ua.VariantType.LocalizedText
00211         elif "EnumValues" in bnames:
00212             return ua.VariantType.ExtensionObject
00213         else:
00214             raise ua.UaError("Enumeration must have a child node describing its type and values")
00215 
00216 
00217 def get_base_data_type(datatype):
00218     """
00219     Looks up the base datatype of the provided datatype Node
00220     The base datatype is either:
00221     A primitive type (ns=0, i<=21) or a complex one (ns=0 i>21 and i<=30) like Enum and Struct.
00222     
00223     Args:
00224         datatype: NodeId of a datype of a variable
00225     Returns:
00226         NodeId of datatype base or None in case base datype can not be determined
00227     """
00228     base = datatype
00229     while base:
00230         if base.nodeid.NamespaceIndex == 0 and isinstance(base.nodeid.Identifier, int) and base.nodeid.Identifier <= 30:
00231             return base
00232         base = get_node_supertype(base)
00233     raise ua.UaError("Datatype must be a subtype of builtin types {0!s}".format(datatype))
00234 
00235 
00236 def get_nodes_of_namespace(server, namespaces=None):
00237     """
00238     Get the nodes of one or more namespaces .      
00239     Args:
00240         server: opc ua server to use
00241         namespaces: list of string uri or int indexes of the namespace to export
00242     Returns:
00243         List of nodes that are part of the provided namespaces
00244     """
00245     if namespaces is None:
00246         namespaces = []
00247     ns_available = server.get_namespace_array()
00248 
00249     if not namespaces:
00250         namespaces = ns_available[1:]
00251     elif isinstance(namespaces, (str, int)):
00252         namespaces = [namespaces]
00253 
00254     # make sure all namespace are indexes (if needed convert strings to indexes)
00255     namespace_indexes = [n if isinstance(n, int) else ns_available.index(n) for n in namespaces]
00256 
00257     # filter nodeis based on the provide namespaces and convert the nodeid to a node
00258     nodes = [server.get_node(nodeid) for nodeid in server.iserver.aspace.keys()
00259              if nodeid.NamespaceIndex != 0 and nodeid.NamespaceIndex in namespace_indexes]
00260     return nodes


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Sat Jun 8 2019 18:26:23