Skip to content
jacopoabramoPublic

About

Rust-powered serial communication library for Python. Drop-in replacement for pyserial

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PyPI PyPI - Python Version PyPI - Status License CI uv Ruff Checked with mypy Conventional Commits

oxiserial

Serial port access for Python, written in Rust. It has the API of pyserial 3.5, and adds an asyncio interface whose I/O calls return futures.

Runs on Windows, Linux and macOS with CPython 3.11 or newer, including the free-threaded build.

Install

pip install oxiserial

Wheels are published for Windows, Linux and macOS. On other platforms pip builds from source, which needs a Rust toolchain.

Replace pyserial

Change the import; the rest of the code stays as it is.

import oxiserial as serial

with serial.Serial("COM3", 115200, timeout=1) as port:
    port.write(b"*IDN?\n")
    print(port.readline())

Standard baud rates are available as an enum, and any other rate the driver supports is accepted as an int:

from oxiserial import Baudrate, Serial

port = Serial("/dev/ttyUSB0", Baudrate.B115200)
port.baudrate = 250000

Read and write from asyncio

oxiserial.aio.Serial takes the same arguments. Its I/O methods return a future that you can await:

import asyncio

from oxiserial.aio import Serial


async def main() -> None:
    async with Serial("/dev/ttyUSB0", 115200, timeout=1) as port:
        await port.write(b"*IDN?\n")
        print(await port.readline())


asyncio.run(main())

The same future can be waited on from plain threads, without an event loop:

from oxiserial.aio import Serial

port = Serial("COM3", 115200, timeout=1)
reply = port.readline()
port.write(b"*IDN?\n").wait()
print(reply.wait(timeout=2))
port.close()

Replace pyserial-asyncio

oxiserial.aio also has pyserial-asyncio's functions, so code written for pyserial-asyncio changes only its import:

import asyncio

from oxiserial import aio as serial_asyncio


async def main() -> None:
    reader, writer = await serial_asyncio.open_serial_connection(
        url="COM3", baudrate=115200
    )
    writer.write(b"*IDN?\n")
    await writer.drain()
    print(await reader.readline())
    writer.close()
    await writer.wait_closed()


asyncio.run(main())

create_serial_connection and connection_for_serial connect an asyncio protocol to a port, as they do in pyserial-asyncio.

Test without hardware

serial_for_url("loop://") opens a port that reads back what is written to it. Other names open the device, as Serial does.

from oxiserial import serial_for_url

port = serial_for_url("loop://", baudrate=115200, timeout=0.01)
port.write(b"ping--")
print(port.read_until(expected=b"--"))  # b'ping--'
port.close()

oxiserial.aio.serial_for_url does the same and returns an oxiserial.aio.Serial.

Find a port

from oxiserial.tools.list_ports import comports

for port in sorted(comports()):
    print(port.device, port.description, port.hwid)

grep(regexp), from the same module, returns only the ports whose device, description or hwid matches regexp, ignoring case.

Differences from pyserial

  • write() also accepts str and sends it as UTF-8.
  • pyserial's deprecated camelCase methods (inWaiting(), setRTS(), ...) are not provided; use the properties (in_waiting, rts, ...).
  • serial_for_url accepts device names and loop://; other URLs, such as socket://, raise ValueError. Serial("loop://") also opens a loopback port.
  • serial.rs485 is not available yet; serial.threaded is oxiserial.threaded.

License

BSD-3-Clause, see LICENSE. Parts derived from pyserial carry its notice in LICENSES/pyserial.txt.

About

Rust-powered serial communication library for Python. Drop-in replacement for pyserial

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages