Closed abhinavrawat27 closed 7 years ago
OPC DA is a completely different protocol than OPC UA as far as I know.
You can use a proxy to convert the OPC-DA interface into a OPC-UA interface. However, this proxy has to run on a Windows computer since OPC-DA is only implemented on Windows.
Hi eskildsf
Can you please mention any proxy software to convert DA to UA. Is it compatible with windows 10.?
I have implemented a proxy in Python using OpenOPC and python-opcua, see http://courses.compute.dtu.dk/02619/software/opcda_to_opcua.py.
Commercial alternatives are also available since this is a relatively common problem. See https://opcfoundation.org/products/view/uagateway or https://opcfoundation.org/products/view/opc-ua-proxy.
@eskildsf I'm trying to use your wrapper.
Its connecting to the DA server, scanning the tags. But for some reason, its crashing at c.properties(node)
Traceback (most recent call last): File "opcda_to_opcua.py", line 135, in
for id, description_of_id, value in c.properties(node): File "C:\Users\Dushyant\Miniconda3\lib\site-packages\OpenOPC.py", line 1004, in properties return list(props) File "C:\Users\Dushyant\Miniconda3\lib\site-packages\OpenOPC.py", line 937, in iproperties property_id = [p for p, d in tag_properties if p > 0] File "C:\Users\Dushyant\Miniconda3\lib\site-packages\OpenOPC.py", line 937, in property_id = [p for p, d in tag_properties if p > 0] TypeError: 'NoneType' object is not callable
I'm using python 3.7 32-bit (as the Matrikon Simulator is also 32-bit, and using x64 was resulting in different error mentioned here
Dear @dushyantbangal,
I am a bit confused. OpenOPC is compatible with Python 2.7 32 bit. How did you manage to use it in Python 3.7?
I have installed Anaconda 2.7 32 bit and Matrikon OPC Simulation server to test if it works and I found a different bug due to the SImulation server. The server exposes tags with values corresponding to dates before the year 1900 which cannot be formatted as a string (see https://sourceforge.net/p/openopc/discussion/709251/thread/1075b4b4/). This is why you get an error in line 937 of OpenOPC.py because it attempts to cast the value of the tag as a string. This type conversion fails and causes the entire code to error.
Removing the nodes "Random.Time", "Bucket Brigade.Time", "Write Only.Time" and "Write Error.Time" resolves the issue. To do this, add the following snippet:
nodes.remove(u'Bucket Brigade.Time')
nodes.remove(u'Random.Time')
nodes.remove(u'Write Error.Time')
nodes.remove(u'Write Only.Time')
before for node in nodes:
in opcda_to_opcua.py
.
This error is differen't from yours. Can you reproduce the same results as me with a similar setup?
Br Eskild
Hello @eskildsf,
I found https://pypi.org/project/OpenOPC-Python3x/ , and just assumed I need to use 3.7.
Now I've done the setup as asked by you, and I'm getting the following error:
Traceback (most recent call last): File "opcda_to_opcua.py", line 125, in
tree[path] = parent.add_folder(idx,folder) File "C:\Users\Dushyant\Anaconda2\lib\site-packages\opcua\common\node.py", line 654, in add_folder return opcua.common.manage_nodes.create_folder(self, nodeid, bname) File "C:\Users\Dushyant\Anaconda2\lib\site-packages\opcua\common\manage_nodes.py", line 41, in create_folder return node.Node(parent.server, _create_object(parent.server, parent.nodeid, nodeid, qname, ua.ObjectIds.FolderType)) File "C:\Users\Dushyant\Anaconda2\lib\site-packages\opcua\common\manage_nodes.py", line 165, in _create_object attrs.Description = ua.LocalizedText(qname.Name) File "C:\Users\Dushyant\Anaconda2\lib\site-packages\opcua\ua\uatypes.py", line 522, in init self.Text = text File "C:\Users\Dushyant\Anaconda2\lib\site-packages\opcua\ua\uatypes.py", line 533, in Text raise ValueError("A LocalizedText object takes a string as argument, not a {}, {}".format(type(text), text)) ValueError: A LocalizedText object takes a string as argument, not a <type 'unicode'>, Random
The error points to tree[path] = parent.add_folder(idx,folder)
in my case.
Also, to avoid any other issues, I'm just passing the following nodes to the for
loop.
[u'Random.Int1', u'Random.Int2', u'Random.Int4']
Hi @eskildsf,
I just had to add .encode("utf-8")
to the folder
and file
variables, and it worked!
Thanks! :)
Dear @eskildsf
I am using your proxy, and tested. It works greatly. Thank you! But I got I issues, which is when I add a new Tag on OPC_DA server, the new tag will not be published to the UA server unless I restart the program. So I add “while True” to loop the program. Then I got another issue: I got so many the same folder and tag on UA I fixed the folder’s problem by putting the tree{} out of the while loop. However, I can’t fix the tag problem. Could anyone help me please. Thanks a lot!
Hi @cjunze,
Sure, I'll try to help you. I am a little bit reluctant though because it appears that you are asking for help regarding your solution to a problem but not the problem itself. I haven't come across a use case before where a dynamic OPC-DA tag space was necessary. Please elaborate on the problem you are trying to solve so I can help you better.
On the face of it there really is no reason why you shouldn't be able to dynamically synchronize the OPC-UA tag space to the OPC-DA tag space. I just can't think of an application where it is relevant.
Have a great day.
Br Eskild
Hi @eskildsf First at all, i appreciate your response.
Here is my case: There are a huge amount of products running with OPC-DA, which products are published many years ago, and only support with OPC-DA. As you know, with the development More and More products will run with OPC-UA. In order to make the manage more convenient, i need to use UA ONLY to read or write. This is the reason why i need the dynamically synchronize DA to UA. Thank you sooo much!
Happy Christmas Eve~
By Cjunze
@cjunze in that case the main issue is that you need to tech yourself more python/programming. Then you will understand that solving your problem is easy
I wanted to monitor 1000+ tags, so my DA server kept freezing on me. Must be an issue from the server side itself.
Hi @eskildsf,
I just had to add
.encode("utf-8")
to thefolder
andfile
variables, and it worked! Thanks! :)
Hi @dushyantbangal, could you please help me. I'm new with python. I would like tor runa an OPC-DA to OPC-UA wrapper. I'm running in the same error as @eskildsf. can you show me where to add .Encode() in the opcda_to_opcua.py code. Could you please send me your corrected file ? Thanks a lot
Hi @eskildsf, I just had to add
.encode("utf-8")
to thefolder
andfile
variables, and it worked! Thanks! :)Hi @dushyantbangal, could you please help me. I'm new with python. I would like tor runa an OPC-DA to OPC-UA wrapper. I'm running in the same error as @eskildsf. can you show me where to add .Encode() in the opcda_to_opcua.py code. Could you please send me your corrected file ? Thanks a lot
Hi @pitch3k,
I suppose the change that @dushyantbangal refers to is to append .encode("utf-8")
at the end of lines 110 and 111 in the opcda_to_opcua.py
script.
Br Eskild
Hi @eskildsf, I just had to add
.encode("utf-8")
to thefolder
andfile
variables, and it worked! Thanks! :)Hi @dushyantbangal, could you please help me. I'm new with python. I would like tor runa an OPC-DA to OPC-UA wrapper. I'm running in the same error as @eskildsf. can you show me where to add .Encode() in the opcda_to_opcua.py code. Could you please send me your corrected file ? Thanks a lot
Hi @pitch3k,
I suppose the change that @dushyantbangal refers to is to append
.encode("utf-8")
at the end of lines 110 and 111 in theopcda_to_opcua.py
script.Br Eskild
Hi @eskildsf , thanks for that hint. I think tonight I found another solution. Just before the error raised (in uatypes.py line 540 I changed "str" to "basestring". It seems to work now
Thank you for sharing your solution, @pitch3k. If you feel like it you can contribute your edit of uatypes.py
in a pull request. I'm sure the manitainers would appreciate it.
Br Eskild
hello @eskildsf , could you please explain to me the SubscriptionHandler class?
hello @eskildsf , could you please explain to me the SubscriptionHandler class?
Hi @enesebastian. The code is only 160 lines so I'd recommend that you read it to gain an understanding. I recommend you to consult the python-freeopcua source code concerning subscriptions and how they are implemented in the library.
If you have concrete questions then you are welcome to ask them here so future readers can benefit as well.
Br Eskild
@pitch3k My changes were on lines 120 and 137
tree[path] = parent.add_folder(idx,folder.encode("utf-8"))
opcua_node = tree[path].add_variable(idx, file.encode("utf-8"), ua.Variant(current_value, ua.VariantType.UInt16))
Though, it might work on 110 and 111 as @eskildsf mentioned, but I haven't tried.
hello @eskildsf , could you please explain to me the SubscriptionHandler class?
Hi @enesebastian. The code is only 160 lines so I'd recommend that you read it to gain an understanding. I recommend you to consult the python-freeopcua source code concerning subscriptions and how they are implemented in the library.
If you have concrete questions then you are welcome to ask them here so future readers can benefit as well.
Br Eskild
hey, I did go through the source code of opcua ( they dont go into details with their methods and classes ) but I didn't really understand what you did in that SubscriptionHandler class. What is i, n and what is the purpose of the final_datachange_notification method ? Thank you for answering !
Hi @enesebastian,
I'll give it a shot.
Subscriptions are a key feature of OPC-UA and allow nodes to be monitored without polling. In python-opcua subscriptions on a server can be registered by the create_subscription
method of the opcua.Server
class. The create_subscription
method needs to know what to do when an event occours and this is exactly what the SubscriptionHandler
class handles (pun intended). In the present code the subscriptions are registered on lines 148 to 149:
handler = SubscriptionHandler(len(writeable_variable_handles))
sub = server.create_subscription(100, handler).subscribe_data_change(writeable_variable_handles.values())
On the first line, the SubscriptionHandler class is instantiated with n=len(writeable_variable_handles)
, so n
is really just the number of monitored variables.
The purpose of the subscription is to monitor writable nodes for changes and then to write those changes to the OPC-DA server.
So when might a subscription trigger? It triggers when the value of the subscribed node is changed but as it turns out it also triggers for newly added nodes. This means that immediately when the subscriptions are registered in lines 148-149 then we immediately get n
calls to the SubscriptionHandler.datachange_notification
method. We only want to forward actual changes so if we ignore the first n
subscription events and handle any future writes by a different method. This is why you see two methods in the SubscriptionHandler
class. The datachange_notification
method will catch events for newly added nodes. Once all n
nodes have emitted an event then the method is substituted by final_datachange_notification
which will actually propagate the event to the OPC-DA server.
Br Eskild
Hi @enesebastian,
I'll give it a shot.
Subscriptions are a key feature of OPC-UA and allow nodes to be monitored without polling. In python-opcua subscriptions on a server can be registered by the
create_subscription
method of theopcua.Server
class. Thecreate_subscription
method needs to know what to do when an event occours and this is exactly what theSubscriptionHandler
class handles (pun intended). In the present code the subscriptions are registered on lines 148 to 149:handler = SubscriptionHandler(len(writeable_variable_handles)) sub = server.create_subscription(100, handler).subscribe_data_change(writeable_variable_handles.values())
On the first line, the SubscriptionHandler class is instantiated with
n=len(writeable_variable_handles)
, son
is really just the number of monitored variables. The purpose of the subscription is to monitor writable nodes for changes and then to write those changes to the OPC-DA server.So when might a subscription trigger? It triggers when the value of the subscribed node is changed but as it turns out it also triggers for newly added nodes. This means that immediately when the subscriptions are registered in lines 148-149 then we immediately get
n
calls to theSubscriptionHandler.datachange_notification
method. We only want to forward actual changes so if we ignore the firstn
subscription events and handle any future writes by a different method. This is why you see two methods in theSubscriptionHandler
class. Thedatachange_notification
method will catch events for newly added nodes. Once alln
nodes have emitted an event then the method is substituted byfinal_datachange_notification
which will actually propagate the event to the OPC-DA server.Br Eskild
Thank you very much for the explanation !
If anyone helps, in the new version of python-opcua
on line 78 replace:
path_as_string = node.get_path_as_string()
with:
path_as_string = node.get_path(as_string=True)
Hello Everyone,
I'm new to python and trying to implement the code.
I'm currently using python 3.9.4 32 bit
I'm getting the following error
Endpoints other than open requested but private key and certificate are not set.
Listening on 172.16.6.208:8080
Traceback (most recent call last):
File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\multiprocessing\queues.py", line 245, in _feed
obj = _ForkingPickler.dumps(obj)
File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\multiprocessing\reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <class 'pywintypes.datetime'>: attribute lookup datetime on pywintypes failed
Traceback (most recent call last):
File "C:\Users\alraza\OPCDA-OPCUA.py", line 168, in
Hello Everyone, I'm new to python and trying to implement the code. I'm currently using python 3.9.4 32 bit I'm getting the following error Endpoints other than open requested but private key and certificate are not set. Listening on 172.16.6.208:8080 Traceback (most recent call last): File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\multiprocessing\queues.py", line 245, in _feed obj = _ForkingPickler.dumps(obj) File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\multiprocessing\reduction.py", line 51, in dumps cls(buf, protocol).dump(obj) _pickle.PicklingError: Can't pickle <class 'pywintypes.datetime'>: attribute lookup datetime on pywintypes failed Traceback (most recent call last): File "C:\Users\alraza\OPCDA-OPCUA.py", line 168, in for reading in c.read(readables): File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\site-packages\OpenOPC.py", line 625, in read return list(results) File "C:\Users\alraza\AppData\Local\Programs\Python\Python39-32\lib\site-packages\OpenOPC.py", line 543, in iread raise TimeoutError('Callback: Timeout waiting for data') OpenOPC.TimeoutError: Callback: Timeout waiting for data
I have succesfully implemented OPC-DA to OPC-UA wrapper code with python 3.9 version with 32 bit. Since the OpenOPC library is only supported by 32 bit python and not with 64 bit. In order to successfully run the code add the following lines after from opcua import ua, uamethod, Server import pywintypes pywintypes.datetime = pywintypes.TimeType
Thank you
Hi all,
I have a OPC DA server running on it. I have tested it on windows with client software and is working fine. I need make an application which will connect to this OPC DA server from linux. Is it possible to use this FreeOPCUA python for DA. Is this library compatible with OPC DA.
Thanks