PySerial
PySerialDocs

Getting Started

Open a serial port, send data, read responses, and close the connection. First working PySerial script in under 5 minutes.

Open a port, send bytes, read a response, close. That's the whole workflow.

First Connection

Find Your Device

import serial.tools.list_ports

for port in serial.tools.list_ports.comports():
    print(f"{port.device}: {port.description}")

Port names vary by platform: /dev/ttyUSB0 on Linux, COM3 on Windows, /dev/cu.usbserial-* on macOS.

Open the Port

import serial

ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
print(f"Connected to {ser.name}")

Send Data

ser.write(b'Hello Serial!\n')

# Strings must be encoded first
message = "AT\r\n"
ser.write(message.encode('utf-8'))

Read Data

# Read one line (blocks until \n or timeout)
line = ser.readline()
print(line.decode('utf-8').strip())

# Read a fixed number of bytes
data = ser.read(10)

# Read everything currently in the buffer
if ser.in_waiting > 0:
    available = ser.read(ser.in_waiting)

Close the Port

ser.close()

Complete Example

import serial
import time

def echo_test(port, baudrate=9600):
    try:
        ser = serial.Serial(port, baudrate, timeout=2)
        time.sleep(1)  # wait for device init

        ser.write(b'AT\r\n')
        response = ser.readline()
        print(f"Sent: AT")
        print(f"Received: {response.decode('utf-8').strip()}")

        ser.close()

    except serial.SerialException as e:
        print(f"Serial error: {e}")
    except FileNotFoundError:
        print("Port not found. Check device connection.")
    except PermissionError:
        print("Permission denied. Add yourself to the dialout group (Linux).")

if __name__ == "__main__":
    echo_test('/dev/ttyUSB0')

Log serial data automatically

TofuPilot records test results from your PySerial scripts, tracks pass/fail rates, and generates compliance reports. Free to start.

Context Manager

Use with for automatic cleanup. The port closes when the block exits, even on exceptions.

import serial

with serial.Serial('/dev/ttyUSB0', 9600, timeout=1) as ser:
    ser.write(b'data\n')
    response = ser.read(100)
# port is closed here

Error Handling

import serial

try:
    ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
    ser.write(b'test\n')
    print(ser.readline().decode().strip())
except serial.SerialException as e:
    print(f"Serial port error: {e}")
except PermissionError:
    print("Permission denied. Linux: sudo usermod -a -G dialout $USER")
except FileNotFoundError:
    print("Port not found. Check connection and port name.")
finally:
    if 'ser' in locals() and ser.is_open:
        ser.close()

Quick Troubleshooting

ProblemFix
ModuleNotFoundErrorpip install pyserial (not serial)
Permission deniedsudo usermod -a -G dialout $USER (Linux)
Port not foundCheck device connection, verify port name
Timeout, no dataVerify baud rate matches on both ends
Garbage charactersTX/RX wires may be swapped