Completed
Push — master ( b499cc...5902be )
by Olivier
08:44 queued 01:39
created

Node._add_modelling_rule()   A

Complexity

Conditions 4

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
c 0
b 0
f 0
dl 0
loc 5
ccs 5
cts 5
cp 1
crap 4
rs 9.2
1
"""
2
High level node object, to access node attribute
3
and browse address space
4
"""
5
6 1
from opcua import ua
7 1
from opcua.common import events
8 1
import opcua.common
9
10 1
def _check_results(results, reqlen = 1):
11 1
    assert len(results) == reqlen, results
12 1
    for r in results:
13 1
        r.check()
14
15 1
def _to_nodeid(nodeid):
16 1
    if isinstance(nodeid, int):
17 1
        return ua.TwoByteNodeId(nodeid)
18 1
    elif isinstance(nodeid, Node):
19 1
        return nodeid.nodeid
20
    elif isinstance(nodeid, ua.NodeId):
21
        return nodeid
22
    elif type(nodeid) in (str, bytes):
23
        return ua.NodeId.from_string(nodeid)
24
    else:
25
        raise ua.UaError("Could not resolve '{0}' to a type id".format(nodeid))
26
27 1
class Node(object):
28
29
    """
30
    High level node object, to access node attribute,
31
    browse and populate address space.
32
    Node objects are usefull as-is but they do not expose the entire
33
    OPC-UA protocol. Feel free to look at the code of this class and call
34
    directly UA services methods to optimize your code
35
    """
36
37 1
    def __init__(self, server, nodeid):
38 1
        self.server = server
39 1
        self.nodeid = None
40 1
        if isinstance(nodeid, Node):
41 1
            self.nodeid = nodeid.nodeid
42 1
        elif isinstance(nodeid, ua.NodeId):
43 1
            self.nodeid = nodeid
44 1
        elif type(nodeid) in (str, bytes):
45 1
            self.nodeid = ua.NodeId.from_string(nodeid)
46 1
        elif isinstance(nodeid, int):
47 1
            self.nodeid = ua.NodeId(nodeid, 0)
48
        else:
49
            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)))
50
51 1
    def __eq__(self, other):
52 1
        if isinstance(other, Node) and self.nodeid == other.nodeid:
53 1
            return True
54 1
        return False
55
56 1
    def __ne__(self, other):
57
        return not self.__eq__(other)
58
59 1
    def __str__(self):
60 1
        return "Node({0})".format(self.nodeid)
61 1
    __repr__ = __str__
62
63 1
    def __hash__(self):
64 1
        return self.nodeid.__hash__()
65
66 1
    def get_browse_name(self):
67
        """
68
        Get browse name of a node. A browse name is a QualifiedName object
69
        composed of a string(name) and a namespace index.
70
        """
71 1
        result = self.get_attribute(ua.AttributeIds.BrowseName)
72 1
        return result.Value.Value
73
74 1
    def get_display_name(self):
75
        """
76
        get description attribute of node
77
        """
78 1
        result = self.get_attribute(ua.AttributeIds.DisplayName)
79 1
        return result.Value.Value
80
81 1
    def get_data_type(self):
82
        """
83
        get data type of node as NodeId
84
        """
85 1
        result = self.get_attribute(ua.AttributeIds.DataType)
86 1
        return result.Value.Value
87
88 1
    def get_data_type_as_variant_type(self):
89
        """
90
        get data type of node as VariantType
91
        This only works if node is a variable, otherwise type
92
        may not be convertible to VariantType
93
        """
94 1
        result = self.get_attribute(ua.AttributeIds.DataType)
95 1
        return opcua.common.ua_utils.data_type_to_variant_type(Node(self.server, result.Value.Value))
96
97 1
    def get_access_level(self):
98
        """
99
        Get the access level attribute of the node as a set of AccessLevel enum values.
100
        """
101
        result = self.get_attribute(ua.AttributeIds.AccessLevel)
