I have the following simple setup:
Serial Device -> PL2303 UART-to-USB -> Win10 machine -> myScript.py using PySerial 3.5
Serial device is connected to the PC via PL2303 UART-to-USB at COM10.
Serial device only sends data when its physical "Send" button is pressed, and it only sends one 20-char \r\n terminated line per press.
Simple code to read the serial device data:
import time
import os
import sys
import serial
ser = serial.Serial("COM10", 9600, timeout=0.5)
while(1):
if ser.in_waiting:
serial_data = str(ser.readline().decode('ascii')) #Read (receive) data
print("Received: " + serial_data) #Print data
time.sleep(0.01) #Slight delay just in case.
The code works fine. However, when the Serial device is unplugged (via USB-to-Serial plug pull) Python crashes with the following exception:
File "D:\Program Files\Python37\lib\serial\serialwin32.py", line 259, in in_waiting
raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
serial.serialutil.SerialException: ClearCommError failed (OSError(22, 'The I/O operation has been aborted because of either a thread exit or an application request.', None, 995))
Now, warnings/exceptions whenever the serial device is physically unplugged are nothing new. PuTTy does that, and so do a number of other terminal emulators and logically so should do PySerial.
HOWEVER, I remember clear as day that at some point in development unplugging the serial device incited no reaction from PySerial. I could even "hot-swap" - unplug one serial device, plug in another and the script would still work and print the received data.
Is this "hot-swapping" possible or did I horribly misremember all of it?
You can use a try-except block to make it hot swappable. This works for me (using an Arduino as the serial device).
import time
import serial
ser = serial.Serial("COM9", 9600, timeout=0.5)
while True:
try:
if ser.in_waiting:
serial_data = str(ser.readline().decode('ascii'))
print("Received: " + serial_data)
time.sleep(0.01)
except:
try:
ser = serial.Serial("COM9", 9600, timeout=0.5)
except:
pass
Currently the device must be plugged in when you start running the code. But you can put the initial serial.Serial call inside its own try-except block to avoid this. Or you could simply leave this line out completely, and it will still work fine.