UART Devices for Linux
uart-devices is a Python library for interacting with UART (Universal Asynchronous Receiver-Transmitter) devices on Linux systems. It provides an asynchronous, structured way to define and communicate with serial devices, abstracting away some of the lower-level details. The current version is 0.1.1, with initial development starting in April 2024 and a low release cadence.
Common errors
-
[Errno 13] Permission denied: '/dev/ttyUSB0'
cause The current user does not have read/write permissions for the specified serial port.fixAdd your user to the 'dialout' group (or 'uucp' on some systems) using `sudo usermod -a -G dialout $USER`. Then, log out and log back in for the changes to take effect. -
FileNotFoundError: [Errno 2] No such file or directory: '/dev/ttyS0'
cause The specified serial port path does not exist, or the device is not connected/enumerated.fixCheck if the serial device is properly connected and recognized by the system. Verify the correct device path (e.g., `/dev/ttyUSB0`, `/dev/ttyACM0`) using `ls /dev/tty*` and update your code. -
serial.serialutil.SerialException: Cannot configure port, something went wrong. Original message: 'I/O operation in progress'
cause The serial port is already in use by another application or process.fixEnsure no other program (e.g., a terminal emulator, another script) is currently accessing the serial port. You might need to restart the device or your system in some cases.
Warnings
- gotcha Accessing serial ports on Linux often requires specific user permissions. If your user is not part of the 'dialout' or 'uucp' group, you will encounter `PermissionError`.
- gotcha The specified UART device path (e.g., `/dev/ttyUSB0`) must exist and refer to an actual connected serial device. Incorrect paths will lead to `FileNotFoundError` or similar issues.
- gotcha Ensure the `baudrate` configured in your `UARTDevice` subclass matches the baud rate of your physical serial device. A mismatch will result in corrupted or unreadable data.
Install
-
pip install uart-devices
Imports
- UARTDevice
from uart_devices import UARTDevice
Quickstart
import asyncio
import logging
import os
from uart_devices import UARTDevice
logging.basicConfig(level=logging.INFO)
# Set UART_DEVICE_PORT environment variable before running, e.g.:
# export UART_DEVICE_PORT=/dev/ttyUSB0
# For demonstration, we use a common default like /dev/ttyS0 if not set.
# Ensure this port exists and you have permissions.
UART_PORT = os.environ.get("UART_DEVICE_PORT", "/dev/ttyS0")
class MySimpleUARTDevice(UARTDevice):
port = UART_PORT
baudrate = 115200 # Common baud rate
async def _async_on_open(self) -> None:
logging.info(f"UART device {self.port} opened successfully.")
async def _async_on_close(self) -> None:
logging.info(f"UART device {self.port} closed.")
async def _async_read_data(self, data: bytes) -> None:
"""Called when data is received."""
logging.info(f"Received data: {data.hex()}")
async def main():
device = MySimpleUARTDevice()
print(f"Attempting to interact with UART device on port: {device.port}...")
try:
await device.open()
# In a real application, you would perform async read/write operations here.
# For this example, we just keep it open briefly and then close.
await asyncio.sleep(0.5)
await device.close()
print(f"Successfully interacted with and closed device on {device.port}.")
except Exception as e:
logging.error(f"Failed to interact with UART device on {device.port}: {type(e).__name__}: {e}")
print("\n--- Troubleshooting Tips ---")
print("1. Check permissions: Ensure your user is in the 'dialout' or 'uucp' group. (e.g., `sudo usermod -a -G dialout $USER` then log out and back in).")
print("2. Verify device path: Ensure `UART_DEVICE_PORT` (e.g., /dev/ttyUSB0, /dev/ttyS0) is correct and the device is connected.")
print("3. Check baud rate: Ensure 115200 matches your device's baud rate.")
if __name__ == "__main__":
asyncio.run(main())