python-opcua icon indicating copy to clipboard operation
python-opcua copied to clipboard

Unable to get data in proper format for nested tags.

Open biswaKL opened this issue 5 years ago • 14 comments
trafficstars

My tags are inside another tag and it is nested. In UA Expert the tree looks like this. opcua

UA Expert is able to fetch the data (both key value pair) for nested tags. how to achieve it in python? I tried something and i am getting the data as well but not in the key value format. It gives me a byte string.

opcua2

Here is the code:

        nodeid = ua.NodeId.from_string('ns=3;s="ERP_Roll_data"."Conveyor"."Mroll"')
        attr = ua.ReadValueId()
        attr.NodeId = nodeid
        # attr.Value = nodeid.
        attr.AttributeId = ua.AttributeIds.Value
        params.NodesToRead.append(attr)

        start = datetime.datetime.now()
        result = client.uaclient.read(params)
        print(len(result))
        for each_result in result:
            print(each_result)

biswaKL avatar Oct 07 '20 13:10 biswaKL

is "Mroll" a custom type? did you load type definitions on clientside before reading?

AndreasHeine avatar Oct 07 '20 13:10 AndreasHeine

is "Mroll" a custom type? -> I have no idea, i am reading a preprogrammed PLC did you load type definitions on clientside before reading? --> No

Should i search the type definations?

biswaKL avatar Oct 07 '20 13:10 biswaKL

Should i search the type definations?

if its from a plc you should always otherwise all UDT's (userdefined data types) in the plc will be not known correctly on clientside

is there a special reason for using the lowlevel api?

AndreasHeine avatar Oct 07 '20 13:10 AndreasHeine

I am new to OPC world. I wanted to do multiple tag acquisition at the same time(since the get_data() was very slow) and this is the only solution i found on internet. So using the same. Thanks for the help. I will check and update tomorrow.

biswaKL avatar Oct 07 '20 14:10 biswaKL

    client = Client("opc.tcp://192.168.10.1:4840/")
    client.connect()
    root = client.get_root_node()
    objects = client.get_objects_node()
    print("Reading before load typedefinitions:")
    node = client.get_node('ns=3;s="Element_Data"."Data"')
    print(node.get_value())
    client.load_type_definitions()  # scan server for custom structures and import them
    print("Reading after load typedefinitions:")
    node = client.get_node('ns=3;s="Element_Data"."Data"')
    print(node.get_value())
    client.disconnect()
C:\Users\andre>python c:/Users/andre/Desktop/client_read-custom_structures.py
WARNING:opcua.client.client:Requested session timeout to be 3600000ms, got 30000ms instead
Reading before load typedefinitions:
ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"RAIL_SEGMENT_UDT"), Encoding:1, 29580 bytes)
Reading after load typedefinitions:
RAIL_SEGMENT_UDT(RAIL_Size: 8, RAIL: RAIL_UDT(....  [ !!! i am not allowed to show all the data but you can get the idea !!! ]

C:\Users\andre>

AndreasHeine avatar Oct 07 '20 14:10 AndreasHeine

The key word you need to study is ExtensionObject. The client doesn't know how to handle the extension object (custom structure) because it doesn't have the definition. Without this it doesn't know how to unpack the binary data sent from the server into the structure.

zerox1212 avatar Oct 07 '20 15:10 zerox1212

Thanks guys, it worked like a charm. client.load_type_definitions()

How ever i am getting another issue: If you see in the above screenshot, MRoll -> Roll is an Array (int32). opcua3

But python is giving me int32 opcua

biswaKL avatar Oct 08 '20 05:10 biswaKL

Parsing is not proper i guess. Roll_Size is come 40, which i guess its the array size. I think the byte mapping is getting messed up, instead of creating an array, and assigning the value into it its assigning the value into next variable.

This is in python: Array value got assigned into Rolls, the same variable is 0 in UAExpert.

Python: opc4

UA Expert: opc5 opc6

biswaKL avatar Oct 08 '20 06:10 biswaKL

~~it might be because of the references... does "Roll" has the reference expose its array~~

forget about that...

which PLC Vendor is it Siemens, B&R, Beckhof ???

AndreasHeine avatar Oct 08 '20 07:10 AndreasHeine

Its SIEMENS - S7 1200

biswaKL avatar Oct 08 '20 07:10 biswaKL

there was something with the s7-1200 and the extension object! still try to remeber...

AndreasHeine avatar Oct 08 '20 07:10 AndreasHeine

it looks like there is no recursion on class build:

ua s7

from opcua import Client

client = Client("opc.tcp://192.168.10.1:4840/")
client.connect()
struct = client.get_node('ns=3;s="Routen_DB"."Routen"')
before = struct.get_value()
client.load_type_definitions()  # scan server for custom structures and import them
after = struct.get_value()
print("before", before)
print("after", after)
print(type(after))
print(after[0])
print(type(after[0]))
print(after[0].DST)

client.disconnect()

OUTPUT:

before [ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), 
ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes), ExtensionObject(TypeId:StringNodeId(ns=3;s=TE_"ROUTE_UDT"), Encoding:1, 68 bytes)]
after [ROUTE_UDT(DST_Size: 32, DST: 1), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, 
DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 
32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0), ROUTE_UDT(DST_Size: 32, DST: 0)]
<class 'list'>
ROUTE_UDT(DST_Size: 32, DST: 1)
<class 'ROUTE_UDT'>
1

should be a list of class "ROUTE_UDT" i guess!?

AndreasHeine avatar Oct 08 '20 08:10 AndreasHeine

Appreciate your help @AndreasHeine but there is one small problem: I dont have access to the PLC code. All i have is a OPC UA server. Besides since UA Expert is able to read it, i dont think problem is at server side. It definitely some client side issue only. I am running out of time now. I will recreate the scenario and try to fix the parsing for array after forking from master branch.

biswaKL avatar Oct 08 '20 08:10 biswaKL

Appreciate your help @AndreasHeine but there is one small problem: I dont have acceess to the PLC code. All i have is a OPC UA server. Besides since UA Expert is able to read it, i dont think problem is at server side. It definitely some client side issue only.

sure my previous post proved that there is something missing in the class building out of a extension object in python opcua

AndreasHeine avatar Oct 08 '20 08:10 AndreasHeine