Import
// CommonJS const { SerialPilot, ReadlineParser } = require('serialpilot')
// ESM / TypeScript import { SerialPilot, ReadlineParser } from ‘serialpilot’
new SerialPilot(options, callback?)
Open a port. Returns a Duplex stream that emits open when the underlying device is ready.
const port = new SerialPilot({
path: '/dev/ttyUSB0',
baudRate: 115200,
dataBits: 8,
parity: 'none',
stopBits: 1,
})
Constructor options
| Option | Type | Default | Notes |
|---|---|---|---|
path | string | — | Required. Device path (e.g. /dev/ttyUSB0, COM3). |
baudRate | number | — | Required. 9600, 115200, etc. |
dataBits | 5 | 6 | 7 | 8 | 8 | |
parity | 'none' | 'even' | 'odd' | 'mark' | 'space' | 'none' | Modbus RTU usually wants 'even'. |
stopBits | 1 | 1.5 | 2 | 1 | |
autoOpen | boolean | true | If false, call port.open() manually. |
highWaterMark | number | 65536 | Stream buffer size in bytes. |
endOnClose | boolean | false | End the stream when the port closes. |
rtscts / xon / xoff / xany | boolean | false | Hardware / software flow control. |
hupcl | boolean | true | Hang up on close (Unix). |
binding | BindingInterface | auto-detect | Override for tests; see Mocking. |
The optional second argument is a callback fired after the port opens (or fails to). If you prefer promises, listen for the open event instead.
Static methods
SerialPilot.list()
Resolves to an array of every serial port the OS knows about. Each entry has path, manufacturer, serialNumber, vendorId, productId, pnpId, and locationId (any of which may be undefined).
const ports = await SerialPilot.list()
SerialPilot.findPorts(filter)
Like list() but filters the result. The filter accepts strings (case-insensitive equality) or regular expressions:
const arduinos = await SerialPilot.findPorts({ manufacturer: /arduino/i, })
const byVid = await SerialPilot.findPorts({ vendorId: ‘2341’, productId: ‘0043’, })
Filter keys: vendorId, productId, serialNumber, manufacturer, path.
SerialPilot.openByDevice(options)
Discovery and open in a single call. Useful when the path may shift (different USB host, different OS) but the device fingerprint stays put.
const port = await SerialPilot.openByDevice({
vendorId: '2341',
baudRate: 115200,
required: true, // throws PortNotFoundError if no match (default)
})
Pass required: false to receive undefined instead of throwing when no port matches.
SerialPilot.parsers
A static record of every parser, in case you'd rather not import them by name:
SerialPilot.parsers.Readline
SerialPilot.parsers.Delimiter
SerialPilot.parsers.ByteLength
SerialPilot.parsers.Regex
SerialPilot.parsers.PacketLength
SerialPilot.parsers.InterByteTimeout
SerialPilot.parsers.Ready
SerialPilot.parsers.SlipEncoder
SerialPilot.parsers.SlipDecoder
SerialPilot.parsers.CCTalk
SerialPilot.parsers.SpacePacket
SerialPilot.parsers.StartEnd
Instance methods
| Method | Returns | Notes |
|---|---|---|
port.write(data, encoding?, cb?) | boolean | Standard Writable. Returns false when the buffer is full — wait for drain. |
port.read(size?) | Buffer | null | Standard Readable. |
port.pipe(stream) | destination | Pipe into a parser or any Writable. |
port.open(cb?) | void | Only needed when constructed with autoOpen: false. |
port.close(cb?) | void | Closes and emits close. |
port.update(options, cb?) | void | Change baud rate without closing. |
port.set(options, cb?) | void | Toggle DTR / RTS / BRK / DSR / CTS lines. |
port.get(cb) | void | Read CTS / DSR / DCD line state. |
port.flush(cb?) | void | Discard buffered data on both directions. |
port.drain(cb?) | void | Wait for the OS write buffer to empty. |
port.isOpen | boolean | Property, not a method. |
Events
| Event | Payload | When |
|---|---|---|
open | — | Fired once, when the port is ready for I/O. |
data | Buffer | Bytes from the device. Inherited from Readable. |
drain | — | The internal write buffer has emptied. |
close | err? | Port has closed; an Error indicates a disconnect. |
error | Error | Anything went wrong. See Errors. |
end | — | The stream's read side ended. |
Common patterns
Open as a promise
function openPort(opts) {
return new Promise((resolve, reject) => {
const port = new SerialPilot(opts)
port.once('open', () => resolve(port))
port.once('error', reject)
})
}
Close as a promise
await new Promise((res, rej) =>
port.close(err => err ? rej(err) : res())
)
Honour backpressure
if (!port.write(buf)) {
await new Promise(res => port.once('drain', res))
}
SerialPilot extends Node's Duplex, so anything that works on a stream — async iteration, pipeline, finished — works here too.