ottowayi / pycomm3

A Python Ethernet/IP library for communicating with Allen-Bradley PLCs.
MIT License
406 stars 88 forks source link

Exception on forward.close after logging data with ENBT/A #319

Open tcplomp opened 3 months ago

tcplomp commented 3 months ago

Pre-checks

Description I'm running a long (hours) datalogger using pycomm3 sometime when I close the connection (PLC.close()) it will report a parse replay failure on the forward_close(). Seems to happen more often after running for a longer (>10 minutes) time. The datalogger will read a set of tags. And when I interrupt it using the exception instructs pycomm3 to close the connection.

Target PLC Model: 1756-L73 Firmware Revision: 32.11 Other Devices in CIP Path: 1756-ENBT/A v 5.006

Code Sample Stripped back to minimal

from pycomm3 import LogixDriver
import logging, time, datetime
from pycomm3.exceptions import RequestError

PLCAddress = 'PC15'
PLC = LogixDriver(PLCAddress, init_program_tags= False)
PLC.open()
print(PLC.info)
logging.info('Connected')
packtags = 'A15S1_PackData','A16S1_PackData','A16S1S3_PackData','A16S3_PackData','A16S3S4_Packdata','A16S4_PackData','A16S4S5_Packdata','A16S5_PackData','A17S1_PackData','A17S2_PackData','A17S3_PackData'
try:
    logging.info('Reading')
    while True: # and ChangeCount < 3:
        for tagname in packtags:
            packdata_i = PLC.read(tagname)
            print('*' , end = '')
        time.sleep(1)

except KeyboardInterrupt:
    pass

except Exception as err:
    logging.exception(err)

finally:
    logging.info('Disconnecting')
    PLC.close()

Additional context Output from DEBUG logging:

2024-07-25 07:22:30,514 Sending generic message: forward_close
2024-07-25 07:22:30,515 Sent: GenericUnconnectedRequestPacket(message=[b'N', b'\x02 \x06$\x01', b"\n\x05'\x04\t\x10\xbd\xea>q", b'\x03\x00\x01\x00 \x02$\x01'])     
2024-07-25 07:22:30,520 Failed to parse reply
Traceback (most recent call last):
  File "C:\Users\plompt\AppData\Local\Programs\Python\Python311\Lib\site-packages\pycomm3\cip\data_types.py", line 156, in encode
    return cls._encode(value)
           ^^^^^^^^^^^^^^^^^^
  File "C:\Users\plompt\AppData\Local\Programs\Python\Python311\Lib\site-packages\pycomm3\cip\data_types.py", line 216, in _encode
    return pack(cls._format, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^
struct.error: ubyte format requires 0 <= number <= 255

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\plompt\AppData\Local\Programs\Python\Python311\Lib\site-packages\pycomm3\packets\ethernetip.py", line 127, in _parse_reply
    self.service = Services.get(Services.from_reply(self.raw[40:41]))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\plompt\AppData\Local\Programs\Python\Python311\Lib\site-packages\pycomm3\cip\services.py", line 99, in from_reply
    val = cls.get(USINT.encode(USINT.decode(reply_service) - 128))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\plompt\AppData\Local\Programs\Python\Python311\Lib\site-packages\pycomm3\cip\data_types.py", line 158, in encode
    raise DataError(f"Error packing {value!r} as {cls.__name__}") from err
pycomm3.exceptions.DataError: Error packing -128 as USINT