pycomm
pycomm copied to clipboard
Compatibility with cpppo
Hi,
"cpppo" (https://github.com/pjkundert/cpppo) is a very cool python library that among other things can simulate a PLC locally. This is quite useful for testing without needing PLC hardware, and I've used it with other client libraries in the past with success. But somehow it does not play well with pycomm.
Here's the output of running a cpppo server and then connecting locally with pycomm from another process. The corresponding pycomm code is below.
Now I can't tell if this is an issue with pycomm or with cpppo, but to me it looks like something is missing in the client connection. Maybe I'm just not doing it right?
$ env/bin/python -m cpppo.server.enip -v a=DINT b=DINT
09-04 17:19:40.192 7f2d82de0700 enip.srv NORMAL main Delaying all responses by 0.0 seconds
09-04 17:19:40.192 7f2d82de0700 enip.srv NORMAL main Creating tag: a=DINT[1]
09-04 17:19:40.192 7f2d82de0700 enip.srv NORMAL main Creating tag: b=DINT[1]
09-04 17:19:40.192 7f2d82de0700 root NORMAL main EtherNet/IP Simulator: ('', 44818)
09-04 17:19:40.193 7f2d82de0700 network NORMAL server_mai enip_srv server PID [21011] running on ('', 44818)
09-04 17:19:40.193 7f2d82de0700 network NORMAL server_mai enip_srv server PID [21011] responding to external done/disable signal
09-04 17:21:48.995 7f2d806b2700 enip.srv NORMAL enip_srv EtherNet/IP Server enip_54710 begins serving peer ('127.0.0.1', 54710)
09-04 17:21:49.005 7f2d806b2700 enip.lgx NORMAL setup Logix.a DINT[ 1] == 0 Attribute 1 added
09-04 17:21:49.006 7f2d806b2700 enip.lgx NORMAL setup Logix.b DINT[ 1] == 0 Attribute 2 added
09-04 17:21:49.026 7f2d806b2700 enip.dev ERROR request EtherNet/IP CIP error at 0 total bytes:
"N\x02 \x06$\x01\n\x05'\x04\t\x10\t\x10\x19q\x03\x00\x01\x00 \x02$\x01"
-^ (byte 0)
09-04 17:21:49.027 7f2d806b2700 enip.dev NORMAL request (0x9999, 1) UCMM Command 0x006f SendRRData failed with Exception: ( dfa_post.( select ) ) sub-machine terminated in a non-terminal state
Request: {
"enip.status": 0,
"enip.sender_context.input": "array('c', '_pycomm_')",
"enip.session_handle": 2518093524,
"enip.length": 40,
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.CPF.count": 2,
"enip.CIP.send_data.CPF.item[0].length": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].length": 24,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('c', \"N\\x02 \\x06$\\x01\\n\\x05'\\x04\\t\\x10\\t\\x10\\x19q\\x03\\x00\\x01\\x00 \\x02$\\x01\")",
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 10,
"enip.command": 111,
"enip.options": 0,
"addr": [
"127.0.0.1",
54710
]
}
Traceback (most recent call last):
File "/home/johfor/kits/cpppo/server/enip/device.py", line 990, in request
CM.request( unc_send )
File "/home/johfor/kits/cpppo/server/enip/device.py", line 1510, in request
for i,(m,s) in enumerate( machine.run( path='request', source=source, data=data )):
File "/home/johfor/kits/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/home/johfor/kits/cpppo/automata.py", line 1291, in delegate
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
NonTerminal: ( dfa_post.( select ) ) sub-machine terminated in a non-terminal state
09-04 17:21:49.028 7f2d806b2700 enip.srv WARNING enip_srv Expected EtherNet/IP response encapsulated message; none found
09-04 17:21:49.028 7f2d806b2700 enip.srv WARNING enip_srv Session ended (server EtherNet/IP status: 0x08 == 8)
09-04 17:21:49.029 7f2d806b2700 enip.srv NORMAL enip_srv enip_54710 done; processed 2 requests over 92 bytes/ 92 received (0 connections remain)
IPython:
In [13]: c = ClxDriver()
In [14]: c.open("127.0.0.1")
Out[14]: True
Doing something else at this point, like reading a tag, results in a "CommError: socket connection broken.".
I ran into exactly this issue this week, and began working on a solution. Through much research I found that the cpppo server you (and I) are running is a generic CIP device, so it will not work with the AllenBradley drivers included with pycomm. From the examples and comments included I can only assume that it would work as advertised with those AB devices named, but I do not have one available to test with.
I am working on a fork to support CIP Generic Messaging, and have gotten it working with cpppo and an off-brand PLC with an EtherNet/IP interface. https://github.com/tyoungNIO/pycomm/blob/generic/pycomm/cip/cip_generic.py
As of today the generic
branch still does not work with any sort of symbolic addressing, but if you supply a full path for the tags to your cpppo.server.enip
, such as a@1/2/3=DINT
, then a call to c.get_attribute_single(1, 2, 3)
will return 4 bytes.
A PLC's IO data (including AB, I believe) will also be available from standard Class IDs, for example 10 for Analog Input. In my case, I can read the first four analog inputs from 10, 1, 3
through 10, 4, 3
, each input is an instance of the AI class from 1 to 4, with the measured value stored in attribute 3. The second AI module begins at 10, 65, 3
, and so forth, according to the manufacturer's documentation.
Hi, Can we get and set attribute for any CIP generic objects using Pycomm and CPPPO? Can Explicit and Implicit both supported by Pycomm and CPPPO? If one to select for the automation then which would you prefer?
Please reply, it's urgent.