In PyQt5, I want to read my serial port after writing (requesting a value) to it. I've got it working using readyRead.connect(self.readingReady)
, but then I'm limited to outputting to only one text field.
The code for requesting parameters sends a string to the serial port. After that, I'm reading the serial port using the readingReady function and printing the result to a plainTextEdit form.
def read_configuration(self):
if self.serial.isOpen():
self.serial.write(f"?request1\n".encode())
self.label_massGainOutput.setText(f"{self.serial.readAll().data().decode()}"[:-2])
self.serial.write(f"?request2\n".encode())
self.serial.readyRead.connect(self.readingReady)
self.serial.write(f"?request3\n".encode())
self.serial.readyRead.connect(self.readingReady)
def readingReady(self):
data = self.serial.readAll()
if len(data) > 0:
self.plainTextEdit_commandOutput.appendPlainText(f"{data.data().decode()}"[:-2])
else: self.serial.flush()
The problem I have, is that I want every answer from the serial port to go to a different plainTextEdit form. The only solution I see now is to write a separate readingReady
function for every request (and I have a lot! Only three are shown now). This must be possible in a better way. Maybe using arguments in the readingReady
function? Or returning a value from the function that I can redirect to the correct form?
Without using the readyRead signal, all my values are one behind. So the first request prints nothing, the second prints the first etc. and the last is not printed out.
Does someone have a better way to implement this functionality?
If reqests are independent of each other you can use request queue, provide callback for each request and switch this callbacks inside readyRead
slot.
class RequestQueue:
def __init__(self, serial):
self._queue = []
self._started = False
self._handler = self._defaultHandler
self._serial = serial
serial.readyRead.connect(self._onReadyRead)
self._message = b''
def _isCompleteMessage(self, data):
return True
def _onReadyRead(self):
data = self._serial.readAll()
self._message += data.data()
if not self._isCompleteMessage(self._message):
return
self._handler(self._message)
self._message = b''
self._handler = self._defaultHandler
self._sendNextRequest()
def _defaultHandler(self, data):
pass
def _sendNextRequest(self):
if len(self._queue) < 1:
self._started = False
self._handler = self._defaultHandler
return
self._started = True
(data, handler) = self._queue[0]
self._queue = self._queue[1:]
self._handler = handler
self._serial.write(data)
def enqueue(self, data, handler):
self._queue.append((data, handler))
if not self._started:
self._sendNextRequest()
if __name__ == "__main__":
...
queue = RequestQueue(serial)
queue.enqueue(f"?request1\n".encode(), lambda data: ui.label1.setText(data.decode()))
queue.enqueue(f"?request2\n".encode(), lambda data: ui.label2.setText(data.decode()))
queue.enqueue(f"?request3\n".encode(), lambda data: ui.label3.setText(data.decode()))
Notice that this queue lives and operates in the same thread, since it uses asyncronous api.