From 09497cfb61cda1c990b82ac8835d285b4f3f7c05 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 18 Jun 2020 10:04:59 +0530 Subject: [PATCH] Features like GUI, PLotting graph and saving the output results in the form of CSV has been added --- .idea/.gitignore | 8 + .idea/inspectionProfiles/Project_Default.xml | 12 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/speedtest-gui.iml | 8 + .idea/vcs.xml | 6 + requirements.txt | 4 + speedtestGUI.py | 328 ++++++++++++++++++ tests/speedtestGUI.py | 0 10 files changed, 387 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/speedtest-gui.iml create mode 100644 .idea/vcs.xml create mode 100644 requirements.txt create mode 100644 speedtestGUI.py create mode 100644 tests/speedtestGUI.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..ab097a6 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d2c7008 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7f9c486 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/speedtest-gui.iml b/.idea/speedtest-gui.iml new file mode 100644 index 0000000..4e6ce24 --- /dev/null +++ b/.idea/speedtest-gui.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..aad11c6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +setuptools~=47.1.1 +numpy~=1.18.5 +matplotlib~=3.2.1 +PyQt5~=5.15.0 \ No newline at end of file diff --git a/speedtestGUI.py b/speedtestGUI.py new file mode 100644 index 0000000..b9656d8 --- /dev/null +++ b/speedtestGUI.py @@ -0,0 +1,328 @@ +import csv +import codecs +import time +import os +import numpy as np #importing the python libraries +from PyQt5.QtCore import QFile +from PyQt5.QtCore import QFileInfo +from PyQt5.QtCore import QPoint +from PyQt5.QtCore import QRect +from PyQt5.QtCore import QSettings +from PyQt5.QtCore import QSize +from PyQt5.QtCore import Qt +from PyQt5.QtCore import QTextStream +from PyQt5.QtCore import QProcess +from PyQt5.QtCore import QDir +from PyQt5.QtGui import QIcon +from PyQt5.QtGui import QFont +from PyQt5.QtWidgets import QAction +from PyQt5.QtWidgets import QApplication +from PyQt5.QtWidgets import QMainWindow +from PyQt5.QtWidgets import QTableWidget +from PyQt5.QtWidgets import QTableWidgetItem +from PyQt5.QtWidgets import QComboBox +from PyQt5.QtWidgets import QAbstractItemView +import matplotlib.pyplot as plt; +#importing the pyqt5 and matplotlib libraries on project +plt.rcdefaults() + + +class Homepage(QMainWindow): + def __init__(self): + super(Homepage, self).__init__() + + self.path = QDir('C:/Speedtest_Save') + if not QDir.exists(self.path): + print("Folder is not Exisiting! Please Wait till it create New.......") #if the folder doesn't exist it throws error message + dir = QDir() + newfolder = 'C:/SpeedTest_Save' #Creating the new folder + dir.mkpath(newfolder) + self.myfile = 'C:/SpeedTest_Save' + '/Speedtest_results.csv' #saving the file + self.isChanged = False + self.setStyleSheet(design(self)) + self.speedtestExec = "C:/Users/jagan/speedtest-cli.exe" #executable file path for the speedtest + + self.cmd = '' + print("Cmd started") + self.list = [] + print("list started") + self.date = "" + print("date started") + self.time = "" + print("time started") + self.download = "" + print("download started") + self.upload = "" + print("upload started") + self.ping = "" + print("Ping started") + self.server = "" + print("Server started") + self.process = QProcess(self) + print("Process Started") + + self.process.started.connect(lambda: self.showMessage("Speed Test Has Been Started")) #showing the test messages + print("Test Started") + + print("Test Completed") + self.process.finished.connect(self.processFinished) + self.process.readyRead.connect(self.processOut) + + self.tableview = QTableWidget() + print("Table creation success") + self.tableview.setColumnCount(6) + print("Process Started") + self.setHeaders() + print("Process Started for the headers") + self.tableview.verticalHeader().setVisible(False) + print("Process Started") + self.tableview.horizontalHeader().setVisible(False) + print("Process Started") + self.tableview.setSelectionBehavior(QAbstractItemView.SelectRows) + print("Process Started") + self.setCentralWidget(self.tableview) + self.setWindowIcon(QIcon.fromTheme('network')) + self.toolbarcreation() + self.createStatusBar() + + self.readSettings() + print("read setting started") + + self.combofillbox() + self.title = "frame" + self.setMinimumSize(440, 220) + + def displaychartdownload(self): #Ploting the download graph + data = [] + for row in range(self.tableview.rowCount()): + data.append(float(self.tableview.item(row, 2).text())) + print(data) + performance = data + y_pos = np.arange(len(performance)) + plt.bar(y_pos, performance, align='center', alpha=0.5) + plt.xticks(y_pos, "") + plt.ylabel('Mbit/s') + plt.title('Speed Test Chart - Download') + plt.show() + + def displaychartupload(self): #plotting the upload chart + plt.rcParams['toolbar'] = 'None' + data = [] + for row in range(self.tableview.rowCount()): + data.append(float(self.tableview.item(row, 3).text())) + print(data) + performance = data + y_pos = np.arange(len(performance)) + plt.bar(y_pos, performance, align='center', alpha=0.5) + plt.xticks(y_pos, "") + plt.ylabel('Mbit/s') + plt.title('Speed Test Chart - Upload') + plt.tight_layout() + plt.show() + + def combofillbox(self): #creating a toolbar function + plt.rcParams['toolbar'] = 'None' + cmd = self.speedtestExec + " --list" #speedtest executable file + serverlist = [] + myprocess = QProcess() + myprocess.start(cmd) + myprocess.waitForFinished(-1) + output = str(myprocess.readAll(), encoding='utf8').rstrip() + serverlist.append(output) + out = ','.join(serverlist) + out = out.partition("Retrieving speedtest.net configuration...")[2] #Retreieving the speedtest configurations + out = out.partition('\n')[2] + mylist = out.rsplit('\n') + self.combo.addItem("auto") + self.combo.addItems(mylist) + self.combo.setCurrentIndex(1) + + def setHeaders(self): #setting width of the column + self.tableview.horizontalHeader().setVisible(False) + font = QFont() + font.setPointSize(8) + self.tableview.horizontalHeader().setFont(font) #setting the table view + self.tableview.setColumnWidth(0, 80) + self.tableview.setColumnWidth(1, 60) + self.tableview.setColumnWidth(2, 70) + self.tableview.setColumnWidth(3, 60) + self.tableview.setColumnWidth(4, 60) + self.tableview.setColumnWidth(5, 100) + self.tableview.setHorizontalHeaderItem(0, QTableWidgetItem("Date")) + self.tableview.setHorizontalHeaderItem(1, QTableWidgetItem("Time")) + self.tableview.setHorizontalHeaderItem(2, QTableWidgetItem("Download")) + self.tableview.setHorizontalHeaderItem(3, QTableWidgetItem("Upload")) + self.tableview.setHorizontalHeaderItem(4, QTableWidgetItem("Ping")) + self.tableview.setHorizontalHeaderItem(5, QTableWidgetItem("Server")) + + def showMessage(self, message): #displaying the status bar message + self.statusBar().showMessage(message) + + def closeEvent(self, event): #saving the Output file on CSV + self.writeSettings() + if self.isChanged == True: + self.createCSV() + event.accept() + + def createActions(self): + root = QFileInfo(__file__).absolutePath() + + def toolbarcreation(self): #creating the frames + self.tb = self.addToolBar("File") + self.title = "PyQt5 Frame" + self.tb.setMovable(False) + self.testAct = QAction(QIcon.fromTheme('media-playback-start'), "Start", self, + statusTip="Speed Test Has Been Started", + triggered=self.startTest) + self.tb.addAction(self.testAct) + self.combo = QComboBox() + self.combo.setFixedWidth(400) + self.tb.addWidget(self.combo) + self.chartActD = QAction(QIcon.fromTheme('chart'), "Graph For Download Speed", self, + statusTip="show Chart", + triggered=self.displaychartdownload) + self.tb.addAction(self.chartActD) + self.chartActU = QAction(QIcon.fromTheme('chart'), "Graph for Upload Speed", self, + statusTip="show Chart", + triggered=self.displaychartupload) + self.tb.addAction(self.chartActU) + + def startTest(self): #Starting the speedtest + self.started = time.time() + self.list = [] + self.date = "" + self.time = "" + self.download = "" + self.upload = "" + self.ping = "" + self.server = "" + if self.combo.currentText() == "automatic_server": + print("automatic_server Started") + self.cmd = self.speedtestExec + else: + myserver = self.combo.currentText().partition(")")[0] + self.cmd = self.speedtestExec + " --server " + myserver + print("Speed Test started *** " + self.cmd) + if QFile.exists(self.speedtestExec): + self.process.start(self.cmd) + else: + self.showMessage("Connection to the server is not reachable") + + def createStatusBar(self): + self.showMessage("Ready") #Alert Message + + def readSettings(self): #read settings + settings = QSettings("cambria", "SpeedTest") #Font selection + pos = settings.value("pos", QPoint(200, 200)) + size = settings.value("size", QSize(400, 400)) + self.resize(size) + self.move(pos) + + def writeSettings(self): #write settings + settings = QSettings("cambria", "SpeedTest") + settings.setValue("pos", self.pos()) + settings.setValue("size", self.size()) + + def addRow(self): #adding the row and setting its date and time + row = self.tableview.rowCount() + newItem = QTableWidgetItem(time.strftime('%d.%m.%Y')) + self.tableview.insertRow(row) + self.tableview.horizontalHeader().setStretchLastSection(True) + column = 0 + self.tableview.setItem(row, column, newItem) + newItem = QTableWidgetItem(time.strftime('%H:%M')) + column = 1 + self.tableview.setItem(row, column, newItem) + newItem = QTableWidgetItem(self.download) + column = 2 + self.tableview.setItem(row, column, newItem) + newItem = QTableWidgetItem(self.upload) + column = 3 + self.tableview.setItem(row, column, newItem) + newItem = QTableWidgetItem(self.ping) + column = 4 + self.tableview.setItem(row, column, newItem) + newItem = QTableWidgetItem(self.server) + column = 5 + self.tableview.setItem(row, column, newItem) + self.isChanged = True + last = self.tableview.rowCount() - 1 + self.tableview.selectRow(last) + self.ended = time.time() - self.started + m, s = divmod(time.time() - self.started, 60) + h, m = divmod(m, 60) + time_str = "%02d:%02d" % (m, s) + print('Operation completed in', time_str) + self.tableview.resizeRowsToContents() + self.showMessage('Speed Test completed in ' + time_str) + + def processOut(self): + try: + output = str(self.process.readAll(), encoding='utf8').rstrip() + except Error: + output = str(self.process.readAll()).rstrip() + self.list.append(output) + + def processFinished(self): + out = ','.join(self.list) + self.download = out.partition("Download: ")[2] + self.download = self.download.partition(' Mbit/s')[0] + + self.upload = out.partition("Upload: ")[2] + self.upload = self.upload.partition(' Mbit/s')[0] + + self.ping = out.partition("km]: ")[2] + self.ping = self.ping.partition(' ms')[0] + self.ping = self.ping.partition('.')[0] + + self.server = out.partition("Hosted by ")[2] + self.server = self.server.partition(' [')[0] + + self.addRow() + + def createCSV(self): #Saving and writting the data in CSV + with open(self.myfile, 'w') as stream: + print("saving", self.myfile) + writer = csv.writer(stream, delimiter='\t') + for row in range(self.tableview.rowCount()): + rowdata = [] + for column in range(self.tableview.columnCount()): + item = self.tableview.item(row, column) + if item is not None: + rowdata.append(item.text()) + else: + rowdata.append('') + writer.writerow(rowdata) + self.isChanged = False + + +def design(self): #Designing the font and background + self.title = "PyQt5 Frame" + return """ + QTableWidget + { + border: 1px solid grey; + border-radius: 0px; + font-family: arial; + font-size: 10pt; + background-color: #ebebeb; + selection-color: violet + } + + + QTableWidget::item:selected + { + color: #F4F4F4; + background: qlineargradient(x1:0, y1:0, x1:2, y1:2, stop:0 #bfc3fb, stop:1 #324864); + } + """ + + +if __name__ == '__main__': + import sys + + app = QApplication(sys.argv) + + mainWin = Homepage() + mainWin.show() + sys.exit(app.exec_()) diff --git a/tests/speedtestGUI.py b/tests/speedtestGUI.py new file mode 100644 index 0000000..e69de29