pjkundert / cpppo Goto Github PK
View Code? Open in Web Editor NEWCommunications Protocol Python Parser and Originator -- EtherNet/IP CIP
Home Page: https://hardconsulting.com/products/6-cpppo-enip-api
License: Other
Communications Protocol Python Parser and Originator -- EtherNet/IP CIP
Home Page: https://hardconsulting.com/products/6-cpppo-enip-api
License: Other
I'm using the cpppo library to discover devices on a network. I'm using the client API to send out a list identity request over UDP. Unfortunately, one of the devices discovered is a PowerFlex 700 which returns a CIP packet with a 0 length field. Looking at the comments in your code it appears that you're aware of this bug in PowerFlex devices and have attempted to code against this in your parser. Unfortunately, this doesn't appear to work for my scenario and so the client object is left in an invalid state, presumably because it's got unparsed data that it's not sure what to do with. The problem I've got then is that the situation is not recoverable; there's no way I can continue the process. The only thing I can do is start again which leads to the same issue. Alternatively, I could use TCP and step through the network addresses for the subnet but this is really inefficient.
If you have any suggestions on how I might recover from this issue that would be great. To help, here's the packet of data that's returned by the Power Flex in Hex.
63000000000000000000000000000000000000000000000001000c00270001000002af129b7d7a91000000000000000001007b0068006e03610020e6242020506f776572466c65782037303020564320343830562032343841202020202020ff
And here's the relevant part from the cpppo logger...
11-16 19:52:16.079 MainThread enip.cli INFO __next__ EtherNet/IP--> 155.125.122.145:44818 rcvd 96: "c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x0c\x00'\x00\x01\x00\x00\x02\xaf\x12\x9b}z\x91\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00{\x00h\x00\n\x03a\x00 \xe6$ PowerFlex 700 VC 480V 248A \xff"
11-16 19:52:16.084 MainThread cpppo INFO terminate ( header.((empty)) : => enip.command = 99 (format '<H' over array('c', 'c\x00'))
11-16 19:52:16.086 MainThread cpppo INFO terminate ( header.((empty)) : => enip.length = 0 (format '<H' over array('c', '\x00\x00'))
11-16 19:52:16.091 MainThread cpppo INFO terminate ( header.((empty)) : => enip.session_handle = 0 (format '<I' over array('c', '\x00\x00\x00\x00'))
11-16 19:52:16.095 MainThread cpppo INFO terminate ( header.((empty)) : => enip.status = 0 (format '<I' over array('c', '\x00\x00\x00\x00'))
11-16 19:52:16.106 MainThread cpppo INFO terminate ( header.((empty)) : => enip.options = 0 (format '<I' over array('c', '\x00\x00\x00\x00'))
11-16 19:52:16.108 MainThread enip.cli INFO __next__ EtherNet/IP 155.125.122.255:44818 done: ((enip.((payload.((byte))) -> ((payload.; next byte 1120: '\x01' : {'peer': ('155.125.122.145', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('c', '\x00\x00\x00\x00\x00\x00\x00\x00')}, 'session_handle': 0, 'length': 0, 'command': 99, 'options': 0}}
11-16 19:52:16.109 MainThread enip.cli INFO __next__ Returning result: {'peer': ('155.125.122.145', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('c', '\x00\x00\x00\x00\x00\x00\x00\x00')}, 'session_handle': 0, 'length': 0, 'command': 99, 'options': 0}}
Thanks for a great library.
I'm evaluating this library for potential commercial use in the future, but am running into some issues. Maybe I'm doing something wrong...
I'm attempting to use the poll.poll example to poll tags from a server simulator I created. The simulator essentially just calls the server.enip.main function with some tags and has two clients (in other threads) that are writing random/function data (sine, cosine, etc.). I want to poll this server using the tag names. I tried both the proxy and proxy_simple classes with no luck. I also tried using different values in the 'params' list:
params = ['random_integer', 'random_boolean']
I get: Unrecognized parameter name: 'random_integer'
params = [('random_integer', 'INT')]
I get: ('random_integer', 'INT') == None
I'm also monitoring this data from the web interface and in the terminal and know this value is successfully being written to.
I can use the class/object/attribute address to target this tag as you would using proxy_simple just fine. This makes me think the issue lies with the server. It doesn't seem to lookup the tag correctly.
I'm working on getting a PLC to test against rather than the simulator, but that may be a while. Any help is appreciated!
PS
Also, may I make a suggestion for the web api? It would be great to have the json object that gets return be much more fleshed out. At a minimum, the tag values should be in raw form rather than a string. It's painful to parse out the tag values from the huge string, particularly when the tag is an array.
When trying to use the example cpppo.cfg in the user manual the software crashes. This is due to the trailing , after "example.com". Removing the , allows this configuration to work properly.
[Identity]
# Generally, strings are not quoted
Product Name = 1756-L61/B LOGIX5561
[TCPIP]
# However, some complex structures require JSON configuration:
Interface Configuration = {
"ip_address": "192.168.0.201",
"network_mask": "255.255.255.0",
"dns_primary": "8.8.8.8",
"dns_secondary": "8.8.4.4",
"domain_name": "example.com",
}
Host Name = controller
Hi
i am approaching this library to have an idea on how to read tags,
In my case i have a L73 processor (clx) in a rack and i would like to read a tag from it.
The plc module is in a rack with other modules in it, (some i/o cards, a EN2T module). The ip address i can reach is the one of the ethernet module.
My quesitons are:
1)how i connect directly to the CLX i need? can't i specify rack/port of the backplane?
thanks
Hi,
Is there any facility available like probing in which we can query for tags from the PLC directly to get to know which are the tags configured?
I am using a Softlogix 5800 EtherNet/IP controller and ENIP card:
When trying to get/query tags I am getting a none (get_attribute) or non-zero (enip_client) status. I have been reviewing the readme for weeks and I still cannot understand what I am missing. I believe the SoftLogix controller only supports "Unconnected" requests (can someone verify?), so using the enip_client may not be an option. If this is the case I am not sure what the proper class/instance/attribute settings are for the get_attribute.
I would extremely appreciate any help here as I have been banging my head against the desk on this one.
python -m cpppo.server.enip.client -i -a 192.168.159.140 "Pump1" -vv
08-15 14:33:43.049 MainThread enip.cli DETAIL init Connect: TCP/IP to ('192.168.159.140', 44818)
08-15 14:33:43.118 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 0,
"enip.CIP.register.protocol_version": 1,
"enip.CIP.register.options": 0,
"enip.options": 0
}
08-15 14:33:43.125 MainThread enip.cli NORMAL init Connect: Success in 0.077s/ 5.000s
08-15 14:33:43.128 MainThread enip.cli DETAIL main Client Register Rcvd 0.079/ 5.000s
08-15 14:33:43.131 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 2147614721,
"enip.CIP.list_identity": {},
"enip.options": 0
}
List Identity 0 from ('192.168.159.140', 44818): {
"count": 1,
"item[0].length": 59,
"item[0].identity_object.sin_addr": "192.168.159.140",
"item[0].identity_object.status_word": 48,
"item[0].identity_object.vendor_id": 1,
"item[0].identity_object.product_name": "SoftLogix5800 EtherNet/IP",
"item[0].identity_object.sin_port": 9216,
"item[0].identity_object.state": 3,
"item[0].identity_object.version": 1,
"item[0].identity_object.device_type": 12,
"item[0].identity_object.sin_family": -18818,
"item[0].identity_object.serial_number": 1881467854,
"item[0].identity_object.product_code": 135,
"item[0].identity_object.product_revision": 277,
"item[0].type_id": 12
}
08-15 14:33:43.157 MainThread enip.cli DETAIL parse_oper Tag: 'Pump1' yields Operation: {'path': [{'symbolic': 'Pump1'}]}.update({'route_path': None, 'send_path': None})
08-15 14:33:43.161 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 2147614721,
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "Pump1",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag.elements": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 76,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')",
"enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.options": 0
}
08-15 14:33:43.168 MainThread enip.cli DETAIL format_pat Formatted Pump1 from: [{'symbolic': 'Pump1'}]
08-15 14:33:43.171 MainThread enip.cli DETAIL issue Sent 0.010/ 5.000s: Single Read Tag Pump1 {
"path.segment[0].symbolic": "Pump1",
"read_tag.elements": 1,
"service": 76,
"input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')"
}
08-15 14:33:43.171 MainThread enip.cli DETAIL issue Sending 1 (Context '0')
08-15 14:33:43.174 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth
08-15 14:33:43.186 MainThread enip.cli DETAIL collect Rcvd 0.010/ 5.000s {
"peer": [
"192.168.159.140",
44818
],
"enip.status": 0,
"enip.sender_context.input": "array('c', '0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 2147614721,
"enip.length": 20,
"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": 4,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 8,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('c', '\xcc\x00\x08\x00')",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag": true,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 204,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.command": 111,
"enip.input": "array('c', '\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x04\x00\xcc\x00\x08\x00')",
"enip.options": 0
}
08-15 14:33:43.197 MainThread enip.cli DETAIL collect Receive 1 (Context '0')
08-15 14:33:43.200 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth
08-15 14:33:43.200 MainThread enip.cli DETAIL validate Client Single Read Tag Pump1 Request: {
"path.segment[0].symbolic": "Pump1",
"read_tag.elements": 1,
"service": 76,
"input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')"
}
08-15 14:33:43.203 MainThread enip.cli DETAIL validate Yields Reply: {
"status": 8,
"input": "array('c', '\xcc\x00\x08\x00')",
"status_ext.size": 0,
"read_tag": true,
"service": 204
}
08-15 14:33:43.207 MainThread enip.cli DETAIL format_pat Formatted Pump1 from: [{'symbolic': 'Pump1'}]
08-15 14:33:43.210 MainThread enip.cli WARNING validate Client Single Read Tag Pump1 returned non-zero status: Status 8
08-15 14:33:43.210 MainThread enip.cli NORMAL validate Pump1 == None: 'Status 8 '
Pump1 == None: 'Status 8 '
08-15 14:33:43.211 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth
08-15 14:33:43.213 MainThread enip.cli NORMAL main Client Tag I/O Average 17.910 TPS ( 0.056s ea).
$ python -m cpppo.server.enip.get_attribute 'Pump1' -a 192.168.159.140 -vv
08-15 14:21:40.471 MainThread enip.cli DETAIL init Connect: TCP/IP to ('192.168.159.140', 44818)
08-15 14:21:40.540 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 0,
"enip.CIP.register.protocol_version": 1,
"enip.CIP.register.options": 0,
"enip.options": 0
}
08-15 14:21:40.549 MainThread enip.cli NORMAL init Connect: Success in 0.079s/ 5.000s
08-15 14:21:40.552 MainThread enip.cli DETAIL parse_oper Tag: "'Pump1'" yields Operation: {'path': [{'symbolic': "'Pump1'"}]}.update({'route_path': None, 'send_path': None})
08-15 14:21:40.553 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 2147614721,
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "'Pump1'",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.get_attribute_single": true,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 14,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b"\x0e\x05\x91\x07'Pump1'\x00")",
"enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.options": 0
}
08-15 14:21:40.561 MainThread enip.cli DETAIL format_pat Formatted 'Pump1' from: [{'symbolic': "'Pump1'"}]
08-15 14:21:40.562 MainThread enip.cli DETAIL issue Sent 0.007/ 5.000s: Single G_A_S 'Pump1' {
"path.segment[0].symbolic": "'Pump1'",
"get_attribute_single": true,
"service": 14,
"input": "bytearray(b"\x0e\x05\x91\x07'Pump1'\x00")"
}
08-15 14:21:40.565 MainThread enip.cli DETAIL issue Sending 1 (Context '0')
08-15 14:21:40.565 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth
08-15 14:21:40.581 MainThread enip.cli DETAIL collect Rcvd 0.014/ 5.000s {
"peer": [
"192.168.159.140",
44818
],
"enip.status": 0,
"enip.sender_context.input": "array('c', '0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 2147614721,
"enip.length": 22,
"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": 6,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 4,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('c', '\x8e\x00\x04\x01\x00\x00')",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.data": [
0
],
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 142,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.command": 111,
"enip.input": "array('c', '\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x06\x00\x8e\x00\x04\x01\x00\x00')",
"enip.options": 0
}
08-15 14:21:40.588 MainThread enip.cli DETAIL collect Receive 1 (Context '0')
08-15 14:21:40.588 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth
Mon Aug 15 14:21:40 2016: 0: Single G_A_S 'Pump1' == None
08-15 14:21:40.591 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth
08-15 14:21:40.592 MainThread enip.get NORMAL main 1 requests in 0.040s at pipeline depth 0; 24.927 TPS
python -m cpppo.server.enip.get_attribute '@4/1/1' -a 192.168.159.140 -v
08-15 14:23:39.404 MainThread enip.cli NORMAL init Connect: Success in 0.062s/ 5.000s
Mon Aug 15 14:23:39 2016: 0: Single G_A_S '@4/1/1' == None
08-15 14:23:39.418 MainThread enip.get NORMAL main 1 requests in 0.013s at pipeline depth 0; 77.811 TPS
While looking into how Rslinx acquires the list of tags from a PLC I ran across an apparently non-standard CIP Service 0x55 which AFAICT may be used to get the tag names from the PLC. However, for this it uses 16 bit instance segments. It looks like cpppo only supports 8 bit segments, is this something that might change?
The possibility to read the tag names (and particularly the tag addresses) would be highly useful.
when I try to do as README file.
there is a step on Page3: git clone [email protected]:pjkundert/cpppo.git
but system reply Permission denied(publickey).
I hope to know whether it is a problem for next steps. Thank you.
Hi, I'm just looking to write a simple script to pull some floats out of a PLC and store in mysql at regular intervals for logging purposes / fault finding purposes. the client.read function seems to return a lot of stuff, is there anyway just to return the actual tag value?
PS D:\ppp\desktop\EIP> enip_server -v --print SCADA[0-10] SCADA[1]=99 'TEXT[1]=(SSTRING)"Hello, world!"' TEXT[0-3] 04-27 16:21:00.229 MainThread root NORMAL main Loaded config files: [] 04-27 16:21:00.229 MainThread enip.srv NORMAL main Delaying all responses by 0.0 seconds 04-27 16:21:00.230 MainThread enip.srv NORMAL main Creating tag: SCADA[0-10] INT[ 1] Traceback (most recent call last): File "c:\users\laptop81\appdata\local\programs\python\python36\lib\runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "c:\users\laptop81\appdata\local\programs\python\python36\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Users\Laptop81\AppData\Local\Programs\Python\Python36\Scripts\enip_server.exe\__main__.py", line 9, in <module> File "c:\users\laptop81\appdata\local\programs\python\python36\lib\site-packages\cpppo\server\enip\main.py", line 1134, in main assert tag_type in typenames, "Invalid tag type; must be one of %r ---your tage_type is - %r" % (list( typenames ),list(tag_type)) AssertionError: Invalid tag type; must be one of ['BOOL', 'INT', 'DINT', 'SINT', 'REAL', 'SSTRING', 'STRING'] ---your tage_type is - ['9', '9']
I have edited the code @ "c:\users\laptop81\appdata\local\programs\python\python36\lib\site-packages\cpppo\server\enip\main.py", line 1134 to know the "tag_type"
assert tag_type in typenames, "Invalid tag type; must be one of %r ---your tage_type is - %r" % (list( typenames ),list(tag_type))
Using Version Python 3.6
I'm using the client to read/write DINT tags like so:
python -m cpppo.server.enip.client -a myaddress "myDINTtag"
python -m cpppo.server.enip.client -a myaddress "myDINTtag=(DINT)1234"
These work as expected.
However, when I attempt to read a string like so:
python -m cpppo.server.enip.client -a myaddress "mySTRINGtag"
I get this error output.
When I try to write a string value like so:
python -m cpppo.server.enip.client -a myaddress "mySTRINGtag=(STRING)asdf"
I get the following result, and the value is not written to the PLC:
mySTRINGtag <= ['asdf']: 'Status 255 [8445]'
Am I doing anything obviously wrong? How can I proceed in debugging this issue?
I'm trying to connect to my PLC and just read/write to a string tag. I've looked at the documentation and through all of the forum posts people have made on here for clues. Right now I'm able to read/write individual characters as DINTs, but that means I'll have to do an ascii translation for every character I want to read or write.
from cpppo.server.enip import client
from time import ctime
host = "172.16.17.160"
tags = ["TRM_ElementReject_Data.Production_Order.DATA[0]*40", "TRM_ElementReject_Data.Production_Order[0]"]
with client.connector( host=host, timeout=5.0 ) as conn:
#write
operations = client.parse_operations(["TRM_ElementReject_Data.Production_Order[0]=(DINT)99"])
failures,replies = conn.process(operations=operations, timeout=5.0)
for rpy in replies:
print rpy
#read tags
print ''
for index,descr,op,reply,status,value in conn.pipeline(operations=client.parse_operations( tags ), depth=2 ):
print "%s: %20s: %s" % ( ctime(), descr, value, )
I've tried something like operations = client.parse_operations(["TRM_ElementReject_Data.Production_Order[0]=(STRING)xyz"])
, but I haven't had any success. Help, please?
So I am trying to read a string that is part of an array of strings out of a AB CompactLogix L18ER. With the structure JugARecipeName STRING[32] and the DATA tag inside is SINT[82] so 32 strings with a length of 82. I get a ValueError: too many values to unpack (expected 2) if I try to read one element. But I can't seem to read JugARepcipeName[1] or JugARecipeName[1].DATA as I just get 'cpppo.automata.NonTerminal: ( data.( select.((noop)) ) ) sub-machine terminated in a non-terminal state' am I doing something wrong to read this?
Examples below:
python3 -m cpppo.server.enip.client -a 192.168.2.210 -l cpppo.txt --print 'JugARecipeName[1].DATA'
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/runpy.py", line 170, in _run_module_as_main
"main", mod_spec)
File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1609, in
sys.exit( main() )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1590, in main
fragment=fragment, printing=printing, timeout=timeout )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1366, in process
transactions = list( self.results( operations=operations, *_kwds ))
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1358, in results
for idx,dsc,req,rpy,sts,val in self.operate( operations, *_kwds ):
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1353, in operate
for idx,dsc,req,rpy,sts,val in harvested:
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1243, in validate
for index,descr,request,reply,status,val in harvested:
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1218, in pipeline
col = next( harvester )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1150, in harvest
issued, self.collect( timeout=timeout )): # must be "lazy" zip!
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1075, in collect
response,elapsed = await( self, timeout=timeout )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 832, in await
for response in cli: # if StopIteration raised immediately, defaults to {} signalling completion
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 509, in next
for mch,sta in engine:
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 1226, in delegate
for which,target in submach: # 75% of runtime is spent inside 'run'
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 1226, in delegate
for which,target in submach: # 75% of runtime is spent inside 'run'
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.5/site-packages/cpppo/automata.py", line 1291, in delegate
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
cpppo.automata.NonTerminal: ( data.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
python3 -m cpppo.server.enip.client -a 192.168.2.210 -l cpppo.txt --print 'JugARecipeName[1].DATA[0]'
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/runpy.py", line 170, in _run_module_as_main
"main", mod_spec)
File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1609, in
sys.exit( main() )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1590, in main
fragment=fragment, printing=printing, timeout=timeout )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1366, in process
transactions = list( self.results( operations=operations, *_kwds ))
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1358, in results
for idx,dsc,req,rpy,sts,val in self.operate( operations, *kwds ):
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1353, in operate
for idx,dsc,req,rpy,sts,val in harvested:
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1243, in validate
for index,descr,request,reply,status,val in harvested:
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 1208, in pipeline
iss = next( issuer )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 932, in issue
for op in operations:
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/client.py", line 205, in parse_operations
seg,elm,cnt = parse_path_elements( tag )
File "/usr/local/lib/python3.5/site-packages/cpppo/server/enip/device.py", line 314, in parse_path_elements
elm, = elm.split( ']' )
ValueError: too many values to unpack (expected 2)
Hi all,
I use cpppio to read a tag named "my_array[0]", and i find the status code replied by my AB PLC is always "Path Segment Error", the cpppo version i used is v3.9.3, the below is my process:
enip_client -a 128.0.21.107 'my_array[0]'
the request is:
0000 6f 00 2e 00 00 30 02 0b 00 00 00 00 30 00 00 00 o....0......0...
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 ................
0020 00 00 00 00 b2 00 1e 00 52 02 20 06 24 01 05 9d ........R. .$...
0030 10 00 4c 06 91 08 6d 79 5f 61 72 72 61 79 28 00 ..L...my_array(.
0040 01 00 01 00 01 00 ......
the reply is:
0000 6f 00 16 00 00 30 02 0b 00 00 00 00 30 00 00 00 o....0......0...
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 ................
0020 00 00 00 00 b2 00 06 00 cc 00 04 01 00 00 ..............
..
i find the cpppo always use 0x52 service code of CM, but why not is 0x4c of RM(route manager)?
can i control only use 0x4c service code of the RM to read/write tags?
I hope to do an experiment to analyse the data transform. but I am not sure how to setup server/client(slaver/master) on two different virtual machine rather than two terminals for same virtual machine. the target is two different IP address for server/client. I hope to gain the method. thank you!
Writing a value to a REAL tag works, but reading it back returns the value rounded down to the nearest integer.
Using the example EthernetIP-server.py code, I am unable to process the ListIdentity command (0x63). Is this command supported? It should be returning the default Logix identity specified in device.py, but I keep getting an EtherNet/IP error.
Here is the log I am getting.
10-05 22:15:17.659 -49088000 enip.srv NORMAL main Delaying all responses by 0.0 seconds
10-05 22:15:17.689 -49088000 enip.srv NORMAL main Creating tag: TagName=DINT[1]
10-05 22:15:17.735 -49088000 root NORMAL main EtherNet/IP Simulator: ('', 44818)
10-05 22:15:17.767 -49088000 network NORMAL server_mai enip_srv server PID [ 981] running on ('', 44818)
10-05 22:15:17.784 -49088000 network NORMAL server_mai enip_srv server PID [ 981] responding to external done/disable signal
10-05 22:15:20.822 -4cc7aba0 enip.srv NORMAL enip_srv EtherNet/IP Server enip_44818 begins serving peer ('192.168.1.99', 44818)
10-05 22:15:20.905 -4cc7aba0 enip.srv DETAIL enip_srv Transaction begins
10-05 22:15:20.979 -4cc7aba0 enip.srv DETAIL enip_srv Transaction receive after 0.072s ( 24 bytes in 0.001/ 0.100s)
10-05 22:15:21.019 -4cc7aba0 enip.srv DETAIL enip_srv ( enip_44818.( header.((empty)) recv: 24: 'c\x00\x00\x0...0\x00\x00\x00'
10-05 22:15:21.883 -4cc7aba0 enip.srv DETAIL enip_srv Transaction parsed after 0.978s
10-05 22:15:21.915 -4cc7aba0 enip.dev DETAIL __init__ Identity, Class ID 0x0001, Instance ID 1 created
10-05 22:15:21.931 -4cc7aba0 enip.dev DETAIL lookup Class 1/0x0001, Instance 1, Attribute None ==> None
10-05 22:15:21.955 -4cc7aba0 enip.dev DETAIL lookup Class 1/0x0001, Instance 0, Attribute None ==> None
10-05 22:15:21.974 -4cc7aba0 enip.dev DETAIL lookup Class 1/0x0001, Instance 0, Attribute None ==> None
10-05 22:15:22.024 -4cc7aba0 enip.dev DETAIL lookup Class 1/0x0001, Instance 0, Attribute None ==> meta-Identity
10-05 22:15:22.223 -4cc7aba0 enip.dev DETAIL __init__ Logix, Class ID 0x0002, Instance ID 1 created
10-05 22:15:22.239 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 1, Attribute None ==> None
10-05 22:15:22.277 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 0, Attribute None ==> None
10-05 22:15:22.300 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 0, Attribute None ==> None
10-05 22:15:22.324 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 0, Attribute None ==> meta-Logix
10-05 22:15:22.363 -4cc7aba0 enip.dev DETAIL __init__ Connection_Manager, Class ID 0x0006, Instance ID 1 created
10-05 22:15:22.379 -4cc7aba0 enip.dev DETAIL lookup Class 6/0x0006, Instance 1, Attribute None ==> None
10-05 22:15:22.420 -4cc7aba0 enip.dev DETAIL lookup Class 6/0x0006, Instance 0, Attribute None ==> None
10-05 22:15:22.437 -4cc7aba0 enip.dev DETAIL lookup Class 6/0x0006, Instance 0, Attribute None ==> None
10-05 22:15:22.464 -4cc7aba0 enip.dev DETAIL lookup Class 6/0x0006, Instance 0, Attribute None ==> meta-Connection_Manager
10-05 22:15:22.503 -4cc7aba0 enip.dev DETAIL __init__ Unknown_Object, Class ID 0x0066, Instance ID 1 created
10-05 22:15:22.530 -4cc7aba0 enip.dev DETAIL lookup Class 102/0x0066, Instance 1, Attribute None ==> None
10-05 22:15:22.564 -4cc7aba0 enip.dev DETAIL lookup Class 102/0x0066, Instance 0, Attribute None ==> None
10-05 22:15:22.583 -4cc7aba0 enip.dev DETAIL lookup Class 102/0x0066, Instance 0, Attribute None ==> None
10-05 22:15:22.608 -4cc7aba0 enip.dev DETAIL lookup Class 102/0x0066, Instance 0, Attribute None ==> meta-Unknown_Object
10-05 22:15:22.733 -4cc7aba0 enip.dev DETAIL __init__ UCMM, Class ID 0x9999, Instance ID 1 created
10-05 22:15:22.748 -4cc7aba0 enip.dev DETAIL lookup Class 39321/0x9999, Instance 1, Attribute None ==> None
10-05 22:15:22.774 -4cc7aba0 enip.dev DETAIL lookup Class 39321/0x9999, Instance 0, Attribute None ==> None
10-05 22:15:22.810 -4cc7aba0 enip.dev DETAIL lookup Class 39321/0x9999, Instance 0, Attribute None ==> None
10-05 22:15:22.835 -4cc7aba0 enip.dev DETAIL lookup Class 39321/0x9999, Instance 0, Attribute None ==> meta-UCMM
10-05 22:15:22.878 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 1, Attribute None ==> Logix
10-05 22:15:22.893 -4cc7aba0 enip.lgx NORMAL setup Logix.TagName DINT[ 1] == 0 Attribute 1 added
10-05 22:15:22.940 -4cc7aba0 enip.dev DETAIL lookup Class 2/0x0002, Instance 1, Attribute 1 ==> TagName DINT[ 1] == 0
10-05 22:15:23.078 -4cc7aba0 enip.lgx ERROR process EtherNet/IP CIP error at 0 total bytes:
''
-^ (byte 0)
10-05 22:15:23.146 -4cc7aba0 enip.srv ERROR enip_srv Failed request: {
"request.enip.status": 0,
"request.enip.sender_context.input": "array('c', '\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08')",
"request.enip.session_handle": 0,
"request.enip.length": 0,
"request.enip.command": 99,
"request.enip.options": 0,
"request.addr": [
"192.168.1.99",
44818
]
}
10-05 22:15:23.207 -4cc7aba0 enip.lgx DETAIL process EtherNet/IP CIP Request (Client ('192.168.1.99', 44818)): {
"addr": [
"192.168.1.99",
44818
]
}
10-05 22:15:23.239 -4cc7aba0 enip.dev DETAIL request EtherNet/IP (Client ('192.168.1.99', 44818)) Session Terminated: '(Unknown)'
10-05 22:15:23.270 -4cc7aba0 enip.lgx DETAIL process EtherNet/IP CIP Response (Client ('192.168.1.99', 44818)): {
"addr": [
"192.168.1.99",
44818
]
}
10-05 22:15:23.331 -4cc7aba0 enip.srv ERROR enip_srv EtherNet/IP error at 24 total bytes:
'c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00'
----------------------------------------------------------------------------------------------^ (byte 24)
Failed with exception:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/cpppo/server/enip/main.py", line 657, in enip_srv
if enip_process( addr, data=data, **kwds ):
File "/usr/local/lib/python2.7/dist-packages/cpppo/server/enip/logix.py", line 695, in process
for i,(m,s) in enumerate( machine.run( path='request.enip', source=source, data=data )):
File "/usr/local/lib/python2.7/dist-packages/cpppo/automata.py", line 655, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python2.7/dist-packages/cpppo/automata.py", line 1300, in delegate
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
NonTerminal: ( CIP.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
10-05 22:15:23.367 -4cc7aba0 enip.srv NORMAL enip_srv enip_44818 done; processed 1 request over 24 bytes/ 24 received (0 connections remain)
10-05 22:15:23.398 -4cc7aba0 network WARNING run enip_srv server failure: ( CIP.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/cpppo/server/network.py", line 132, in run
super( server_thread, self ).run()
File "/usr/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/local/lib/python2.7/dist-packages/cpppo/server/enip/main.py", line 657, in enip_srv
if enip_process( addr, data=data, **kwds ):
File "/usr/local/lib/python2.7/dist-packages/cpppo/server/enip/logix.py", line 695, in process
for i,(m,s) in enumerate( machine.run( path='request.enip', source=source, data=data )):
File "/usr/local/lib/python2.7/dist-packages/cpppo/automata.py", line 655, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python2.7/dist-packages/cpppo/automata.py", line 1300, in delegate
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
NonTerminal: ( CIP.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
Hi
It seems command line usage requires that a number be int16 when being sent.
It is possible to send 32bit aka DINT via command line?
struct.error: short format requires SHRT_MIN <= number <= SHRT_MAX
user$ python -m cpppo.server.enip.client -a 127.0.0.2 MYTAG2=32768
Also, is it possible to have multiple different data types be sent for 1 tag? Furthermore, is there a way to state what type of datatype is being sent?
eg.
python -m cpppo.server.enip.client -a 127.0.0.2 MYTAG2=(int16)32767, (dint)50000
Thanks
I am using the Poller class to read periodically a few tags from an AB Micro820 PLC, so running CPPPO in simple mode without send_path and route_path as false.
Usually it works just fine, reading some default tags into the PLC one at a time (as this plc doesn't support multi request), but sometimes happens this kind of error that i cannot debug at all or figure out why is it happening:
In this time the library doesn't read correctly the tags and throws an error. This kind of problem happens randomly and more frequently if i reduce the timing of the poller down to half a second (usually working at 1s reading).
Any idea what's happening there?
Thanks in advance!
I'm using cpppo==3.9.7
with python 3.6.1's asyncio and just got this warning when running my program with python -Wdefault myscript.py
:
[...]/.venv/lib/python3.6/site-packages/cpppo/server/enip/client.py:853: DeprecationWarning: 'async' and 'await' will become reserved keywords in Python 3.7
def await( cli, timeout=None ):
It comes from this line:
https://github.com/pjkundert/cpppo/blob/master/server/enip/client.py#L853
Renaming this would help future proof the repo.
So I've been trying to wrap my head around EtherNet/IP over the past week to try to read data from a Keyence DL-EP1 networking adapter. I've read through the cpppo readme multiple times and read quite a few documents about ethernet/ip, but I'm still a little confused about the implementation of the cpppo methods as far as how they interface with a given device. Here's some details of my application:
The DL-EP1 networking adapter takes data from a sensor amplifier and stores it in the following manner:
12.530mm -> Data = 12530 and Number of Decimal Places = 3
I can use poll.py and Get_Attribute_Single (Service code = 0x0E) to read the data = 12530, but to read the number of decimal places I need to use the Service Code = 0x4D at the same Class/Instance/Attribute.
Can I use one of the cpppo methods to specify a Service Code, Class ID, Instance ID, and Attribute ID in order to read this information?
Thanks,
Bryan
Is it possible to have an option that is encoding the output under JSON format? Currently it's printing all the tags line by line, i think it will be nice to able to format it into json string.
I've been playing around with this library and trying to collect tags from a controllogix at fairly high speed, 100ms or less. It seems to require quite a bit more CPU load than I expected. For 6 REAL variable polled every 100ms I sit around 30% of a i7-4710MQ CPU @ 2.50GHz × 8 CPU. The 30% is the process on a single thread not the entire processor. When I read 3 of those tags its at about 20%. A 10% jump for 3 additional tags. I plan on probably around 100 tags in total.
I'm using the Polling api. Is this library not really capable of reading many tags rapidly? Is there perhaps a better api I could use? Or is this a limitation of python and I should be looking at using something like C/C++?
While investigating the possibility of using cpppo in "production" to read thousands of tags as quickly as possible, I've noticed that the performance is limited by CPU usage and not network or PLC. Some testing with PyPy showed a significant increase in throughput (similar to the library we're using now, which is written in C) but still apparently limited by the CPU.
What are your thoughts about performance? Have you considered options like Cython for optimizing "bottlenecks"?
Knowing the structure of the UDT is it possible to read the UDT as a whole? I've been successful reading the UDT by explicitly reading the specific tag ie "struc.someVariable". If it is possible is there an example created you can point me to or perhaps make an example?
For directly accessing tags inside "function blocks" (not sure this is the right terminology) it's necessary to use periods in the tag names, e.g. "ACC_MISC_PLC01_ALMA01.HLimit". Currently this does not seem to work.
I have a ControlLogix PLC, and want to realize the communication between ROS and this PLC. Previously, I was using slot 0 of PLC, it was fine, but now after changing to slot 4, I could not send the tag to PLC even though I can ping the PLC. Does anybody can help me? Thank you!
I'm attempting to read/write from a Rockwell E300, but I'm unable to get the write half working.
python3 -m cpppo.server.enip.get_attribute -S -a 10.20.4.9 "@0x09/1/3" "@0x09/1/3=(BOOL)1" -v
09-29 09:47:07.815 MainThread enip.cli NORMAL __init__ Connect: Success in 0.031s/ 5.000s
Thu Sep 29 09:47:07 2016: 0: Single G_A_S @0x0009/1/3 == [0]
Thu Sep 29 09:47:07 2016: 1: Single S_A_S @0x0009/1/3 == None
09-29 09:47:07.834 MainThread enip.get NORMAL main 2 requests in 0.015s at pipeline depth 0; 129.873 TPS
Does anyone have experience with this?
I'm using CPPPO for reading string data from the PLC. Here is the Error I'm getting while trying to read string tag.
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
cpppo.automata.NonTerminal: ( data.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
Here is the detailed log of the request:
debian@DattusBBB84BC:~/code_repository/branches/EthernetIP/python-codes/source$ python3 -m cpppo.server.enip.client --print -vvv 'CIP1_Data_Log_Text[0]' -a 10.10.135.120
07-25 09:33:28.784 MainThread enip.cli DETAIL init Connect: TCP/IP to ('10.10.135.120', 44818)
07-25 09:33:29.171 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 0,
"enip.CIP.register.protocol_version": 1,
"enip.CIP.register.options": 0,
"enip.options": 0
}
07-25 09:33:29.178 MainThread enip.cli INFO cip_send EtherNet/IP: 24 + CIP: 4 == 28 bytes total
07-25 09:33:29.180 MainThread enip.cli INFO send EtherNet/IP--> 10.10.135.120:44818 send 28: b'e\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00'
07-25 09:33:29.183 MainThread enip.cli INFO next EtherNet/IP--> 10.10.135.120:44818 rcvd 28: b'e\x00\x04\x00\x01\x00:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00'
07-25 09:33:29.188 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.command = 101 (format b'<H' over array('B', [101, 0]))
07-25 09:33:29.192 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.length = 4 (format b'<H' over array('B', [4, 0]))
07-25 09:33:29.197 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.session_handle = 3801089 (format b'<I' over array('B', [1, 0, 58, 0]))
07-25 09:33:29.202 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.status = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:33:29.210 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.options = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:33:29.216 MainThread enip.cli INFO next EtherNet/IP 10.10.135.120:44818 done: ((enip.((payload.((byte))) -> ((payload.; next byte 28: None : {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [0, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 3801089, 'length': 4, 'command': 101, 'input': array('B', [1, 0, 0, 0]), 'options': 0}}
07-25 09:33:29.220 MainThread cpppo INFO run ( register.( protocol_version.((byte)) -- limit='enip.CIP.register...length' == 4; ending at symbol 4 vs. None
07-25 09:33:29.225 MainThread cpppo INFO terminate ( register.( protocol_version.((byte)) : => enip.CIP.register.protocol_version = 1 (format b'<H' over array('B', [1, 0]))
07-25 09:33:29.229 MainThread cpppo INFO terminate ( register.( protocol_version.((byte)) : => enip.CIP.register.options = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:33:29.232 MainThread enip.cli INFO next Returning result: {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [0, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 3801089, 'length': 4, 'CIP': {'register': {'protocol_version': 1, 'options': 0}}, 'command': 101, 'input': array('B', [1, 0, 0, 0]), 'options': 0}}
07-25 09:33:29.235 MainThread enip.cli NORMAL init Connect: Success in 0.451s/ 5.000s
07-25 09:33:29.237 MainThread enip.cli DETAIL main Client Register Rcvd 0.453/ 5.000s
07-25 09:33:29.240 MainThread enip.cli DETAIL parse_oper Tag: 'CIP1_Data_Log_Text[0]' yields Operation: {'path': [{'symbolic': 'CIP1_Data_Log_Text'}, {'element': 0}]}.update({'route_path': None, 'send_path': None})
07-25 09:33:29.247 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 3801089,
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "CIP1_Data_Log_Text",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[1].element": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag.elements": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 76,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b'L\x0b\x91\x12CIP1_Data_Log_Text(\x00\x01\x00')",
"enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.options": 0
}
07-25 09:33:29.257 MainThread enip.cli INFO cip_send EtherNet/IP: 24 + CIP: 56 == 80 bytes total
07-25 09:33:29.259 MainThread enip.cli INFO send EtherNet/IP--> 10.10.135.120:44818 send 80: b'o\x008\x00\x01\x00:\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00(\x00R\x02 \x06$\x01\x05\x9d\x1a\x00L\x0b\x91\x12CIP1_Data_Log_Text(\x00\x01\x00\x01\x00\x01\x00'
07-25 09:33:29.262 MainThread enip.cli DETAIL format_pat Formatted CIP1_Data_Log_Text[0] from: [{'symbolic': 'CIP1_Data_Log_Text'}, {'element': 0}]
07-25 09:33:29.264 MainThread enip.cli DETAIL issue Sent 0.019/ 5.000s: Single Read Tag CIP1_Data_Log_Text[0] {
"path.segment[0].symbolic": "CIP1_Data_Log_Text",
"path.segment[1].element": 0,
"read_tag.elements": 1,
"service": 76,
"input": "bytearray(b'L\x0b\x91\x12CIP1_Data_Log_Text(\x00\x01\x00')"
}
07-25 09:33:29.269 MainThread enip.cli DETAIL issue Sending 1 (Context b'0')
07-25 09:33:29.271 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth
07-25 09:33:29.274 MainThread enip.cli INFO next EtherNet/IP--> 10.10.135.120:44818 rcvd 136: b'o\x00p\x00\x01\x00:\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00`\x00\xcc\x00\x00\x00\xa0\x02\xce\x0f\x1f\x00\x00\x00CIP PATH #2 WASH W/HOT SANITIZE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
07-25 09:33:29.278 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.command = 111 (format b'<H' over array('B', [111, 0]))
07-25 09:33:29.282 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.length = 112 (format b'<H' over array('B', [112, 0]))
07-25 09:33:29.287 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.session_handle = 3801089 (format b'<I' over array('B', [1, 0, 58, 0]))
07-25 09:33:29.291 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.status = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:33:29.300 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.options = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:33:29.340 MainThread enip.cli INFO next EtherNet/IP 10.10.135.120:44818 done: ((enip.((payload.((byte))) -> ((payload.; next byte 164: None : {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [48, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 3801089, 'length': 112, 'command': 111, 'input': array('B', [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 178, 0, 96, 0, 204, 0, 0, 0, 160, 2, 206, 15, 31, 0, 0, 0, 67, 73, 80, 32, 80, 65, 84, 72, 32, 35, 50, 32, 87, 65, 83, 72, 32, 87, 47, 72, 79, 84, 32, 83, 65, 78, 73, 84, 73, 90, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 'options': 0}}
07-25 09:33:29.345 MainThread cpppo INFO run ( send_data.( interface.((byte)) -- limit='enip.CIP.send_data...length' == 112; ending at symbol 112 vs. None
07-25 09:33:29.350 MainThread cpppo INFO terminate ( send_data.( interface.((byte)) : => enip.CIP.send_data.interface = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:33:29.355 MainThread cpppo INFO terminate ( send_data.( interface.((byte)) : => enip.CIP.send_data.timeout = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:33:29.361 MainThread cpppo INFO terminate ( CPF.( count.((byte)) : => enip.CIP.send_data.CPF.count = 2 (format b'<H' over array('B', [2, 0]))
07-25 09:33:29.367 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.type_id = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:33:29.372 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.length = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:33:29.378 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.type_id = 178 (format b'<H' over array('B', [178, 0]))
07-25 09:33:29.383 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.length = 96 (format b'<H' over array('B', [96, 0]))
07-25 09:33:29.387 MainThread cpppo INFO run ( unconnected_send.( select.((noop)) -- limit='enip.CIP.send_data.CPF.item__.unconnected_send..length' == 96; ending at symbol 112 vs. 112
07-25 09:33:29.498 MainThread cpppo INFO terminate ( read_tag.( service.((byte)) : => service = 204 (format b'B' over array('B', [204]))
07-25 09:33:29.503 MainThread cpppo INFO terminate ( status.( status.((byte)) : => status = 0 (format b'B' over array('B', [0]))
07-25 09:33:29.506 MainThread cpppo INFO terminate ( status.( status.((byte)) : => status_ext.size = 0 (format b'B' over array('B', [0]))
07-25 09:33:29.512 MainThread cpppo INFO terminate ( read_tag.( service.((byte)) : => read_tag.type = 672 (format b'<H' over array('B', [160, 2]))
Traceback (most recent call last):
File "/usr/lib/python3.2/runpy.py", line 161, in _run_module_as_main
"main", fname, loader, pkg_name)
File "/usr/lib/python3.2/runpy.py", line 74, in _run_code
exec(code, run_globals)
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1649, in
sys.exit( main() )
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1630, in main
fragment=fragment, printing=printing, timeout=timeout )
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1406, in process
transactions = list( self.results( operations=operations, **kwds ))
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1398, in results
for idx,dsc,req,rpy,sts,val in self.operate( operations, **kwds ):
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1393, in operate
for idx,dsc,req,rpy,sts,val in harvested:
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1283, in validate
for index,descr,request,reply,status,val in harvested:
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1258, in pipeline
col = next( harvester )
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1190, in harvest
issued, self.collect( timeout=timeout )): # must be "lazy" zip!
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 1115, in collect
response,elapsed = await( self, timeout=timeout )
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 872, in await
for response in cli: # if StopIteration raised immediately, defaults to {} signalling completion
File "/usr/local/lib/python3.2/dist-packages/cpppo/server/enip/client.py", line 546, in next
for mch,sta in engine:
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 1226, in delegate
for which,target in submach: # 75% of runtime is spent inside 'run'
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 1226, in delegate
for which,target in submach: # 75% of runtime is spent inside 'run'
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 645, in run
source=source, machine=machine, path=path, data=data, ending=ending ):
File "/usr/local/lib/python3.2/dist-packages/cpppo/automata.py", line 1291, in delegate
raise NonTerminal( "%s sub-machine terminated in a non-terminal state" % ( self ))
cpppo.automata.NonTerminal: ( data.( select.((noop)) ) ) sub-machine terminated in a non-terminal state
I tried reading it using EPATH as well, as you have mentioned in one of the past issue and here is the log for the same. Here lies one question to me as, for the PLC I am using the TAG is written like CIP1_Data_Log_Text[0].DATA/82, according to your answer to the similar question was if you query using path the symbolic will be DATA and there should be element as number. But here its given like DATA/82.
debian@DattusBBB84BC:~/code_repository/branches/EthernetIP/python-codes/source$ python3 -m cpppo.server.enip.client --print -vvv '@{"symbolic":"CIP1_Data_Log_Text"}/{"element":0}/{"symbolic":"DATA"}/{"element":82}' -a 10.10.135.120
07-25 09:46:53.110 MainThread enip.cli DETAIL init Connect: TCP/IP to ('10.10.135.120', 44818)
07-25 09:46:53.499 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 0,
"enip.CIP.register.protocol_version": 1,
"enip.CIP.register.options": 0,
"enip.options": 0
}
07-25 09:46:53.506 MainThread enip.cli INFO cip_send EtherNet/IP: 24 + CIP: 4 == 28 bytes total
07-25 09:46:53.508 MainThread enip.cli INFO send EtherNet/IP--> 10.10.135.120:44818 send 28: b'e\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00'
07-25 09:46:53.511 MainThread enip.cli INFO next EtherNet/IP--> 10.10.135.120:44818 rcvd 28: b'e\x00\x04\x00\x01\x00?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00'
07-25 09:46:53.515 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.command = 101 (format b'<H' over array('B', [101, 0]))
07-25 09:46:53.519 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.length = 4 (format b'<H' over array('B', [4, 0]))
07-25 09:46:53.524 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.session_handle = 4128769 (format b'<I' over array('B', [1, 0, 63, 0]))
07-25 09:46:53.529 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.status = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:46:53.537 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.options = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:46:53.542 MainThread enip.cli INFO next EtherNet/IP 10.10.135.120:44818 done: ((enip.((payload.((byte))) -> ((payload.; next byte 28: None : {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [0, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 4128769, 'length': 4, 'command': 101, 'input': array('B', [1, 0, 0, 0]), 'options': 0}}
07-25 09:46:53.546 MainThread cpppo INFO run ( register.( protocol_version.((byte)) -- limit='enip.CIP.register...length' == 4; ending at symbol 4 vs. None
07-25 09:46:53.551 MainThread cpppo INFO terminate ( register.( protocol_version.((byte)) : => enip.CIP.register.protocol_version = 1 (format b'<H' over array('B', [1, 0]))
07-25 09:46:53.555 MainThread cpppo INFO terminate ( register.( protocol_version.((byte)) : => enip.CIP.register.options = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:46:53.558 MainThread enip.cli INFO next Returning result: {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [0, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 4128769, 'length': 4, 'CIP': {'register': {'protocol_version': 1, 'options': 0}}, 'command': 101, 'input': array('B', [1, 0, 0, 0]), 'options': 0}}
07-25 09:46:53.561 MainThread enip.cli NORMAL init Connect: Success in 0.450s/ 5.000s
07-25 09:46:53.563 MainThread enip.cli DETAIL main Client Register Rcvd 0.452/ 5.000s
07-25 09:46:53.565 MainThread enip.cli DETAIL parse_oper Tag: '@{"symbolic":"CIP1_Data_Log_Text"}/{"element":0}/{"symbolic":"DATA"}/{"element":82}' yields Operation: {'path': [{'symbolic': 'CIP1_Data_Log_Text'}, {'element': 0}, {'symbolic': 'DATA'}, {'element': 82}]}.update({'route_path': None, 'send_path': None})
07-25 09:46:53.575 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')",
"enip.session_handle": 4128769,
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "CIP1_Data_Log_Text",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[1].element": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[2].symbolic": "DATA",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[3].element": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag.elements": 1,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 76,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b'L\x0f\x91\x12CIP1_Data_Log_Text(\x00\x91\x04DATA(R\x01\x00')",
"enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6,
"enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.options": 0
}
07-25 09:46:53.585 MainThread enip.cli INFO cip_send EtherNet/IP: 24 + CIP: 64 == 88 bytes total
07-25 09:46:53.588 MainThread enip.cli INFO send EtherNet/IP--> 10.10.135.120:44818 send 88: b'o\x00@\x00\x01\x00?\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x000\x00R\x02 \x06$\x01\x05\x9d"\x00L\x0f\x91\x12CIP1_Data_Log_Text(\x00\x91\x04DATA(R\x01\x00\x01\x00\x01\x00'
07-25 09:46:53.590 MainThread enip.cli DETAIL format_pat Formatted CIP1_Data_Log_Text.DATA[82] from: [{'symbolic': 'CIP1_Data_Log_Text'}, {'element': 0}, {'symbolic': 'DATA'}, {'element': 82}]
07-25 09:46:53.593 MainThread enip.cli DETAIL issue Sent 0.021/ 5.000s: Single Read Tag CIP1_Data_Log_Text.DATA[82] {
"path.segment[0].symbolic": "CIP1_Data_Log_Text",
"path.segment[1].element": 0,
"path.segment[2].symbolic": "DATA",
"path.segment[3].element": 82,
"read_tag.elements": 1,
"service": 76,
"input": "bytearray(b'L\x0f\x91\x12CIP1_Data_Log_Text(\x00\x91\x04DATA(R\x01\x00')"
}
07-25 09:46:53.599 MainThread enip.cli DETAIL issue Sending 1 (Context b'0')
07-25 09:46:53.601 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth
07-25 09:46:53.603 MainThread enip.cli INFO next EtherNet/IP--> 10.10.135.120:44818 rcvd 44: b'o\x00\x14\x00\x01\x00?\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x04\x00\xcc\x00\x05\x00'
07-25 09:46:53.608 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.command = 111 (format b'<H' over array('B', [111, 0]))
07-25 09:46:53.612 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.length = 20 (format b'<H' over array('B', [20, 0]))
07-25 09:46:53.616 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.session_handle = 4128769 (format b'<I' over array('B', [1, 0, 63, 0]))
07-25 09:46:53.621 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.status = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:46:53.629 MainThread cpppo INFO terminate ( header.( command.((byte)) : => enip.options = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:46:53.639 MainThread enip.cli INFO next EtherNet/IP 10.10.135.120:44818 done: ((enip.((payload.((byte))) -> ((payload.; next byte 72: None : {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [48, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 4128769, 'length': 20, 'command': 111, 'input': array('B', [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 178, 0, 4, 0, 204, 0, 5, 0]), 'options': 0}}
07-25 09:46:53.644 MainThread cpppo INFO run ( send_data.( interface.((byte)) -- limit='enip.CIP.send_data...length' == 20; ending at symbol 20 vs. None
07-25 09:46:53.649 MainThread cpppo INFO terminate ( send_data.( interface.((byte)) : => enip.CIP.send_data.interface = 0 (format b'<I' over array('B', [0, 0, 0, 0]))
07-25 09:46:53.654 MainThread cpppo INFO terminate ( send_data.( interface.((byte)) : => enip.CIP.send_data.timeout = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:46:53.660 MainThread cpppo INFO terminate ( CPF.( count.((byte)) : => enip.CIP.send_data.CPF.count = 2 (format b'<H' over array('B', [2, 0]))
07-25 09:46:53.666 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.type_id = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:46:53.670 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.length = 0 (format b'<H' over array('B', [0, 0]))
07-25 09:46:53.677 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.type_id = 178 (format b'<H' over array('B', [178, 0]))
07-25 09:46:53.682 MainThread cpppo INFO terminate ( each.( type_id.((byte)) : => enip.CIP.send_data.CPF.item__.length = 4 (format b'<H' over array('B', [4, 0]))
07-25 09:46:53.686 MainThread cpppo INFO run ( unconnected_send.( select.((noop)) -- limit='enip.CIP.send_data.CPF.item__.unconnected_send..length' == 4; ending at symbol 20 vs. 20
07-25 09:46:53.697 MainThread cpppo INFO terminate ( read_tag.( service.((byte)) : => service = 204 (format b'B' over array('B', [204]))
07-25 09:46:53.702 MainThread cpppo INFO terminate ( status.( status.((byte)) : => status = 5 (format b'B' over array('B', [5]))
07-25 09:46:53.705 MainThread cpppo INFO terminate ( status.( status.((byte)) : => status_ext.size = 0 (format b'B' over array('B', [0]))
07-25 09:46:53.710 MainThread enip.cli INFO next Returning result: {'peer': ('10.10.135.120', 44818), 'enip': {'status': 0, 'sender_context': {'input': array('B', [48, 0, 0, 0, 0, 0, 0, 0])}, 'session_handle': 4128769, 'length': 20, 'CIP': {'send_data': {'interface': 0, 'CPF': {'count': 2, 'item': [{'length': 0, 'type_id': 0}, {'length': 4, 'unconnected_send': {'request': {'status': 5, 'input': array('B', [204, 0, 5, 0]), 'status_ext': {'size': 0}, 'read_tag': True, 'service': 204}}, 'type_id': 178}]}, 'timeout': 0}}, 'command': 111, 'input': array('B', [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 178, 0, 4, 0, 204, 0, 5, 0]), 'options': 0}}
07-25 09:46:53.744 MainThread enip.cli DETAIL collect Rcvd 0.110/ 5.000s {
"peer": [
"10.10.135.120",
44818
],
"enip.status": 0,
"enip.sender_context.input": "array('B', [48, 0, 0, 0, 0, 0, 0, 0])",
"enip.session_handle": 4128769,
"enip.length": 20,
"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": 4,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('B', [204, 0, 5, 0])",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag": true,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 204,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.timeout": 0,
"enip.command": 111,
"enip.input": "array('B', [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 178, 0, 4, 0, 204, 0, 5, 0])",
"enip.options": 0
}
07-25 09:46:53.752 MainThread enip.cli DETAIL collect Receive 1 (Context b'0')
07-25 09:46:53.754 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth
07-25 09:46:53.757 MainThread enip.cli DETAIL validate Client Single Read Tag CIP1_Data_Log_Text.DATA[82] Request: {
"path.segment[0].symbolic": "CIP1_Data_Log_Text",
"path.segment[1].element": 0,
"path.segment[2].symbolic": "DATA",
"path.segment[3].element": 82,
"read_tag.elements": 1,
"service": 76,
"input": "bytearray(b'L\x0f\x91\x12CIP1_Data_Log_Text(\x00\x91\x04DATA(R\x01\x00')"
}
07-25 09:46:53.763 MainThread enip.cli DETAIL validate Yields Reply: {
"status": 5,
"input": "array('B', [204, 0, 5, 0])",
"status_ext.size": 0,
"read_tag": true,
"service": 204
}
07-25 09:46:53.768 MainThread enip.cli DETAIL format_pat Formatted CIP1_Data_Log_Text.DATA[82] from: [{'symbolic': 'CIP1_Data_Log_Text'}, {'element': 0}, {'symbolic': 'DATA'}, {'element': 82}]
07-25 09:46:53.771 MainThread enip.cli WARNING validate Client Single Read Tag CIP1_Data_Log_Text.DATA[82] returned non-zero status: Status 5
07-25 09:46:53.772 MainThread enip.cli NORMAL validate CIP1_Data_Log_Text.DATA[82][ 82-82 ]+ 0 == None: 'Status 5 '
CIP1_Data_Log_Text.DATA[82][ 82-82 ]+ 0 == None: 'Status 5 '
07-25 09:46:53.775 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth
07-25 09:46:53.777 MainThread enip.cli NORMAL main Client Tag I/O Average 4.705 TPS ( 0.213s ea).
Here as you can see, the output I'm getting is None and Status is 5.
Can you please help me solving this issue?
Hi, I'm trying to read 100 "TEXT" tag using pipeline on one of the embedded device, I'm getting performance of 8 to 11 sec by varying depth and multiple values. Can you please help with the proper combination of depth and multiple to get good performance. Also I want to do the same for reading 1000 SCADA tags.
I am trying to get Powerflex525X VFD working with CPPPO. It's working with requesting with "@0x0093/3/9" format for getting tag values but when I'm requesting with Tag name "Output_Current" mentioned in document, it's returning with None as response.
Also If you can spread some light on how to communicate with Powerflex with Get_Attribute_Single/All from CPPPO library.
Hi Perry, i've started a project about Ethernet/IP and i've been reading some information about it.
I need to write a python program using this cpppo library that needs to connect to a server running an Ethernet/IP simulator by Molex in an specific IP address on port 44818.
Using an Ethernet/IP object reader I need to validate that I'm connected and I need to show data from the controller, in this case (RSLinx Server), a first step will be to read and show All Atributtes of the object 0x01 that corresponds to the identity. (there's an image attached in this post that shows the Molex Ethernet/IP Simulator)
I saw that the following code could be helpful for what I need:
from cpppo.server.enip import client
from cpppo.server.enip.getattr import attribute_operations
HOST = "181.49.9.154" #this is the IP address running the Ethernet/IP Sim device
TAGS = ["@4/100/3"] # I don't know what this line means, is it like an identity address?
with client.connector(host=HOST) as conn:
for index, descr, op, reply, status, value in conn.synchronous(
operations=attribute_operations(
TAGS, route_path=[], send_path='' )):
print(": %20s: %s" % (descr, value))
the output of the code is this:
: Single G_A_S @0x0004/100/3: None
is this output (: Single G_A_S) an identity or something in the simulator by Molex running in 181.49.9.154?
@0x0004/100/3: None. I see that I didn't catch anything in @0x0004/100/3 (don't know what it means btw)
Browsing the Internet I saw this code that might be helpful on getting the 0x01 object identity:
request = cpppo.dotdict({'service': 0x01, 'path':{'segment':[{'class':Ix.class_id},{'instance':Ix.instance_id}]}})
gaa = Ix.request( request )
log.normal( "Identity Get Attributes All: %r, data: %s", gaa, enip.enip_format( request ))
but adding this code above to the first set of coding I get an error: request = cpppo.dotdict({'service': 0x01, 'path':{'segment':[{'class':Ix.class_id},{'instance':Ix.instance_id}]}})
NameError: name 'cpppo' is not defined
I don't know why I'm getting this error with those lines because there is the cpppo.server.enip import
Thanks for taking your time to read this post.
any help would be really appreciate it!
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.
This looks like a great bit of code.
Can I just confirm that it should be possible I to route through an 1756-EN2TR Ethernet module to the Control Logix PLC eg 5572S? I've run the enip.client to list connections and I can only see the Ethernet module not the CPU.
Thanks for your help
Hi, I'm new to python and I need to write a program using this cpppo library that needs to connect to a server running an Ethernet/IP simulator by Molex in an specific IP address on port 44818.
Using an Ethernet/IP object reader I need to validate that I'm connected and I need to show data from the controller, in this case (RSLinx Server), a first step will be to read object 0x01 that corresponds to the identity. (there's an image attached in this post that shows the Molex Ethernet/IP Simulator)
i wanted to test this weather.py example but I'm getting an error in the line from cpppo.server.enip import device, REAL that tells me this:
The debugged program raised the exception unhandled ImportError
"No module named 'cpppo'"
I've already installed the cpppo library using the terminal command pip install cpppo, so, i've got the library installed already.
Could you guys please help with this matter.
Thanks so much in advance.
Hi,
this looks like a nice project and I started looking into whether it might be useful for writing tests for an EtherIP communication project we have. We're using a C EtherIP library from http://ics-web.sns.ornl.gov/kasemir/etherip/ and it's working fine for communicating with our Allen-Bradley PLCs.
However, I have trouble getting that library to talk to the cpppo test server and I'm wondering if this should even be expected to work. This is what I'm doing:
Starting the test server:
# python -m cpppo.server.enip --print SCADA=INT[1]
and then I run the test program included with the EtherIP library:
# ./ether_ip_test -v 10 -i 127.0.0.1 -p 44818 SCADA
The result is "No response" and the server prints out the following traceback:
11-11 15:36:36.861 7f610f4ef700 enip.lgx ERROR process EtherNet/IP CIP error at 0 total bytes:
''
-^ (byte 0)
11-11 15:36:36.861 7f610f4ef700 enip.srv ERROR enip_srv Failed request: {
"request.addr": [
"127.0.0.1",
59815
],
"request.enip.command": 4,
"request.enip.length": 0,
"request.enip.options": 0,
"request.enip.sender_context.input": "array('c', 'Funstuff')",
"request.enip.session_handle": 0,
"request.enip.status": 0
}
11-11 15:36:36.862 7f610f4ef700 enip.srv ERROR enip_srv EtherNet/IP error at 24 total bytes:
'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Funstuff\x00\x00\x00\x00'
-------------------------------------------------------------------------^ (byte 24)
Failed with exception:
Traceback (most recent call last):
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/server/enip/main.py", line 664, in enip_srv
if enip_process( addr, data=data, **kwds ):
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/server/enip/logix.py", line 681, in process
source.chain( data.request.enip.input )
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/dotdict.py", line 201, in __getattr__
raise AttributeError( str( exc ))
AttributeError: 'input'
11-11 15:36:36.863 7f610f4ef700 network WARNING run enip_srv server failure: 'input'
Traceback (most recent call last):
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/server/network.py", line 131, in run
super( server_thread, self ).run()
File "/usr/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/server/enip/main.py", line 664, in enip_srv
if enip_process( addr, data=data, **kwds ):
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/server/enip/logix.py", line 681, in process
source.chain( data.request.enip.input )
File "/home/johfor/.local/lib/python2.7/site-packages/cpppo/dotdict.py", line 201, in __getattr__
raise AttributeError( str( exc ))
AttributeError: 'input'
I'm using configparser
to generate this config file. All the Identity attributes get loaded and work but "ip_address" is still using the default 127.0.0.1
.
[Identity]
vendor number = 1
device type = 19
product code number = 45
product revision = 711
status word = 0
serial number = 497368838
product name = 1756-IB32/B DCIN
state = 0
configuration consistency value = 0
heartbeat interval = 0
[TCPIP]
interface configuration = {'ip_address': '172.17.0.2', 'network_mask': '255.255.0.0', 'dns_primary': '8.8.8.8', 'dns_secondary': '8.8.4.4', 'domain_name': 'example.com'}
host name = controller
Hi,
First of all thanks for your library! Really a good Job!
I am using it to connect to an Omron PLC
I got success reading CIP values, but not writing.
python -m cpppo.server.enip.get_attribute -a 192.168.0.50 "@4/100/3" "@4/102/3" "@4/103/3" "@4/104/3" "@4/105/3"=(DINT)77 "@4/106/3"=(DINT)44 "@4/105/3" "@4/106/3"
I got the answer True from the two writing variables and values from reading ones.
Is the form of the writing requests correct?
If the form is correct is there anything I can try or it should depend on PLC's settings?
Can I use other request methods (I tryed proxy(ip).write but is not yet implemented LOL) ?
Thanks in advance
Hey there,
I'm new to Ethernet/IP and CIP, and recently discovered this project. Fantastic stuff. Just playing with your CLI apps has taught me a lot. My plan is to use your python libraries as test harness for a C/C++ app that will use another open-source project, OpENer (https://github.com/EIPStackGroup/OpENer), which I'm sure you're aware of.
Right now, I'm in the stage of making sure all the parts talk to each other. The OpENer library has a test app that presents a handful of assembly objects, with some instance IDs like 0x64, 0x96, and 0x97. I'm trying a command like the following
python -m cpppo.server.enip.get_attribute -a 192.168.3.13 "@4/100/3" --send-path=""
Unfortunately, I always get back this:
Fri Sep 8 17:32:08 2017: 0: Single G_A_S @0x0004/100/3 == None
I'm also using the Molex windows tool to send "Get Attribute Single" and "Set Attribute Single" commands to 4/100/3, and that does succeed, so I know that the OpENer app can be responsive. Also, as a sanity check, using the following identity query works as well:
python -m cpppo.server.enip.client -a 192.168.3.13 -i
Do I need to something special to talk to an assembly object?
Hi,
I'm working on CPPPO for the development of EIP Client since quite sometime. I was wandering if it supports threading for reading the client or not?
I have created one method which is having host IP, port and list of tags and I'm creating pipeline to read data.
Can you please tell me that if the query to the client that is conn.pipeline(operations=client.parse_operations(tags),depth=depth,multiple=multiple,fragment = True, timeout=1.0) can be threaded as I want to query more than one devices over the network together and I'm facing issues in that?
I tried installing cppio under Python 2.6 (CentOS 6) and I got this error:
Downloading/unpacking cpppo
Downloading cpppo-2.9.1.tar.gz (202kB): 202kB downloaded
Running setup.py egg_info for package cpppo
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/tmp/pip-build-johfor/cpppo/setup.py", line 14, in <module>
if sys.version_info.major < 3:
AttributeError: 'tuple' object has no attribute 'major'
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/tmp/pip-build-johfor/cpppo/setup.py", line 14, in <module>
if sys.version_info.major < 3:
AttributeError: 'tuple' object has no attribute 'major'
This is apparently only supported in >=2.7. I have no idea if there are other things preventing cpppo from working on 2.6, but at least it's a good idea to state somewhere that it's only compatible with 2.7 and up.
Not really an issue, so much as a question. Is there any facility to browse tags and get a list of all tags on the PLC?
Hello,
I am trying to read a tag on a Allen Bradley PLC. I was able to read the tags from Linux PC and there was no issue with that.
An other computer, tried to read the same tag and which made the other computer not being able to read it and vice versa.
This the snippet of the code, I am using on both of these computers.
def read_cip(tag, plc_ip_address):
try:
with client.connector( host= plc_ip_address) as conn:
req = conn.read(tag)
try:
assert conn.readable( timeout=0.1 ), "Failed to receive reply"
rpy = next(conn)
except AssertionError:
print "Need more time!!"
return rpy.enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_frag.data[0]
except socket.error:
print "Wrong ip or network error"
please share your thoughts on this.
from cpppo.server.enip.get_attribute import proxy as plc
host = "192.168.178.15"
param = "@0x6b/1/1=(DINT)5"
fanuc = plc(host=host)
try:
with fanuc:
result, = fanuc.write(param)
except Exception as e:
print param, e
When I issue this I get @0x6b/1/1=(DINT)5 'str' object has no attribute 'items'
I have tried making param a list of strings, list of tuples, parameter_substitution
, but I get the same error, with a different type instead of str
.
I am trying to achieve the same programmatically as python -m cpppo.server.enip.get_attribute -a 192.168.178.15 -S "@0x6b/1/1=(DINT)5"
.
I've been working on getting this library to properly write to my PLC for the past couple of days. Now this is not a device I myself programmed, but something I am trying to control with a python script. I have connected directly to it and the images below are from RSLinx Data Monitoring on the program to grab the tag names. I can read information from the device with the proxy.read interface. For example below:
with via:
params = via.parameter_substitution('Local:1:I.Data')
value, = via.read(params)
# with input on device is switched to off
> value
[0]
# with input on device is switched to on
> value
[1]
with via:
params = via.parameter_substitution('Local:1:I.Data = (SINT)1')
value, = via.write(params, checking=True)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-115-5ddb72bb3208> in <module>()
1 with via:
2 params = via.parameter_substitution('Local:1:I.Data = (SINT)1')
----> 3 value, = via.write(params, checking=True)
4
/Users/esheets/.virtualenvs/c3po/lib/python3.6/site-packages/cpppo/server/enip/get_attribute.py in read(self, attributes, printing, checking)
438 if checking:
439 assert len( bad ) == 0, \
--> 440 "read failed to access %d attributes: %s" % ( len( bad ), ', '.join( bad ))
441
442 def read_details( self, attributes ):
AssertionError: read failed to access 1 attributes: Local:1:I.Data = (SINT)1: status 5
Is there something I am missing? Based on these images that tag is classified as Read/Write so I should be able to change this value from 0 -> 1, and thus turning on the PLC actions.
Hello SIr,
I am using the latest cpppo release and read() from client.py is no longer functional. I checked the same program working in 2.6.1.
Here is a code snippet of that:
while True:
try:
with client.connector( host= plc_ip_address) as conn:
while True:
time_prev=time.time()
req = conn.read("tag_1")
try:
assert conn.readable( timeout=2.0 ), "Failed to receive reply"
rpy = next(conn)
d.data.append(rpy.enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_frag.data[0])#0
except AssertionError:
print "Response timed out!! Tearing Connection and Reconnecting!!!!!"
break
except AttributeError:
print "Tag not written:::Will try again::"
break
I am getting the message as an attribute error. But the same program gets the tag on computer having the old cpppo 2.6.1 I guess. Any thoughts?.
Hi,
I try to use cpppo with OMRON PLC (CJ1, CJ2 and NJ with ethernet card EIP21), but I can't read/write memory.
With this command, I can see product on the network :
python -m cpppo.server.enip.client --udp --broadcast --list-identity -a 192.168.0.255
List Identity 0 from ('192.168.0.2', 44818): {
"count": 1,
"item[0].type_id": 12,
"item[0].length": 44,
"item[0].identity_object.version": 1,
"item[0].identity_object.sin_family": 2,
"item[0].identity_object.sin_port": 44818,
"item[0].identity_object.sin_addr": "192.168.0.2",
"item[0].identity_object.vendor_id": 47,
"item[0].identity_object.device_type": 12,
"item[0].identity_object.product_code": 13,
"item[0].identity_object.product_revision": 258,
"item[0].identity_object.status_word": 53,
"item[0].identity_object.serial_number": 8822956,
"item[0].identity_object.product_name": "CJ2B-EIP21",
"item[0].identity_object.state": 3
}
List Identity 1 from ('192.168.0.4', 44818): {
"count": 1,
"item[0].type_id": 12,
"item[0].length": 46,
"item[0].identity_object.version": 1,
"item[0].identity_object.sin_family": 2,
"item[0].identity_object.sin_port": 44818,
"item[0].identity_object.sin_addr": "192.168.0.4",
"item[0].identity_object.vendor_id": 47,
"item[0].identity_object.device_type": 12,
"item[0].identity_object.product_code": 1613,
"item[0].identity_object.product_revision": 257,
"item[0].identity_object.status_word": 48,
"item[0].identity_object.serial_number": 9243817,
"item[0].identity_object.product_name": "NS10-TV01-V2",
"item[0].identity_object.state": 3
}
But when I try to read/write memory area, cpppo return None
python -m cpppo.server.enip.get_attribute -a 192.168.0.2 "@0xC4/0x10/3"
Tue Jun 20 08:29:56 2017: 0: Single G_A_S @0x00C4/16/3 == None
In the EIP21 documentation, to read CPU unit mode, I have these informations :
Service code = 0x0E
Class ID = 0xC4
Instance ID = 0x00
Request service data Attribute ID = 0x64
Other exemple to write a byte data
Service code = 0x1C
Class ID = 0xC4
Instance ID = Specifies area (01 Hex to 14 Hex)
Request service data Attribute ID = Address, No. of read bytes
What's the commande to read byte area memory with a service code?
Normally default route path is ok for my configuration (I have de CPU and next to the EIP21 ethernet card with unit number 0). I try to specifie de route path, but cpppo return an error :
python -m cpppo.server.enip.get_attribute -a 192.168.0.2 --route-path '[{"link": 0, "port": 1}]' "@0xC4/0x10/3"
Traceback (most recent call last):
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\r
unpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\r
unpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\s
ite-packages\cpppo-3.9.7-py3.6.egg\cpppo\server\enip\get_attribute.py", line 803
, in <module>
sys.exit( main() )
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\s
ite-packages\cpppo-3.9.7-py3.6.egg\cpppo\server\enip\get_attribute.py", line 758
, in main
route_path = json.loads( args.route_path ) if args.route_pa
th \
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Can you help me to connect cpppo with OMRON plc?
Thanks.
Hello,
I want to be able to test the example weather.py from the same machine.
First, I opened the source and put my own API key. Then I run the example using python weather.py
, and then, in another terminal, tried to get the temperature of a city using tags, with something like python -m cpppo.server.enip.get_attribute "New York"
, but it seems that __getitem__
is never called.
Should I use a specific CIP Class/Instance/Attribute to obtain weather of a city? Or another tool?
Many thanks in advance, your library has helped me to introduce myself to this protocol.
Is there any way to query a compactlogix using cpppo to determine which tags are available to read from?
I'm sorry I don't really have an issue, but I don't see a forum for asking questions about cpppo other than here. If there is one, please feel free to point me to more appropriate place.
I want to implement an Ethernet/IP server for a device and wondering if this is the best way to go about it with cpppo.
Thank you for any suggestions.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.