Completed
Push — master ( 5ff98e...08e4db )
by Olivier
68:12 queued 62:14
created

opcua.common.Node.set_attribute()   A

Complexity

Conditions 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1
Metric Value
cc 1
dl 0
loc 12
ccs 9
cts 9
cp 1
crap 1
rs 9.4286
1
"""
2
High level node object, to access node attribute
3
and browse address space
4
"""
5
6 1
from opcua import ua
7
8
9 1
class Node(object):
10
11
    """
12
    High level node object, to access node attribute,
13
    browse and populate address space.
14
    Node objects are usefull as-is but they do not expose the entire possibilities of the OPC-UA protocol. Feel free to look at Node code and
15
    """
16
17 1
    def __init__(self, server, nodeid):
18 1
        self.server = server
19 1
        self.nodeid = None
20 1
        if isinstance(nodeid, ua.NodeId):
21 1
            self.nodeid = nodeid
22 1
        elif type(nodeid) in (str, bytes):
23 1
            self.nodeid = ua.NodeId.from_string(nodeid)
24
        elif isinstance(nodeid, int):
25
            self.nodeid = ua.NodeId(nodeid, 0)
26
        else:
27
            raise ua.UAError("argument to node must be a NodeId object or a string defining a nodeid found {} of type {}".format(nodeid, type(nodeid)))
28
29 1
    def __eq__(self, other):
30 1
        if isinstance(other, Node) and self.nodeid == other.nodeid:
31 1
            return True
32 1
        return False
33
34 1
    def __str__(self):
35
        return "Node({})".format(self.nodeid)
36 1
    __repr__ = __str__
37
38 1
    def get_browse_name(self):
39
        """
40
        Get browse name of a node. A browse name is a QualifiedName object
41
        composed of a string(name) and a namespace index.
42
        """
43 1
        result = self.get_attribute(ua.AttributeIds.BrowseName)
44 1
        return result.Value.Value
45
46 1
    def get_display_name(self):
47
        """
48
        get description attribute of node
49
        """
50 1
        result = self.get_attribute(ua.AttributeIds.DisplayName)
51 1
        return result.Value.Value
52
53 1
    def get_data_type(self):
54
        """
55
        get data type of node
56
        """
57 1
        result = self.get_attribute(ua.AttributeIds.DataType)
58 1
        return result.Value.Value
59
60 1
    def get_node_class(self):
61
        """
62
        get node class attribute of node
63
        """
64 1
        result = self.get_attribute(ua.AttributeIds.NodeClass)
65 1
        return result.Value.Value
66
67 1
    def get_description(self):
68
        """
69
        get description attribute class of node
70
        """
71 1
        result = self.get_attribute(ua.AttributeIds.Description)
72 1
        return result.Value.Value
73
74 1
    def get_value(self):
75
        """
76
        Get value of a node as a python type. Only variables ( and properties) have values.
77
        An exception will be generated for other node types.
78
        """
79 1
        result = self.get_data_value()
80 1
        return result.Value.Value
81
82 1
    def get_data_value(self):
83
        """
84
        Get value of a node as a DataValue object. Only variables (and properties) have values.
85
        An exception will be generated for other node types.
86
        DataValue contain a variable value as a variant as well as server and source timestamps
87
        """
88 1
        return self.get_attribute(ua.AttributeIds.Value)
89
90 1
    def set_value(self, value, varianttype=None):
91
        """
92
        Set value of a node. Only variables(properties) have values.
93
        An exception will be generated for other node types.
94
        value argument is either:
95
        * a python built-in type, converted to opc-ua
96
        optionnaly using the variantype argument.
97
        * a ua.Variant, varianttype is then ignored
98
        * a ua.DataValue, you then have full control over data send to server
99
        """
100 1
        datavalue = None
101 1
        if isinstance(value, ua.DataValue):
102 1
            datavalue = value
103 1
        elif isinstance(value, ua.Variant):
104 1
            datavalue = ua.DataValue(value)
105
        else:
106 1
            datavalue = ua.DataValue(ua.Variant(value, varianttype))
107 1
        self.set_attribute(ua.AttributeIds.Value, datavalue)
108
109 1
    set_data_value = set_value
110
111 1
    def set_writable(self, writable=True):
