# Building a pyserial Plug for Serial Devices
URL: /guides/pyserial-plug
Talk to a DUT or instrument over a UART from an OpenHTF plug with pyserial — port discovery, command/response with timeouts, line framing, reading a serial number and firmware version into measurements, and capturing a boot log as an attachment.
The most common DUT interface on a production line is a UART: a debug console, a bootloader, an AT-command modem, a proprietary ASCII protocol. pyserial opens the port; an OpenHTF plug owns it for the duration of the test.
Prefer selecting by USB `serial_number` (the adapter's, not the DUT's): `/dev/ttyUSB0` and `COM3` change when cables move.
**Timeouts everywhere.** `serial.Serial(timeout=1)` bounds each `read`; the plug adds a per-command deadline on top. A hung DUT then fails the phase in seconds, not forever.
**Framing.** Decide what ends a response — a prompt, a newline, a fixed length, a checksum — and implement exactly that. `readline()` alone is only right for single-line replies.
**Echo.** Many consoles echo the command; strip it.
**Binary protocols.** Use `bytes`, `struct.pack`/`unpack`, and `ser.read(n)`; skip the `decode`.
**Flow control and DTR.** Some boards reset when DTR toggles on open. `serial.Serial(port=None)` then `ser.dtr = False; ser.port = port; ser.open()` avoids the pulse.
**Boot logs as attachments.** Capture the whole boot with `read_until_pattern` and attach it; when a unit fails later, the log is already in the record. For continuous capture in the background, the bundled `SerialCollectionPlug` does it in a thread.
**Windows** ports are `COM3`; above `COM9` use `\\\\.\\COM10`.