752 lines
34 KiB
Python
752 lines
34 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Form implementation generated from reading ui file 'test.ui'
|
|
#
|
|
# Created by: PyQt5 UI code generator 5.15.9
|
|
#
|
|
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
|
# run again. Do not edit this file unless you know what you are doing.
|
|
|
|
|
|
##########Es muss noch überprüft werden, ob der PC mit der Waage überhaupt verbunden ist
|
|
|
|
#from PyQt5 import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
from PyQt5.QtWidgets import QApplication
|
|
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject
|
|
import serial
|
|
import binascii
|
|
import math
|
|
import mariadb
|
|
import time
|
|
import threading
|
|
|
|
|
|
db_config = {
|
|
'user': 'dbUser',
|
|
'password': 'dbPassword',
|
|
'host': 'localhost',
|
|
'database': 'projectGeislinger',
|
|
'port': 3306 # Standard port for MariaDB
|
|
}
|
|
|
|
# Establishing the connection
|
|
conn = mariadb.connect(**db_config)
|
|
# Create a cursor to execute queries
|
|
cursor = conn.cursor()
|
|
|
|
# Konfiguration der seriellen Schnittstelle
|
|
ser = serial.Serial('/dev/ttyUSB0', 9600)
|
|
|
|
waageEingeschwungen = False
|
|
|
|
|
|
def wahrscheinlichkeitsDichte(x,mue, var):
|
|
# in der Funktion wird der Wahrscheinlichkeitsdichtenwert der Variable x für eine bestimmte Normalverteilung berechnet
|
|
standardabweichung = var**0.5
|
|
|
|
result = 1/(standardabweichung * (2*math.pi)**0.5 ) * math.exp(-0.5 * ((x-mue)/standardabweichung)**2)
|
|
|
|
return result
|
|
|
|
def calcWahrscheinlichkeitFromDichte(x,mue, var):
|
|
# in der Funktion wird die Wahrscheinlichkeit via der Wahrscheinlichkeitsdichte berechnet, indem das Verhältnis aus der dem Bauteil zugehörigen Wahrscheinlichkeitsdichte zu der maximalen Wahrscheinlichkeitsdichte berechnet wird
|
|
p1 = wahrscheinlichkeitsDichte(x,mue, var)
|
|
p_max = wahrscheinlichkeitsDichte(mue,mue, var)
|
|
|
|
return p1/p_max
|
|
|
|
|
|
|
|
#class Worker(QThread):
|
|
class Worker(QObject):
|
|
#progress = pyqtSignal(int)
|
|
objectDetectionStartSignal = pyqtSignal(str)
|
|
objectDetectionFinishedSignal = pyqtSignal(int, object)
|
|
|
|
checkWaageStartSignal = pyqtSignal(int, int, str)
|
|
checkWaageUpdateSignal = pyqtSignal(int, int)
|
|
checkWaageFinishedSignal = pyqtSignal(int)
|
|
|
|
waageStoppedSignal = pyqtSignal(int)
|
|
stopLoopSignal = pyqtSignal(bool) #das Signal wird verwendet um direkt den stopLoop-Wert zu ändern (also kein Funktionsaufruf)
|
|
|
|
stopLoop = False
|
|
btTypeIsSet = False
|
|
correctBtNr = False
|
|
|
|
|
|
def __init__(self):
|
|
super(Worker, self).__init__()
|
|
stopLoop = False
|
|
|
|
|
|
def getDataOfArticleType(self, allArticles, articleType):
|
|
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
|
for i in allArticles:
|
|
if i[1] == articleType:
|
|
return i
|
|
|
|
return -1
|
|
|
|
def waageNichtEingeschwungenOutput(self):
|
|
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
|
|
|
def readWaage(self):
|
|
# in folgender Funktion wird die Waage ausgelesen
|
|
|
|
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
|
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
|
|
|
|
|
if ser.is_open == False:
|
|
ser.open()
|
|
|
|
|
|
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
|
ser.write(b'getWeight\n')
|
|
#ser.write(b'tare\n')
|
|
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
|
|
|
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
|
lenString = len(serialString)-1
|
|
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
|
#print("ist eingeschwungen") #Debuggingausgabe
|
|
waageEingeschwungen = True
|
|
else:
|
|
print("die Waage ist noch nicht eingeschwungen")
|
|
waageEingeschwungen = False
|
|
|
|
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
|
intString = ""
|
|
for i in serialString:
|
|
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
|
intString = intString + i
|
|
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
|
## Waage auslesen - ENDE
|
|
|
|
ser.close()
|
|
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
|
|
|
return waageEingeschwungen, intString
|
|
|
|
def objectTypeDetectionThread(self, auftragsnummer):
|
|
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
|
|
|
#print("objectTypeDetectionThread - Running in thread:", threading.current_thread().name) #Debuggausgabe
|
|
|
|
# Parameterdefinition
|
|
propDensVect = []
|
|
|
|
self.btTypeIsSet = False
|
|
|
|
while(self.btTypeIsSet == False and self.stopLoop == False):
|
|
|
|
# Auslesen der Waage
|
|
waageEingeschwungen, intString = self.readWaage()
|
|
if waageEingeschwungen == False:
|
|
self.waageNichtEingeschwungenOutput()
|
|
else:
|
|
|
|
# Datenbankabfrage
|
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
|
cursor.execute(sql_query)
|
|
auftragEinzelteilDaten = cursor.fetchall()
|
|
|
|
'''
|
|
# Display data #Debugausgabe
|
|
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
|
for row in auftragEinzelteilDaten:
|
|
print(row)
|
|
'''
|
|
|
|
# in der Folge werden alle Wahrscheinlichkeitsdichten der Auftragsbauteile berechnet und in dem Vektor gesammelt
|
|
for row in auftragEinzelteilDaten:
|
|
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),float(row[6]), float(row[7])), row[1], row[5]])
|
|
|
|
# Jenen Eintrag des propDensVect raussuchen, welcher die größte Wahrscheinlichkeitsdichte beinhaltet
|
|
maxpropDens = 0
|
|
einzelteilID = 0
|
|
rowData = None
|
|
for row in propDensVect:
|
|
if row[0] > maxpropDens:
|
|
maxpropDens = row[0]
|
|
einzelteilID = row[1]
|
|
rowData = row
|
|
|
|
# überprüfen, ob das aufliegende Bauteil in der Auftragstabelle vorhanden ist
|
|
if(einzelteilID == 0):
|
|
print("Es wurde kein Bauteil aus der Auftragsliste (Tabelle) erkannt.")
|
|
else:
|
|
print("Bei dem Bauteil" , einzelteilID , "wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
|
|
|
# Wahrscheinlichkeit berechnen, dass das angegebene Bauteil auch wirklich diesem entspricht
|
|
prop = 0
|
|
for row in auftragEinzelteilDaten:
|
|
if row[1] == einzelteilID:
|
|
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6]), float(row[7]))
|
|
break
|
|
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
|
|
|
# den Bool auf true setzen, damit die Schleife beendet wird - dieser wird auf True gesetzt, wenn ein Bauteiltyp erkannt wird
|
|
self.btTypeIsSet = True
|
|
|
|
if(self.stopLoop == False):
|
|
# ein Signal zurück an den MainThreat senden, mit den Infos/Ergebnissen, der Typenbestimmung
|
|
self.objectDetectionFinishedSignal.emit(einzelteilID, rowData)
|
|
else:
|
|
self.waageStoppedSignal.emit(einzelteilID)
|
|
|
|
|
|
|
|
def checkWaageThread(self, einzelteilID, teileZuViel, auftragsnummer):
|
|
|
|
|
|
self.correctBtNr = False
|
|
prevAnzahl = 0
|
|
anzahl = 0
|
|
einzelteilID = einzelteilID
|
|
|
|
while (self.correctBtNr == False and self.stopLoop == False):
|
|
|
|
#überprüfen, ob die Waage eingeschwungen ist (und damit korrekte Ergebnisse liefert)
|
|
waageEingeschwungen, intString = self.readWaage()
|
|
if waageEingeschwungen == False:
|
|
self.waageNichtEingeschwungenOutput()
|
|
else:
|
|
|
|
# Datenbankabfrage - holen der Auftrags- und Bauteilinfos
|
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + auftragsnummer
|
|
cursor.execute(sql_query)
|
|
auftragDaten = cursor.fetchall()
|
|
|
|
'''
|
|
# Display data - zum Debuggen
|
|
print("Ausgabe der Auftragsdetails:")
|
|
print("id|EinzelteilID|Auftragsnummer|Anzahl")
|
|
for row in auftragDaten:
|
|
print(row)
|
|
'''
|
|
|
|
#auslesen, wie viele Bauteile des Types laut Auftrag vorhanden sein sollen
|
|
anzBauteile_soll = 0
|
|
idVorhanden = False
|
|
for row in auftragDaten:
|
|
if row[1] == einzelteilID:
|
|
anzBauteile_soll = row[3]
|
|
idVorhanden = True
|
|
|
|
if(idVorhanden == False):
|
|
print("Die gewählte Pos.Nr ist nicht in der Auftragsliste (Tabelle) vorhanden.")
|
|
return
|
|
|
|
# Berechnen der Wahrscheinlichkeitsdichten - der Betrag aller Wahrscheinlichkeitsdichten werden im propDensVect gespeichert
|
|
propDensVect = []
|
|
articleData = self.getDataOfArticleType(auftragDaten, einzelteilID)
|
|
for i in range(1,anzBauteile_soll+teileZuViel+1):
|
|
# Mathematische Sätze, auf welchen die Berechnung basiert:
|
|
# seien X1,..., Xn unabhängige Zufallsvariablen die N(mue_i, sigma_i^2) verteilt sind, dann ist X = X1+...+Xn - N(mue, sigma^2) verteilt mit mue=mue1+...+mue_n, sigma^2 = sigma_1^2+...+sigma_n^2
|
|
mueGes = float(articleData[6])*i # Berechnen des äquivalenten Mittelwert
|
|
varGes = float(articleData[7])*i # Berechnen der äquivalenten Varianz
|
|
propDensVect.append([wahrscheinlichkeitsDichte(float(intString),mueGes, varGes), i])
|
|
|
|
# durch den propDensVect iterieren und jenen Eintrag mit der höchsten Wahrscheinlichkeitsdichte raussuchen
|
|
maxpropDens = 0
|
|
for row in propDensVect:
|
|
if row[0] > maxpropDens:
|
|
maxpropDens = row[0]
|
|
anzahl = row[1]
|
|
|
|
# damit nur etwas gemacht wird (zb ein Updatesignal an den Hauptthread zurücksenden), wenn sich die berechnete Anzahl ändert
|
|
if prevAnzahl != anzahl:
|
|
prevAnzahl = anzahl
|
|
|
|
# Die Wahrscheinlichkeit berechnen, dass das obige Ergebnis auch dem Bauteil entspricht
|
|
if anzahl > 0:
|
|
for row in auftragDaten:
|
|
if row[1] == einzelteilID:
|
|
prop = calcWahrscheinlichkeitFromDichte(float(intString),float(row[6])*anzahl, float(row[7])*anzahl)
|
|
break
|
|
print("Die Wahrscheinlichkeit, dass es das Bauteil ist, beträgt: ", prop)
|
|
|
|
# wenn genug Bauteile vorhanden sind, dann soll die Schleife beendet werden
|
|
if (anzahl == anzBauteile_soll):
|
|
self.correctBtNr = True
|
|
|
|
# Konsolenausgabe
|
|
if maxpropDens > 0:
|
|
print("Bei der Anzahl" , anzahl , "des Bauteiltypes", einzelteilID, ",wurde die höchste Wahrscheinlichkeitsdichte berechnet.")
|
|
self.checkWaageUpdateSignal.emit(einzelteilID, anzahl)
|
|
|
|
else:
|
|
print("Von der ausgewählten Bauteiltype liegt die berechnete Wahrscheinlichkeit bei 0, dass zwischen 0 und", anzBauteile_soll+teileZuViel, "Bauteilen auf der Waage liegen.")
|
|
print("Falls die korrekte Anzhl an Bauteilen auf der Waage liegt, könnte der Fehler in einer falschen Kalibrierung der Waage liegen (TARE).")
|
|
|
|
if(self.stopLoop == False):
|
|
self.checkWaageFinishedSignal.emit(einzelteilID)
|
|
else:
|
|
self.waageStoppedSignal.emit(einzelteilID)
|
|
|
|
|
|
|
|
|
|
class Ui_MainWindow(object):
|
|
def setupUi(self, MainWindow):
|
|
self.auftragsnummer = ""
|
|
self.teileZuViel = 0 # Anzahl an Bauteilen, welche zu viel drinnen sein können - der Parameter kann selbst gesetzt werden #####
|
|
self.correctBtNr = False
|
|
self.btTypeIsSet = False
|
|
|
|
|
|
MainWindow.setObjectName("MainWindow")
|
|
MainWindow.resize(1090, 675)
|
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
|
self.centralwidget.setObjectName("centralwidget")
|
|
self.btn1 = QtWidgets.QPushButton(self.centralwidget)
|
|
self.btn1.setGeometry(QtCore.QRect(700, 45, 111, 25))
|
|
self.btn1.setObjectName("btn1")
|
|
self.AuftragsdetailsTable = QtWidgets.QTableWidget(self.centralwidget)
|
|
self.AuftragsdetailsTable.setGeometry(QtCore.QRect(10, 300, 661, 192))
|
|
self.AuftragsdetailsTable.setObjectName("AuftragsdetailsTable")
|
|
self.AuftragsdetailsTable.setColumnCount(6)
|
|
self.AuftragsdetailsTable.setRowCount(0)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(0, item)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(1, item)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(2, item)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(3, item)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(5, item)
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setHorizontalHeaderItem(4, item)
|
|
self.label = QtWidgets.QLabel(self.centralwidget)
|
|
self.label.setGeometry(QtCore.QRect(500, 20, 121, 17))
|
|
self.label.setObjectName("label")
|
|
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
|
|
self.textEdit.setGeometry(QtCore.QRect(450, 40, 221, 31))
|
|
self.textEdit.setObjectName("textEdit")
|
|
self.bauteilTypBtn = QtWidgets.QPushButton(self.centralwidget)
|
|
self.bauteilTypBtn.setGeometry(QtCore.QRect(700, 150, 161, 25))
|
|
self.bauteilTypBtn.setObjectName("bauteilTypBtn")
|
|
self.checkWaageBtn = QtWidgets.QPushButton(self.centralwidget)
|
|
self.checkWaageBtn.setGeometry(QtCore.QRect(700, 460, 161, 25))
|
|
self.checkWaageBtn.setObjectName("checkWaageBtn")
|
|
self.stopLoopBtn = QtWidgets.QPushButton(self.centralwidget)
|
|
self.stopLoopBtn.setGeometry(QtCore.QRect(700, 500, 161, 25))
|
|
self.stopLoopBtn.setObjectName("stopLoopBtn")
|
|
self.waageTareBtn = QtWidgets.QPushButton(self.centralwidget)
|
|
self.waageTareBtn.setGeometry(QtCore.QRect(700, 100, 161, 25))
|
|
self.waageTareBtn.setObjectName("waageTareBtn")
|
|
self.bauteiltypTextbox = QtWidgets.QTextEdit(self.centralwidget)
|
|
self.bauteiltypTextbox.setGeometry(QtCore.QRect(700, 290, 221, 31))
|
|
self.bauteiltypTextbox.setObjectName("bauteiltypTextbox")
|
|
self.BezeichnungLabel = QtWidgets.QLabel(self.centralwidget)
|
|
self.BezeichnungLabel.setGeometry(QtCore.QRect(700, 270, 181, 20))
|
|
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
|
self.PosNrLabel = QtWidgets.QLabel(self.centralwidget)
|
|
self.PosNrLabel.setGeometry(QtCore.QRect(700, 200, 67, 17))
|
|
self.PosNrLabel.setObjectName("PosNrLabel")
|
|
self.PosNrTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
|
self.PosNrTxtFeld.setGeometry(QtCore.QRect(700, 220, 191, 31))
|
|
self.BezeichnungLabel.setObjectName("BezeichnungLabel")
|
|
self.teileZuVielLabel = QtWidgets.QLabel(self.centralwidget)
|
|
self.teileZuVielLabel.setGeometry(QtCore.QRect(700, 350, 350, 17))
|
|
self.teileZuVielLabel.setObjectName("teileZuVielLabel")
|
|
self.teileZuVielTxtFeld = QtWidgets.QTextEdit(self.centralwidget)
|
|
self.teileZuVielTxtFeld.setGeometry(QtCore.QRect(700, 370, 191, 31))
|
|
MainWindow.setCentralWidget(self.centralwidget)
|
|
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
|
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 22))
|
|
self.menubar.setObjectName("menubar")
|
|
MainWindow.setMenuBar(self.menubar)
|
|
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
|
self.statusbar.setObjectName("statusbar")
|
|
MainWindow.setStatusBar(self.statusbar)
|
|
'''
|
|
item = QtWidgets.QTableWidgetItem()
|
|
font = QtGui.QFont()
|
|
font.setPointSize(8)
|
|
item.setFont(font)
|
|
self.AuftragsdetailsTable.setVerticalHeaderItem(0,item)
|
|
'''
|
|
self.retranslateUi(MainWindow)
|
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
|
|
|
def retranslateUi(self, MainWindow):
|
|
_translate = QtCore.QCoreApplication.translate
|
|
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
|
self.btn1.setText(_translate("MainWindow", "load Auftrag"))
|
|
self.btn1.clicked.connect(self.auftragsBtnClicked)
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(0)
|
|
item.setText(_translate("MainWindow", "Pos.-Nr"))
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(1)
|
|
item.setText(_translate("MainWindow", "Matnr mit hoechster Version"))
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(2)
|
|
item.setText(_translate("MainWindow", "Bezeichnung + Werkstoff"))
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(3)
|
|
item.setText(_translate("MainWindow", "Soll-Menge"))
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(4)
|
|
item.setText(_translate("MainWindow", "Ist-Menge"))
|
|
item = self.AuftragsdetailsTable.horizontalHeaderItem(5)
|
|
item.setText(_translate("MainWindow", "Lgort"))
|
|
self.label.setText(_translate("MainWindow", "Auftragsnummer:"))
|
|
self.bauteilTypBtn.setText(_translate("MainWindow", "Bauteiltyp erkennen"))
|
|
self.bauteilTypBtn.clicked.connect(self.objectTypeDetection)
|
|
self.AuftragsdetailsTable.cellClicked.connect(self.onTableCellClick)
|
|
#self.AuftragsdetailsTable.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
|
|
#item = self.AuftragsdetailsTable.verticalHeaderItem(0)
|
|
#item.setText(_translate("MainWindow", "test"))
|
|
self.BezeichnungLabel.setText(_translate("MainWindow", "Bezeichnung"))
|
|
self.PosNrLabel.setText(_translate("MainWindow", "Pos.-Nr:"))
|
|
self.teileZuVielLabel.setText(_translate("MainWindow", "Zu prüfende Teileanzahl über Auftragsanzahl:"))
|
|
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
|
self.checkWaageBtn.setText(_translate("MainWindow", "check Waage"))
|
|
self.checkWaageBtn.clicked.connect(self.checkWaage)
|
|
self.stopLoopBtn.setText(_translate("MainWindow", "stop loop"))
|
|
self.stopLoopBtn.clicked.connect(self.stopLoopClicked)
|
|
self.waageTareBtn.setText(_translate("MainWindow", "Waage tarieren"))
|
|
self.waageTareBtn.clicked.connect(self.onTareClick)
|
|
|
|
self.thread = QThread()
|
|
self.worker = Worker()
|
|
self.worker.moveToThread(self.thread)
|
|
self.worker.objectDetectionFinishedSignal.connect(self.objectTypeDetectionFinished)
|
|
self.worker.waageStoppedSignal.connect(self.threadStopped)
|
|
self.worker.stopLoopSignal.connect(lambda status: setattr(self.worker, 'stopLoop', status))
|
|
|
|
|
|
|
|
|
|
def onTareClick(self):
|
|
#Tarieren der Waage
|
|
if ser.is_open == False:
|
|
ser.open()
|
|
ser.write(b'tare\n')
|
|
ser.close()
|
|
|
|
|
|
def onCheckboxCheck(self):
|
|
if self.checkBox.isChecked() == True:
|
|
print("clickedCheckboxTrue")
|
|
else:
|
|
print("clickedCheckboxFalse")
|
|
|
|
def getRowNr(self, posNr):
|
|
for i in range(0,self.AuftragsdetailsTable.rowCount()):
|
|
if(self.AuftragsdetailsTable.item(i,0).text() == str(posNr)):
|
|
return i
|
|
# brauche ich hier vermutlich nicht mehr - ist in den Worker Thread kopiert worden
|
|
def waageNichtEingeschwungenOutput(self):
|
|
print("Die Waage ist noch nicht eingeschwungen - Ergebnisse sind dadurch noch fehlerhaft.")
|
|
|
|
|
|
def onTableCellClick(self):
|
|
self.PosNrTxtFeld.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),0).text())
|
|
self.bauteiltypTextbox.setText(self.AuftragsdetailsTable.item(self.AuftragsdetailsTable.currentRow(),2).text())
|
|
|
|
|
|
def setAuftragsnummer(self):
|
|
self.auftragsnummer = self.textEdit.toPlainText()
|
|
if(not self.auftragsnummer):
|
|
self.auftragsnummer = ""
|
|
self.textEdit.setText("")
|
|
|
|
def checkAuftragsnummerEmpty(self):
|
|
if self.auftragsnummer == "":
|
|
print("Das Auftragsnummernfeld ist leer.")
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def checkPosNrEmpty(self):
|
|
if self.PosNrTxtFeld.toPlainText() == "":
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
# eventuell benötigt man die Funktion hier nicht mehr, da sie zu den Threads kopiert wurde
|
|
def getDataOfArticleType(self, allArticles, articleType):
|
|
# die Funktion geht die Liste mit allen Artikeln durch und gibt jenen Eintrag, welcher mit dem "articleType" übereinstimmt zurück
|
|
for i in allArticles:
|
|
if i[1] == articleType:
|
|
return i
|
|
|
|
return -1
|
|
|
|
def updateGUI(self):
|
|
self.PosNrLabel.repaint() #GUI aktualisieren
|
|
QApplication.processEvents() #GUI aktualisieren
|
|
|
|
def setRowColor(self, rowID,r,g,b):
|
|
self.AuftragsdetailsTable.item(rowID, 0).setBackground(QtGui.QColor(r,g,b))
|
|
self.AuftragsdetailsTable.item(rowID, 1).setBackground(QtGui.QColor(r,g,b))
|
|
self.AuftragsdetailsTable.item(rowID, 2).setBackground(QtGui.QColor(r,g,b))
|
|
self.AuftragsdetailsTable.item(rowID, 3).setBackground(QtGui.QColor(r,g,b))
|
|
self.AuftragsdetailsTable.item(rowID, 4).setBackground(QtGui.QColor(r,g,b))
|
|
self.AuftragsdetailsTable.item(rowID, 5).setBackground(QtGui.QColor(r,g,b))
|
|
|
|
#wird hier vermutlich nicht mehr benötigt - wurde in die Workerklasse kopiert
|
|
def readWaage(self):
|
|
# in folgender Funktion wird die Waage ausgelesen
|
|
|
|
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
|
#print("port to which it is connected: ", ser.portstr) #Debuggingausgabe
|
|
self.checkPosNrEmpty()
|
|
|
|
if ser.is_open == False:
|
|
ser.open()
|
|
|
|
|
|
#an die Waage den Befehl senden, dass sie ausgelesen werden soll
|
|
ser.write(b'getWeight\n')
|
|
#ser.write(b'tare\n')
|
|
serialString = ser.readline().decode('utf-8').rstrip() #Auslesen des Serial-Strings/der Messung der Waage
|
|
|
|
# wenn am Ende des Strings kg steht, dann ist die Waage eingeschwungen - das wird hiermit überprüft
|
|
lenString = len(serialString)-1
|
|
if serialString[lenString] == "g" and serialString[lenString-1] == "k":
|
|
#print("ist eingeschwungen") #Debuggingausgabe
|
|
waageEingeschwungen = True
|
|
else:
|
|
print("die Waage ist noch nicht eingeschwungen")
|
|
waageEingeschwungen = False
|
|
|
|
#aus dem String werden alle Zeichen, welche nicht zur Darstellung der Zahl benötigt werden entfernt
|
|
intString = ""
|
|
for i in serialString:
|
|
if i=="-" or i=="0" or i=="." or i=="1" or i=="2" or i=="3" or i=="4" or i=="5" or i=="6" or i=="7" or i=="8" or i=="9":
|
|
intString = intString + i
|
|
print("Wert, welcher von der Waage ausgelesen wurde: " + intString + "kg")
|
|
## Waage auslesen - ENDE
|
|
|
|
ser.close()
|
|
#print("connection is open: ", ser.is_open) #Debuggingausgabe
|
|
|
|
return waageEingeschwungen, intString
|
|
|
|
def auftragsBtnClicked(self):
|
|
databaseQueryWorking = False #wird für die Überprüfung, ob die Datenbankabfrage fehlerhaft ist, verwendet
|
|
auftragEinzelteilDaten = []
|
|
|
|
self.setAuftragsnummer()
|
|
if(not self.checkAuftragsnummerEmpty()):
|
|
|
|
|
|
sql_query = "SELECT Auftraege.id, EinzelteilID, Auftragsnummer, Anzahl, Einzelteile.id, Bezeichnung, CAST(projectGeislinger.Einzelteile.GewichtMittelwert AS CHAR), CAST(projectGeislinger.Einzelteile.GewichtVarianz AS CHAR) FROM projectGeislinger.Auftraege, projectGeislinger.Einzelteile where projectGeislinger.Auftraege.EinzelteilID = projectGeislinger.Einzelteile.id AND projectGeislinger.Auftraege.Auftragsnummer = " + self.auftragsnummer
|
|
try:
|
|
cursor.execute(sql_query)
|
|
# Fetch results
|
|
auftragEinzelteilDaten = cursor.fetchall()
|
|
databaseQueryWorking = True
|
|
except:
|
|
print("Fehler in der Datenbankabfrage.")
|
|
|
|
|
|
|
|
if databaseQueryWorking==True and len(auftragEinzelteilDaten)>0:
|
|
'''
|
|
# Display data
|
|
print("Ausgabe der Auftragsdetails des obigen Auftrags, inklusive Einzelteildetails:")
|
|
for row in auftragEinzelteilDaten:
|
|
if str(row[2]) == self.auftragsnummer:
|
|
print("passt")
|
|
print(row)
|
|
'''
|
|
|
|
### die Auftragsdaten in die Tabelle laden
|
|
self.AuftragsdetailsTable.setRowCount(len(auftragEinzelteilDaten))
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
counter = 0
|
|
for row in auftragEinzelteilDaten:
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 0, self.item)
|
|
self.item.setText(str(row[1]))
|
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 1, self.item)
|
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 2, self.item)
|
|
self.item.setText(str(row[5]))
|
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 3, self.item)
|
|
self.item.setText(str(row[3]))
|
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 4, self.item)
|
|
self.item.setText(str("0"))
|
|
self.item = QtWidgets.QTableWidgetItem()
|
|
self.AuftragsdetailsTable.setItem(counter, 5, self.item)
|
|
self.item.setFlags(self.item.flags() & ~QtCore.Qt.ItemIsEditable)
|
|
counter = counter +1
|
|
|
|
elif(databaseQueryWorking==True and len(auftragEinzelteilDaten)==0):
|
|
print("Es wurde in der Datenbank kein Auftrag mit dieser Auftragsnummer gefunden.")
|
|
|
|
def stopLoopClicked(self):
|
|
# damit wird beim Klick auf den Stopbutton der stopLoop-boolWert in der Workerklasse auf true gesetzt -> der Stop des Threads wird initiiert
|
|
self.worker.stopLoopSignal.emit(True)
|
|
|
|
|
|
def checkWaage(self):
|
|
#print("Running in thread:", threading.current_thread().name) # Debuggingausgabe
|
|
|
|
QApplication.processEvents()
|
|
|
|
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
|
self.worker.stopLoopSignal.emit(False)
|
|
|
|
# überprüfen, ob ein Bauteiltyp gesetzt wurde
|
|
if(self.checkPosNrEmpty()==True):
|
|
print("Das Pos.-Nr.-Feld ist leer.")
|
|
return
|
|
|
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
|
print("Der Auftrag muss zuerst geladen werden.")
|
|
return
|
|
|
|
# den GUI Wert von Textfeld TeileZuViel in die Variable schreiben
|
|
self.teileZuViel = int(float(self.teileZuVielTxtFeld.toPlainText()))
|
|
self.teileZuVielTxtFeld.setText(str(self.teileZuViel))
|
|
|
|
#übernehmen der BauteilID aus dem Feld Pos.-Nr
|
|
einzelteilID = int(self.PosNrTxtFeld.toPlainText())
|
|
|
|
#zum setzen den Farbe der gesamten Reihe auf Orange
|
|
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
|
|
|
# den Thread starten, welcher die Bauteilanzahl überprüft
|
|
self.worker.checkWaageStartSignal.connect(self.worker.checkWaageThread)
|
|
self.worker.checkWaageUpdateSignal.connect(self.checkWaageUpdate)
|
|
self.worker.checkWaageFinishedSignal.connect(self.checkWaageFinished)
|
|
self.thread.started.connect(lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer))
|
|
self.thread.start()
|
|
|
|
def checkWaageUpdate(self, einzelteilID, anzahl):
|
|
# die Funktion updated die (vom Thread) berechnete Bauteilanzahl in der GUI
|
|
self.AuftragsdetailsTable.item(self.getRowNr(einzelteilID), 4).setText(str(anzahl)) # in die Tabelle die Anzahl an berechneten Bauteilen reinschreiben
|
|
|
|
|
|
def checkWaageFinished(self, einzelteilID):
|
|
self.setRowColor(self.getRowNr(einzelteilID),0,255,0) #zum setzen den Farbe der gesamten Reihe auf Grün
|
|
|
|
# den Thread beenden
|
|
self.thread.quit()
|
|
self.thread.wait()
|
|
try:
|
|
self.thread.started.disconnect(lambda: self.worker.checkWaageStartSignal.emit(einzelteilID, self.teileZuViel, self.auftragsnummer)) # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
|
print("Der Thread wurde beendet.")
|
|
except:
|
|
print("Disconnecting the thread did not work.") # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
|
|
|
# GUI updaten
|
|
#self.updateGUI()
|
|
|
|
def objectTypeDetection(self):
|
|
# in dieser Funktion wird der Typ des Bauteils automatisch erkannt
|
|
|
|
'''
|
|
if(self.checkPosNrEmpty()==True):
|
|
print("Das Pos.-Nr.-Feld ist leer.")
|
|
return
|
|
'''
|
|
|
|
# die Loopvariable des Workers auf False setzten, damit die Schleife durchgelaufen wird (diese wird zum Abbruch der Schleife benötigt -> siehe stopLoop)
|
|
self.worker.stopLoopSignal.emit(False)
|
|
|
|
# überprüfen, ob der Auftrag in die Tabelle geladen wurde
|
|
if(self.AuftragsdetailsTable.item(0,0) == None):
|
|
print("Der Auftrag muss zuerst geladen werden.")
|
|
return
|
|
|
|
# speichert den Wert, welcher im Textfeld steht in Variablen im Code
|
|
self.setAuftragsnummer()
|
|
|
|
# starten des Threats, welcher den Bauteiltyp zurück gibt
|
|
self.worker.objectDetectionStartSignal.connect(self.worker.objectTypeDetectionThread)
|
|
self.thread.started.connect(lambda: self.worker.objectDetectionStartSignal.emit(self.auftragsnummer))
|
|
self.thread.start()
|
|
|
|
def objectTypeDetectionFinished(self, einzelteilID, rowData):
|
|
# wenn der Typ des Objektes erkannt wurde, dann soll die Funktion aufgerufen werden
|
|
|
|
# Schreiben der Bauteiltype und Pos.-Nr in die jeweiligen Felder
|
|
self.PosNrTxtFeld.setText(str(rowData[1]))
|
|
self.bauteiltypTextbox.setText(rowData[2])
|
|
|
|
# setzt den Boolean, um aus der Schleife raus zu gehen
|
|
self.btTypeIsSet = True
|
|
|
|
#zum setzen den Farbe der gesamten Reihe auf Orange
|
|
self.setRowColor(self.getRowNr(einzelteilID),255,165,0)
|
|
|
|
# den Thread beenden
|
|
self.thread.quit()
|
|
self.thread.wait()
|
|
try:
|
|
self.thread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
|
except:
|
|
print("Disconnecting the thread did not work.")
|
|
|
|
# wenn der Bauteiltyp erkannt wurde, dann soll die GUI aktualisiert werden und anschließend die CheckWaage-Funktion aufgerufen werden
|
|
self.updateGUI()
|
|
self.checkWaage()
|
|
|
|
def threadStopped(self, einzelteilID):
|
|
# wenn kein Bauteil erkannt wurde, dann ist die EinzenteilID = 0
|
|
if(einzelteilID > 0):
|
|
self.setRowColor(self.getRowNr(einzelteilID),255,255,255) #zum setzen den Farbe der gesamten Reihe auf Weiß
|
|
|
|
# den Thread beenden
|
|
self.thread.quit()
|
|
self.thread.wait()
|
|
try:
|
|
self.thread.started.disconnect() # Trenne das Signal, damit es beim nächsten Start keine Konflikte gibt
|
|
print("Der Thread wurde beendet.")
|
|
except:
|
|
print("Disconnecting the thread did not work.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
app = QtWidgets.QApplication(sys.argv)
|
|
MainWindow = QtWidgets.QMainWindow()
|
|
ui = Ui_MainWindow()
|
|
ui.setupUi(MainWindow)
|
|
MainWindow.show()
|
|
sys.exit(app.exec_())
|
|
|
|
|
|
|
|
|
|
|