ant01 (Customer) asked a question.

Productivity 2000 Ethernet/IP Explicit Messaging with Python Script

Hi, I am new to this and don't really know where to get started or where to look at. I need to write a Python script to communicate with Productivity 2000 in order to read data from the controller and send commands back. I have no idea where to start, if someone has done something similar before please help me to at least get started. Your help would be very appreciated. I have a PLC and PC on the same network and using sockets I was able to receive messages from P2K (though there weren't the ones I configured the PLC to sent)


  • z28z34man (Customer)

    I have done socket communication between a python script and a productivity and i have done modbuss TCP where the python script is the client and other scripts where the python script is the server between a productivity and a python script. I know of a few Ethernet IP libraries but i haven't tried them out yet.

    Selected as Best
  • RBPLC (Customer)

    Do you have to use EthernetIP? There are several people on this forum that have used PyModbus. Search this forum for those posts is you can use Modbus.

    • ant01 (Customer)

      No, actually I don't need to use Ethernet/IP. Thank you for your advice, I was able to find a lot of useful information.

  • z28z34man (Customer)

    I have done socket communication between a python script and a productivity and i have done modbuss TCP where the python script is the client and other scripts where the python script is the server between a productivity and a python script. I know of a few Ethernet IP libraries but i haven't tried them out yet.

    Selected as Best
    • ant01 (Customer)

      Thank you, not sure why I got stuck with the idea to use Ethernet/IP, it would be a lot easier to use TCP/IP and sockets.

      • z28z34man (Customer)

        Not a problem. if you need some example code I could probably dig some up.

      • z28z34man (Customer)

        This should get you started. Whatever you send with the CPOE instruction it will print to the console

         

        1. import socket
        2. import select
        3.  
        4. HEADER_LENGTH = 10
        5.  
        6. IP = "192.168.100.150"
        7. PORT = 1234
        8.  
        9. # Create a socket
        10. # socket.AF_INET - address family, IPv4, some otehr possible are AF_INET6, AF_BLUETOOTH, AF_UNIX
        11. # socket.SOCK_STREAM - TCP, conection-based,
        12. # socket.SOCK_DGRAM - UDP, connectionless, datagrams, socket.SOCK_RAW - raw IP packets
        13. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        14.  
        15. # SO_ - socket option
        16. # SOL_ - socket option level
        17. # Sets REUSEADDR (as a socket option) to 1 on socket
        18. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        19.  
        20. # Bind, so server informs operating system that it's going to use given IP and port
        21. # For a server using 0.0.0.0 means to listen on all available interfaces,
        22. # useful to connect locally to 127.0.0.1 and remotely to LAN interface IP
        23. server_socket.bind((IP, PORT))
        24.  
        25. # This makes server listen to new connections
        26. server_socket.listen()
        27.  
        28. # List of sockets for select.select()
        29. sockets_list = [server_socket]
        30.  
        31. print(f'Listening for connections on {IP}:{PORT}...')
        32.  
        33.  
        34. # Handles message receiving
        35. def receive_message(client_socket):
        36.  
        37. try:
        38. full_msg = ''
        39. msg = client_socket.recv(128)
        40. full_msg += msg.decode("utf-8")
        41. return full_msg
        42.  
        43. except:
        44.  
        45. # If we are here, client closed connection violently, for example by pressing ctrl+c on his script
        46. # or just lost his connection
        47. # socket.close() also invokes socket.shutdown(socket.SHUT_RDWR)
        48. # what sends information about closing the socket (shutdown read/write)
        49. # and that's also a cause when we receive an empty message
        50. return False
        51.  
        52.  
        53. while True:
        54.  
        55. # Calls Unix select() system call or Windows select() WinSock call with three parameters:
        56. # - rlist - sockets to be monitored for incoming data
        57. # - wlist - sockets for data to be send to
        58. # (checks if for example buffers are not full and socket is ready to send some data)
        59. # - xlist - sockets to be monitored for exceptions
        60. # (we want to monitor all sockets for errors, so we can use rlist)
        61. # Returns lists:
        62. # - reading - sockets we received some data on (that way we don't have to check sockets manually)
        63. # - writing - sockets ready for data to be send thru them
        64. # - errors - sockets with some exceptions
        65. # This is a blocking call, code execution will "wait" here and "get" notified in case any action should be taken
        66. read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
        67.  
        68. # Iterate over notified sockets
        69. for notified_socket in read_sockets:
        70.  
        71. # If notified socket is a server socket - new connection, accept it
        72. if notified_socket == server_socket:
        73.  
        74. # Accept new connection
        75. # That gives us new socket - client socket, connected to this given client only, it's unique for that client
        76. # The other returned object is ip/port set
        77. client_socket, client_address = server_socket.accept()
        78. # Add accepted socket to select.select() list
        79. sockets_list.append(client_socket)
        80.  
        81. print('Accepted new connection from {}:{}'
        82. .format(*client_address))
        83.  
        84. # Else existing socket is sending a message
        85. else:
        86.  
        87. # Receive message
        88. message = receive_message(notified_socket)
        89.  
        90. # If False, client disconnected, cleanup
        91. if message is False:
        92. print('Closed connection')
        93.  
        94. # Remove from list for socket.socket()
        95. sockets_list.remove(notified_socket)
        96.  
        97. continue
        98. print(message)
        99.  
        100. # It's not really necessary to have this, but will handle some socket exceptions just in case
        101. for notified_socket in exception_sockets:
        102.  
        103. # Remove from list for socket.socket()
        104. sockets_list.remove(notified_socket)

         

         

        Expand Post
  • ssweber (Customer)

    I've used umodbus (https://umodbus.readthedocs.io/en/latest/) with good results.

     

    Want to read a single register? ::

     

    import socket

    from umodbus.client import tcp

    address = 'PLC ADDRESS HERE' ##eg 192.168.1.xxx

    plc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    plc.settimeout(2)

    plc.connect((address, 502))

    message = tcp.read_holding_registers(slave_id=1, starting_address=0, quantity=1)

    response = tcp.send_message(message, plc)

    plc.close()

    Expand Post