102
        return ua.AccessLevel.parse_bitfield(result.Value.Value)
103
104 1
    def get_user_access_level(self):
105
        """
106
        Get the user access level attribute of the node as a set of AccessLevel enum values.
107
        """
108
        result = self.get_attribute(ua.AttributeIds.UserAccessLevel)
109
        return ua.AccessLevel.parse_bitfield(result.Value.Value)
110
111 1
    def get_event_notifier(self):
112
        """
113
        Get the event notifier attribute of the node as a set of EventNotifier enum values.
114
        """
115 1
        result = self.get_attribute(ua.AttributeIds.EventNotifier)
116 1
        return ua.EventNotifier.parse_bitfield(result.Value.Value)
117
118 1
    def set_event_notifier(self, values):
119
        """
120
        Set the event notifier attribute.
121
122
        :param values: an iterable of EventNotifier enum values.
123
        """
124 1
        event_notifier_bitfield = ua.EventNotifier.to_bitfield(values)
125 1
        self.set_attribute(ua.AttributeIds.EventNotifier, ua.DataValue(ua.Variant(event_notifier_bitfield, ua.VariantType.Byte)))
126
127 1
    def get_node_class(self):
128
        """
129
        get node class attribute of node
130
        """
131 1
        result = self.get_attribute(ua.AttributeIds.NodeClass)
132 1
        return result.Value.Value
133
134 1
    def get_description(self):
135
        """
136
        get description attribute class of node
137
        """
138 1
        result = self.get_attribute(ua.AttributeIds.Description)
139 1
        return result.Value.Value
140
141 1
    def get_value(self):
142
        """
143
        Get value of a node as a python type. Only variables ( and properties) have values.
144
        An exception will be generated for other node types.
145
        """
146 1
        result = self.get_data_value()
147 1
        return result.Value.Value
148
149 1
    def get_data_value(self):
150
        """
151
        Get value of a node as a DataValue object. Only variables (and properties) have values.
152
        An exception will be generated for other node types.
153
        DataValue contain a variable value as a variant as well as server and source timestamps
154
        """
155 1
        return self.get_attribute(ua.AttributeIds.Value)
156
157 1
    def set_array_dimensions(self, value):
158
        """
159
        Set attribute ArrayDimensions of node
160
        make sure it has the correct data type
161
        """
162 1
        v = ua.Variant(value, ua.VariantType.UInt32)
163 1
        self.set_attribute(ua.AttributeIds.ArrayDimensions, ua.DataValue(v))
164
165 1
    def get_array_dimensions(self):
166
        """
167
        Read and return ArrayDimensions attribute of node
168
        """
169 1
        res = self.get_attribute(ua.AttributeIds.ArrayDimensions)
170 1
        return res.Value.Value
171
172 1
    def set_value_rank(self, value):
173
        """
174
        Set attribute ArrayDimensions of node
175
        """
176 1
        v = ua.Variant(value, ua.VariantType.Int32)
177 1
        self.set_attribute(ua.AttributeIds.ValueRank, ua.DataValue(v))
178
179 1
    def get_value_rank(self):
180
        """
181
        Read and return ArrayDimensions attribute of node
182
        """
183 1
        res = self.get_attribute(ua.AttributeIds.ValueRank)
184 1
        return res.Value.Value
185
186 1
    def set_value(self, value, varianttype=None):
187
        """
188
        Set value of a node. Only variables(properties) have values.
189
        An exception will be generated for other node types.
190
        value argument is either:
191
        * a python built-in type, converted to opc-ua
192
        optionnaly using the variantype argument.
193
        * a ua.Variant, varianttype is then ignored
194
        * a ua.DataValue, you then have full control over data send to server
195
        """
196 1
        datavalue = None
197 1
        if isinstance(value, ua.DataValue):
198 1
            datavalue = value
199 1
        elif isinstance(value, ua.Variant):
200 1
            datavalue = ua.DataValue(value)
