serial-arbiter 0.2.0

Serial Port Arbiter - Manages serial port access and ensures it recovers from failures
Documentation
import serial
import time
import json

seq = 0
seq_old = 0
rpm = 1.0
r = 0.0
g = 0.0
b = 0.0

def make_request():
    global seq
    global seq_old
    global r
    global g
    global b
    if seq_old != seq:
        seq_old = seq
        r += 1
        if r >= 12:
            r = 0
            g += 1
            if g >= 12:
                g = 0
                b += 1
                if b >= 12:
                    b = 0
    pxarr = []
    for px in range(0, 12):
        if b == px:
            pxarr.extend([0, 0, 50])
        elif g == px:
            pxarr.extend([20, 0, 0])
        elif r == px:
            pxarr.extend([0, 30, 0])
        else:
            pxarr.extend([0, 0, 0])
        # if g == px:
        #     pxarr.append(25)
        # else:
        #     pxarr.append(0)
        # if r == px:
        #     pxarr.append(25)
        # else:
        #     pxarr.append(0)
        # if b == px:
        #     pxarr.append(25)
        # else:
        #     pxarr.append(0)
    return json.dumps({
        'id': seq,
        'jsonrpc': "2.0",
        'method': "set_pixels",
        'params': pxarr,
    })

if __name__ == "__main__":
    ser = serial.Serial()
    ser.port = '/dev/ttyACM1'            # Device name or None.
    ser.baudrate = 4000000               # (int) – Baud rate such as 9600 or 115200 etc.
    ser.bytesize = serial.EIGHTBITS      # Number of data bits. Possible values: FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS
    ser.parity = serial.PARITY_NONE      # Enable parity checking. Possible values: PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE
    ser.stopbits = serial.STOPBITS_ONE   # Number of stop bits. Possible values: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
    ser.timeout = 0                      # (float) – Set a read timeout value in seconds.
    ser.xonxoff = False                  # (bool) – Enable software flow control.
    ser.rtscts = False                    # (bool) – Enable hardware (RTS/CTS) flow control.
    ser.dsrdtr = False                    # (bool) – Enable hardware (DSR/DTR) flow control.
    ser.write_timeout = 0                # (float) – Set a write timeout value in seconds.
    ser.inter_byte_timeout = None        # (float) – Inter-character timeout, None to disable (default).
    ser.exclusive = False                # (bool) – Set exclusive access mode (POSIX only). A port cannot be opened in exclusive access mode if it is already open in exclusive access mode.
    ser.open()
    print(ser.name)
    now_time = time.monotonic()
    last_time = now_time
    print_time = now_time
    while True:
        # print(cnt, f"SEND ", end='')
        try:
            # sent = ser.write(b'{"jsonrpc":"2.0","id":777,"method":"set_timings","params":{"T1":2,"T2":5,"T3":3}}\n')
            request = make_request()
            # print(request, end='')
            request = f"{request}\n"
            request = bytes(request, encoding='utf-8')
            sent = ser.write(request)
            sent = format(f"OK[{sent}]")
        except serial.serialutil.SerialTimeoutException:
            # print(f" TIMEOUT")
            # time.sleep(0.000001)
            continue

        seq += 1

        # print(f" {sent}", end='')
        # time.sleep(0.0001)

        recv = ser.read_until(expected='\n')
        # print(f" :: RECV {recv}")
        # time.sleep(0.0001)
        now_time = time.monotonic()
        elapsed_time = now_time - last_time
        last_time = now_time
        additional_delay = (1.0 / rpm / 12.0) - elapsed_time
        if additional_delay > 0.0:
            time.sleep(additional_delay)

        if now_time >= print_time:
            real_rpm = 1.0 / (elapsed_time * 12.0)
            freq = 1.0 / elapsed_time
            print(f"WANT RPM: {round(rpm)} REAL RPM: {round(real_rpm)} --> {round(freq)} Hz")

            if (rpm - real_rpm) < 2.0:
                rpm *= 1.1
            print_time = now_time + 0.5