I've written a Python QGIS plugin that reads data from an AIS receiver via the Serial package. It will be similar in function to the GPS Information panel in that it will show your position on the map canvas and work in the background allowing the user to continue using QGIS.

I've written a while loop such that on a button click; QGIS will constantly monitor the serial port for a message. Once a message is received in its entirety (using readline()) the loop begins again.

I have now run into an issue I didn't plan for in that while the loop is running I can't do anything else with QGIS until I terminate this loop. Obviously my intention is that this plugin will work in the background (like GPS information panel) and that the user can do their normal GIS tasks.

Can anyone point me in the right direction. I'm not sure if there is a specific terminology for what I'm trying to achieve.

    def connectAIS(self):
    with serial.Serial(port=self.dockwidget.cb_comPort.currentText(), baudrate=self.dockwidget.cb_baudRate.currentText(),
                       parity='N', stopbits=1, bytesize=8, timeout=None) as ser:
        while ser.isOpen():
                dataOut = open('//positionLogger.txt', 'a')
                aismsg = ser.readline()
                dataOut.write(str('\n' + str(aismsg)))
  • 1
    You could try multithreading. I.e. run the while loop in the background. Although this is something I haven't really used. – Joseph Jun 29 '18 at 10:18
  • That link has a good example. However if I run two threads, how do I specify that I want the QGIS GUI (and all the other QGIS functions) to run as the 'other' thread. – James Keating Jul 4 '18 at 8:59

As @Joseph says, you need threading for this (or asynchronous calls).

It's because your loop is 'blocked' waiting for the output of the serial read(). Once it has read a value, the loop continues. Until then the code will seem to 'hang' while it waits for data.

If you do this asynchronously, then the call will start 'in the background', and you tell it to do the rest of the loop when it's finished. In the meantime, execution can continue (so releasing things for the GUI to continue)

Try looking for 'python asynchronous serial port read' or similar.

If you're using PySerial, it looks like there's an asynchronous version under development using Asynchio.

Threads are another possibility, and are how long-running tasks can do things like updating a progress bar. There are plenty of examples for QGIS 2.x but I've not seen any for QGIS 3 yet.

For more details you might have more luck on Stack Overflow as this is more a general python coding question.

  • Good tip. I've spent the day looking into this. I'm still not sure that I've got a grasp of the concept. Does the asynchronous calls approach allow your script to run one or more processes in the same script, or does it allow QGIS itself to operate as normal in the background while this script keeps monitoring the serial port similar to the original GPS information panel? – James Keating Jul 2 '18 at 10:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.