You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am trying to open a serial port using ModbusSerialClient, using invalid connection settings (provided by the user) for instance bytesize=6. In this case, connect method in serial.py fails because the following exception is raised from pyserial:
File "/home/pi/repos/test/venv/lib/python3.9/site-packages/pymodbus/client/serial.py", line 219, in connect
self.socket.inter_byte_timeout = self.inter_byte_timeout
File "/home/pi/repos/test/venv/lib/python3.9/site-packages/serial/serialutil.py", line 412, in inter_byte_timeout
self._reconfigure_port()
File "/home/pi/repos/test/venv/lib/python3.9/site-packages/serial/serialposix.py", line 517, in _reconfigure_port
termios.tcsetattr(
termios.error: (22, 'Invalid argument')
The problem is that unlike serial.SerialException, termios.error is not handled in the connect method.
def connect(self):
"""Connect to the modbus serial server."""
if self.socket:
return True
try:
self.socket = serial.serial_for_url(
self.comm_params.host,
timeout=self.comm_params.timeout_connect,
bytesize=self.comm_params.bytesize,
stopbits=self.comm_params.stopbits,
baudrate=self.comm_params.baudrate,
parity=self.comm_params.parity,
exclusive=True,
)
if self.strict:
self.socket.inter_byte_timeout = self.inter_byte_timeout
self.last_frame_end = None
except serial.SerialException as msg:
Log.error("{}", msg)
self.close()
return self.socket is not None
Because of this, the connection will not be closed properly and when I try to open the serial port again (with correct connection settings), I will get the following error:
ERROR:pymodbus.logging:[Errno 11] Could not exclusively lock port /dev/ttyS0: [Errno 11] Resource temporarily unavailable
Expected Behavior
I think ModbusSerialClient should also handle termios.error on connect and close the connection properly.
Code
The following code does the following:
Attempt 1: Tries to open serial connection with wrong connection settings and fails. But it wraps ModbusSerialClient in try-catch and will explicitly close the connection when termios.error is caught
Attempt 2: Tries to open serial connection with correct connection settings after the previous connection had failed, and succeeds because serial port has been closed properly in the previous attempt.
Attempt 3: Tries to open serial connection with wrong connection settings and fails, but does not close the connection (just uses with without explicit try-catch).
Attempt 4: Tries to open serial connection with correct connection settings after the previous connection had failed, and fails because serial port has not been closed properly in the previous attempt.
Notes:
I could not reproduce the exact same behavior on x86. The error can be reproduced consistently on Raspberry Pi 4.
There is no Modbus device connected to the serial port. That's why we see Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received). The intention is to just test the serial port not to actually read from a device.
importloggingimporttermiosimportpymodbusfrompymodbus.clientimportModbusSerialClientlogging.basicConfig(level=logging.INFO)
pymodbus.pymodbus_apply_logging_config("DEBUG")
port='/dev/ttyS0'baudrate=9600parity='N'stopbits=1method='rtu'bytesize=Noneattempt=0defconnect_using_with(attempt, method, port, baudrate, parity, stopbits, bytesize):
logging.info('---------------------------------------------------------')
logging.info(f'connection attempt {attempt} ...')
try:
logging.info(f'connection settings: method={method}, port={port}, baudrate={baudrate}, parity={parity}, stopbits={stopbits}, bytesize={bytesize}')
withModbusSerialClient(method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize) asclient:
logging.info(client)
rr=client.read_coils(1, 1, slave=1)
logging.info(f'results for atttempt {attempt}={rr}')
logging.info(f'connection attempt {attempt} susccessful :)')
excepttermios.errorase:
logging.error(f'connection attempt {attempt} failed :(')
logging.exception(f'termios error: {e}')
defconnect_using_try_catch_close(attempt, method, port, baudrate, parity, stopbits, bytesize):
logging.info('---------------------------------------------------------')
logging.info(f'connection attempt {attempt} ...')
try:
logging.info(f'connection settings: method={method}, port={port}, baudrate={baudrate}, parity={parity}, stopbits={stopbits}, bytesize={bytesize}')
client=ModbusSerialClient(method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize)
client.connect()
logging.info(client)
rr=client.read_coils(1, 1, slave=1)
logging.info(f'results for atttempt {attempt}={rr}')
logging.info(f'connection attempt {attempt} susccessful :)')
excepttermios.errorase:
logging.error(f'connection attempt {attempt} failed :(')
logging.exception(f'termios error: {e}')
client.close() # <-- explictly closing on failurelogging.info(f'connection closed')
# attempt 1 should fail because bytesize 6 is invalidattempt+=1bytesize=6connect_using_try_catch_close(attempt=attempt, method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize)
# attempt 2 should succeed because bytesize 8 is valid and previous connection is properly closedattempt+=1bytesize=8connect_using_with(attempt=attempt, method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize)
# attempt 3 should fail because bytesize 6 is invalid attempt+=1bytesize=6connect_using_with(attempt=attempt, method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize)
# attempt 4 should fail because even bytesize 8 is valid previous connection is not properly closedattempt+=1bytesize=8connect_using_with(attempt=attempt, method=method, port=port, baudrate=baudrate, parity=parity, stopbits=stopbits, bytesize=bytesize)
Just as a sidetone, bytesize=6 is legal for serial communication (not for modbus though), so it might be you have a hardware problem on top of this problem.
Versions
pymodbus==3.6.6
,pyserial==3.5
Pymodbus Specific
Description
I am trying to open a serial port using
ModbusSerialClient
, using invalid connection settings (provided by the user) for instancebytesize=6
. In this case,connect
method inserial.py
fails because the following exception is raised frompyserial
:The problem is that unlike
serial.SerialException
,termios.error
is not handled in theconnect
method.Because of this, the connection will not be closed properly and when I try to open the serial port again (with correct connection settings), I will get the following error:
Expected Behavior
I think
ModbusSerialClient
should also handletermios.error
onconnect
and close the connection properly.Code
The following code does the following:
ModbusSerialClient
in try-catch and will explicitly close the connection whentermios.error
is caughtwith
without explicit try-catch).Notes:
x86
. The error can be reproduced consistently on Raspberry Pi 4.Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received)
. The intention is to just test the serial port not to actually read from a device.Logs
The text was updated successfully, but these errors were encountered: