diff --git a/README.md b/README.md index fd9de8a..f609460 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # jfsCounter GUI für den jfsESP_counter + ` s1000 sets timebase to 1ms o10000 sets output to 10kHz output is >Value<\n in Hertz diff --git a/counter.py b/counter.py new file mode 100644 index 0000000..aaf034e --- /dev/null +++ b/counter.py @@ -0,0 +1,255 @@ +from PyQt5 import QtCore, QtWidgets, QtGui +from PyQt5.QtWidgets import QMainWindow, QApplication +import sys,time,os +import serial +from serial.tools.list_ports import comports +import glob +import pyqtgraph as pg +import traceback +import gui + +class MainWindow(QtWidgets.QMainWindow,gui.Ui_MainWindow): + def __init__(self): + super(MainWindow,self).__init__() + self.ui = gui.Ui_MainWindow() + self.ui.setupUi(self) + ## Plotwindow + self.x = [] + self.y = [] + self.grafwd = pg.PlotWidget() + self.ui.gridLayout_3.addWidget(self.grafwd,0,1,1,1) + self.data_line = self.grafwd.plot(self.x,self.y, pen=(0,255,0)) + ## Threads + self.timebase = 50 + self.thdx ={} + self.threadpool = QtCore.QThreadPool() + ## serial + self.populate_ports() + ## gui + self.ui.pushButton.pressed.connect(self.connect2board) + self.ui.pushButton_2.pressed.connect(self.disconnect2board) + self.ui.pushButton_3.pressed.connect(self.startesp32) + self.ui.pushButton_4.pressed.connect(self.stopesp32) + self.ui.pushButton_5.pressed.connect(self.clearPlot) + self.ui.pushButton_6.pressed.connect(self.setFrequency) + times = ['1','5','10','50','100','500','10000'] + self.ui.comboBox_2.addItems(times) + self.ui.comboBox_2.setCurrentText(str(self.timebase)) + self.ui.comboBox_2.currentIndexChanged['QString'].connect(self.setTimebase) + self.ui.checkBox.stateChanged.connect(self.testLauf) + + self.closeButtons() + ### Link zur Doku + #self.webEngineView.setUrl(QtCore.QUrl("file:///C:/Users/jens/ownCloud/www/jfs/git2022/jfsPoseidon/test.html")) + file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "doku\\testMd.html")) + file_path = file_path.replace("\\",'/') + file_path = 'file:///'+file_path + self.ui.webEngineView.setUrl(QtCore.QUrl(file_path)) + # Populate the available ports + def populate_ports(self): + result = [] + for port in comports(): + result.append(port.name) + self.ui.comboBox.addItems(result) + self.globports = result + print("Ports have been populated.",self.globports) + + def setTimebase(self): + self.timebase=int(self.ui.comboBox_2.currentText()) + + def closeButtons(self): + self.ui.pushButton.setEnabled(True) + self.ui.pushButton_2.setEnabled(False) + self.ui.pushButton_3.setEnabled(False) + self.ui.pushButton_4.setEnabled(False) + self.ui.pushButton_5.setEnabled(False) + self.ui.pushButton_6.setEnabled(False) + self.ui.checkBox.setEnabled(False) + + def openButtons(self): + self.ui.pushButton.setEnabled(False) + self.ui.pushButton_2.setEnabled(True) + self.ui.pushButton_3.setEnabled(True) + #self.ui.pushButton_4.setEnabled(True) + self.ui.pushButton_5.setEnabled(True) + self.ui.pushButton_6.setEnabled(True) + self.ui.checkBox.setEnabled(True) + + def connect2board(self): + self.esp32_port = self.ui.comboBox.currentText() + self.statusBar().showMessage("You clicked CONNECT TO Esp32") + try: + port_declared = self.esp32_port in vars() + try: + print("connect to .. ",self.esp32_port) + self.esp32_serial = serial.Serial() + self.esp32_serial.port = self.esp32_port + self.esp32_serial.baudrate = 115200 + self.esp32_serial.parity = serial.PARITY_NONE + self.esp32_serial.stopbits = serial.STOPBITS_ONE + self.esp32_serial.bytesize = serial.EIGHTBITS + self.esp32_serial.timeout = 1 + self.esp32_serial.open() + self.openButtons() + time.sleep(0.1) + self.statusBar().showMessage("Successfully connected to esp32 board.") + except: + self.statusBar().showMessage("Cannot connect to board. Try again..") + except AttributeError: + self.statusBar().showMessage("Please plug in the board and select a proper port, then press connect.") + + def disconnect2board(self): + self.statusBar().showMessage("You clicked DISCONNECT FROM ESP32") + print("Disconnecting from board..") + time.sleep(0.1) + self.esp32_serial.close() + self.closeButtons() + print("Board has been disconnected") + + def startesp32(self): + self.clearPlot() + self.thdx[0]= ThC(index=1,port = self.esp32_serial,base=self.timebase) + self.threadpool.start(self.thdx[0]) + self.thdx[0].signals.datasignal.connect(self.updateData) + self.ui.pushButton_3.setEnabled(False) + self.ui.pushButton_4.setEnabled(True) + self.ui.comboBox_2.setEnabled(False) + + def stopesp32(self): + self.thdx[0].stop() + self.ui.pushButton_3.setEnabled(True) + self.ui.pushButton_4.setEnabled(False) + self.ui.comboBox_2.setEnabled(True) + + def updateData(self,x,y): + self.x.append(x) + self.y.append(y) + self.data_line.setData(self.x,self.y) + + def clearPlot(self): + self.x.clear() + self.y.clear() + self.data_line.setData(self.x,self.y) + + def setFrequency(self): + s = self.ui.lineEdit.text() + cmd='o'+str(s)+'\n' + self.statusBar().showMessage(cmd) + thread = Thread(self.sendToEsp32, cmd) + thread.signals.finished.connect(lambda:self.thread_finished(thread)) + self.threadpool.start(thread) + + def sendToEsp32(self, sendStr): + print(f" sending {sendStr}") + self.esp32_serial.write(sendStr.encode('utf-8')) + self.esp32_serial.flushInput() + + def testLauf(self,state): + if state == QtCore.Qt.Checked: + self.thdx[1] = ThC_2(port = self.esp32_serial) + self.threadpool.start(self.thdx[1]) + else: + self.thdx[1].stop() + + def thread_finished(self, th): + print("Your thread has completed. Now terminating..") + th.stop() + print("Thread has been terminated.") + print("=============================\n\n") + + +############################### +# MULTITHREADING : SIGNALS CLASS +# ############################## +class WorkerSignals(QtCore.QObject): + finished = QtCore.pyqtSignal() + error = QtCore.pyqtSignal(tuple) + result = QtCore.pyqtSignal(object) + progress = QtCore.pyqtSignal(int) + datasignal = QtCore.pyqtSignal(int,float) + +class Thread(QtCore.QRunnable): + def __init__(self, fn, *args, **kwargs): + super().__init__() + self.runs = True + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals = WorkerSignals() + def run(self): + try: + result = self.fn(*self.args, **self.kwargs) + except: + traceback.print_exc() + exctype, value = sys.exc_info()[:2] + self.signals.error.emit((exctype, value, traceback.format_exc())) + else: + self.signals.result.emit(result) # Return the result of the processing + finally: + self.signals.finished.emit() + self.stop() + def stop(self): + self.runs = False + +class ThC(QtCore.QRunnable): + #datasignal = QtCore.pyqtSignal(int,float) + def __init__(self,port=None,index=0,base=100): + super().__init__() + self.index = index + self.is_running = True + self.port = port + self.base = base + self.signals = WorkerSignals() + def run(self): + print(f"Thread {self.index} started") + self.port.flushOutput() + self.port.flushInput() + i = self.base*1000 + cmd = 's'+str(i)+'\n' + self.port.write(cmd.encode('utf-8')) + cnt = 0; + while True: + cnt+=1 + inp = self.port.readline() + try: + if inp[0] == 62 and inp[-3] == 60 : + inp = inp[1:-3] + try: + y = float(inp.decode('utf-8')) + self.signals.datasignal.emit(cnt,y) + except ValueError: + pass + except IndexError: + pass + time.sleep(0.001) + if self.is_running==False: + break + def stop(self): + self.is_running=False + print(f"Thread {self.index} stopped") + +class ThC_2(QtCore.QRunnable): + def __init__(self,port=None): + super().__init__() + self.is_running = True + self.port=port + def run(self): + cnt=0 + while True: + cnt+= 1 + if cnt >= 100 : cnt = 1 + cmd = 'o'+str(cnt*10000)+'\n' + print(cmd) + self.port.write(cmd.encode('utf-8')) + time.sleep(1) + if self.is_running==False: + break + def stop(self): + self.is_running=False + print(f'Thread ThC-2 stopped') + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/counter.ui b/counter.ui new file mode 100644 index 0000000..4ce3b9e --- /dev/null +++ b/counter.ui @@ -0,0 +1,195 @@ + + + MainWindow + + + + 0 + 0 + 1260 + 871 + + + + MainWindow + + + + + + + 1 + + + + Counter + + + + + + + + + + Port + + + + + + + + + + open Port + + + + + + + close Port + + + + + + + Timebase [ms] + + + + + + + + + + start + + + + + + + stop + + + + + + + clear Display + + + + + + + + + + + set Frequency + + + + + + + + + + Testlauf + + + + + + + on + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Doku + + + + + + + about:blank + + + + + + + + + + + + + + 0 + 0 + 1260 + 26 + + + + + + + + QWebEngineView + QWidget +
QtWebEngineWidgets/QWebEngineView
+
+
+ + +
diff --git a/doku/jens.jpg b/doku/jens.jpg new file mode 100644 index 0000000..7de168a Binary files /dev/null and b/doku/jens.jpg differ diff --git a/doku/testMd.html b/doku/testMd.html new file mode 100644 index 0000000..f5bbf17 --- /dev/null +++ b/doku/testMd.html @@ -0,0 +1,48 @@ +