201
        else:
202 1
            datavalue = ua.DataValue(ua.Variant(value, varianttype))
203 1
        self.set_attribute(ua.AttributeIds.Value, datavalue)
204
205 1
    set_data_value = set_value
206
207 1
    def set_writable(self, writable=True):
208
        """
209
        Set node as writable by clients.
210
        A node is always writable on server side.
211
        """
212 1
        if writable:
213 1
            self.set_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.CurrentWrite)
214 1
            self.set_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.CurrentWrite)
215
        else:
216 1
            self.unset_attr_bit(ua.AttributeIds.AccessLevel, ua.AccessLevel.CurrentWrite)
217 1
            self.unset_attr_bit(ua.AttributeIds.UserAccessLevel, ua.AccessLevel.CurrentWrite)
218
219 1
    def set_attr_bit(self, attr, bit):
220 1
        val = self.get_attribute(attr)
221 1
        val.Value.Value = ua.ua_binary.set_bit(val.Value.Value, bit)
222 1
        self.set_attribute(attr, val)
223
224 1
    def unset_attr_bit(self, attr, bit):
225 1
        val = self.get_attribute(attr)
226 1
        val.Value.Value = ua.ua_binary.unset_bit(val.Value.Value, bit)
227 1
        self.set_attribute(attr, val)
228
229 1
    def set_read_only(self):
230
        """
231
        Set a node as read-only for clients.
232
        A node is always writable on server side.
233
        """
234
        return self.set_writable(False)
235
236 1
    def set_attribute(self, attributeid, datavalue):
237
        """
238
        Set an attribute of a node
239
        attributeid is a member of ua.AttributeIds
240
        datavalue is a ua.DataValue object
241
        """
242 1
        attr = ua.WriteValue()
243 1
        attr.NodeId = self.nodeid
244 1
        attr.AttributeId = attributeid
245 1
        attr.Value = datavalue
246 1
        params = ua.WriteParameters()
247 1
        params.NodesToWrite = [attr]
248 1
        result = self.server.write(params)
249 1
        result[0].check()
250
251 1
    def get_attribute(self, attr):
252
        """
253
        Read one attribute of a node
254
        result code from server is checked and an exception is raised in case of error
255
        """
256 1
        rv = ua.ReadValueId()
257 1
        rv.NodeId = self.nodeid
258 1
        rv.AttributeId = attr
259 1
        params = ua.ReadParameters()
260 1
        params.NodesToRead.append(rv)
261 1
        result = self.server.read(params)
262 1
        result[0].StatusCode.check()
263 1
        return result[0]
264
265 1
    def get_attributes(self, attrs):
266
        """
267
        Read several attributes of a node
268
        list of DataValue is returned
269
        """
270 1
        params = ua.ReadParameters()
271 1
        for attr in attrs:
272 1
            rv = ua.ReadValueId()
273 1
            rv.NodeId = self.nodeid
274 1
            rv.AttributeId = attr
275 1
            params.NodesToRead.append(rv)
276
277 1
        results = self.server.read(params)
278 1
        return results
279
280 1
    def get_children(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified):
281
        """
282
        Get all children of a node. By default hierarchical references and all node classes are returned.
283
        Other reference types may be given:
284
        References = 31
285
        NonHierarchicalReferences = 32
286
        HierarchicalReferences = 33
287
        HasChild = 34
288
        Organizes = 35
289
        HasEventSource = 36
290
        HasModellingRule = 37
291
        HasEncoding = 38
292
        HasDescription = 39
293
        HasTypeDefinition = 40
294
        GeneratesEvent = 41
295
        Aggregates = 44
296
        HasSubtype = 45
297
        HasProperty = 46
298
        HasComponent = 47
299
        HasNotifier = 48
300
        HasOrderedComponent = 49
301
        """
302 1
        return self.get_referenced_nodes(refs, ua.BrowseDirection.Forward, nodeclassmask)
