Using PySerial for Hardware Serial Communication

 

Getting Started with pySerial - Zilogic Systems

Documentation

CleanShot 2022-08-18 at 09.35.54

PySerial has documentation in the documentation folder, however cmake dose not working inside the folder.

brew install sphinx

Trying out

import serial

Open port with no timeout

def c2_1_1():
    """Open port with no timeout"""
    ser = serial.Serial(port="/dev/cu.usbmodem83201", baudrate=9600, timeout=1)  # open serial port
    print(ser.name)  # check which port was really used
    # bytes = b'...' literals = a sequence of octets (integers between 0 and 255)
    """
    >>> print(out)
    b'hello,Python!'
    >>> out.decode('utf-8')
    'hello,Python!'
    """
    ser.write(b"hello")
    ser.close()
/Users/azat/Developer/Python/unisat_data_local/venv/bin/python /Users/azat/Developer/Python/unisat_data_local/src/usart/trying.py 
/dev/cu.usbmodem83201

Process finished with exit code 0

Open named port at “9600,8,N,1

def c2_1_2():
    """Open named port at "9600,8,N,1" """
    with serial.Serial(port="/dev/cu.usbmodem83201", baudrate=9600, timeout=1) as ser:
        x = ser.read()  # read one byte
        s = ser.read(10)  # read 10 byte
        line = ser.readline()  # read a `\n` terminated line

CleanShot 2022-08-18 at 10.40.27

Open port at 9600,8,E,1 non blocking HW handshaking

def c2_1_3():
    """Open port at 9600,8,E,1 non blocking HW handshaking """
    ser = serial.Serial(port="/dev/cu.usbmodem83201", baudrate=9600, timeout=0, parity=serial.PARITY_NONE,
                        stopbits=serial.STOPBITS_ONE)

CleanShot 2022-08-18 at 10.40.27

Get a Serial instance and configure/open it later

def c2_2():
    """Get a Serial instance and configure/open it later"""
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.port = "/dev/cu.usbmodem83201"
    print(ser)
    print(ser.open())
    print(ser.is_open)
    print(ser.close())

CleanShot 2022-08-18 at 10.42.22

Get a Serial instance using context manager and configure it later

def c2_3():
    with serial.Serial() as ser:
        ser.baudrate = 9600
        ser.port = "/dev/cu.usbmodem83201"
        print(ser)
        print(ser.open())
        print(ser.is_open)
        print(ser.write(b"hello"))
Serial<id=0x104c17ee0, open=False>(port='/dev/cu.usbmodem83201', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
None
True
5

EOL

def c2_3_1():
    import io
    ser = serial.serial_for_url('loop://', timeout=1)
    sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))

    sio.write("hello\n")
    sio.flush()  # It is buffering. required to get the data out
    hello = sio.readline()
    print(hello == "hello\n")

CleanShot 2022-08-18 at 11.29.29

Listing All Ports

From the Terminal

❯ python -m serial.tools.list_ports
/dev/cu.Bluetooth-Incoming-Port
/dev/cu.usbmodem83201
2 ports found

From Python code

def c2_4():
    """List all ports"""
    from serial.tools import list_ports
    list_port_info: ListPortInfo = list_ports.comports()
    for each in list_port_info:
        print("-------------------Serial Device Info-------------------")
        all_attrs = get_cls_attrs(each)
        for key in all_attrs:
            print(f"{key} = {getattr(each,key)}")
-------------------Serial Device Info-------------------
vid = 9025
location = 8-3.2
device = /dev/cu.usbmodem83201
description = IOUSBHostDevice
interface = None
product = IOUSBHostDevice
pid = 67
hwid = USB VID:PID=2341:0043 SER=85937313337351619040 LOCATION=8-3.2
serial_number = 85937313337351619040
manufacturer = Arduino (www.arduino.cc)
name = cu.usbmodem83201
-------------------Serial Device Info-------------------
vid = None
location = None
device = /dev/cu.Bluetooth-Incoming-Port
description = n/a
interface = None
product = None
pid = None
hwid = n/a
serial_number = None
manufacturer = None
name = cu.Bluetooth-Incoming-Port
def c2_4_1():
    """List all ports and get device as list"""
    from serial.tools import list_ports
    list_port_info: ListPortInfo = list_ports.comports()
    result = [each.device for each in list_port_info]
    return result
['/dev/cu.usbmodem83201', '/dev/cu.Bluetooth-Incoming-Port']

Automatically Detect UniSat Data Provider Port

def is_unisat_data_provider(port: str) -> bool:
    """Check if the port is correct for UniSat Data Provider.
    We check this by reading 10 seconds of serial data and compare the received bytes with the PSoTT
    protocol.
    """
    with serial.Serial(port=port, baudrate=9600, timeout=10) as ser:
        s = ser.read(100)  # read 10 byte
        decoded = s.decode('utf-8')
    return 'subID' in decoded

Architecture

This project is based on PSoTT architecture and protocol. It is mainly desined and implemented for IoT devices and edge hardware.

CleanShot 2022-08-17 at 10.03.26

Usually IoT devices (if they are cable of sending http requests) can embed this project as its core.