pyserial
pyserial copied to clipboard
How to detect if a serial port is being used by another application?
How do I detect if a serial port is being used by another application?
E.g. on a terminal, I have picocom /dev/ttyUSB0 -b 115200
running. Separately, I have an application running this script.
port='/dev/ttyUSB0'
try:
serial_port = serial.Serial(port=port, baudrate=115200, timeout=1)
except serial.SerialException as e:
print("could not open serial port '{}': {}".format(port, e))
else:
print("serial port is not busy.")
serial_port.close()
Yet this script returns serial port not busy.
.
According to serialposix.py#L523, the serial.Serial.read()
method will throw a SerialException
relating to device disconnected or multiple access on port?
. I tried it but could not get the desired response. What am I doing wrong here? I think I have corrected my except expression here.
import serial
port='/dev/ttyUSB0'
try:
serial_port = serial.Serial(port=port, baudrate=115200, timeout=5 )
read_data = serial_port.read()
except serial.serialutil.SerialException as err:
raise err
else:
print('serial_port = ', serial_port.__dict__)
print('read_data = ', read_data)
print("0 serial port is not busy.")
serial_port.close()
if not read_data:
print("1 serial port is busy.")
Output:
serial_port = {'is_open': True, 'portstr': '/dev/ttyUSB0', 'name': '/dev/ttyUSB0', '_port': '/dev/ttyUSB0', '_baudrate': 115200, '_bytesize': 8, '_parity': 'N', '_stopbits': 1, '_timeout': 5, '_write_timeout': None, '_xonxoff': False, '_rtscts': False, '_dsrdtr': False, '_inter_byte_timeout': None, '_rs485_mode': None, '_rts_state': True, '_dtr_state': True, '_break_state': False, '_exclusive': None, 'fd': 6, 'pipe_abort_read_r': 7, 'pipe_abort_read_w': 8, 'pipe_abort_write_r': 9, 'pipe_abort_write_w': 10}
read_data = b''
0 serial port is not busy.
1 serial port is busy.
Trying the same code. Getting the expected results.
import serial
def check_port_status(port_name: str, baudrate: int = 115200):
if port_name is None:
return
if baudrate is None:
return
## config
# baudrate = 115200
# port_name = "/dev/tty.SLAB_USBtoUART"
try:
# print("port name: ", port_name)
# print("baudrate: ", baudrate)
serial_port = serial.Serial(port=port_name, baudrate=baudrate, timeout=5)
read_data = serial_port.read()
except serial.serialutil.SerialException as err:
## get the error arguments and print
code, context = err.args # tuple
if(code == 16):
print(f"port {port_name} is busy, please close and try again.")
pass
elif(code == 2):
print(f"port name: {port_name} is not valid.")
pass
return (False, code)
else:
print('serial_port = ', serial_port.__dict__)
print('read_data = ', read_data)
print("serial port is not busy.")
serial_port.close()
return (True, 1)
if __name__ == "__main__":
# main()
port_name = '/dev/tty.SLAB_USBtoUART'
baudrate = 115200
check_port_status(port_name=port_name, baudrate=baudrate)
Output Instance 1 (Port is not busy):
serial_port = {'is_open': True, 'portstr': '/dev/tty.SLAB_USBtoUART', 'name': '/dev/tty.SLAB_USBtoUART', '_port': '/dev/tty.SLAB_USBtoUART', '_baudrate': 115200, '_bytesize': 8, '_parity': 'N', '_stopbits': 1, '_timeout': 5, '_write_timeout': None, '_xonxoff': False, '_rtscts': False, '_dsrdtr': False, '_inter_byte_timeout': None, '_rs485_mode': None, '_rts_state': True, '_dtr_state': True, '_break_state': False, '_exclusive': None, 'fd': 3, 'pipe_abort_read_r': 4, 'pipe_abort_read_w': 5, 'pipe_abort_write_r': 6, 'pipe_abort_write_w': 7}
read_data = b'x'
serial port is not busy.
Output Instance 2 (Port is busy):
port /dev/tty.SLAB_USBtoUART is busy, please close and try again.
Output Instance 3 (Port is not active):
port name: /dev/tty.SLAB_USBtoUART is not valid.
To reproduce:
run:
python3 <file_name.py>
How do I detect if a serial port is being used by another application?
E.g. on a terminal, I have
picocom /dev/ttyUSB0 -b 115200
running. Separately, I have an application running this script.port='/dev/ttyUSB0' try: serial_port = serial.Serial(port=port, baudrate=115200, timeout=1) except serial.SerialException as e: print("could not open serial port '{}': {}".format(port, e)) else: print("serial port is not busy.") serial_port.close()
Yet this script returns
serial port not busy.
.
Is this issue resolved?
Trying the same code. Getting the expected results.
import serial def check_port_status(port_name: str, baudrate: int = 115200): if port_name is None: return if baudrate is None: return ## config # baudrate = 115200 # port_name = "/dev/tty.SLAB_USBtoUART" try: # print("port name: ", port_name) # print("baudrate: ", baudrate) serial_port = serial.Serial(port=port_name, baudrate=baudrate, timeout=5) read_data = serial_port.read() except serial.serialutil.SerialException as err: ## get the error arguments and print code, context = err.args # tuple if(code == 16): print(f"port {port_name} is busy, please close and try again.") pass elif(code == 2): print(f"port name: {port_name} is not valid.") pass return (False, code) else: print('serial_port = ', serial_port.__dict__) print('read_data = ', read_data) print("serial port is not busy.") serial_port.close() return (True, 1) if __name__ == "__main__": # main() port_name = '/dev/tty.SLAB_USBtoUART' baudrate = 115200 check_port_status(port_name=port_name, baudrate=baudrate)
Output Instance 1 (Port is not busy):
serial_port = {'is_open': True, 'portstr': '/dev/tty.SLAB_USBtoUART', 'name': '/dev/tty.SLAB_USBtoUART', '_port': '/dev/tty.SLAB_USBtoUART', '_baudrate': 115200, '_bytesize': 8, '_parity': 'N', '_stopbits': 1, '_timeout': 5, '_write_timeout': None, '_xonxoff': False, '_rtscts': False, '_dsrdtr': False, '_inter_byte_timeout': None, '_rs485_mode': None, '_rts_state': True, '_dtr_state': True, '_break_state': False, '_exclusive': None, 'fd': 3, 'pipe_abort_read_r': 4, 'pipe_abort_read_w': 5, 'pipe_abort_write_r': 6, 'pipe_abort_write_w': 7} read_data = b'x' serial port is not busy.
Output Instance 2 (Port is busy):
port /dev/tty.SLAB_USBtoUART is busy, please close and try again.
Output Instance 3 (Port is not active):
port name: /dev/tty.SLAB_USBtoUART is not valid.
To reproduce: run:
python3 <file_name.py>
Hi Satish, Thanks for the write up. (Did you validate your code when the port was occupied by picocom application?) I was also facing the same issue as @sunbearc22 was facing. I have installed latest pyserial v3.5 on Ubuntu v22.04.
I have re-used your code and tried against 3 different scenarios
Scen-1. Port /dev/ttyACM4 was fee (i.e., port is available/ready to use)
Verification-1: Cross verification using lsof command which gives no output
$ lsof /dev/ttyACM4
Verification-2: Using your code,
$ python3 serial_port_busy_check.py
serial_port = {'is_open': True, 'portstr': '/dev/ttyACM4', 'name': '/dev/ttyACM4', '_port': '/dev/ttyACM4', '_baudrate': 115200, '_bytesize': 8, '_parity': 'N', '_stopbits': 1, '_timeout': 5, '_write_timeout': None, '_xonxoff': False, '_rtscts': False, '_dsrdtr': False, '_inter_byte_timeout': None, '_rs485_mode': None, '_rts_state': True, '_dtr_state': True, '_break_state': False, '_exclusive': None, 'fd': 3, 'pipe_abort_read_r': 4, 'pipe_abort_read_w': 5, 'pipe_abort_write_r': 6, 'pipe_abort_write_w': 7}
read_data = b'E'
serial port is not busy.
Scen-2. Port /dev/ttyACM4 not present in the system (i.e., hardware is not connected to the system) Verification-1: Cross verification using lsof command which gives error
$ lsof /dev/ttyACM4
lsof: status error on /dev/ttyACM4: No such file or directory
;
;
Verification-2: Using your code,
$ python3 serial_port_busy_check.py
port name: /dev/ttyACM4 is not valid.
Scen-3. Port /dev/ttyACM4 was used by picocom application (i.e., port is already busy with other process) Verification-1: Cross verification using lsof command which gives port details in the output
$ lsof /dev/ttyACM4
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
picocom 383023 xyz_user 3uW CHR 166,4 0t0 1398 /dev/ttyACM4
Verification-2: Using your code,
$ python3 serial_port_busy_check.py
serial_port = {'is_open': True, 'portstr': '/dev/ttyACM4', 'name': '/dev/ttyACM4', '_port': '/dev/ttyACM4', '_baudrate': 115200, '_bytesize': 8, '_parity': 'N', '_stopbits': 1, '_timeout': 5, '_write_timeout': None, '_xonxoff': False, '_rtscts': False, '_dsrdtr': False, '_inter_byte_timeout': None, '_rs485_mode': None, '_rts_state': True, '_dtr_state': True, '_break_state': False, '_exclusive': None, 'fd': 3, 'pipe_abort_read_r': 4, 'pipe_abort_read_w': 5, 'pipe_abort_write_r': 6, 'pipe_abort_write_w': 7}
read_data = b''
serial port is not busy.
my concern is Scen-3 where code logic shows 'serial port is not busy' even the port was occupied by other application (in my case picocom application.)
Wondering why read_data = serial_port.read()
instruction is not detecting the busy port, where lsof
command is able to....
If anybody has resolved this issue, feel free to add the comments.
Thanks
i'm using this method to fill tkinter combobox.
def serial_ports():
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
return result
@harryberlin This has nothing to do with the issue, and is also pretty bad to return 256 COM ports on Windows. You can just use "import serial.tools.list_ports", and then use this:
ports = [port.device for port in serial.tools.list_ports.comports()]
to get only the usable serial ports. This should work on all platforms (tested on Linux).
ok, did add extra sorted()
ports = [port.device for port in sorted(serial.tools.list_ports.comports())]