112
        """
113
        Set node as writable by clients.
114
        A node is always writable on server side.
115
        """
116 1
        if writable:
117 1
            self.set_attribute(ua.AttributeIds.AccessLevel, ua.DataValue(ua.Variant(ua.AccessLevelMask.CurrentWrite, ua.VariantType.Byte)))
118 1
            self.set_attribute(ua.AttributeIds.UserAccessLevel, ua.DataValue(ua.Variant(ua.AccessLevelMask.CurrentWrite, ua.VariantType.Byte)))
119
        else:
120 1
            self.set_attribute(ua.AttributeIds.AccessLevel, ua.DataValue(ua.Variant(ua.AccessLevelMask.CurrentRead, ua.VariantType.Byte)))
121 1
            self.set_attribute(ua.AttributeIds.AccessLevel, ua.DataValue(ua.Variant(ua.AccessLevelMask.CurrentRead, ua.VariantType.Byte)))
122
123 1
    def set_read_only(self):
124
        """
125
        Set a node as read-only for clients.
126
        A node is always writable on server side.
127
        """
128
        return self.set_writable(False)
129
130 1
    def set_attribute(self, attributeid, datavalue):
131
        """
132
        Set an attribute of a node
133
        """
134 1
        attr = ua.WriteValue()
135 1
        attr.NodeId = self.nodeid
136 1
        attr.AttributeId = attributeid
137 1
        attr.Value = datavalue
138 1
        params = ua.WriteParameters()
139 1
        params.NodesToWrite = [attr]
140 1
        result = self.server.write(params)
141 1
        result[0].check()
142
143 1
    def get_attribute(self, attr):
144
        """
145
        Read one attribute of a node
146
        result code from server is checked and an exception is raised in case of error
147
        """
148 1
        rv = ua.ReadValueId()
149 1
        rv.NodeId = self.nodeid
150 1
        rv.AttributeId = attr
151 1
        params = ua.ReadParameters()
152 1
        params.NodesToRead.append(rv)
153 1
        result = self.server.read(params)
154 1
        result[0].StatusCode.check()
155 1
        return result[0]
156
157 1
    def get_attributes(self, attrs):
158
        """
159
        Read several attributes of a node
160
        list of DataValue is returned
161
        """
162
        params = ua.ReadParameters()
163
        for attr in attrs:
164
            rv = ua.ReadValueId()
165
            rv.NodeId = self.nodeid
166
            rv.AttributeId = attr
167
            params.NodesToRead.append(rv)
168
169
        results = self.server.read(params)
170
        return results
171
172 1
    def get_children(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified):
173
        """
174
        Get all children of a node. By default hierarchical references and all node classes are returned.
175
        Other reference types may be given:
176
        References = 31
177
        NonHierarchicalReferences = 32
178
        HierarchicalReferences = 33
179
        HasChild = 34
180
        Organizes = 35
181
        HasEventSource = 36
182
        HasModellingRule = 37
183
        HasEncoding = 38
184
        HasDescription = 39
185
        HasTypeDefinition = 40
186
        GeneratesEvent = 41
187
        Aggregates = 44
188
        HasSubtype = 45
189
        HasProperty = 46
190
        HasComponent = 47
191
        HasNotifier = 48
192
        HasOrderedComponent = 49
193
        """
194 1
        references = self.get_children_descriptions(refs, nodeclassmask)
195 1
        nodes = []
196 1
        for desc in references:
197 1
            node = Node(self.server, desc.NodeId)
198 1
            nodes.append(node)
199 1
        return nodes
200
201 1
    def get_properties(self):
202
        """
203
        return properties of node.
204
        properties are child nodes with a reference of type HasProperty and a NodeClass of Variable
205
        """
206
        return self.get_children(refs=ua.ObjectIds.HasProperty, nodeclassmask=ua.NodeClass.Variable)