Erster Test

+
    +
  1. lets go
  2. +
  3. oder was
  4. +
  5. naja
  6. +
+
+ +
+
+
+

Aufbau

+ +
+
+ +

Abbau

+
+
This is a python THing
+lets do it now
+
+

ok in an imperial way then

+

I Love My science

+

Entwicklung

+
- [ ] Juni 2022
+- [ ] This creates an Environment for the Software based on 
+- [ ] poseidon https://github.com/pachterlab/poseidon
+- [ ] PyQtGraph https://www.pyqtgraph.org/
+
+conda create --name piPyGra
+conda activate piPyGra
+conda install -c conda-forge pyqtgraph
+conda install pyserial
+pip install pyinstaller pyqt5
+pip install PyQtWebEngine
+.... work ... 
+conda deactivate
+
+conda activate PiPyGra
+Ananconda prompt designer
+pyuic5 -x gui2.ui -o gui2.py
+
+
+ \ No newline at end of file diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..30587d1 --- /dev/null +++ b/gui.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'counter.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# 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. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1260, 871) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout_6 = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout_6.setObjectName("gridLayout_6") + self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.gridLayout_5 = QtWidgets.QGridLayout(self.tab) + self.gridLayout_5.setObjectName("gridLayout_5") + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setObjectName("gridLayout_4") + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setObjectName("gridLayout") + self.label = QtWidgets.QLabel(self.tab) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.comboBox = QtWidgets.QComboBox(self.tab) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1) + self.pushButton = QtWidgets.QPushButton(self.tab) + self.pushButton.setObjectName("pushButton") + self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1) + self.pushButton_2 = QtWidgets.QPushButton(self.tab) + self.pushButton_2.setObjectName("pushButton_2") + self.gridLayout.addWidget(self.pushButton_2, 0, 3, 1, 1) + self.label_2 = QtWidgets.QLabel(self.tab) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 4, 1, 1) + self.comboBox_2 = QtWidgets.QComboBox(self.tab) + self.comboBox_2.setObjectName("comboBox_2") + self.gridLayout.addWidget(self.comboBox_2, 0, 5, 1, 1) + self.pushButton_3 = QtWidgets.QPushButton(self.tab) + self.pushButton_3.setObjectName("pushButton_3") + self.gridLayout.addWidget(self.pushButton_3, 0, 6, 1, 1) + self.pushButton_4 = QtWidgets.QPushButton(self.tab) + self.pushButton_4.setObjectName("pushButton_4") + self.gridLayout.addWidget(self.pushButton_4, 0, 7, 1, 1) + self.pushButton_5 = QtWidgets.QPushButton(self.tab) + self.pushButton_5.setObjectName("pushButton_5") + self.gridLayout.addWidget(self.pushButton_5, 0, 8, 1, 1) + self.gridLayout_4.addLayout(self.gridLayout, 0, 0, 1, 1) + self.gridLayout_2 = QtWidgets.QGridLayout() + self.gridLayout_2.setObjectName("gridLayout_2") + self.pushButton_6 = QtWidgets.QPushButton(self.tab) + self.pushButton_6.setObjectName("pushButton_6") + self.gridLayout_2.addWidget(self.pushButton_6, 0, 0, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(self.tab) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout_2.addWidget(self.lineEdit, 0, 1, 1, 1) + self.label_3 = QtWidgets.QLabel(self.tab) + self.label_3.setObjectName("label_3") + self.gridLayout_2.addWidget(self.label_3, 0, 2, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.tab) + self.checkBox.setObjectName("checkBox") + self.gridLayout_2.addWidget(self.checkBox, 0, 3, 1, 1) + self.gridLayout_4.addLayout(self.gridLayout_2, 0, 1, 1, 1) + self.gridLayout_5.addLayout(self.gridLayout_4, 0, 0, 1, 1) + self.gridLayout_3 = QtWidgets.QGridLayout() + self.gridLayout_3.setObjectName("gridLayout_3") + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem, 0, 0, 1, 1) + self.widget = QtWidgets.QWidget(self.tab) + self.widget.setObjectName("widget") + self.gridLayout_3.addWidget(self.widget, 0, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem1, 1, 1, 1, 1) + self.gridLayout_5.addLayout(self.gridLayout_3, 1, 0, 1, 1) + self.tabWidget.addTab(self.tab, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.verticalLayout = QtWidgets.QVBoxLayout(self.tab_2) + self.verticalLayout.setObjectName("verticalLayout") + self.webEngineView = QtWebEngineWidgets.QWebEngineView(self.tab_2) + self.webEngineView.setUrl(QtCore.QUrl("about:blank")) + self.webEngineView.setObjectName("webEngineView") + self.verticalLayout.addWidget(self.webEngineView) + self.tabWidget.addTab(self.tab_2, "") + self.gridLayout_6.addWidget(self.tabWidget, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1260, 26)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(1) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.label.setText(_translate("MainWindow", "Port")) + self.pushButton.setText(_translate("MainWindow", "open Port")) + self.pushButton_2.setText(_translate("MainWindow", "close Port")) + self.label_2.setText(_translate("MainWindow", "Timebase [ms]")) + self.pushButton_3.setText(_translate("MainWindow", "start")) + self.pushButton_4.setText(_translate("MainWindow", "stop")) + self.pushButton_5.setText(_translate("MainWindow", "clear Display")) + self.pushButton_6.setText(_translate("MainWindow", "set Frequency")) + self.label_3.setText(_translate("MainWindow", "Testlauf")) + self.checkBox.setText(_translate("MainWindow", "on")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Counter")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Doku")) +from PyQt5 import QtWebEngineWidgets + + +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_())