How do I correctly manage the serial resource? [Python]

Viewed 49

I'm working on an automation project with python and an Arduino. I need to run a test that ensures that the Arduino is connected (and not some other device). I have a simple test case that works, but doesn't manage the serial object's memory at all. I've got a solution that I feel should work, however it causes an issue with the serial connection. The result is that the first read returns an empty string. Subsequent reads return the correct value. For my application I need it to read correctly on the first try.

Here is the test code I used. This code works just fine (it's how I know the issue isn't on the Arduino side of things)

ser = serial.Serial('/dev/tty.usbmodem14101', 9600, timeout=1)
    ser.flush()
    while True:
        text = input("Input: ")
        ser.write(bytes(text, 'utf-8'))
        time.sleep(0.2)
        line = ser.readline().decode('utf-8').rstrip()

        print(line)

This is my attempt at creating a better way to manage the serial resource using the context manager and the with statement. I tried 2 things. The ArduinoWith class only returns false (and prints and empty string) with no indication of any input on the Arduino. The ArduinoSelf has the same result the first time, but returns True the second time.

import serial
import time
from contextlib import contextmanager

@contextmanager
def arduino_serial_connection(path, rate, timeout=1):
    connection = serial.Serial(path, rate, timeout=timeout)
    yield connection
    connection.close()

class ArduinoWith:
    def __init__(self):
        pass

    def connection_test(self):
        try:
            with arduino_serial_connection('/dev/tty.usbmodem14101', 9600) as connection:
                connection.write(b"S\n")
                time.sleep(0.2)
                answer = connection.readline().decode('utf-8').rstrip()#connection.read(8)
                if answer == "H":
                    return True
                else:
                    print("Answer: \"" + answer +"\"")
        except serial.serialutil.SerialTimeoutException:
            print("Timeout")
        except Exception:
           print("Execption")
        return False

class ArduinoSelf:
    def __init__(self):
        self.ser = serial.Serial('/dev/tty.usbmodem14101', 9600, timeout=1)

    def connection_test(self):
        try:
            self.ser.write(b"S\n")
            time.sleep(0.2)
            answer = self.ser.readline().decode('utf-8').rstrip()#connection.read(8)
            if answer == "H":
                return True
            else:
                print("Answer: \"" + answer +"\"")
        except serial.serialutil.SerialTimeoutException:
            print("Timeout")
        except Exception:
           print("Execption")
        return False


a1 = ArduinoWith()
print(a1.connection_test())
time.sleep(1)
a2 = ArduinoSelf()
print(a2.connection_test())
time.sleep(1)
print(a2.connection_test())

I'm not exactly sure why running the method a second time on the ArduinoSelf class worked, but it did and that made me think there must be something that I'm not initializing correctly.

0 Answers
Related