How to Import and Use pySerial in Python: A Quick Guide
Why Serial Communication Still Matters
Even with wireless everything, many projects still need a reliable, low‑level link between a computer and a device—think Arduino boards, GPS modules, or industrial sensors. Serial ports (UART, RS‑232, USB‑to‑serial adapters) provide that bridge, and Python’s pySerial library makes the connection surprisingly painless.
Getting pySerial Ready
First things first: the library isn’t part of the standard distribution, so you have to install it. Open a terminal and run:
pip install pyserial
If you’re juggling multiple Python versions, you might prefer pip3 or a virtual environment. The installation itself takes a few seconds, and the package pulls in all the platform‑specific drivers you’ll need.
Importing the Module the Right Way
Once the package is on your system, importing is straightforward. Most tutorials show the bare import serial, but a couple of nuances can save you headaches later:
import serialimport sys
The sys import isn’t required for serial work per se, but it gives you quick access to sys.exit() if something goes wrong while opening the port.
Dealing with Platform Differences
Windows uses names like COM3, while Linux/macOS expect /dev/ttyUSB0 or /dev/ttyS0. A tiny helper function can hide this mess:
def default_port():if sys.platform.startswith('win'):
return 'COM3'
else:
return '/dev/ttyUSB0'
This way you only write the port name once, and your script stays portable.
Opening a Serial Connection
The heart of any pySerial script is the Serial object. Here’s a minimal, yet robust, example:
try:ser = serial.Serial(
port=default_port(),
baudrate=9600,
timeout=1
)
except serial.SerialException as e:
print(f'Could not open port: {e}')
sys.exit(1)
Notice the explicit timeout—without it, read operations could block forever, which is rarely what you want in an interactive script.
Fine‑tuning Communication Settings
If your device uses odd parity or a non‑standard stop‑bit count, you can pass those arguments as well:
ser = serial.Serial(port=default_port(),baudrate=115200,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=0.5)
Those constants (e.g., serial.EIGHTBITS) make the code self‑documenting, which is a win for anyone who revisits the script months later.
Reading and Writing Data
Reading comes in two flavors: raw bytes or decoded strings. For most sensor data, a line‑oriented approach works best:
line = ser.readline().decode('utf-8').strip()print(f'Received: {line}')
Writing is equally simple:
command = 'LED ON\n'ser.write(command.encode('utf-8'))
Remember the newline character if the device expects it; otherwise you’ll get “command not recognized” errors that are hard to trace.
Cleaning Up
Leaving a port open can lock the device for other programs. Always close the connection when you’re done:
ser.close()Wrap the whole thing in a try…finally block if you prefer to guarantee cleanup even when an exception slips through.
Common Pitfalls and How to Dodge Them
- Wrong baud rate. Mismatched speeds produce garbled output. Double‑check the device’s documentation.
- Missing drivers. On Windows, the USB‑to‑serial chip may need a separate driver (e.g., FTDI or CP210x).
- Permission errors on Linux. If you see “Permission denied,” add your user to the
dialoutgroup or run the script withsudo—the former is safer. - Buffer overflows. Reading too slowly can fill the input buffer, causing the device to stop sending. Adjust
timeoutor read more frequently.
Putting It All Together: A Tiny Data Logger
Below is a compact script that opens a serial link, records ten lines to a CSV file, and shuts down cleanly. It demonstrates the best practices discussed earlier:
import csvimport serial
import sys
def default_port():
return 'COM3' if sys.platform.startswith('win') else '/dev/ttyUSB0'
try:
ser = serial.Serial(port=default_port(),
baudrate=9600,
timeout=1)
except serial.SerialException as err:
print(f'Error: {err}')
sys.exit(1)
with open('log.csv', 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['timestamp', 'value'])
for _ in range(10):
line = ser.readline().decode('utf-8').strip()
if line:
writer.writerow([time.time(), line])
print(f'Logged: {line}')
ser.close()
Feel free to tweak the loop count, file name, or CSV columns to match your project’s needs.
Where to Go Next
If you’ve made it this far, you’re ready to explore more advanced territory: handling binary protocols, employing asyncio for non‑blocking reads, or integrating pySerial with GUI frameworks like Tkinter or PyQt. The library’s documentation is a treasure trove of examples, and the community on Stack Overflow often has “gotchas” specific to niche hardware.