Closed karyuv closed 7 years ago
Ya, I've been working on generalizing the cpppo methods to more cleanly handle writes. It works fine (you can try it out using cpppo.server.enip.client via the Command-Line Interface (see docs). Remember to specify the data type as DINT, eg ... 'some_tag[0-3]=(DINT)0,1,2,3'
I have an experimental branch called 'feature-proxy-write' that is a work-in-progress, to get the cpppo.server.enip.get_attribute 'proxy' interface to cleanly handle both reading and writing. You could take a look at that.
I have been much too busy to work on this; some Cpppo "Support" contracts could help that... ;)
Hello Sir, Thanks a lot for your swift reply. Here is the python code; which tries to write an array of dints.
while True:
try:
with client.connector( host= plc_ip_address) as conn:
while True:
time_prev=time.time()
data = []
for c in range(5):
data.append(int(0))
req = conn.write("CDS_PLC_RawData_TLC", data,"DINT")
try:
rpy = next(conn)
print rpy
except AssertionError:
print "Response timed out!! Tearing Connection and Reconnecting!!!!!"
break
except AttributeError:
print "Tag J1_pos not written:::Will try again::"
break
Here is my error:
_Traceback (most recent call last):
File "./tag_write.py", line 27, in
Any thoughts?. Thank you.
The conn.write API is pretty low level, and needs alot of detail information. This is usually provided by client.parse_operations:
>>> from cpppo.server.enip import client
>>> list(client.parse_operations([ "some_tag=(DINT)0,1,2,3"] ))
[{'path': [{'symbolic': 'some_tag'}], 'elements': 4, 'data': [0, 1, 2, 3], 'method': 'write', 'tag_type': 196}]
So, if you want to call it directly, supply:
from cpppo.server.enip import client
client.write( [{'path': [{'symbolic': 'some_tag'}], elements=len( data ), data=data, tag_type=client.enip.DINT.tag_type )
Also; don't forget that there is a turn-around time, awaiting the response from the client device.
I've rewritten your example to be a bit more correct:
import socket
import time
from cpppo.server.enip import client
plc_ip_address = "127.0.0.1"
timeout = 5.0
while True:
try:
with client.connector( host= plc_ip_address, timeout=timeout ) as conn:
while True:
data = [int(0) for c in range( 5 )]
req = conn.write( "CDS_PLC_RawData_TLC", elements=len( data ), data=data,
tag_type=client.enip.DINT.tag_type )
rpy,ela = client.await( conn, timeout=timeout )
print rpy
except AssertionError:
print "Response timed out!! Tearing Connection and Reconnecting!!!!!"
except AttributeError:
print "Tag J1_pos not written:::Will try again::"
except socket.error as exc:
print "Couldn't send command: %s" % ( exc )
time.sleep( .1 )
All this is sort of taken care of, if you use the client.connector API's simple 'process' method. This performs all tag I/O (allows pipeline depth, multiple request packets, etc., if desired), and synchronously returns the list of response after all I/O is complete:
#
# Run simulator in another window:
# python -m cpppo.server.enip -va localhost --print CDS_PLC_RawData_TLC=DINT[4]
#
import socket
import time
import cpppo
from cpppo.server.enip import client
plc_ip_address = "127.0.0.1"
timeout = 5.0
import logging
#cpppo.log_cfg['level'] = logging.DETAIL
logging.basicConfig( **cpppo.log_cfg )
tags = ["CDS_PLC_RawData_TLC[0-3]=(DINT)0,1,2,3"]
while True:
try:
with client.connector( host=plc_ip_address, timeout=timeout ) as conn:
operations = client.parse_operations( tags )
failures,replies = conn.process(
operations=operations, timeout=timeout )
for rpy in replies:
print rpy
except Exception as exc:
print "EtherNet/IP I/O Failed: %s" % ( exc )
time.sleep( .1 )
Hello Sir, Thanks a lot for the code!!. It is working well :).
I have one more question; I have been using the client.main(["-a", plc_ip_address, Tag]) to write tags to PLC. I was looking for other write features; as it was not that quick as connector.write. Connector.write is fast because it an unconnected send?.
All EtherNet/IP CIP I/O in the Cpppo library use "Unconnected" sends. The key to faster I/O is to set up the connection, and then to use it without closing it. The client.main API always sets up, uses, and then closes a connection. By maintaining your own connection and then using it repeatedly, you get much higher transaction rates.
To improve this much, much further -- use the client.pipeline API. This allows you to issue multiple transaction requests, before receiving the transaction replies. You can keep the PLC "saturated" with requests, instead of letting it sit idle while you await the response to a previous request.
Hello Everyone, I have been using this library for a variety of projects and its very useful!!.
I have used client.connector read function in the past to read some tag values on the PLC side and it works great!!. Now I am trying to write an array of dints using client.connector's write function. Any thoughts on that?. Is it possible to share any code snippets?. Thank you.