Jarrett Dunn Jarrett Dunn - 3 years ago 159
Python Question

Signals not passing from thread to GUI

This telemetry program that reads data in from a serial string coming in on a USB port. The GUI is defined in a QML file and reading the serial port is taken care of by a string. The GUI loads and works correctly. The button on the GUI send has an event handler that that causes a signal to be sent back to the GUI. That works perfectly. The serial read thread starts and runs correctly. It reads and parses the data and prints it to the screen. However the signals are not making it back to the GUI.

This is driving me crazy, thanks for the help.

main.py

import sys
import serial
from io import StringIO
import csv
from openpyxl import Workbook
import datetime
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QThread

global ser
#define and open the serial port
ser=serial.Serial('COM6')

class Dash(QObject):
def __init__(self):
QObject.__init__(self)

ampHourvalue = pyqtSignal(int, arguments=['amphour'])


@pyqtSlot(int)
def reset(self, value):

value=100 #put amp hour capacity here
self.ampHourvalue.emit(value)

class ThreadClass(QThread):
# Create the signal
auxVoltage = pyqtSignal(str, arguments=['auxvolt'])
mainVoltage = pyqtSignal(int, arguments=['mainvolt'])
arrayCurrent = pyqtSignal(int, arguments=['arraycurrent'])
motorCurrent = pyqtSignal(int, arguments=['motorcurrent'])


def __init__(self, parent=None):
super(ThreadClass, self).__init__(parent)

def run(self):
try:
wb=load_workbook("History.xls") #attemps to open the history excel file
except:
wb=Workbook() #creates and empty excel workbook if histortory is not found

WorkSheetName=datetime.date.today() #get todays date
ws = wb.create_sheet("%s" %WorkSheetName) #create worksheet with the date as tittle

while True:
data=ser.readline(120) #read the stream
print(data)
data=data.decode() #convert stream from bytes to characters
data=StringIO(data)#convert a stream of characters into string
dataset=csv.reader(data, delimiter= ',') #read the CSV string into individual array
dataset=list(dataset) #convert the array to list

ws.append(dataset[0])
wb.save("History.xls")

#extract individual data points
aux=dataset[0][1]
print("Aux ", aux)
mainvolt=dataset[0][2]
print("Main ", mainvolt)
arraycurrent=dataset[0][3]
motorcurrent=dataset[0][4]

# Emit the signals
self.auxVoltage.emit(aux)
self.mainVoltage.emit(mainvolt)
self.arrayCurrent.emit(arraycurrent)
self.motorCurrent.emit(motorcurrent)

pass


def main():
import sys
# Create an instance of the application
app = QGuiApplication(sys.argv)

#start the thread
threadclass=ThreadClass()
threadclass.start()


# Create QML engine
engine = QQmlApplicationEngine()
# Create a Dash object
dashboard = Dash()
# And register it in the context of QML
engine.rootContext().setContextProperty("dashboard", dashboard)
# Load the qml file into the engine
engine.load("take2.qml")

engine.quit.connect(app.quit)
sys.exit(app.exec_())


if __name__ == "__main__":
main()


take2.qml

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
import QtQuick.Extras 1.4


ApplicationWindow {
id: applicationWindow
visible: true
width: 1000
height: 500
color: "black"
title: "I like Telemetry"

Text {
id: text1
x: 300
y: 6
width: 353
height: 34
text: qsTr("Solar Car Telemetry System")
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
font.family: "Times New Roman"
font.pixelSize: 30
color: "grey"
}


CircularGauge {
id: circularGauge
x: 55
y: 111
width: 308
height: 279
anchors.verticalCenter: rowLayout.verticalCenter

Text {
id: text2
x: 143
y: 226
text: qsTr("Speed")
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 12
color: "grey"
}
}

CircularGauge {
id: auxvoltgauge
x: 381
y: 92
width: 151
height: 141
stepSize: .5
maximumValue: 15
value:1


Text {
id: text3
x: 445
width: 69
text: qsTr("Aux Battery")
anchors.top: parent.top
anchors.topMargin: -17
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 12
color: "grey"
}

Text {
id: text5
x: 64
y: 106
text: qsTr("Volts")
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
font.pixelSize: 12
color: "grey"
}
}

CircularGauge {
id: circularGauge2
x: 381
y: 288
width: 151
height: 141
visible: true


Text {
id: text4
x: 445
y: 259
text: qsTr("Main Battery")
anchors.top: parent.top
anchors.topMargin: -17
fontSizeMode: Text.FixedSize
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 12
color: "grey"
}
Text {
id: text6
x: 64
y: 106
text: qsTr("Volts")
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
font.pixelSize: 12
color: "grey"
}
}

Gauge {
id: amphourgauge
x: 803
y: 103
width: 114
height: 294
anchors.verticalCenterOffset: 0
anchors.verticalCenter: parent.verticalCenter
value: 50

Text {
id: text7
x: 30
y: 260
text: qsTr("AMP HOURS")
anchors.bottom: parent.bottom
anchors.bottomMargin: -25
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 18
color: "grey"
}

}



Button {
id: amphourreset
objectName: amphourreset
x: 795
y: 434
text: qsTr("Reset")

onClicked: dashboard.reset(amphourgauge.value)
}



Gauge {
id: arraycurrent
x: 621
y: 160

Text {
id: text10
text: qsTr("Array Current")
font.pixelSize: 12
color: "grey"
anchors.top: parent.top
anchors.topMargin: -17
fontSizeMode: Text.FixedSize
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}

Gauge {
id: motorcurrent
x: 710
y: 160

Text {
id: text9
text: qsTr("Motor Current")
font.pixelSize: 12
color: "grey"
anchors.top: parent.top
anchors.topMargin: -17
fontSizeMode: Text.FixedSize
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}

Connections {
target: dashboard

onAmpHourvalue: {
// sub was set through arguments=['amphour']
amphourgauge.value = amphour
}

onAuxVoltage: {
// sub was set through arguments=['auxvolt']
auxvoltgauge.value = auxvolt
}
}


}

Answer Source

@daegontaven was correct. The problem was the thread was not connected to the thread containing the GUI. Connecting the two threads solve the issue. I to reorder some of the code.

class ThreadClass(QThread):
    # Create the signal
    ampHourvalue = pyqtSignal(float, arguments=['amphour'])
    auxVoltage = pyqtSignal(float, arguments=['auxvolt'])
    mainVoltage = pyqtSignal(float, arguments=['mainvolt'])
    arrayCurrent = pyqtSignal(float, arguments=['arraycurrent'])
    motorCurrent = pyqtSignal(float, arguments=['motorcur'])


    def __init__(self, parent=None):
        super(ThreadClass, self).__init__(parent)
        #connects  the signals from the thread to the signals in the thread that is running the GUI

        self.auxVoltage.connect(dashboard.auxVoltage)
        self.mainVoltage.connect(dashboard.mainVoltage)
        self.motorCurrent.connect(dashboard.motorCurrent)
        self.arrayCurrent.connect(dashboard.arrayCurrent)
        self.ampHourvalue.connect(dashboard.ampHourvalue)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download