303
304 1
    def get_properties(self):
305
        """
306
        return properties of node.
307
        properties are child nodes with a reference of type HasProperty and a NodeClass of Variable
308
        """
309 1
        return self.get_children(refs=ua.ObjectIds.HasProperty, nodeclassmask=ua.NodeClass.Variable)
310
311 1
    def get_variables(self):
312
        """
313
        return variables of node.
314
        properties are child nodes with a reference of type HasComponent and a NodeClass of Variable
315
        """
316 1
        return self.get_children(refs=ua.ObjectIds.HasComponent, nodeclassmask=ua.NodeClass.Variable)
317
318 1
    def get_methods(self):
319
        """
320
        return methods of node.
321
        properties are child nodes with a reference of type HasComponent and a NodeClass of Method
322
        """
323 1
        return self.get_children(refs=ua.ObjectIds.HasComponent, nodeclassmask=ua.NodeClass.Method)
324
325 1
    def get_children_descriptions(self, refs=ua.ObjectIds.HierarchicalReferences, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
326 1
        return self.get_references(refs, ua.BrowseDirection.Forward, nodeclassmask, includesubtypes)
327
328 1
    def get_encoding_refs(self):
329
        return self.get_referenced_nodes(ua.ObjectIds.HasEncoding, ua.BrowseDirection.Forward)
330
331 1
    def get_description_refs(self):
332
        return self.get_referenced_nodes(ua.ObjectIds.HasDescription, ua.BrowseDirection.Forward)
333
334 1
    def get_references(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
335
        """
336
        returns references of the node based on specific filter defined with:
337
338
        refs = ObjectId of the Reference
339
        direction = Browse direction for references
340
        nodeclassmask = filter nodes based on specific class
341
        includesubtypes = If true subtypes of the reference (ref) are also included
342
        """
343 1
        desc = ua.BrowseDescription()
344 1
        desc.BrowseDirection = direction
345 1
        desc.ReferenceTypeId = _to_nodeid(refs)
346 1
        desc.IncludeSubtypes = includesubtypes
347 1
        desc.NodeClassMask = nodeclassmask
348 1
        desc.ResultMask = ua.BrowseResultMask.All
349
350 1
        desc.NodeId = self.nodeid
351 1
        params = ua.BrowseParameters()
352 1
        params.View.Timestamp = ua.get_win_epoch()
353 1
        params.NodesToBrowse.append(desc)
354 1
        params.RequestedMaxReferencesPerNode = 0
355 1
        results = self.server.browse(params)
356
357 1
        references = self._browse_next(results)
358 1
        return references
359
360 1
    def _browse_next(self, results):
361 1
        references = results[0].References
362 1
        while results[0].ContinuationPoint:
363
            params = ua.BrowseNextParameters()
364
            params.ContinuationPoints = [results[0].ContinuationPoint]
365
            params.ReleaseContinuationPoints = False
366
            results = self.server.browse_next(params)
367
            references.extend(results[0].References)
368 1
        return references
369
370 1
    def get_referenced_nodes(self, refs=ua.ObjectIds.References, direction=ua.BrowseDirection.Both, nodeclassmask=ua.NodeClass.Unspecified, includesubtypes=True):
371
        """
372
        returns referenced nodes based on specific filter
373
        Paramters are the same as for get_references
374
375
        """
376 1
        references = self.get_references(refs, direction, nodeclassmask, includesubtypes)
377 1
        nodes = []
378 1
        for desc in references:
379 1
            node = Node(self.server, desc.NodeId)
380 1
            nodes.append(node)
381 1
        return nodes
382
383 1
    def get_type_definition(self):
384
        """
385
        returns type definition of the node.
386
        """
387 1
        references = self.get_references(refs=ua.ObjectIds.HasTypeDefinition, direction=ua.BrowseDirection.Forward)
388 1
        if len(references) == 0:
389 1
            return None
390 1
        return references[0].NodeId
391
392 1
    def get_path(self, max_length=20, as_string=False):
393
        """
394
        Attempt to find path of node from root node and return it as a list of Nodes.
395
        There might several possible paths to a node, this function will return one
396
        Some nodes may be missing references, so this method may
397
        return an empty list
398
        Since address space may have circular references, a max length is specified
399
400
        """
401 1
        path = self._get_path(max_length)
402 1
        path = [Node(self.server, ref.NodeId) for ref in path]
403 1
        path.append(self)
404 1
        if as_string:
405 1
            path = [el.get_browse_name().to_string() for el in path]
406 1
        return path
407
408 1
    def _get_path(self, max_length=20):
409
        """
410
        Attempt to find path of node from root node and return it as a list of Nodes.
411
        There might several possible paths to a node, this function will return one
412
        Some nodes may be missing references, so this method may
413
        return an empty list
414
        Since address space may have circular references, a max length is specified
415
416
        """
417 1
        path = []
418 1
        node = self
419 1
        while True:
420 1
            refs = node.get_references(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse)
421 1
            if len(refs) > 0:
422 1
                path.insert(0, refs[0])
423 1
                node = Node(self.server, refs[0].NodeId)
424 1
                if len(path) >= (max_length -1):
425 1
                    return path
426
            else:
427 1
                return path
428
429 1
    def get_parent(self):
430
        """
431
        returns parent of the node.
432
        A Node may have several parents, the first found is returned.
433
        This method uses reverse references, a node might be missing such a link,
434
        thus we will not find its parent.
435
        """
436 1
        refs = self.get_references(refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse)
437 1
        if len(refs) > 0:
438 1
            return Node(self.server, refs[0].NodeId)
439
        else:
440
            return None
441
442 1
    def get_child(self, path):
443
        """
444
        get a child specified by its path from this node.
445
        A path might be:
446
        * a string representing a qualified name.
447
        * a qualified name
448
        * a list of string
449
        * a list of qualified names
450
        """
451 1
        if type(path) not in (list, tuple):
452 1
            path = [path]
453 1
        rpath = self._make_relative_path(path)
454 1
        bpath = ua.BrowsePath()
455 1
        bpath.StartingNode = self.nodeid
456 1
        bpath.RelativePath = rpath
457 1
        result = self.server.translate_browsepaths_to_nodeids([bpath])
458 1
        result = result[0]
459 1
        result.StatusCode.check()
460
        # FIXME: seems this method may return several nodes
461 1
        return Node(self.server, result.Targets[0].TargetId)
462
463 1
    def _make_relative_path(self, path):
464 1
        rpath = ua.RelativePath()
465 1
        for item in path:
466 1
            el = ua.RelativePathElement()
467 1
            el.ReferenceTypeId = ua.TwoByteNodeId(ua.ObjectIds.HierarchicalReferences)
468 1
            el.IsInverse = False
469 1
            el.IncludeSubtypes = True
470 1
            if isinstance(item, ua.QualifiedName):
471
                el.TargetName = item
472
            else:
473 1
                el.TargetName = ua.QualifiedName.from_string(item)
474 1
            rpath.Elements.append(el)
475 1
        return rpath
476
477 1
    def read_raw_history(self, starttime=None, endtime=None, numvalues=0):
478
        """
479
        Read raw history of a node
480
        result code from server is checked and an exception is raised in case of error
481
        If numvalues is > 0 and number of events in period is > numvalues
482
        then result will be truncated
483
        """
484 1
        details = ua.ReadRawModifiedDetails()
485 1
        details.IsReadModified = False
486 1
        if starttime:
487 1
            details.StartTime = starttime
488
        else:
489 1
            details.StartTime = ua.get_win_epoch()
490 1
        if endtime:
491 1
            details.EndTime = endtime
492
        else:
493 1
            details.EndTime = ua.get_win_epoch()
494 1
        details.NumValuesPerNode = numvalues
495 1
        details.ReturnBounds = True
496 1
        result = self.history_read(details)
497 1
        return result.HistoryData.DataValues
498
499 1
    def history_read(self, details):
500
        """
501
        Read raw history of a node, low-level function
502
        result code from server is checked and an exception is raised in case of error
503
        """
504 1
        valueid = ua.HistoryReadValueId()
505 1
        valueid.NodeId = self.nodeid
506 1
        valueid.IndexRange = ''
507
508 1
        params = ua.HistoryReadParameters()
509 1
        params.HistoryReadDetails = details
510 1
        params.TimestampsToReturn = ua.TimestampsToReturn.Both
511 1
        params.ReleaseContinuationPoints = False
512 1
        params.NodesToRead.append(valueid)
513 1
        result = self.server.history_read(params)[0]
514 1
        return result
515
516 1
    def read_event_history(self, starttime=None, endtime=None, numvalues=0, evtypes=ua.ObjectIds.BaseEventType):
517
        """
518
        Read event history of a source node
519
        result code from server is checked and an exception is raised in case of error
520
        If numvalues is > 0 and number of events in period is > numvalues
521
        then result will be truncated
522
        """
523
524 1
        details = ua.ReadEventDetails()
525 1
        if starttime:
526 1
            details.StartTime = starttime
527
        else:
528 1
            details.StartTime = ua.get_win_epoch()
529 1
        if endtime:
530 1
            details.EndTime = endtime
531
        else:
532 1
            details.EndTime = ua.get_win_epoch()
533 1
        details.NumValuesPerNode = numvalues
534
535 1
        if not isinstance(evtypes, (list, tuple)):
536 1
            evtypes = [evtypes]
537
538 1
        evtypes = [Node(self.server, evtype) for evtype in evtypes]
539
540 1
        evfilter = events.get_filter_from_event_type(evtypes)
541 1
        details.Filter = evfilter
542
543 1
        result = self.history_read_events(details)
544 1
        event_res = []
545 1
        for res in result.HistoryData.Events:
546 1
            event_res.append(events.Event.from_event_fields(evfilter.SelectClauses, res.EventFields))
547 1
        return event_res
548
549 1
    def history_read_events(self, details):
550
        """
551
        Read event history of a node, low-level function
552
        result code from server is checked and an exception is raised in case of error
553
        """
554 1
        valueid = ua.HistoryReadValueId()
555 1
        valueid.NodeId = self.nodeid
556 1
        valueid.IndexRange = ''
557
558 1
        params = ua.HistoryReadParameters()
559 1
        params.HistoryReadDetails = details
560 1
        params.TimestampsToReturn = ua.TimestampsToReturn.Both
561 1
        params.ReleaseContinuationPoints = False
562 1
        params.NodesToRead.append(valueid)
563 1
        result = self.server.history_read(params)[0]
564 1
        return result
565
566 1
    def delete(self, delete_references=True, recursive=False):
567
        """
568
        Delete node from address space
569
        """
570
        results = opcua.common.manage_nodes.delete_nodes(self.server, [self], recursive, delete_references)
571
        _check_results(results)
572
573 1
    def _fill_delete_reference_item(self, rdesc, bidirectional = False):
574 1
        ditem = ua.DeleteReferencesItem()
575 1
        ditem.SourceNodeId = self.nodeid
576 1
        ditem.TargetNodeId = rdesc.NodeId
577 1
        ditem.ReferenceTypeId = rdesc.ReferenceTypeId
578 1
        ditem.IsForward = rdesc.IsForward
579 1
        ditem.DeleteBidirectional = bidirectional
580 1
        return ditem
581
582 1
    def delete_reference(self, target, reftype, forward=True, bidirectional=True):
583
        """
584
        Delete given node's references from address space
585
        """
586 1
        known_refs = self.get_references(reftype, includesubtypes=False)
587 1
        targetid = _to_nodeid(target)
588
589 1
        for r in known_refs:
590 1
            if r.NodeId == targetid and r.IsForward == forward:
591 1
                rdesc = r
592 1
                break
593
        else:
594 1
            raise ua.UaStatusCodeError(ua.StatusCodes.BadNotFound)
595
596 1
        ditem = self._fill_delete_reference_item(rdesc, bidirectional)
597 1
        self.server.delete_references([ditem])[0].check()
598
599 1
    def add_reference(self, target, reftype, forward=True, bidirectional=True):
600
        """
601
        Add reference to node
602
        """
603
604 1
        aitem = ua.AddReferencesItem()
605 1
        aitem.SourceNodeId = self.nodeid
606 1
        aitem.TargetNodeId = _to_nodeid(target)
607 1
        aitem.ReferenceTypeId = _to_nodeid(reftype)
608 1
        aitem.IsForward = forward
609
610 1
        params = [aitem]
611
612 1
        if bidirectional:
613 1
            aitem2 = ua.AddReferencesItem()
614 1
            aitem2.SourceNodeId = aitem.TargetNodeId
615 1
            aitem2.TargetNodeId = aitem.SourceNodeId
616 1
            aitem2.ReferenceTypeId = aitem.ReferenceTypeId
617 1
            aitem2.IsForward = not forward
618 1
            params.append(aitem2)
619
620 1
        results = self.server.add_references(params)
621 1
        _check_results(results, len(params))
622
623 1
    def set_modelling_rule(self, mandatory):
624
        """
625
        Add a modelling rule reference to Node.
626
        When creating a new object type, its variable and child nodes will not
627
        be instanciated if they do not have modelling rule
628
        if mandatory is None, the modelling rule is removed
629
        """
630
        # remove all existing modelling rule
631 1
        rules = self.get_references(ua.ObjectIds.HasModellingRule)
632 1
        self.server.delete_references(list(map(self._fill_delete_reference_item, rules)))
633
        # add new modelling rule as requested
634 1
        if mandatory is not None:
635 1
            rule = ua.ObjectIds.ModellingRule_Mandatory if mandatory else ua.ObjectIds.ModellingRule_Optional
636 1
            self.add_reference(rule, ua.ObjectIds.HasModellingRule, True, False)
637
638 1
    def add_folder(self, nodeid, bname):
639 1
        return  opcua.common.manage_nodes.create_folder(self, nodeid, bname)
640
641 1
    def add_object(self, nodeid, bname, objecttype=None):
642 1
        return opcua.common.manage_nodes.create_object(self, nodeid, bname, objecttype)
643
644 1
    def add_variable(self, nodeid, bname, val, varianttype=None, datatype=None):
645 1
        return opcua.common.manage_nodes.create_variable(self, nodeid, bname, val, varianttype, datatype)
646
647 1
    def add_object_type(self, nodeid, bname):
648 1
        return opcua.common.manage_nodes.create_object_type(self, nodeid, bname)
649
650 1
    def add_variable_type(self, nodeid, bname, datatype):
651
        return opcua.common.manage_nodes.create_variable_type(self, nodeid, bname, datatype)
652
653 1
    def add_data_type(self, nodeid, bname, description=None):
654 1
        return opcua.common.manage_nodes.create_data_type(self, nodeid, bname, description=None)
655
656 1
    def add_property(self, nodeid, bname, val, varianttype=None, datatype=None):
657 1
        return opcua.common.manage_nodes.create_property(self, nodeid, bname, val, varianttype, datatype)
658
659 1
    def add_method(self, *args):
660 1
        return opcua.common.manage_nodes.create_method(self, *args)
661
662 1
    def add_reference_type(self, nodeid, bname, symmetric=True, inversename=None):
663 1
        return opcua.common.manage_nodes.create_reference_type(self, nodeid, bname, symmetric, inversename)
664
665 1
    def call_method(self, methodid, *args):
666
        return opcua.common.methods.call_method(self, methodid, *args)
667