Search code examples
pythonplcopc-uaopc

How to make opcua more efficient in python?


i'm currently writing a python skript which interacts with a PLC via OPC UA.

The communication with OPC UA seems very slow. I measured the time for writing 5 values to the PLC with time.perf_counter() which results in 20ms.

Eventually im trying to write/read up to 100 variables in one cycle. This would result in a cyclic time of 2sec.

The PLC ist connected to the PC via a switch.

The 5 variables I tested: _node are Node objects; statusword is in ushort(hex); the others are int

opc.set_value(self.statusword_node,  get_statusnumber(self.statusword))
opc.set_value(self.actualspeed_node, self.actualspeed)
opc.set_value(self.errorcode_node,   self.errorcode)
opc.set_value(self.motorcurrent_node,self.motorcurrent)
opc.set_value(self.motortorque_node, self.motortorque)

opc is an object from my OpcClient class. set_value is the follwing function:

def set_value(node: Node, value) -> None:
    '''sets value to node object'''
    node.set_value(get_uadatatype(value))

the function get_uadatatype() returns the value as a uadatatype:

def get_uadatatype(value) -> ua.DataValue:
    '''checks the type of value and converts it into a ua.DataValue type'''
    if isinstance(value, bool):
        return ua.DataValue(ua.Variant(value, ua.VariantType.Boolean))

    elif isinstance(value, int) or isinstance(value, np.uint16):
        return ua.DataValue(ua.Variant(value, ua.VariantType.Int16))

    elif isinstance(value, float):
        return ua.DataValue(ua.Variant(value, ua.VariantType.Float))

    else:
        loginfo(f"Please import convert function for {type(value)}")
        raise ValueError

Which part of the programm slows it down? Or is it just impossible to write values faster with opc?

Thanks for your help:)


Solution

  • What slows you down is the network. Each set_value, does a network request/response with the server.

    To speed things up you need to do a batch write:

    nodes = [ 
        self.statusword_node,
        self.actualspeed_node,
        ...
    ]
    values = [
        get_statusnumber(self.statusword),
        self.actualspeed,
        ...
    ]
    
    opc.set_values(nodes, values)