207
208 1
    def get_children_descriptions(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
209
        """
210
        return all attributes of child nodes as UA BrowseResult structs
211
        """
212 1
        desc = ua.BrowseDescription()
213 1
        desc.BrowseDirection = ua.BrowseDirection.Forward
214 1
        desc.ReferenceTypeId = ua.TwoByteNodeId(refs)
215 1
        desc.IncludeSubtypes = includesubtypes
216 1
        desc.NodeClassMask = nodeclassmask
217 1
        desc.ResultMask = ua.BrowseResultMask.All
218
219 1
        desc.NodeId = self.nodeid
220 1
        params = ua.BrowseParameters()
221 1
        params.View.Timestamp = ua.win_epoch_to_datetime(0)
222 1
        params.NodesToBrowse.append(desc)
223 1
        results = self.server.browse(params)
224 1
        return results[0].References
225
226 1
    def get_child(self, path):
227
        """
228
        get a child specified by its path from this node.
229
        A path might be:
230
        * a string representing a qualified name.
231
        * a qualified name
232
        * a list of string
233
        * a list of qualified names
234
        """
235 1
        if type(path) not in (list, tuple):
236 1
            path = [path]
237 1
        rpath = ua.RelativePath()
238 1
        for item in path:
239 1
            el = ua.RelativePathElement()
240 1
            el.ReferenceTypeId = ua.TwoByteNodeId(ua.ObjectIds.HierarchicalReferences)
241 1
            el.IsInverse = False
242 1
            el.IncludeSubtypes = True
243 1
            if isinstance(item, ua.QualifiedName):
244
                el.TargetName = item
245
            else:
246 1
                el.TargetName = ua.QualifiedName.from_string(item)
247 1
            rpath.Elements.append(el)
248 1
        bpath = ua.BrowsePath()
249 1
        bpath.StartingNode = self.nodeid
250 1
        bpath.RelativePath = rpath
251 1
        result = self.server.translate_browsepaths_to_nodeids([bpath])
252 1
        result = result[0]
253 1
        result.StatusCode.check()
254
        # FIXME: seems this method may return several nodes
255 1
        return Node(self.server, result.Targets[0].TargetId)
256
257 1
    def read_raw_history(self, starttime=None, endtime=None, numvalues=0, returnbounds=True):
258
        """
259
        Read raw history of a node
260
        result code from server is checked and an exception is raised in case of error
261
        """
262
        details = ua.ReadRawModifiedDetails()
263
        details.IsReadModified = False
264
        if starttime:
265
            details.StartTime = starttime
266
        if endtime:
267
            details.EndTime = endtime
268
        details.NumValuesPerNode = numvalues
269
        details.ReturnBounds = returnbounds
270
        return self.history_read(details)
271
272 1
    def history_read(self, details):
273
        """
274
        Read raw history of a node, low-level function
275
        result code from server is checked and an exception is raised in case of error
276
        """
277
        valueid = ua.HistoryReadValueId()
278
        valueid.NodeId = self.nodeid
279
        valueid.IndexRange = ''
280
281
        params = ua.HistoryReadParameters()
282
        params.HistoryReadDetails = details
283
        params.TimestampsToReturn = ua.TimestampsToReturn.Both
284
        params.ReleaseContinuationPoints = False
285
        params.NodesToRead.append(valueid)
286
        result = self.server.history_read(params)[0]
287
        return result.HistoryData
288
289
    # Hack for convenience methods
290
    # local import is ugly but necessary for python2 support
291
    # feel fri to propose something better but I want to split all those 
292
    # create methods fro Node
293
294 1
    def add_folder(*args, **kwargs):
295 1
        from opcua.common import create_nodes
296 1
        return create_nodes.create_folder(*args, **kwargs)
297
298 1
    def add_object(*args, **kwargs):
299 1
        from opcua.common import create_nodes
300 1
        return create_nodes.create_object(*args, **kwargs)
301
302 1
    def add_variable(*args, **kwargs):
303 1
        from opcua.common import create_nodes
304 1
        return create_nodes.create_variable(*args, **kwargs)
305
306 1
    def add_property(*args, **kwargs):
307 1
        from opcua.common import create_nodes
308 1
        return create_nodes.create_property(*args, **kwargs)
309
310 1
    def add_method(*args, **kwargs):
311 1
        from opcua.common import create_nodes
312 1
        return create_nodes.create_method(*args, **kwargs)
313
314 1
    def call_method(*args, **kwargs):
315 1
        from opcua.common import methods
316 1
        return methods.call_method(*args, **kwargs)
317
318