Completed
Pull Request — master (#133)
by Denis
02:36
created

opcua.common.Node.set_value_rank()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

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