Search code examples
pythonserializationserial-portsubclasspyserial

Python pySerial - Problem using subclasses


I'm working on a project in Python that uses two or more serial ports to manage some devices from my RPi. When ports are open in the same file and I send commands to different instances of serial.Serial object everything works fine. This is an example:

import serial

device1_port = "/dev/ttyUSB0"
device2_port = "/dev/ttyUSB1"

# Command sent to device 1. No problem
d1 = serial.Serial(device1_port, timeout = 0.5)
d1.write(b'GET MUTE\n')
output1 = d1.readline()
print("Device 1 output: " + str(output1))


# Command sent to device 2. No problem
d2 = serial.Serial(device2_port, timeout = 1)
d2.write(b'00vP\r')
output2 = d2.readline()
print("Device 2 output: " + str(output2))

Output:

Device 1 output: b'DATA MUTE OFF\r\n'
Device 2 output: b'00vP0\r'

The problem comes when I try to separate one device from another using subclasses of serial.Serial. The reason is I want to deal with them like objects with their own methods (each device needs a lot of different commands, status queries...).

class device1(serial.Serial):
    def __init__(self, port, timeout):
        super().__init__(port, timeout)
        serial.Serial(port, timeout)

    def command1(self):
        self.write(b'SET MUTE OFF\n')
        self.write(b'GET MUTE\n')
        output = self.readline()
        print("Device 1 output: " + str(output))


class device2(serial.Serial):
    def __init__(self, port, timeout):
        super().__init__(port, timeout)
        serial.Serial(port, timeout)

    def command2(self):
        self.write(b'00vP\r')
        output = self.readline()
        print("Device 2 output: " + str(output))

device1_port = "/dev/ttyUSB0"
device2_port = "/dev/ttyUSB1"

d1 = device1(device1_port, timeout=0.5)
d2 = device2(device2_port, timeout=1)

d1.command1()
d2.command2()

When I run this code the output is:

Device 1 output: b'DATA MUTE OFF\r\n'
_

and it keeps waiting forever for the second device. I'm forced to Ctrl + C and I get this:

^CTraceback (most recent call last):
  File "./ct3.py", line 35, in <module>
    d2.command2()
  File "./ct3.py", line 23, in command2
    output = self.readline()
  File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 483, in read
    ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
KeyboardInterrupt

It's seems like there is some kind of conflict between the two subclasses but, obviously I have no idea what I'm doing wrong.

Can someone help me please?


Solution

  • You shouldn't be calling serial.Serial(port, timeout) from your __init__, as super().__init__(...) is already doing this. See these answers. You don't even need an __init__ if you are not going to change what the base class does.

    Also, there is a difference in your two versions with respect to the use of positional and keyword arguments. serial.Serial()'s first 2 positional arguments are port, baudrate, so you need to explicitly use the keyword argument timeout=:

    def __init__(self, port, timeout):
        super().__init__(port, timeout=timeout)