{"id":5417,"library":"pyserial-asyncio","title":"pySerial-asyncio","description":"pySerial-asyncio is an asynchronous I/O extension for the Python Serial Port package (pySerial). It provides support for working with serial ports through asyncio Transports, Protocols, and Streams. Compatible with Python 3.5 and later, it depends on pySerial. The current version is 0.6. The project appears to be in maintenance mode, with no new releases since 2021, and a fork `pyserial-asyncio-fast` addressing some critical issues.","status":"maintenance","version":"0.6","language":"en","source_language":"en","source_url":"https://github.com/pyserial/pyserial-asyncio","tags":["asyncio","serial","hardware","io","communication"],"install":[{"cmd":"pip install pyserial-asyncio","lang":"bash","label":"Install latest stable version"}],"dependencies":[{"reason":"Core dependency for serial port communication.","package":"pyserial","optional":false}],"imports":[{"symbol":"serial_asyncio","correct":"import serial_asyncio"},{"note":"Preferred for simpler stream-based I/O over `create_serial_connection`.","symbol":"open_serial_connection","correct":"from serial_asyncio import open_serial_connection"},{"note":"Used when implementing custom `asyncio.Protocol` subclasses.","symbol":"create_serial_connection","correct":"from serial_asyncio import create_serial_connection"}],"quickstart":{"code":"import asyncio\nimport os\nimport serial_asyncio\n\nasync def main():\n    # For testing, use a virtual serial port like 'loop://'.\n    # On Linux, you can create virtual ports using 'socat -d -d pty,raw,echo=0 pty,raw,echo=0'.\n    # Replace 'loop://' with your actual port (e.g., '/dev/ttyUSB0' or 'COM1').\n    port = os.environ.get('SERIAL_PORT', 'loop://')\n    baudrate = int(os.environ.get('SERIAL_BAUDRATE', '115200'))\n\n    print(f\"Attempting to open serial port {port} at {baudrate} baud...\")\n    try:\n        # open_serial_connection returns (StreamReader, StreamWriter)\n        reader, writer = await serial_asyncio.open_serial_connection(url=port, baudrate=baudrate)\n        print(\"Serial port opened successfully.\")\n    except Exception as e:\n        print(f\"Failed to open serial port: {e}\")\n        return\n\n    try:\n        message = b\"Hello pySerial-asyncio!\\n\"\n        print(f\"Sending: {message.decode().strip()}\")\n        writer.write(message)\n        await writer.drain() # Crucial to ensure data is sent\n\n        print(\"Waiting for response...\")\n        response = await reader.readline() # Read until newline\n        print(f\"Received: {response.decode().strip()}\")\n\n    except Exception as e:\n        print(f\"Error during serial communication: {e}\")\n    finally:\n        print(\"Closing serial port...\")\n        writer.close()\n        await writer.wait_closed()\n        print(\"Serial port closed.\")\n\nif __name__ == '__main__':\n    asyncio.run(main())","lang":"python","description":"This example demonstrates how to open an asynchronous serial connection using `open_serial_connection`, send data, and read a response. It uses environment variables for port and baudrate to allow easy testing with virtual or real serial ports. The `writer.drain()` call is essential to ensure buffered data is transmitted."},"warnings":[{"fix":"Consider migrating to `pyserial-asyncio-fast` (from the Home Assistant project), which is a drop-in replacement designed to address the event loop blocking issues and improve performance. It is a separate package and requires `pip install pyserial-asyncio-fast` and changing `import serial_asyncio` to `import serial_asyncio_fast as serial_asyncio`.","message":"The `pyserial-asyncio` library is known to block the asyncio event loop due to blocking sleep calls, especially on Windows, which can lead to performance issues and unresponsiveness in asynchronous applications. This library is also not actively maintained, with the last release being in 2021.","severity":"breaking","affected_versions":"<=0.6"},{"fix":"Always follow `writer.write(data)` with `await writer.drain()` to ensure reliable data transmission.","message":"When using `StreamWriter` objects obtained from `open_serial_connection`, it is critical to call `await writer.drain()` after `writer.write()` to ensure that all buffered data is flushed and sent over the serial port. Forgetting to call `drain()` can result in data not being transmitted, especially in tight loops or when the buffer fills up.","severity":"gotcha","affected_versions":"All"},{"fix":"Be aware of potential performance implications on Windows. If performance is critical, thoroughly test your application on Windows or consider alternative approaches.","message":"On Windows, `pyserial-asyncio` uses a polling-based implementation for serial I/O, which may be less performant and slower compared to the native event-driven implementations on POSIX systems (Linux, macOS, BSD).","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure that `asyncio.Lock` and other event-loop-dependent objects are initialized within the context of the `asyncio` event loop where they will be used, ideally within an `async` function that is scheduled by `asyncio.run()` or `loop.run_until_complete()`.","message":"When working with `asyncio`, creating `asyncio.Lock` objects (or similar synchronization primitives) outside of an actively running event loop can lead to subtle bugs and exceptions when the lock is later acquired or released in a different event loop (e.g., one started by `asyncio.run()`).","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}