FreeOpcUa / python-opcua

LGPL Pure Python OPC-UA Client and Server
http://freeopcua.github.io/
GNU Lesser General Public License v3.0
1.34k stars 660 forks source link

Error in parsing packet from a node opcua client #1038

Open andreafresa opened 4 years ago

andreafresa commented 4 years ago

Hello everyone, I have an opc ua server written in python with a address space that I want to crawl from the client using the object NodeCrawler from node-opcua. The stack of the client is node-opcua. They both use the OpcUa Binary protocol, but when I send a ReadRequest to the server an exception is raised because of the parsing of the packet. The exception is: TypeError: object of type 'int' has no len()

So my point is

  1. Is it possible to make them interoperate?
  2. Do you have something for crawling an address space from the client without knowing the path to the node? (Only for Object, no Types)

If you need a .pcap for analyzing a possible bug I can send it to you.

Thank you for the attention

zerox1212 commented 4 years ago

Are you saying node-opcua is throwing the type error? Or this error shows up in your server?

andreafresa commented 4 years ago

Yes, the error is raised in the server when a packet from the node-opcua client arrives.

swamper123 commented 4 years ago

Can you post the whole error trace? Otherwise we don't know where something has blown up.

andreafresa commented 4 years ago

Hey , I will try to answer asap to your request. Btw, can I ask you if it is possible inside the object to retrieve a node without specifying the complete path from an opc-ua client? Example: The Object "Object1" has a property "p1". Object1 is inside "Object2". can I ask directly for p1 without specifying the full path in the Address Space?

swamper123 commented 4 years ago

If I uunderstood you right, you want to know a way without asking like: root.get_child(["0;Objects", f"{idx}:Object1",f"{idx}:Object2"]) ??

If you know the Node ID of your target, you should simply request the node via _getnode Method of the Client class.

andreafresa commented 4 years ago

You are right, but let´s assume you don´t know the NodeId or the path. You only know the DisplayName and that it is an Object. Is there a way to retrieve it, so in the future you will know which is the NodeId?

zerox1212 commented 4 years ago

In what case would you only know the DisplayName? Sounds like a bad design.

I always used String NodeId where the string was at least 1 level deep to avoid what you are talking about.

For example Object2.property1. In fact this library supports parent name inheritance with string node id if you use instantiate (from what I remember).

AndreasHeine commented 4 years ago

There are only two design ways: first by id (explicit declaration) second by nesting (path)

andreafresa commented 4 years ago

You should have a look at what the node opcua developer did with the NodeCrawler, might be an interesting tool for your stack

zerox1212 commented 4 years ago

Do you have link? Usually when people ask to search address space for node we just tell them to search recursively.

andreafresa commented 4 years ago

Can you make an example of how can I do it recursively? I have a link to an issue on the github page so you can have a check of what I am talking about: https://github.com/node-opcua/node-opcua/issues/43

zerox1212 commented 4 years ago

I don't know if there is an example. Normally I would say just keep calling get_children to build a list. You just have to be careful because a UA server could have thousands of nodes.

AndreasHeine commented 4 years ago

maybe have a look at the "etree" library, opc ua and xml are quite similar in structure and for xml there are some crawlers Crawling sitemap.xml

andreafresa commented 4 years ago

I found a solution with the function get_node_children (http://docs.ros.org/kinetic/api/ros_opcua_impl_python_opcua/html/ua__utils_8py_source.html). It returns the descendent in the opcua tree starting from a defined node inside a list. Why not including something like this in the library?

swamper123 commented 4 years ago

@AndreasHeine Either an etree or a nested, mutable dict could be an efficient solution. @andreafresa Like @zerox1212 said, it is not a good idea to deal just with display names. The risk that some device may change the name or another node within the same namespace and the same displayname can cause trouble ( I have one Object garage, with two car-oobjects inside. They both are named car and are objects, but different). The nodeid is the only one which is unique in a server. Crawling is a way to find a child node, but this costs a lot of time (compared to a nodeid solution) and you may not get what you wanted.

oroulet commented 4 years ago

@andreafresa why do you want crawl the address space? But you are not the first one asking so yes, you can make a very short example and I will merge it to make the world a better place ;-) (As far as I understand this is also only an example in nodejs, not really a tool)

swamper123 commented 4 years ago

In that case I would give you the hints: