node.py
Go to the documentation of this file.
00001 """
00002 High level node object, to access node attribute
00003 and browse address space
00004 """
00005 
00006 from opcua import ua
00007 from opcua.common import events
00008 import opcua.common
00009 
00010 class Node(object):
00011 
00012     """
00013     High level node object, to access node attribute,
00014     browse and populate address space.
00015     Node objects are usefull as-is but they do not expose the entire
00016     OPC-UA protocol. Feel free to look at the code of this class and call
00017     directly UA services methods to optimize your code
00018     """
00019 
00020     def __init__(self, server, nodeid):
00021         self.server = server
00022         self.nodeid = None
00023         if isinstance(nodeid, Node):
00024             self.nodeid = nodeid.nodeid
00025         elif isinstance(nodeid, ua.NodeId):
00026             self.nodeid = nodeid
00027         elif type(nodeid) in (str, bytes):
00028             self.nodeid = ua.NodeId.from_string(nodeid)
00029         elif isinstance(nodeid, int):
00030             self.nodeid = ua.NodeId(nodeid, 0)
00031         else:
00032             raise ua.UaError("argument to node must be a NodeId object or a string defining a nodeid found {0} of type {1}".format(nodeid, type(nodeid)))
00033 
00034     def __eq__(self, other):
00035         if isinstance(other, Node) and self.nodeid == other.nodeid:
00036             return True
00037         return False
00038 
00039     def __ne__(self, other):
00040         return not self.__eq__(other)
00041 
00042     def __str__(self):
00043         return "Node({0})".format(self.nodeid)
00044     __repr__ = __str__
00045 
00046     def __hash__(self):
00047         return self.nodeid.__hash__()
00048 
00049     def get_browse_name(self):
00050         """
00051         Get browse name of a node. A browse name is a QualifiedName object
00052         composed of a string(name) and a namespace index.
00053         """
00054         result = self.get_attribute(ua.AttributeIds.BrowseName)
00055         return result.Value.Value
00056 
00057     def get_display_name(self):
00058         """
00059         get description attribute of node
00060         """
00061         result = self.get_attribute(ua.AttributeIds.DisplayName)
00062         return result.Value.Value
00063 
00064     def get_data_type(self):
00065         """
00066         get data type of node as NodeId
00067         """
00068         result = self.get_attribute(ua.AttributeIds.DataType)
00069         return result.Value.Value
00070 
00071     def get_data_type_as_variant_type(self):
00072         """
00073         get data type of node as VariantType
00074         This only works if node is a variable, otherwise type
00075         may not be convertible to VariantType
00076         """
00077         result = self.get_attribute(ua.AttributeIds.DataType)
00078         return ua.datatype_to_varianttype(result.Value.Value)
00079 
00080     def get_access_level(self):
00081         """
00082         Get the access level attribute of the node as a set of AccessLevel enum values.
00083         """
00084         result = self.get_attribute(ua.AttributeIds.AccessLevel)
00085         return ua.AccessLevel.parse_bitfield(result.Value.Value)
00086 
00087     def get_user_access_level(self):
00088         """
00089         Get the user access level attribute of the node as a set of AccessLevel enum values.
00090         """
00091         result = self.get_attribute(ua.AttributeIds.UserAccessLevel)
00092         return ua.AccessLevel.parse_bitfield(result.Value.Value)
00093 
00094     def get_event_notifier(self):
00095         """
00096         Get the event notifier attribute of the node as a set of EventNotifier enum values.
00097         """
00098         result = self.get_attribute(ua.AttributeIds.EventNotifier)
00099         return ua.EventNotifier.parse_bitfield(result.Value.Value)
00100 
00101     def set_event_notifier(self, values):
00102         """
00103         Set the event notifier attribute.
00104 
00105         :param values: an iterable of EventNotifier enum values.
00106         """
00107         event_notifier_bitfield = ua.EventNotifier.to_bitfield(values)
00108         self.set_attribute(ua.AttributeIds.EventNotifier, ua.DataValue(ua.Variant(event_notifier_bitfield, ua.VariantType.Byte)))
00109 
00110     def get_node_class(self):
00111         """
00112         get node class attribute of node
00113         """
00114         result = self.get_attribute(ua.AttributeIds.NodeClass)
00115         return result.Value.Value
00116 
00117     def get_description(self):
00118         """
00119         get description attribute class of node
00120         """
00121         result = self.get_attribute(ua.AttributeIds.Description)
00122         return result.Value.Value
00123 
00124     def get_value(self):
00125         """
00126         Get value of a node as a python type. Only variables ( and properties) have values.
00127         An exception will be generated for other node types.
00128         """
00129         result = self.get_data_value()
00130         return result.Value.Value
00131 
00132     def get_data_value(self):
00133         """
00134         Get value of a node as a DataValue object. Only variables (and properties) have values.
00135         An exception will be generated for other node types.
00136         DataValue contain a variable value as a variant as well as server and source timestamps
00137         """
00138         return self.get_attribute(ua.AttributeIds.Value)
00139 
00140     def set_array_dimensions(self, value):
00141         """
00142         Set attribute ArrayDimensions of node
00143         make sure it has the correct data type
00144         """
00145         v = ua.Variant(value, ua.VariantType.UInt32)
00146         self.set_attribute(ua.AttributeIds.ArrayDimensions, ua.DataValue(v))
00147 
00148     def get_array_dimensions(self):
00149         """
00150         Read and return ArrayDimensions attribute of node
00151         """
00152         res = self.get_attribute(ua.AttributeIds.ArrayDimensions)
00153         return res.Value.Value
00154 
00155     def set_value_rank(self, value):
00156         """
00157         Set attribute ArrayDimensions of node
00158         """
00159         v = ua.Variant(value, ua.VariantType.Int32)
00160         self.set_attribute(ua.AttributeIds.ValueRank, ua.DataValue(v))
00161 
00162     def get_value_rank(self):
00163         """
00164         Read and return ArrayDimensions attribute of node
00165         """
00166         res = self.get_attribute(ua.AttributeIds.ValueRank)
00167         return res.Value.Value
00168 
00169     def set_value(self, value, varianttype=None):
00170         """
00171         Set value of a node. Only variables(properties) have values.
00172         An exception will be generated for other node types.
00173         value argument is either:
00174         * a python built-in type, converted to opc-ua
00175         optionnaly using the variantype argument.
00176         * a ua.Variant, varianttype is then ignored
00177         * a ua.DataValue, you then have full control over data send to server
00178         """
00179         datavalue = None
00180         if isinstance(value, ua.DataValue):
00181             datavalue = value
00182         elif isinstance(value, ua.Variant):
00183             datavalue = ua.DataValue(value)
00184         else:
00185             datavalue = ua.DataValue(ua.Variant(value, varianttype))
00186         self.set_attribute(ua.AttributeIds.Value, datavalue)
00187 
00188     set_data_value = set_value
00189 
00190     def set_writable(self, writable=True):
00191         """
00192         Set node as writable by clients.
00193         A node is always writable on server side.
00194         """
00195         if writable:
00196             self.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.CurrentWrite)
00197             self.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.CurrentWrite)
00198         else:
00199             self.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.CurrentWrite)
00200             self.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.CurrentWrite)
00201 
00202     def set_attr_bit(self, attr, bit):
00203         val = self.get_attribute(attr)
00204         val.Value.Value = ua.ua_binary.set_bit(val.Value.Value, bit)
00205         self.set_attribute(attr, val)
00206 
00207     def unset_attr_bit(self, attr, bit):
00208         val = self.get_attribute(attr)
00209         val.Value.Value = ua.ua_binary.unset_bit(val.Value.Value, bit)
00210         self.set_attribute(attr, val)
00211 
00212     def set_read_only(self):
00213         """
00214         Set a node as read-only for clients.
00215         A node is always writable on server side.
00216         """
00217         return self.set_writable(False)
00218 
00219     def set_attribute(self, attributeid, datavalue):
00220         """
00221         Set an attribute of a node
00222         attributeid is a member of ua.AttributeIds
00223         datavalue is a ua.DataValue object
00224         """
00225         attr = ua.WriteValue()
00226         attr.NodeId = self.nodeid
00227         attr.AttributeId = attributeid
00228         attr.Value = datavalue
00229         params = ua.WriteParameters()
00230         params.NodesToWrite = [attr]
00231         result = self.server.write(params)
00232         result[0].check()
00233 
00234     def get_attribute(self, attr):
00235         """
00236         Read one attribute of a node
00237         result code from server is checked and an exception is raised in case of error
00238         """
00239         rv = ua.ReadValueId()
00240         rv.NodeId = self.nodeid
00241         rv.AttributeId = attr
00242         params = ua.ReadParameters()
00243         params.NodesToRead.append(rv)
00244         result = self.server.read(params)
00245         result[0].StatusCode.check()
00246         return result[0]
00247 
00248     def get_attributes(self, attrs):
00249         """
00250         Read several attributes of a node
00251         list of DataValue is returned
00252         """
00253         params = ua.ReadParameters()
00254         for attr in attrs:
00255             rv = ua.ReadValueId()
00256             rv.NodeId = self.nodeid
00257             rv.AttributeId = attr
00258             params.NodesToRead.append(rv)
00259 
00260         results = self.server.read(params)
00261         return results
00262 
00263     def get_children(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified):
00264         """
00265         Get all children of a node. By default hierarchical references and all node classes are returned.
00266         Other reference types may be given:
00267         References = 31
00268         NonHierarchicalReferences = 32
00269         HierarchicalReferences = 33
00270         HasChild = 34
00271         Organizes = 35
00272         HasEventSource = 36
00273         HasModellingRule = 37
00274         HasEncoding = 38
00275         HasDescription = 39
00276         HasTypeDefinition = 40
00277         GeneratesEvent = 41
00278         Aggregates = 44
00279         HasSubtype = 45
00280         HasProperty = 46
00281         HasComponent = 47
00282         HasNotifier = 48
00283         HasOrderedComponent = 49
00284         """
00285         return self.get_referenced_nodes(refs, ua.BrowseDirection.Forward, nodeclassmask)
00286 
00287     def get_properties(self):
00288         """
00289         return properties of node.
00290         properties are child nodes with a reference of type HasProperty and a NodeClass of Variable
00291         """
00292         return self.get_children(refs=ua.ObjectIds.HasProperty, nodeclassmask=ua.NodeClass.Variable)
00293 
00294     def get_variables(self):
00295         """
00296         return variables of node.
00297         properties are child nodes with a reference of type HasComponent and a NodeClass of Variable
00298         """
00299         return self.get_children(refs=ua.ObjectIds.HasComponent, nodeclassmask=ua.NodeClass.Variable)
00300 
00301     def get_methods(self):
00302         """
00303         return methods of node.
00304         properties are child nodes with a reference of type HasComponent and a NodeClass of Method
00305         """
00306         return self.get_children(refs=ua.ObjectIds.HasComponent, nodeclassmask=ua.NodeClass.Method)
00307 
00308     def get_children_descriptions(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
00309         return self.get_references(refs, ua.BrowseDirection.Forward, nodeclassmask, includesubtypes)
00310 
00311     def get_references(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
00312         """
00313         returns references of the node based on specific filter defined with:
00314 
00315         refs = ObjectId of the Reference
00316         direction = Browse direction for references
00317         nodeclassmask = filter nodes based on specific class
00318         includesubtypes = If true subtypes of the reference (ref) are also included
00319         """
00320         desc = ua.BrowseDescription()
00321         desc.BrowseDirection = direction
00322         desc.ReferenceTypeId = ua.TwoByteNodeId(refs)
00323         desc.IncludeSubtypes = includesubtypes
00324         desc.NodeClassMask = nodeclassmask
00325         desc.ResultMask = ua.BrowseResultMask.All
00326 
00327         desc.NodeId = self.nodeid
00328         params = ua.BrowseParameters()
00329         params.View.Timestamp = ua.get_win_epoch()
00330         params.NodesToBrowse.append(desc)
00331         results = self.server.browse(params)
00332         return results[0].References
00333 
00334     def get_referenced_nodes(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
00335         """
00336         returns referenced nodes based on specific filter
00337         Paramters are the same as for get_references
00338 
00339         """
00340         references = self.get_references(refs, direction, nodeclassmask, includesubtypes)
00341         nodes = []
00342         for desc in references:
00343             node = Node(self.server, desc.NodeId)
00344             nodes.append(node)
00345         return nodes
00346 
00347     def get_type_definition(self):
00348         """
00349         returns type definition of the node.
00350         """
00351         references = self.get_references(refs=ua.ObjectIds.HasTypeDefinition, direction=ua.BrowseDirection.Forward)
00352         if len(references) == 0:
00353             return None
00354         return references[0].NodeId
00355 
00356     def get_path_as_string(self, max_length=20):
00357         """
00358         Attempt to find path of node from root node and return it as a list of strings.
00359         There might several possible paths to a node, this function will return one
00360         Some nodes may be missing references, so this method may
00361         return an empty list
00362         Since address space may have circular references, a max length is specified
00363 
00364         """
00365         path = self._get_path(max_length)
00366         path = [ref.BrowseName.to_string() for ref in path]
00367         path.append(self.get_browse_name().to_string())
00368         return path
00369 
00370     def get_path(self, max_length=20):
00371         """
00372         Attempt to find path of node from root node and return it as a list of Nodes.
00373         There might several possible paths to a node, this function will return one
00374         Some nodes may be missing references, so this method may
00375         return an empty list
00376         Since address space may have circular references, a max length is specified
00377 
00378         """
00379         path = self._get_path(max_length)
00380         path = [Node(self.server, ref.NodeId) for ref in path]
00381         path.append(self)
00382         return path
00383 
00384     def _get_path(self, max_length=20):
00385         """
00386         Attempt to find path of node from root node and return it as a list of Nodes.
00387         There might several possible paths to a node, this function will return one
00388         Some nodes may be missing references, so this method may
00389         return an empty list
00390         Since address space may have circular references, a max length is specified
00391 
00392         """
00393         path = []
00394         node = self
00395         while True:
00396             refs = node.get_references(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse)
00397             if len(refs) > 0:
00398                 path.insert(0, refs[0])
00399                 node = Node(self.server, refs[0].NodeId)
00400                 if len(path) >= (max_length -1):
00401                     return path
00402             else:
00403                 return path
00404 
00405     def get_parent(self):
00406         """
00407         returns parent of the node.
00408         A Node may have several parents, the first found is returned.
00409         This method uses reverse references, a node might be missing such a link,
00410         thus we will not find its parent.
00411         """
00412         refs = self.get_references(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse)
00413         if len(refs) > 0:
00414             return Node(self.server, refs[0].NodeId)
00415         else:
00416             return None
00417 
00418     def get_child(self, path):
00419         """
00420         get a child specified by its path from this node.
00421         A path might be:
00422         * a string representing a qualified name.
00423         * a qualified name
00424         * a list of string
00425         * a list of qualified names
00426         """
00427         if type(path) not in (list, tuple):
00428             path = [path]
00429         rpath = self._make_relative_path(path)
00430         bpath = ua.BrowsePath()
00431         bpath.StartingNode = self.nodeid
00432         bpath.RelativePath = rpath
00433         result = self.server.translate_browsepaths_to_nodeids([bpath])
00434         result = result[0]
00435         result.StatusCode.check()
00436         # FIXME: seems this method may return several nodes
00437         return Node(self.server, result.Targets[0].TargetId)
00438 
00439     def _make_relative_path(self, path):
00440         rpath = ua.RelativePath()
00441         for item in path:
00442             el = ua.RelativePathElement()
00443             el.ReferenceTypeId = ua.TwoByteNodeId(ua.ObjectIds.HierarchicalReferences)
00444             el.IsInverse = False
00445             el.IncludeSubtypes = True
00446             if isinstance(item, ua.QualifiedName):
00447                 el.TargetName = item
00448             else:
00449                 el.TargetName = ua.QualifiedName.from_string(item)
00450             rpath.Elements.append(el)
00451         return rpath
00452 
00453     def read_raw_history(self, starttime=None, endtime=None, numvalues=0):
00454         """
00455         Read raw history of a node
00456         result code from server is checked and an exception is raised in case of error
00457         If numvalues is > 0 and number of events in period is > numvalues
00458         then result will be truncated
00459         """
00460         details = ua.ReadRawModifiedDetails()
00461         details.IsReadModified = False
00462         if starttime:
00463             details.StartTime = starttime
00464         else:
00465             details.StartTime = ua.get_win_epoch()
00466         if endtime:
00467             details.EndTime = endtime
00468         else:
00469             details.EndTime = ua.get_win_epoch()
00470         details.NumValuesPerNode = numvalues
00471         details.ReturnBounds = True
00472         result = self.history_read(details)
00473         return result.HistoryData.DataValues
00474 
00475     def history_read(self, details):
00476         """
00477         Read raw history of a node, low-level function
00478         result code from server is checked and an exception is raised in case of error
00479         """
00480         valueid = ua.HistoryReadValueId()
00481         valueid.NodeId = self.nodeid
00482         valueid.IndexRange = ''
00483 
00484         params = ua.HistoryReadParameters()
00485         params.HistoryReadDetails = details
00486         params.TimestampsToReturn = ua.TimestampsToReturn.Both
00487         params.ReleaseContinuationPoints = False
00488         params.NodesToRead.append(valueid)
00489         result = self.server.history_read(params)[0]
00490         return result
00491 
00492     def read_event_history(self, starttime=None, endtime=None, numvalues=0, evtypes=ua.ObjectIds.BaseEventType):
00493         """
00494         Read event history of a source node
00495         result code from server is checked and an exception is raised in case of error
00496         If numvalues is > 0 and number of events in period is > numvalues
00497         then result will be truncated
00498         """
00499 
00500         details = ua.ReadEventDetails()
00501         if starttime:
00502             details.StartTime = starttime
00503         else:
00504             details.StartTime = ua.get_win_epoch()
00505         if endtime:
00506             details.EndTime = endtime
00507         else:
00508             details.EndTime = ua.get_win_epoch()
00509         details.NumValuesPerNode = numvalues
00510 
00511         if not isinstance(evtypes, (list, tuple)):
00512             evtypes = [evtypes]
00513 
00514         evtypes = [Node(self.server, evtype) for evtype in evtypes]
00515 
00516         evfilter = events.get_filter_from_event_type(evtypes)
00517         details.Filter = evfilter
00518 
00519         result = self.history_read_events(details)
00520         event_res = []
00521         for res in result.HistoryData.Events:
00522             event_res.append(events.Event.from_event_fields(evfilter.SelectClauses, res.EventFields))
00523         return event_res
00524 
00525     def history_read_events(self, details):
00526         """
00527         Read event history of a node, low-level function
00528         result code from server is checked and an exception is raised in case of error
00529         """
00530         valueid = ua.HistoryReadValueId()
00531         valueid.NodeId = self.nodeid
00532         valueid.IndexRange = ''
00533 
00534         params = ua.HistoryReadParameters()
00535         params.HistoryReadDetails = details
00536         params.TimestampsToReturn = ua.TimestampsToReturn.Both
00537         params.ReleaseContinuationPoints = False
00538         params.NodesToRead.append(valueid)
00539         result = self.server.history_read(params)[0]
00540         return result
00541 
00542     def delete(self, delete_references=True):
00543         """
00544         Delete node from address space
00545         """
00546         ditem = ua.DeleteNodesItem()
00547         ditem.NodeId = self.nodeid
00548         ditem.DeleteTargetReferences = delete_references
00549         params = ua.DeleteNodesParameters()
00550         params.NodesToDelete = [ditem]
00551         result = self.server.delete_nodes(params)
00552         result[0].check()
00553 
00554     def add_folder(self, nodeid, bname):
00555         return  opcua.common.manage_nodes.create_folder(self, nodeid, bname)
00556 
00557     def add_object(self, nodeid, bname, objecttype=None):
00558         return opcua.common.manage_nodes.create_object(self, nodeid, bname, objecttype)
00559 
00560     def add_variable(self, nodeid, bname, val, varianttype=None, datatype=None):
00561         return opcua.common.manage_nodes.create_variable(self, nodeid, bname, val, varianttype, datatype)
00562 
00563     def add_object_type(self, nodeid, bname):
00564         return opcua.common.manage_nodes.create_object_type(self, nodeid, bname)
00565 
00566     def add_variable_type(self, nodeid, bname, datatype):
00567         return opcua.common.manage_nodes.create_variable_type(self, nodeid, bname, datatype)
00568 
00569     def add_data_type(self, nodeid, bname, description=None):
00570         return opcua.common.manage_nodes.create_data_type(self, nodeid, bname, description=None)
00571 
00572     def add_property(self, nodeid, bname, val, varianttype=None, datatype=None):
00573         return opcua.common.manage_nodes.create_property(self, nodeid, bname, val, varianttype, datatype)
00574 
00575     def add_method(self, *args):
00576         return opcua.common.manage_nodes.create_method(self, *args)
00577 
00578     def add_reference_type(self, parent, nodeid, bname):
00579         return opcua.common.manage_nodes.create_reference_type(parent, nodeid, bname)
00580 
00581     def call_method(self, methodid, *args):
00582         return opcua.common.methods.call_method(self, methodid, *args)


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