Flask appears to prevent PyQt5 UI from updating.
The respective code works properly for either PyQt5 or Flask - but not together. I understand that it may need to do with the way threading is set up.
Any assistance would be greatly appreciated. TIA.
`
import sys
import serial
import threading
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
from flask import Flask, render_template, request, redirect, url_for
app1 = Flask(__name__)
ser = serial.Serial ("/dev/ttyS0", 57600,timeout=3) #Open port with baud rate
count=0
temp = []
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
global count
count = 1
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('PyQt5 vs Flask')
self.lbl1 = QLabel('Count '+str(count), self)
self.lbl1.move(100, 50)
self.show()
threading.Timer(5,self.refresh).start()
def refresh(self):
global count
count +=1
print("UI ",count)
self.lbl1.setText('Count'+str(count))
threading.Timer(5,self.refresh).start()
def get_uart():
global temp
if ser.inWaiting()>0:
temp =[str(float(x.decode('utf-8'))) for x in ser.read_until().split(b',')]
print(temp)
threading.Timer(1,get_uart).start()
@app1.route("/")
def index():
global temp
templateData = {'temp1' : temp[1] ,'temp2' : temp[2]}
return render_template('index.html',**templateData)
if __name__ == "__main__":
app = QApplication(sys.argv)
pyqt5 = Example()
threading.Timer(1,get_uart).start()
ser.flushInput()
#app1.run(host='0.0.0.0',threaded=True, port=5000) # ,debug=True)
sys.exit(app.exec_())
`
Need to have a UI to control the data analysis to be displayed on Website.
The better way deal with (possibly waiting) processes, is to use Qt's own threads.
In this example I've created a QObject subclass that does all processing and eventually sends a signal whenever the condition is valid. I can't install flask right now, so I've not tested the whole code, but you'll get the idea.
The trick is to use a "worker" QObject that does the processing. Once the object is created is moved to a new QThread, where it does all its processing without blocking the event loop (thus, the GUI).
You can also create other signals for that object and connect to your slots (which might also be standard python functions/methods outside the QtApplication) which will be called whenever necessary.
class Counter(QtCore.QObject):
changed = QtCore.pyqtSignal(str)
def __init__(self):
super().__init__()
self.count = 0
def run(self):
while True:
self.thread().sleep(1)
if ser.inWaiting() > 0:
self.changed.emit('{}: {}'.format(self.count, [str(float(x.decode('utf-8'))) for x in ser.read_until().split(b',')]))
self.count += 1
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.counter = Counter()
self.counterThread = QtCore.QThread()
self.counter.moveToThread(self.counterThread)
self.counterThread.started.connect(self.counter.run)
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('PyQt5 vs Flask')
self.lbl1 = QtWidgets.QLabel('Count {}'.format(self.counter.count), self)
self.lbl1.move(100, 50)
self.counter.changed.connect(self.lbl1.setText)
self.counterThread.start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
pyqt5 = Example()
pyqt5.show()
I think the problem stems from how Flask is activated. If the app.run command is given any parameters (even if in a Thread), then it blocks other commands.
The only way I was able to make Flask and PyQt5 work at the same time, was to activate Flask in a dedicated Thread WITHOUT any parameters - SEE BELOW for the various combinations.
Question: Is this a Flask/Python Bug or Feature or some other explanation related to Development vs Production deployment??
In any case, I would like any help with finding a way to deploy flask in a Port other than 5000 - WITHOUT Flask Blocking other code.
import sys
import serial
import threading
import atexit
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
from flask import Flask, render_template, request, redirect, url_for
ser = serial.Serial ("/dev/ttyS0", 57600,timeout=3) #Open port with baud rate
app = Flask(__name__)
count=0
temp = []
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
global count
count = 1
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('PyQt5 vs Flask')
self.lbl1 = QLabel("Count "+str(count)+" ", self)
self.lbl1.move(100, 50)
self.show()
threading.Timer(5,self.refresh).start()
def refresh(self):
global count
global str_data
count +=1
self.lbl1.setText("Count "+str(count)+" ")
threading.Timer(0.5,self.refresh).start()
def get_uart():
global temp
if ser.inWaiting()>0:
temp =[str(float(x.decode('utf-8'))) for x in ser.read_until().split(b',')]
print(temp)
threading.Timer(1,get_uart).start()
@app.route("/")
def blank():
global count
data="Count "+str(count)
return data
if __name__ == "__main__":
threading.Timer(5,get_uart).start()
#app.run ## Does not block further execution. Website IS NOT available
#app.run() ## Blocks further execution. Website available at port 5000 without Refresh value
#app.run(port=5123) ## Blocks further execution. Website available at port 5123 without Refresh value
#app.run(threaded=True) ## Blocks further execution. Website available at port 5000 without Refresh value
#threading.Thread(target=app.run()).start() ## Blocks further execution. Website available at port 5000 without Refresh value
#threading.Thread(target=app.run(port=5123)).start() ## Blocks further execution. Website available at port 5123 without Refresh value
#threading.Thread(target=app.run(threaded=True)).start() ## Blocks further execution. Website available at port 5000 without Refresh value
threading.Thread(target=app.run).start() ## Flask DOES NOT block. Website is available at port 5000 with Refresh value
print("Flask does not block")
app1 = QApplication(sys.argv)
pyqt5 = Example()
sys.exit(app1.exec_())
[SOLVED]
All Flask parameters can be defined as:
port = int(os.environ.get('PORT', local_port))
kwargs = {'host': '127.0.0.1', 'port': port , 'threaded' : True, 'use_reloader': False, 'debug':False}
threading.Thread(target=app.run, daemon = True, kwargs=kwargs).start()
and Flask will NOT Block and run with the parameters defined in kwargs.