freeOPCUA Python multiple subscriptions

Viewed 4710

I'm using the minimal example client and server for the python opcua github and I can't seem to figure out how to subscribe to multiple variables with different intervals. What I would like to do is have certain values updated at a high frequency and others at a much lower frequency.

I was successful by passing a list to

handle = sub.subscribe_data_change(monitoredNodes)

monitoredNodes being a list of the nodeIDs.

However then anytime any variable in the list changes if fires the data change event in the subHandler and I'm using if statements to figure out which variable changed. If I want to subscribe to 1000 variables it seems cumbersome and inefficient to have 100 if statements ran for every event.

If anyone has any experience with this I'd love to here how to handle this properly. Below is the code from the example client modified by me slightly.

import sys
sys.path.insert(0, "..")
import re
from IPython import embed


from opcua import Client

def getChildren(node):
 children = extractName(root.get_child(node).get_children_descriptions())
 return children

def extractName(description):
 qualifiedNames = re.findall(r"QualifiedName\(.*?\)", str(description))
 nodeNames = re.findall("\d:[a-z,A-Z_]*", str(qualifiedNames))
 return nodeNames

class SubHandler(object):

def datachange_notification(self, node, val, data):
    pass
    #print("Python: New data change event", node, val)

def event_notification(self, event):
    print("Python: New event", event)


if __name__ == "__main__":

client = Client("opc.tcp://0.0.0.0:4840/freeopcua/server/")
try:
    client.connect()
    # Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
    root = client.get_root_node()
    print("Objects node is: ", root.get_browse_name())

    # Node objects have methods to read and write node attributes as well       as browse or populate address space
    print("Children of root are: ", root.get_children())

    rootNode = extractName(str(root.get_children_descriptions()))
    print(rootNode)
    print('''
    The following nodes are found on root.
    Press enter the corresponding number to go deeper.
    ''')
    path = ['0:Objects']
    children=[]

    while True:
        for node in enumerate(getChildren(path)):
            print(node[0], ": ", node[1])
        print("Enter 99 to exit or 88 to go back to top")
        sel = int(input('Please make a selection\n' ))
        if sel == 99:
            break
        elif sel == 88:
            path = []
            children = []
        elif sel == 11:
            print(path)
            print(root.get_child(path).get_value())
            print(root.get_child(path))
        else:
            if path == []:
                path.append(rootNode[sel])
                #print(path)
                #print(getChildren(path))
            else:
                children = getChildren(path)
                path.append(children[sel])
                #print(getChildren(path))

    # Now getting a variable node using its browse path
    myvar = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"])
    obj = root.get_child(["0:Objects", "2:MyObject"])
    print("myvar is: ", myvar.get_value())

    # subscribing to a variable node
    handler = SubHandler()
    sub = client.create_subscription(500, handler)
    handle = sub.subscribe_data_change(myvar)

    embed()
finally:
    client.disconnect()
1 Answers

Ok so for anyone trying to do what I'm trying to do and having issues. I think using a subscription for variables that you only want to update a specific intervals is not the right way. It seems that by subscribing to a variable you will get every change in that variable. If your subscription period is longer than the rate at which it changes then the change event will fire multiple times with all the historical changes since the last update. This isn't what I wanted.

Instead I would recommend using a timer task like that in the apscheduler module for python and perform a read on the variable(s) at regular intervals. This seems to do what I want.

Related