diff --git a/src/Connect_DLT.py b/src/Connect_DLT.py index f11f044..bdedd72 100755 --- a/src/Connect_DLT.py +++ b/src/Connect_DLT.py @@ -13,7 +13,6 @@ def __init__(self,file_path,project_file,output_dir): self.file_path = file_path self.file_name ='' print(self.file_path) - print("out put dire is==" +self.outDIR) self.cleaner() def cleaner(self): try: @@ -49,16 +48,14 @@ def convert_dlt_log_text(self): temp_file = os.listdir(self.file_path) print(temp_file[0]) try: - - self.file_name=f'{self.outDIR}/traceLog{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt' + self.file_name=f'{self.outDIR}/traceLog.txt' process = subprocess.run(["dlt_viewer","-c",f'C:/Users/{getpass.getuser()}/AppData/Local/dlt_viewer/cache/{temp_file[0]}',self.file_name],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) - - except Exception as e: print(e) def get_cpu(self): Get_data_from_DLT.Get_data.monitor_cpu_mem() + def check(self,uttearnce): Get_data_from_DLT.Get_data(self.file_name,utterance=uttearnce) diff --git a/src/Get_cpu_usage.py b/src/Get_cpu_usage.py deleted file mode 100644 index ca114d2..0000000 --- a/src/Get_cpu_usage.py +++ /dev/null @@ -1,53 +0,0 @@ - - -import subprocess -import re -import time as t - -def calculate_cpu_usage(log_line): - # Extract the total CPU and idle values - total_cpu_match = re.search(r'(\d+)%cpu', log_line) - idle_match = re.search(r'(\d+)%idle', log_line) - - if not total_cpu_match or not idle_match: - raise ValueError("Log line does not contain expected CPU or idle values.") - - total_cpu = int(total_cpu_match.group(1)) - idle = int(idle_match.group(1)) - - # Calculate CPU usage - usage = total_cpu - idle - usage=float(usage//8) # This sysytem have 8 core - print(usage) - - -def monitor_cpu_mem(): - process = subprocess.Popen( - ["adb", "shell", "top", "-d", "1"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - - - try: - for line in process.stdout: - # Match CPU usage line - if re.search(r'\d+%cpu', line): - # print("CPU:", line.strip()) - calculate_cpu_usage(line.strip()) - - - # Match Memory usage line - elif re.search(r'Mem:', line) or re.search(r'Swap:', line): - # print("Memory:", line.strip()) - process.terminate() - except KeyboardInterrupt: - process.terminate() - print("Stopped monitoring.") - finally: - process.stdout.close() - - -if __name__ == "__main__": - print(monitor_cpu_mem()) \ No newline at end of file diff --git a/src/Sample_Test_GUI.py b/src/Sample_Test_GUI.py deleted file mode 100644 index c7a5272..0000000 --- a/src/Sample_Test_GUI.py +++ /dev/null @@ -1,265 +0,0 @@ - -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtWidgets import * -from PyQt5.QtGui import QMovie -import os -import sys -from gtts import gTTS -import speech_recognition as sr -import pandas as pd -import subprocess -import signal -import platform -import time as t -import pyttsx3 -import TTS_main - - -cols = [0] -filename = '' -class Ui_MainWindow(object): - filename = '' - def setupUi(self, MainWindow): - MainWindow.setObjectName("MainWindow") - MainWindow.resize(446, 423) - self.centralwidget = QtWidgets.QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - self.centralwidget.setStyleSheet("background-color: #272e2a") - self.Speak_button = QtWidgets.QPushButton(self.centralwidget) - self.Speak_button.setGeometry(QtCore.QRect(360, 330, 81, 31)) - self.Speak_button.setObjectName("Speak_button") - self.Speak_button.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#01ff01")) - self.Input = QtWidgets.QPlainTextEdit(self.centralwidget) - self.Input.setGeometry(QtCore.QRect(0, 330, 351, 31)) - self.Input.setPlaceholderText("") - self.Input.setObjectName("Input") - self.Input.setStyleSheet("background-color: #545755") - self.anim = QtWidgets.QLabel(self.centralwidget) - self.anim.setGeometry(QtCore.QRect(70, 10, 431, 231)) - self.anim.setObjectName("anim") - self.movie = QMovie("ld.gif") - self.anim.setMovie(self.movie) - self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_2.setGeometry(QtCore.QRect(0, 270, 191, 27)) - self.pushButton_2.setObjectName("FileSlector") - self.pushButton_2.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#08c6f5")) - self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_3.setGeometry(QtCore.QRect(250, 270, 91, 27)) - self.pushButton_3.setObjectName("pushButton_3") - self.pushButton_3.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#01ff01")) - self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_4.setGeometry(QtCore.QRect(350, 270, 91, 27)) - self.pushButton_4.setObjectName("pushButton_4") - self.pushButton_4.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#ff0000")) - self.label = QtWidgets.QLabel(self.centralwidget) - self.label.setGeometry(QtCore.QRect(0, 300, 431, 20)) - self.label.setStyleSheet("color :#ffffff") - font = QtGui.QFont() - font.setPointSize(11) - self.label.setFont(font) - self.label.setObjectName("label") - MainWindow.setCentralWidget(self.centralwidget) - self.statusbar = QtWidgets.QStatusBar(MainWindow) - self.statusbar.setObjectName("statusbar") - MainWindow.setStatusBar(self.statusbar) - self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 24)) - self.menubar.setObjectName("menubar") - MainWindow.setMenuBar(self.menubar) - self.retranslateUi(MainWindow) - self.pushButton_2.clicked.connect(self.file) - self.Speak_button.clicked.connect(self.speak) - self.pushButton_3.clicked.connect(self.start_btn) - self.pushButton_4.clicked.connect(self.exit) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.Speak_button.setText(_translate("MainWindow", "Speak")) - self.pushButton_2.setText(_translate("MainWindow", "Select File")) - self.pushButton_3.setText(_translate("MainWindow", "Start")) - self.pushButton_4.setText(_translate("MainWindow", "stop")) - self.label.setText(_translate("MainWindow", "selected file:")) - - def animation_area(self): - self.movie.start() - - def file(self): - file_dialog = QFileDialog() - file_dialog.setWindowTitle("Open File") - file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile) - file_dialog.setViewMode(QFileDialog.ViewMode.Detail) - if file_dialog.exec(): - selected_files = file_dialog.selectedFiles() - print("Selected File:", selected_files[0]) - self.filename = selected_files[0] - self.label.setText(selected_files[0]) - print(self.filename) - def start_btn(self): - if self.filename.endswith('xlsx' or 'xls'): - print("excel file found") - else: - self.warn(mesg="No file selected") - return - syestem = platform.system() - print(syestem) - # try: - # while subprocess.check_output(["fuser",self.filename], text=True): - # check_st(filename=self.filename,system=syestem) - # except subprocess.CalledProcessError: - # print("File is not open by any process. Proceeding.") - - file_iteration(filename=self.filename) - def exit(self): - sys.exit() - def speak(self): - text = self.Input.toPlainText() - if text == '': - self.warn(mesg="Enter some text to continue") - return - self.animation_area() - tts_converter(text) - self.Input.clear() - # listen() - def warn(self,mesg): - msg = QMessageBox() - msg.setIcon(QMessageBox.Warning) - msg.setText(mesg) - msg.setWindowTitle('Warning') - msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) - msg.exec_() - -def tts_converter(command): - engine = pyttsx3.init() - engine.setProperty("rate", 150) - engine.say(command) - engine.runAndWait() - - -def listen(): - print("\033[1m\033[33;32m[-]audio played , listening now . . .") - recognizer = sr.Recognizer() - converted_text = "Empty" - # for index,name in enumerate(sr.Microphone.list_microphone_names()): - # print(f"{index} , {name}") - with sr.Microphone(device_index=4)as inputsource: - print("\033[1m\033[33;32m[+]listening for audio...") - recognizer.adjust_for_ambient_noise(inputsource,duration=.5) - voiceinput = recognizer.record(inputsource,duration=10) - try: - converted_text = recognizer.recognize_google(voiceinput) - print("\033[1m\033[33;32m[+]user said ,",converted_text) - except KeyboardInterrupt: - print("\033[1m\033[33;32mKeyboard : interupt happened") - exit(0) - except sr.exceptions.UnknownValueError: - print("\033[1m\033[33;32m[*]exception : user said nothing") - print(f'User said {converted_text}') - return converted_text - -def check_st(filename,system): - if system == 'Linux': - try: - output = subprocess.check_output(["fuser",filename], text=True) - #print(output) - lines = output.strip().split("/") # Skip the header - for line in lines: - print(line) - parts = line.split() - pid = int(parts[0]) - print(f"File is open by PID {pid}, killing it...") - os.kill(pid, signal.SIGKILL) - print(f"Process {pid} killed.") - except subprocess.CalledProcessError: - print("File is not open by any process. Proceeding.") - file_iteration(filename=filename) - elif system == 'Windows': - print('windows') - -def file_iteration(filename): - print(filename) - data = pd.read_excel(filename,usecols=cols) - print(data) - for index,row in data.iterrows(): - tts_converter("Hey Mini") - tts_converter(row['commands']) - TTS_main.print_fun() - t.sleep(5) - # result = listen() - # data.at[index,'Results'] = f'{result}' - # data.to_excel('words.xlsx',index=False,engine='openpyxl') - # print(result) - -if __name__ == "__main__": - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # self.Chat_scrollArea = QtWidgets.QScrollArea(self.centralwidget) - # self.Chat_scrollArea.setGeometry(QtCore.QRect(0, 0, 441, 261)) - # self.Chat_scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) - # self.Chat_scrollArea.setWidgetResizable(True) - # self.Chat_scrollArea.setObjectName("Chat_scrollArea") - # self.Chat_container = QtWidgets.QWidget() - # self.Chat_container.setGeometry(QtCore.QRect(0, 0, 439, 259)) - # self.Chat_container.setObjectName("Chat_container") - # self.verticalLayoutWidget = QtWidgets.QWidget(self.Chat_container) - # self.verticalLayoutWidget.setGeometry(QtCore.QRect(-1, -1, 441, 261)) - # self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - # self.caht_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) - # self.caht_layout.setContentsMargins(0, 0, 0, 0) - # self.caht_layout.setObjectName("caht_layout") - # self.caht_layout.addStretch() - # self.Chat_scrollArea.setWidget(self.Chat_container) \ No newline at end of file diff --git a/src/TTS_main.py b/src/TTS_main.py index 4e8ef21..8dcfd38 100755 --- a/src/TTS_main.py +++ b/src/TTS_main.py @@ -25,25 +25,21 @@ def __init__(self,mcu_ip,input_excel,directory,dlp_file,load,stack): self.inputExcel = input_excel self.outputExcel = f"Test_run_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.xlsx" self.Lang = 'en' - self.numIters = 5 self.outDIr = directory self.load = load - #self.outDIr = self.outDIr + f"/Test_run_on_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}" + self.load_time = 0 self.command_wait_deviceStart="wait-for-device" - self.report_excel_file = "output_from_test_run.xlsx" - self.report_excel_file = self.outDIr + self.report_excel_file self.dlp = dlp_file self.excel = Update_Excel() self.cache = f'C:/Users/{getpass.getuser()}/AppData/Local/dlt_viewer/cache' - self.audioDir = 'audio' self.load_process = None self.newDlp = self.dlpfile_constructor('artifacts/file_DLT.dlp',self.mcuIp) self.dlt = Connet_DLT_class(self.cache,self.newDlp,self.outDIr) - self.utils = utils.tts_main() + logging.basicConfig( - filename=f"{self.outDIr}/overall_log.txt", + filename=f"{self.outDIr}/overall_log{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt", filemode="w", # if file exist, clear it then open and write level=logging.DEBUG, format="%(asctime)s:%(levelname)s:%(message)s", @@ -51,19 +47,11 @@ def __init__(self,mcu_ip,input_excel,directory,dlp_file,load,stack): ) logging.Logger - - self.main() - self.test_init() + df = pd.read_excel(self.inputExcel) + '''doing some maths here to calculate how much time of load we need to give based on how much of utterance we have''' + self.load_time = (df.size) * 15 + - def main(self): - print(self.inputExcel) - print(self.mcuIp) - print(self.outputExcel) - print(self.Lang) - print(self.outDIr) - print(self.numIters) - print(self.load) - def test_init(self): command = 'adb devices' logging.info("Starting the WUW test run...") @@ -72,18 +60,6 @@ def test_init(self): adb_result=self.run_adb_command(self.command_wait_deviceStart) print("after adb connect call") logging.info(adb_result) - # for i in range(3): - # result=subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - # if result.returncode != 0: - # logging.error(f"adb command for devices failed, please check the error: {result.stderr.decode('utf-8')}") - # raise Exception(f'adb command failed failed: {result.stderr.decode("utf-8")}') - # if self.mcuIp in result.stdout.decode("utf-8"): - # logging.info(" the device is identified and adb can work") - # device_started=True - # break - # else: - # logging.error(f"The device is not identified , see the error: {result} ") - # print("device not found") logging.info("Now setting the audio outdevices") if self.inputExcel != None: self.loadutterances(logging) @@ -93,7 +69,6 @@ def run_adb_command(self, command): adb_command = "adb " + command else: adb_command = "adb -s " + self.mcuIp + " " + command - try: result = subprocess.run(adb_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = result.stdout.decode('utf-8') @@ -103,33 +78,27 @@ def run_adb_command(self, command): print(f"[WARNING] ADB command failed: {error.strip()}") return error return output - except Exception as e: print(f"[ERROR] Exception occurred while running adb: {e}") return str(e) - def loadutterances(self,logger): df = pd.read_excel(self.inputExcel) - '''doing some maths here to calculate how much time of load we need to give based on how much of utterance we have''' - load_time = (df.size) * 14 - + print(f"this is the load time from my opt{self.load_time}") if self.load: print("give load") logging.info("Going to give some cpu stress") - adb_thread = threading.Thread(target= lambda : self.run_load_adb_command(time=load_time)) + adb_thread = threading.Thread(target= lambda : self.run_load_adb_command(time=self.load_time)) adb_thread.start() - - # print(df) + for index, row in df.iterrows(): utterance = row['Utterances'] if utterance: try: - # print(f"Generating TTS for: {utterance}") self.speak_utterance(text=utterance) print(f"Played utterance {utterance}") except Exception as e: print(e) - # self.utils.warn(mesg="Test Completed ") + if self.load: try: if hasattr(self, 'load_process') and self.load_process and self.load_process.poll() is None: @@ -138,6 +107,9 @@ def loadutterances(self,logger): except Exception as e: print(f"Error terminating ADB process: {e}") adb_thread.join() + + self.excel.send_mail() + def tts(self,text): engine = pyttsx3.init() engine.setProperty("rate", 150) @@ -149,12 +121,11 @@ def tts(self,text): def speak_utterance(self, text, lang="en"): self.run_adb_command('shell input tap 500 600') self.dlt.cleaner() - stop_event = threading.Event() + log_thread = threading.Thread(target=self.dlt.start_dlt) log_thread.start() time.sleep(1) - self.run_adb_command('shell cmd car_service inject-custom-input 1012;sleep 0.2; cmd car_service inject-custom-input 1013') time.sleep(1) print(f"๐Ÿ”Š Speaking: {text}") @@ -162,9 +133,11 @@ def speak_utterance(self, text, lang="en"): logging.info(f"Played utterance: {text}") time.sleep(10) - stop_event.set() + log_thread.join() + self.dlt.stop_dlt() + self.dlt.convert_dlt_log_text() self.dlt.check(uttearnce=text) # print("Gonna call the main thing here") @@ -227,11 +200,19 @@ def dlpfile_constructor(self,original_path,new_hostname): return None if __name__ == "__main__": + # this how the schedule works --> see the bat file created at run time parser = argparse.ArgumentParser(description="A simple script with command line arguments.") - parser.add_argument("name", type=str, help="Your name") - parser.add_argument("--age", type=int, default=30, help="Your age (optional)") - + parser.add_argument("--ip", required=True, type=str, help="Target device IP (ADB).") + parser.add_argument("--excel", type=str, help="Path to input Excel (optional).") + parser.add_argument("--dir", required=True, type=Path, help="Output/log folder.") + parser.add_argument("--dlp", type=str, help="DLT project file.") + parser.add_argument("--load", type=lambda x: str(x).lower() in ("yes", "1", "true", "y"), help="Give system load via ADB.") + parser.add_argument("--tech", type=str, default="BCA", help="Tech stack (e.g. BCA).") args = parser.parse_args() - print(f"Hello, {args.name}!") - print(f"You are {args.age} years old.") \ No newline at end of file + + TTSObj = Test_begin(args.ip,args.excel,args.dir,args.dlp,args.load,args.tech) + TTSObj.test_init() + + + \ No newline at end of file diff --git a/src/Task_sched_automate_UI.py b/src/Task_sched_automate_UI.py index fd552e0..a8ff52b 100644 --- a/src/Task_sched_automate_UI.py +++ b/src/Task_sched_automate_UI.py @@ -1,205 +1,490 @@ + from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import ( - QApplication, QMainWindow, QWidget, QPushButton, QLabel, - QVBoxLayout, QHBoxLayout, QStackedWidget, QLineEdit, QTextEdit, - QFrame, QScrollArea,QRadioButton,QFileDialog,QMessageBox,QComboBox + QLabel, QGraphicsBlurEffect, QWidget, QPushButton, QSizePolicy, + QVBoxLayout, QHBoxLayout, QStackedWidget, QLineEdit, QGroupBox, + QScrollArea, QRadioButton, QFileDialog, QMessageBox, QComboBox ) -from PyQt5.QtGui import QIcon,QFont,QPixmap,QMovie -from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon, QFont, QPixmap, QMovie +from PyQt5.QtCore import Qt, QTimer, QThread, QObject, pyqtSignal, pyqtSlot from datetime import datetime -from PyQt5.QtCore import pyqtSignal -import Test_runner_GUI -from styles import * import subprocess import os + from TTS_main import Test_begin + +# ---------- Worker that runs the heavy core code off the GUI thread ---------- +class Worker(QObject): + finished = pyqtSignal() # emitted when core function finishes normally + error = pyqtSignal(str) # emitted when an exception occurs when something goes wrong + + def __init__(self, core_obj: Test_begin): + super().__init__() + self.core = core_obj + + @pyqtSlot() + def run(self): + try: + #heavy work; keep it out of the main thread + self.core.test_init() + self.finished.emit() + except Exception as e: + self.error.emit(str(e)) + + class Main_utils_page(QWidget): def __init__(self): super().__init__() - self.sig_use = pyqtSignal() self.page = self.main_page() - self.runnerlogDir = "Auto_Testrun_"+ datetime.now().strftime('%Y-%m-%d_%H-%M-%S') - + + self.runnerlogDir = "Auto_Testrun_" + datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + + # runtime holders + self.test_obj = None + self.timer = None + self.rem_load_time = 0 + self.thread = None + self.worker = None + def main_page(self): page = self.create_card() main_layout = QHBoxLayout() main_layout.setAlignment(Qt.AlignCenter) main_layout.addWidget(page) page.setLayout(main_layout) - return page - + return page + def create_card(self): card = QWidget() - card.setStyleSheet("background-color: #302D2D; border-radius: 12px; padding: 2px;") - vbox = QVBoxLayout() - vbox.setAlignment(Qt.AlignTop) - vbox.setSpacing(15) - - label = QLabel("Start A Task or Schedule One") - label.setStyleSheet(my_style) - label.setAlignment(Qt.AlignCenter) - label.setObjectName("headers") - vbox.addWidget(label) - # ---------- IP Address Input ---------- - ip_path_edit = QLineEdit() - ip_path_edit.setPlaceholderText("IP Address") - ip_path_edit.setStyleSheet(my_style) - ip_path_edit.setText('169.254.80.') - vbox.addWidget(ip_path_edit) - - # ---------- Excel File Input ---------- - exe_path_edit = QLineEdit() - exe_path_edit.setPlaceholderText("Path to Excel") - exe_path_edit.setStyleSheet(my_style) - browse_btn = QPushButton("Browse") - browse_btn.setStyleSheet(my_style) - browse_btn.setFixedSize(100,30) - browse_btn.clicked.connect(lambda: exe_path_edit.setText( + blur_effect = QGraphicsBlurEffect() + blur_effect.setBlurRadius(10) + + card.setStyleSheet("background-color: #1E1E1E; border-radius: 12px;") + # card.setStyleSheet("background : transparent") + main_layout = QVBoxLayout(card) + main_layout.setSpacing(16) + + # ----- Connection Details ----- + connection_group = QGroupBox("Connection Details") + connection_group.setFixedSize(720,60) + connection_group.setStyleSheet(""" + QGroupBox { + color: #FFFFFF; + font-size: 13px; + font-weight: bold; + border: 1px solid #555555; + border-radius: 6px; + margin-top: 10px; + } + QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding: 0 4px; + } + """) + connection_group.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + + conn_layout = QVBoxLayout(connection_group) + conn_layout.setContentsMargins(8, 8, 8, 8) + conn_layout.setSpacing(5) + + self.ip_path_edit = QLineEdit() + self.ip_path_edit.setFixedSize(600,30) + self.ip_path_edit.setPlaceholderText("IP Address") + self.ip_path_edit.setText("169.254.80.") + self.ip_path_edit.setStyleSheet(""" + QLineEdit { + background-color: #3B3B3B; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 3px; + font-size : 14px ; + } + """) + conn_layout.addWidget(self.ip_path_edit) + + # ----- File Paths ----- + file_group = QGroupBox("File Paths") + file_group.setStyleSheet(connection_group.styleSheet()) + file_layout = QVBoxLayout(file_group) + file_group.setFixedSize(720,170) + + # Path to Excel + self.exe_path_edit = QLineEdit() + self.exe_path_edit.setFixedSize(590,30) + self.exe_path_edit.setPlaceholderText("Path to Excel") + self.exe_path_edit.setStyleSheet(self.ip_path_edit.styleSheet()) + browse_btn_excel = QPushButton("Browse") + browse_btn_excel.setFixedSize(100, 30) + browse_btn_excel.setStyleSheet(""" + QPushButton { + background-color: #4CAF50; + color: white; + border-radius: 4px; + } + QPushButton:hover { + background-color: #3C8D40; + } + """) + browse_btn_excel.clicked.connect(lambda: self.exe_path_edit.setText( QFileDialog.getOpenFileName(None, "Select Excel", "", "Excel Files (*.xlsx)")[0] )) - exe_hbox = QHBoxLayout() - exe_hbox.addWidget(exe_path_edit) - exe_hbox.addWidget(browse_btn) - vbox.addLayout(exe_hbox) + exe_hbox.addWidget(self.exe_path_edit) + exe_hbox.addWidget(browse_btn_excel) + file_layout.addLayout(exe_hbox) - # ---------- Log Folder Input ---------- + # Path to Log Folder self.log_path_edit = QLineEdit() + self.log_path_edit.setFixedSize(590,30) self.log_path_edit.setPlaceholderText("Path to Log Folder") - self.log_path_edit.setStyleSheet(my_style) - log_browse_btn = QPushButton("Browse") - log_browse_btn.setStyleSheet(my_style) - log_browse_btn.setFixedSize(100,30) - # log_browse_btn.clicked.connect(lambda: log_path_edit.setText( - # QFileDialog.getExistingDirectory(self, 'Select Log Folder') - # )) - log_browse_btn.clicked.connect(self.select_log_folder) - + self.log_path_edit.setStyleSheet(self.ip_path_edit.styleSheet()) + browse_btn_log = QPushButton("Browse") + browse_btn_log.setFixedSize(100, 30) + browse_btn_log.setStyleSheet(browse_btn_excel.styleSheet()) + browse_btn_log.clicked.connect(self.select_log_folder) log_hbox = QHBoxLayout() log_hbox.addWidget(self.log_path_edit) - log_hbox.addWidget(log_browse_btn) - vbox.addLayout(log_hbox) - - # ---------- DLP Project File ---------- - fp_path_edit = QLineEdit() - fp_path_edit.setPlaceholderText("Project file for DLT / ECU Configuration file to start dlt (*Rack wise)") - fp_path_edit.setStyleSheet(my_style) - fp_browse_btn = QPushButton("Browse") - fp_browse_btn.setStyleSheet(my_style) - fp_browse_btn.setFixedSize(100,30) - fp_browse_btn.clicked.connect(lambda: fp_path_edit.setText( - QFileDialog.getOpenFileName(None, "Select DLP File", "", "DLP Files (*.DLP)")[0] - )) + log_hbox.addWidget(browse_btn_log) + file_layout.addLayout(log_hbox) + # Project File + self.fp_path_edit = QLineEdit() + self.fp_path_edit.setFixedSize(590,30) + self.fp_path_edit.setPlaceholderText("Project File (optional)") + self.fp_path_edit.setStyleSheet(self.ip_path_edit.styleSheet()) + browse_btn_fp = QPushButton("Browse") + browse_btn_fp.setFixedSize(100, 30) + browse_btn_fp.setStyleSheet(browse_btn_excel.styleSheet()) + browse_btn_fp.clicked.connect(lambda: self.fp_path_edit.setText( + QFileDialog.getOpenFileName(None, "Select DLP File", "", "DLP Files (*.dlp *.DLP)")[0] + )) fp_hbox = QHBoxLayout() - fp_hbox.addWidget(fp_path_edit) - fp_hbox.addWidget(fp_browse_btn) - msg_label = QLabel("*DLP File will created on runtime with the given ip so this is optional part") - msg_label.setStyleSheet("color:white;") + fp_hbox.addWidget(self.fp_path_edit) + fp_hbox.addWidget(browse_btn_fp) + file_layout.addLayout(fp_hbox) + + # ----- Execution Settings ----- + exec_group = QGroupBox("Execution Settings") + exec_group.setStyleSheet(connection_group.styleSheet()) + exec_group.setFixedSize(720,180) + exec_layout = QVBoxLayout(exec_group) - vbox.addLayout(fp_hbox) - vbox.addWidget(msg_label) - # ---------- Time Input ---------- - time_input = QLineEdit() - time_input.setStyleSheet(my_style) - time_input.setPlaceholderText("Schedule Time (HH:MM, e.g., 14:30) optional IN DEVLOPMENT") - vbox.addWidget(time_input) - msg_label1 = QLabel("*Windows feature to schdule this as a task using task schduler. Run in headless mode") - msg_label1.setStyleSheet("color:white;") - vbox.addWidget(msg_label1) - - # ---------- Buttons ---------- + # Schedule Time + self.time_input = QLineEdit() # keep a handle for schedule + self.time_input.setPlaceholderText("Schedule Time (HH:MM)") + self.time_input.setFixedSize(600,30) + self.time_input.setStyleSheet(self.ip_path_edit.styleSheet()) + + exec_layout.addWidget(self.time_input) + + # Radio buttons group + radio_layout = QVBoxLayout() + radio_layout.setContentsMargins(0, 0, 0, 0) + radio_layout.setSpacing(4) + + radio_label = QLabel("Give CPU load through ADB") + radio_label.setStyleSheet(""" + QLabel { + color: #FFFFFF; + background: transparent; + font-size: 13px; + font-weight : bold; + } + """) + radio_label.setFixedHeight(18) + radio_layout.addWidget(radio_label) + + radio_buttons_row = QHBoxLayout() + radio_buttons_row.setContentsMargins(0, 0, 0, 0) + radio_buttons_row.setSpacing(12) + self.give_load = QRadioButton("Yes") + self.give_no_load = QRadioButton("No") + self.give_no_load.setChecked(True) # default to No + + radio_common = """ + QRadioButton { + color: #CFCFCF; + background: transparent; + } + QRadioButton::indicator { + width: 16px; + height: 16px; + border-radius: 8px; + border: 2px solid #999999; + background: transparent; + } + QRadioButton::indicator:checked { + border: 2px solid #2196F3; + background-color: qradialgradient( + cx: 0.5, cy: 0.5, radius: 0.6, + fx: 0.5, fy: 0.5, + stop: 0 #2196F3, stop: 1 transparent + ); + } + """ + self.give_load.setStyleSheet(radio_common) + self.give_no_load.setStyleSheet(radio_common) + + radio_buttons_row.addWidget(self.give_load) + radio_buttons_row.addWidget(self.give_no_load) + radio_buttons_row.addStretch() + + radio_layout.addLayout(radio_buttons_row) + exec_layout.addLayout(radio_layout) + + # Dropdown label + stack_label = QLabel("Select stack") + stack_label.setStyleSheet(""" + QLabel { + color: #FFFFFF; + background: transparent; + font-size: 13px; + font-weight : bold; + } + """) + # stack_label.setFixedHeight(18) + exec_layout.addWidget(stack_label) + + # Dropdown + self.tech_stack = QComboBox() + self.tech_stack.setFixedSize(600,30) + self.tech_stack.addItem("BCA") + self.tech_stack.addItem("Cerance") + self.tech_stack.setStyleSheet(""" + QComboBox { + background-color: #3B3B3B; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 4px; + + } + QComboBox::drop-down { border: none; } + QComboBox QAbstractItemView { + background-color: #3B3B3B; + color: white; + selection-background-color: #007ACC; + selection-color: white; + } + """) + exec_layout.addWidget(self.tech_stack) + + # ----- Action Buttons + Status ----- btn_hbox = QHBoxLayout() + self.test_btn = QPushButton("Start Test") + self.test_btn.setFixedHeight(40) + self.test_btn.setStyleSheet(""" + QPushButton { + background-color: #007ACC; + color: white; + border-radius: 4px; + font-weight: bold; + } + QPushButton:hover { background-color: #005A99; } + QPushButton:disabled { background-color: #3b3b3b; color: #999; } + """) + self.test_btn.clicked.connect(self.start_test) schedule_btn = QPushButton("Schedule") - schedule_btn.setStyleSheet(my_style) - schedule_btn.setFixedSize(100,50) + schedule_btn.setFixedHeight(40) + schedule_btn.setStyleSheet(""" + QPushButton { + background-color: #007ACC; + color: white; + border-radius: 4px; + } + QPushButton:hover { background-color: #005A99; } + """) schedule_btn.clicked.connect(lambda: self.create_and_schedule_task( - exe_path_edit.text(), - "MyApp_Task", - time_input.text() - )) - checkbox_layout = QVBoxLayout() - checkbox_label = QLabel("Give load to system?") - checkbox_label.setStyleSheet(my_style) - Give_load = QRadioButton("Yes (System may break๐Ÿšจ)") - Give_no_load = QRadioButton("No (Much safer)") - Give_load.setStyleSheet("color: white;") - Give_no_load.setStyleSheet("color: white;") - checkbox_layout.addWidget(checkbox_label) - checkbox_layout.addWidget(Give_load) - checkbox_layout.addWidget(Give_no_load) - tech_stack = QComboBox() - tech_stack.addItem("BCA") - tech_stack.addItem("Cerance") - test_btn = QPushButton("Start Test") - test_btn.setStyleSheet(my_style) - test_btn.setFixedSize(100,50) - - test_btn.clicked.connect(lambda: Test_begin( - mcu_ip=ip_path_edit.text(), - input_excel=exe_path_edit.text(), - directory=self.runnerlogDir, - dlp_file=fp_path_edit.text(), - load=Give_load.isChecked(), - stack=tech_stack.currentText() + ip=self.ip_path_edit.text(), + excel=self.exe_path_edit.text(), + dir=self.runnerlogDir, + dlp=self.fp_path_edit.text(), + load=self.give_load.isChecked(), + stack=self.tech_stack.currentText(), + time_str=self.time_input.text() )) - tech_stack.setStyleSheet(combo_sheet) - checkbox_layout.addWidget(tech_stack) - vbox.addLayout(checkbox_layout) - btn_hbox.addWidget(test_btn) + btn_hbox.addWidget(self.test_btn) btn_hbox.addWidget(schedule_btn) - vbox.addLayout(btn_hbox) - # ---------- Final Card Layout ---------- - card.setLayout(vbox) + + label_group = QGroupBox() + label_group.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) + label_group.setStyleSheet(connection_group.styleSheet()) + label_layout = QVBoxLayout(label_group) + + self.status_label = QLabel("Time Remaining: 0s") + self.status_label.setStyleSheet(""" + QLabel { + color: #CFCFCF; + background: transparent; + font-size: 12px; + font-weight : bold; + } + """) + label_layout.addWidget(self.status_label) + + # ----- Assemble Layout ----- + main_layout.addWidget(connection_group) + main_layout.addWidget(file_group) + main_layout.addWidget(exec_group) + main_layout.addWidget(label_group) + main_layout.addLayout(btn_hbox) + return card def select_log_folder(self): folder_path = QFileDialog.getExistingDirectory(self, 'Select Log Folder') if folder_path: self.log_path_edit.setText(folder_path) - self.runnerlogDir=os.path.join(self.log_path_edit.text(),self.runnerlogDir) - os.mkdir(self.runnerlogDir) - - def printer(self): - print("god") - print(self.time_input.text()) - print(self.exe_input.text()) - - - def create_and_schedule_task(self, exe_path, task_name, time_str): - print(exe_path) - print(task_name) - print(time_str) - cwd = os.getcwd()+'/bats' - #we Create .bat file (i dont know how much safe is this one) - os.makedirs(cwd, exist_ok=True) # Create the directory if it doesn't exist - bat_path = os.path.join(cwd, f"{task_name}.bat") - # bat_path = os.path.join(cwd , f"{task_name}.bat") - with open(bat_path, 'w') as f: - f.write(f'start "" "{exe_path}"\n') - - # Schedule task using schtasks , like running a command in linux (can bring improvements) - hour, minute = time_str.split(":") - # https://learn.microsoft.com/en-us/windows/win32/taskschd/schtasks for your reference - # this is definetley gonna break the system + self.runnerlogDir = os.path.join(self.log_path_edit.text(), self.runnerlogDir) + try: + os.makedirs(self.runnerlogDir, exist_ok=True) + except Exception as e: + QMessageBox.critical(self, "Folder Error", f"Could not create log folder:\n{e}") + + # ----------------- Test flow ----------------- + def start_test(self): + # Build core object + self.test_obj = Test_begin( + mcu_ip=self.ip_path_edit.text(), + input_excel=self.exe_path_edit.text(), + directory=self.runnerlogDir, + dlp_file=self.fp_path_edit.text(), + load=self.give_load.isChecked(), + stack=self.tech_stack.currentText() + ) + + # Initialize countdown from core's computed load_time + self.rem_load_time = int(getattr(self.test_obj, 'load_time', 0) or 0) + self.status_label.setText(f"Time Remaining: {self.rem_load_time}s") + + # Start UI timer (1 Hz) + if self.timer: + self.timer.stop() + self.timer = QTimer(self) + self.timer.timeout.connect(self.update_timer) + self.timer.start(1000) + + #disabling the test button while test running + self.test_btn.setDisabled(True) + + self.thread = QThread(self) + self.worker = Worker(self.test_obj) + self.worker.moveToThread(self.thread) + + # Wire signals + self.thread.started.connect(self.worker.run) + self.worker.finished.connect(self.on_core_finished) + self.worker.error.connect(self.on_core_error) + + + self.worker.finished.connect(self.thread.quit) + self.worker.finished.connect(self.worker.deleteLater) + self.thread.finished.connect(self.thread.deleteLater) + self.worker.error.connect(self.thread.quit) + self.worker.error.connect(self.worker.deleteLater) + + self.thread.start() + + def update_timer(self): + # countdown while the worker runs + if self.rem_load_time > 0: + self.rem_load_time -= 1 + self.status_label.setText(f"Time Remaining: {self.rem_load_time}s") + else: + # just stop the timer; core may still be finishing up a second later + self.timer.stop() + + @pyqtSlot() + def on_core_finished(self): + # Stop timer if still running + if self.timer and self.timer.isActive(): + self.timer.stop() + self.status_label.setText("โœ… Test finished") + self.test_btn.setDisabled(False) + + @pyqtSlot(str) + def on_core_error(self, message: str): + if self.timer and self.timer.isActive(): + self.timer.stop() + self.status_label.setText("โŒ Error during test") + self.test_btn.setDisabled(False) + QMessageBox.critical(self, "Test Error", message) + + # ----------------- Scheduler / BAT creation ----------------- + def create_and_schedule_task(self, ip, excel, dir, dlp, load, stack, time_str): + if not time_str or ":" not in time_str: + QMessageBox.warning(self, "Invalid Time", "Please enter time as HH:MM") + return + + task_name = "MyAppTaskV1.0.1" + python_exe = os.path.abspath(os.sys.executable) + script_dir = os.path.dirname(os.path.abspath(__file__)) + FILES_DIR = os.path.join(script_dir, "..", "files") + os.makedirs(FILES_DIR, exist_ok=True) + script_path = os.path.join(script_dir, "TTS_main.py") + + # Quote paths + excel_path = f'"{excel}"' + dir_path = f'"{dir}"' + dlp_path = f'"{dlp}"' + + bat_file = os.path.join(FILES_DIR, f"{task_name}.bat") + bat_content = f"""@echo off +cd /d "{script_dir}" +"{python_exe}" "{script_path}" --ip {ip} --excel {excel_path} --dir {dir_path} --dlp {dlp_path} --load {str(load).lower()} --tech {stack} +pause +""" + + try: + with open(bat_file, "w", encoding="utf-8") as f: + f.write(bat_content) + except Exception as e: + QMessageBox.critical(self, "BAT Error", f"Failed to write BAT file:\n{e}") + return + + try: + hour, minute = time_str.split(":") + except ValueError: + QMessageBox.warning(self, "Invalid Time", "Please enter time as HH:MM") + return + command = [ - "schtasks", - "/Create", - "/SC", "DAILY", + "schtasks", "/Create", + "/SC", "ONCE", "/TN", task_name, - "/TR", f'"{bat_path}"', + "/TR", f'"{bat_file}"', "/ST", f"{hour}:{minute}", "/F" ] - + try: subprocess.run(command, check=True) QMessageBox.information(self, "Scheduled", f"Task '{task_name}' scheduled at {time_str}") except subprocess.CalledProcessError as e: QMessageBox.critical(self, "Error", f"Failed to schedule task:\n{str(e)}") + # Optional helper (if you still want a standalone creator) + def create_tts_bat(self, ip, excel_path, dir_path, dlp_path, load, tech, bat_name="run_tts"): + python_exe = os.path.abspath(os.sys.executable) + script_dir = os.path.dirname(os.path.abspath(__file__)) + script_path = os.path.join(script_dir, "TTS_main.py") + excel_path = f'"{excel_path}"' + dir_path = f'"{dir_path}"' + dlp_path = f'"{dlp_path}"' + bat_file = os.path.join(script_dir, f"{bat_name}.bat") + bat_content = f"""@echo off +cd /d "{script_dir}" +"{python_exe}" "{script_path}" --ip {ip} --excel {excel_path} --dir {dir_path} --dlp {dlp_path} --load {str(load).lower()} --tech {tech} +pause +""" + with open(bat_file, "w", encoding="utf-8") as f: + f.write(bat_content) + print(f"Batch file created at: {bat_file}") + return bat_file diff --git a/src/Test_runner_GUI.py b/src/Test_runner_GUI.py index b96f44f..d3ae65a 100644 --- a/src/Test_runner_GUI.py +++ b/src/Test_runner_GUI.py @@ -10,9 +10,9 @@ from PyQt5 import QtCore, QtGui, QtWidgets import sys from PyQt5.QtWidgets import ( - QApplication, QMainWindow, QWidget, QPushButton, QLabel, - QVBoxLayout, QHBoxLayout, QStackedWidget, QLineEdit, QTextEdit, - QFrame, QScrollArea,QSizePolicy,QGridLayout,QFileDialog,QMessageBox,QComboBox + QApplication, QMessageBox, QWidget, QPushButton, QLabel, + QVBoxLayout, QHBoxLayout, QGraphicsOpacityEffect, QLineEdit, QGraphicsBlurEffect, + QFrame, QScrollArea,QSizePolicy,QGridLayout,QFileDialog,QGroupBox,QComboBox ) from PyQt5.QtGui import QIcon,QFont,QPixmap,QMovie from PyQt5.QtCore import Qt @@ -30,7 +30,11 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): self.tts = utils.tts_main() - + MainWindow.setStyleSheet(""" + QMainWindow { + background-color :#2B2B2B + } + """) self.isEditing = False self.isEditingDevName = '' self.my_style = """ @@ -64,26 +68,11 @@ def setupUi(self, MainWindow): } """ - self.btn_sheet=''' -QPushButton { - color: rgb(255, 255, 255); - background-color: #2B2B2B ; - border: 0px solid; - text-align:left; - font-family: 'Source Code Pro' ; - border-radius : 10px -} -QPushButton:hover { - background-color: #B3B3B3; - font-size:12px; - border-radius : 0px; - margin : 2px; -} -''' + + MainWindow.setObjectName("MainWindow") - MainWindow.resize(1100, 600) - MainWindow.setMinimumSize(QtCore.QSize(1000, 500)) - MainWindow.setStyleSheet("background-color: #2B2B2B;") + MainWindow.resize(600, 600) + # MainWindow.setStyleSheet("background-image: url('C:/Users/jithin.sreekala/OneDrive - Acsia Technologies Private Limited/Desktop/POC/Poc_from_gitHub/Python_testing/src/assets/bck.jpg')") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") #self.centralwidget.setStyleSheet() @@ -93,7 +82,7 @@ def setupUi(self, MainWindow): self.verticalLayout.setObjectName("verticalLayout") self.Top_Bar = QtWidgets.QFrame(self.centralwidget) self.Top_Bar.setMaximumSize(QtCore.QSize(16777215, 30)) - self.Top_Bar.setStyleSheet("background-color:#2B2B2B;") + self.Top_Bar.setStyleSheet("background:transparent;") self.Top_Bar.setFrameShape(QtWidgets.QFrame.NoFrame) self.Top_Bar.setFrameShadow(QtWidgets.QFrame.Raised) self.Top_Bar.setObjectName("Top_Bar") @@ -111,16 +100,15 @@ def setupUi(self, MainWindow): self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") + self.Btn_Toggle = QtWidgets.QLabel(self.frame_toggle) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.Btn_Toggle.sizePolicy().hasHeightForWidth()) self.Btn_Toggle.setSizePolicy(sizePolicy) - # self.pixmap1 = QPixmap('src/assets/logo.png') - # self.Btn_Toggle.setPixmap(self.pixmap1) self.Btn_Toggle.setScaledContents(True) - self.Btn_Toggle.setStyleSheet("background-color: #2B2B2B;") + self.Btn_Toggle.setStyleSheet("background : transparent;") self.Btn_Toggle.setObjectName("Btn_Toggle") self.verticalLayout_2.addWidget(self.Btn_Toggle) @@ -129,12 +117,17 @@ def setupUi(self, MainWindow): self.frame_top.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_top.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_top.setObjectName("frame_top") + self.frame_top.setStyleSheet("background : transparent") + opacity_effect = QGraphicsOpacityEffect() + opacity_effect.setOpacity(0.0) + self.frame_top.setGraphicsEffect(opacity_effect) self.horizontalLayout.addWidget(self.frame_top) self.verticalLayout.addWidget(self.Top_Bar) self.Content = QtWidgets.QFrame(self.centralwidget) self.Content.setFrameShape(QtWidgets.QFrame.NoFrame) self.Content.setFrameShadow(QtWidgets.QFrame.Raised) self.Content.setObjectName("Content") + # self.Content.setStyleSheet("background : transparent") self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.Content) self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_2.setSpacing(0) @@ -143,6 +136,7 @@ def setupUi(self, MainWindow): self.frame_left_menu.setMinimumSize(QtCore.QSize(150, 0)) self.frame_left_menu.setMaximumSize(QtCore.QSize(150, 16777215)) # self.frame_left_menu.setStyleSheet("background-color: rgb(35, 35, 35);") + self.frame_left_menu.setStyleSheet("background : transparent;") self.frame_left_menu.setStyleSheet("background-color: #2B2B2B;") self.frame_left_menu.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_left_menu.setFrameShadow(QtWidgets.QFrame.Raised) @@ -154,40 +148,82 @@ def setupUi(self, MainWindow): self.frame_top_menus.setFrameShape(QtWidgets.QFrame.NoFrame) self.frame_top_menus.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_top_menus.setObjectName("frame_top_menus") + + # self.frame_top_menus.setGraphicsEffect(blur_effect) + self.frame_top_menus.setStyleSheet("background : transparent") + + # Sidebar layout self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_top_menus) + self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setSpacing(4) # Small spacing between buttons self.verticalLayout_4.setObjectName("verticalLayout_4") - self.btn_home_page = QtWidgets.QPushButton(self.frame_top_menus) + + # Sidebar style (matches app theme) + sidebar_btn_style = """ + QPushButton { + background : transparent; + color: #ffffff; + border: none; + padding: 8px; + text-align: left; + font-size: 12px; + font-weight: bold; + } + QPushButton:hover { + background-color: #c0c0c0; + } + QPushButton:pressed { + background-color: #007ACC; + color: white; + } + """ + + # Create buttons + self.btn_home_page = QtWidgets.QPushButton(" Home", self.frame_top_menus) self.btn_home_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_home_page.setStyleSheet(self.btn_sheet) - self.btn_home_page.setObjectName("btn_home_page") - self.btn_home_page.setIcon(QIcon('src/assets/list.svg')) - - self.btn_new_page = QtWidgets.QPushButton(self.frame_top_menus) + self.btn_home_page.setStyleSheet(sidebar_btn_style) + self.btn_home_page.setIcon(QIcon("src/assets/list.svg")) + self.btn_home_page.setIconSize(QtCore.QSize(20, 20)) + + self.btn_new_page = QtWidgets.QPushButton(" New Task", self.frame_top_menus) self.btn_new_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_new_page.setStyleSheet(self.btn_sheet) - self.btn_new_page.setObjectName("btn_new_page") - self.btn_new_page.setIcon(QIcon('src/assets/add.svg')) - - self.btn_sttings_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_sttings_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_sttings_page.setStyleSheet(self.btn_sheet) - self.btn_sttings_page.setObjectName("Rack_sttings_page") - self.btn_sttings_page.setIcon(QIcon('src/assets/settings.svg')) + self.btn_new_page.setStyleSheet(sidebar_btn_style) + self.btn_new_page.setIcon(QIcon("src/assets/add.svg")) + self.btn_new_page.setIconSize(QtCore.QSize(20, 20)) - self.btn_general_page = QtWidgets.QPushButton(self.frame_top_menus) + self.btn_general_page = QtWidgets.QPushButton(" General", self.frame_top_menus) self.btn_general_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_general_page.setStyleSheet(self.btn_sheet) - self.btn_general_page.setObjectName("btn_general_page") - self.btn_general_page.setIcon(QIcon('src/assets/speak.svg')) - - self.btn_sched_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_sched_page.setMinimumSize(QtCore.QSize(0,40)) - self.btn_sched_page.setStyleSheet(self.btn_sheet) - self.btn_sched_page.setIcon(QIcon('src/assets/Timer.svg')) - for widget in [self.btn_home_page,self.btn_new_page,self.btn_general_page,self.btn_sched_page,self.btn_sttings_page]: + self.btn_general_page.setStyleSheet(sidebar_btn_style) + self.btn_general_page.setIcon(QIcon("src/assets/speak.svg")) + self.btn_general_page.setIconSize(QtCore.QSize(20, 20)) + + self.btn_sched_page = QtWidgets.QPushButton(" Schedule", self.frame_top_menus) + self.btn_sched_page.setMinimumSize(QtCore.QSize(0, 40)) + self.btn_sched_page.setStyleSheet(sidebar_btn_style) + self.btn_sched_page.setIcon(QIcon("src/assets/Timer.svg")) + self.btn_sched_page.setIconSize(QtCore.QSize(20, 20)) + + self.btn_sttings_page = QtWidgets.QPushButton(" Settings", self.frame_top_menus) + self.btn_sttings_page.setMinimumSize(QtCore.QSize(0, 40)) + self.btn_sttings_page.setStyleSheet(sidebar_btn_style) + self.btn_sttings_page.setIcon(QIcon("src/assets/settings.svg")) + self.btn_sttings_page.setIconSize(QtCore.QSize(20, 20)) + + # Add all buttons to sidebar + for widget in [ + self.btn_home_page, + self.btn_new_page, + self.btn_general_page, + self.btn_sched_page, + self.btn_sttings_page + ]: + widget.setCursor(Qt.PointingHandCursor) # Pointer on hover self.verticalLayout_4.addWidget(widget) + + # Add stretch so buttons stay at the top + self.verticalLayout_4.addStretch() + self.verticalLayout_3.addWidget(self.frame_top_menus, 0, QtCore.Qt.AlignTop) self.horizontalLayout_2.addWidget(self.frame_left_menu) self.frame_pages = QtWidgets.QFrame(self.Content) @@ -199,12 +235,15 @@ def setupUi(self, MainWindow): self.stackedWidget = QtWidgets.QStackedWidget(self.frame_pages) self.stackedWidget.setObjectName("stackedWidget") - self.stackedWidget.setStyleSheet('background-color : #302D2D ;') + self.stackedWidget.setStyleSheet('background : transparent;') self.page1 = self.home_page() self.page2 = self.add_page() self.page3 = self.sched_page() self.page4 = self.use_page() self.page5 = self.rack_page() + self.t_page = self.add_page() + + self.stackedWidget.addWidget(self.t_page) self.stackedWidget.addWidget(self.page1) self.stackedWidget.addWidget(self.page2) self.stackedWidget.addWidget(self.page3) @@ -227,8 +266,10 @@ def rack_page(self): page = QWidget() h_box = QHBoxLayout() self.card = ButtonControl() + h_box.addWidget(self.card) page.setLayout(h_box) + return page def home_page(self): @@ -265,85 +306,227 @@ def home_page(self): return page #config page def add_page(self): - page = QWidget() - layout = QVBoxLayout() - label = QLabel("Add or create a device configuration") - label.setStyleSheet(my_style) + self.page = QWidget() + layout = QVBoxLayout(self.page) + layout.setSpacing(20) + layout.setContentsMargins(30, 20, 30, 20) + + # Header label + label = QLabel("Add or Create a Device Configuration") label.setAlignment(Qt.AlignCenter) - label.setObjectName("headers") - layout.setSpacing(20) - layout.setContentsMargins(0, 0, 0, 0) + label.setStyleSheet(""" + QLabel { + color: #FFFFFF; + font-size: 16px; + font-weight: bold; + } + """) layout.addWidget(label) + + # Group box for device details + device_group = QGroupBox("Device Details") + device_group.setStyleSheet(""" + QGroupBox { + color: #FFFFFF; + font-size: 13px; + font-weight: bold; + border: 1px solid #555555; + background-color: #1E1E1E; + border-radius: 6px; + margin-top: 10px; + } + QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding: 0 4px; + } + """) + group_layout = QVBoxLayout(device_group) + group_layout.setSpacing(12) + + # Input style + input_style = """ + QLineEdit { + background-color: #3B3B3B; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 6px; + } + QLineEdit:focus { + border: 1px solid #007ACC; + } + """ + + # Device name, IP, Port self.input_name = QLineEdit() self.input_name.setPlaceholderText("Device Name") + self.input_name.setStyleSheet(input_style) + self.input_ip = QLineEdit() self.input_ip.setPlaceholderText("IP Address") + self.input_ip.setStyleSheet(input_style) + self.input_port = QLineEdit() self.input_port.setPlaceholderText("Port") - self.input_dlt = QLineEdit() - self.input_dlt.setPlaceholderText("input DLT path") - self.input_dlt.mousePressEvent =lambda event , input=self.input_dlt:self.file(event,self.input_dlt) - self.input_adb = QLineEdit() - self.input_adb.setPlaceholderText("input ADB path") - self.input_adb.mousePressEvent = lambda event , input=self.input_adb:self.file(event,self.input_adb) + self.input_port.setStyleSheet(input_style) + + group_layout.addWidget(self.input_name) + group_layout.addWidget(self.input_ip) + group_layout.addWidget(self.input_port) + + # File path inputs with browse buttons + def make_path_input(placeholder, click_handler): + container = QHBoxLayout() + line_edit = QLineEdit() + line_edit.setPlaceholderText(placeholder) + line_edit.setStyleSheet(input_style) + browse_btn = QPushButton("Browse") + browse_btn.setCursor(Qt.PointingHandCursor) + browse_btn.setStyleSheet(""" + QPushButton { + background-color: #4CAF50; + color: white; + border: none; + border-radius: 4px; + padding: 6px 10px; + } + QPushButton:hover { + background-color: #3C8D40; + } + """) + browse_btn.clicked.connect(lambda: click_handler(line_edit)) + container.addWidget(line_edit) + container.addWidget(browse_btn) + return container + + dlt_layout = make_path_input("Input DLT Path", lambda inp: self.file(None, inp)) + adb_layout = make_path_input("Input ADB Path", lambda inp: self.file(None, inp)) + + group_layout.addLayout(dlt_layout) + group_layout.addLayout(adb_layout) + + layout.addWidget(device_group) + + # Save button self.save_btn = QPushButton("Save Device") self.save_btn.setFixedHeight(36) - self.save_btn.setStyleSheet(self.my_style) - self.save_btn.setFixedWidth(150) + self.save_btn.setCursor(Qt.PointingHandCursor) + self.save_btn.setStyleSheet(""" + QPushButton { + background-color: #007ACC; + color: white; + border: none; + border-radius: 4px; + padding: 8px 16px; + font-size: 13px; + font-weight: bold; + } + QPushButton:hover { + background-color: #005A99; + } + """) self.save_btn.clicked.connect(self.save_device) - for widget in [self.input_name, self.input_ip, self.input_port, self.input_dlt,self.input_adb, self.save_btn]: - widget.setStyleSheet(self.my_style) - layout.addWidget(widget) + + layout.addWidget(self.save_btn, alignment=Qt.AlignRight) layout.addStretch() - page.setLayout(layout) - return page + + return self.page + + #edit page will be loaded after this - def edit_page(self,device): + def edit_page(self, device): self.isEditing = True self.isEditingDevName = device["name"] print("Editing device:", device) + self.E_page = QWidget() layout = QVBoxLayout() - label = QLabel("Edit a device configuration") - label.setStyleSheet(my_style) + layout.setSpacing(16) + layout.setContentsMargins(40, 20, 40, 20) + + # === Header === + label = QLabel("Edit Device Configuration") + label.setStyleSheet(""" + font-size: 22px; + font-weight: bold; + color: white; + """) label.setAlignment(Qt.AlignCenter) - label.setObjectName("headers") - layout.setSpacing(20) - layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(label) + # === Input Fields === + input_style = """ + QLineEdit { + background-color: #1e1e1e; + color: white; + border: 1px solid #555; + border-radius: 6px; + padding: 6px 10px; + font-size: 14px; + } + QLineEdit:focus { + border: 1px solid #007ACC; + } + """ + self.input_name = QLineEdit(device.get("name", "")) + self.input_name.setPlaceholderText("Device Name") + self.input_name.setStyleSheet(input_style) + self.input_ip = QLineEdit(device.get("ip", "")) + self.input_ip.setPlaceholderText("IP Address") + self.input_ip.setStyleSheet(input_style) + self.input_port = QLineEdit(device.get("port", "")) - self.input_dlt = QLineEdit(device.get("dlt_path", "")) - self.input_adb = QLineEdit(device.get("adb_path", "")) + self.input_port.setPlaceholderText("Port") + self.input_port.setStyleSheet(input_style) - for input_field in [self.input_dlt, self.input_adb]: - input_field.mousePressEvent = lambda event, input=input_field: self.file(event, input) + self.input_dlt = QLineEdit(device.get("dlt_path", "")) + self.input_dlt.setPlaceholderText("DLT Path") + self.input_dlt.setStyleSheet(input_style) + self.input_dlt.mousePressEvent = lambda event, input=self.input_dlt: self.file(event, self.input_dlt) - for field in [self.input_name, self.input_ip, self.input_port, self.input_dlt, self.input_adb]: - field.setStyleSheet(self.my_style) + self.input_adb = QLineEdit(device.get("adb_path", "")) + self.input_adb.setPlaceholderText("ADB Path") + self.input_adb.setStyleSheet(input_style) + self.input_adb.mousePressEvent = lambda event, input=self.input_adb: self.file(event, self.input_adb) - self.save_btn = QPushButton("Save Device") - self.save_btn.setFixedWidth(100) - self.save_btn.setStyleSheet(self.my_style) + # === Save Button === + self.save_btn = QPushButton("๐Ÿ’พ Save Changes") + self.save_btn.setFixedHeight(40) + self.save_btn.setStyleSheet(""" + QPushButton { + background-color: #4CAF50; + color: white; + font-size: 14px; + font-weight: bold; + border-radius: 6px; + padding: 6px 12px; + } + QPushButton:hover { background-color: #45A049; } + QPushButton:pressed { background-color: #2E7D32; } + """) self.save_btn.clicked.connect(self.save_device) - for widget in [self.input_name, self.input_ip, self.input_port, self.input_dlt, self.input_adb, self.save_btn]: + # === Add all widgets === + for widget in [self.input_name, self.input_ip, self.input_port, self.input_dlt, self.input_adb]: layout.addWidget(widget) + layout.addSpacing(10) + layout.addWidget(self.save_btn, alignment=Qt.AlignCenter) layout.addStretch() + self.E_page.setLayout(layout) self.stackedWidget.addWidget(self.E_page) self.stackedWidget.setCurrentWidget(self.E_page) + def clear_form(self): self.input_name.clear() self.input_ip.clear() self.input_port.clear() - self.input_adb.clear() - self.input_dlt.clear() #settings page def sched_page(self): page = Main_utils_page().page @@ -352,66 +535,136 @@ def sched_page(self): return page def use_page(self): self.E_page = QWidget() - main_layout = QVBoxLayout() - label = QLabel("Test to Speech") - label.setStyleSheet(my_style) + main_layout = QVBoxLayout(self.E_page) + main_layout.setSpacing(20) + main_layout.setContentsMargins(20, 20, 20, 20) + + # === Header === + label = QLabel("Text to Speech") label.setAlignment(Qt.AlignCenter) - label.setObjectName("headers") - main_layout.setSpacing(0) - main_layout.setContentsMargins(0, 0, 0, 0) + label.setStyleSheet(""" + QLabel { + color: #ffffff; + font-size: 18px; + font-weight: bold; + } + """) main_layout.addWidget(label) + # === TOP HALF === top_half = QWidget() - top_layout = QHBoxLayout() - top_layout.setSpacing(20) - # --- LEFT + top_layout = QHBoxLayout(top_half) + top_layout.setSpacing(30) + + # --- LEFT SECTION (Inputs) left_layout = QVBoxLayout() - left_layout.setSpacing(10) + left_layout.setSpacing(15) + + label_style = "QLabel { color: #ffffff; font-size: 15px; font-weight:bold ;}" + input_style = """ + QLineEdit { + background-color: #3B3B3B; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 6px; + } + QLineEdit:focus { + border: 2px solid #007ACC; + } + """ + button_style = """ + QPushButton { + background-color: #007ACC; + color: white; + border: none; + border-radius: 4px; + padding: 6px 12px; + font-weight: bold; + } + QPushButton:hover { + background-color: #005A99; + } + """ + + # --- Custom Words Section --- self.label = QLabel("Input Custom Words to Speak") + self.label.setStyleSheet(label_style) self.Input_words = QLineEdit() - self.Input_words.setPlaceholderText("Input words to speak") + self.Input_words.setPlaceholderText("Type words to speak...") + self.Input_words.setStyleSheet(input_style) + self.Input_words.setFixedHeight(30) self.btn_speak = QPushButton("Speak") - self.btn_speak.setFixedWidth(100) + self.btn_speak.setFixedWidth(120) + self.btn_speak.setStyleSheet(button_style) self.btn_speak.clicked.connect(self.start_speak) + left_layout.addWidget(self.label) + left_layout.addWidget(self.Input_words) + left_layout.addWidget(self.btn_speak, alignment=Qt.AlignLeft) + + # --- Excel File Section --- self.label_excel = QLabel("Use Custom Excel File") + self.label_excel.setStyleSheet(label_style) self.Input_excel = QLineEdit() - self.Input_excel.setPlaceholderText("Input Excel file path") - self.Input_excel.mousePressEvent= lambda event, input=self.Input_excel: self.file(event, input) + self.Input_excel.setPlaceholderText("Select Excel file path...") + self.Input_excel.setStyleSheet(input_style) + self.Input_excel.mousePressEvent = lambda event, input=self.Input_excel: self.file(event, input) + self.Input_excel.setFixedHeight(30) self.btn_speak_excel = QPushButton("Start") - self.btn_speak_excel.setFixedWidth(100) + self.btn_speak_excel.setFixedWidth(120) + self.btn_speak_excel.setStyleSheet(button_style) self.btn_speak_excel.clicked.connect(self.start_file) - for field in [self.label, self.Input_words, self.btn_speak, - self.label_excel, self.Input_excel, self.btn_speak_excel]: - field.setStyleSheet(self.my_style) - left_layout.addWidget(field) + left_layout.addWidget(self.label_excel) + left_layout.addWidget(self.Input_excel) + left_layout.addWidget(self.btn_speak_excel, alignment=Qt.AlignLeft) left_layout.addStretch() - # --- RIGHT (30%) + # --- RIGHT SECTION (GIF + Selector) right_layout = QVBoxLayout() - self.movie = QMovie('/home/adin/Desktop/p3V1/Python_testing/src/dj.gif') - self.gif_label = QLabel("Music GIF here") - self.gif_label.setFixedSize(200, 150) - #self.gif_label.setStyleSheet("border: 1px solid gray;") - self.gif_label.setMovie(self.movie) + right_layout.setSpacing(15) + + self.gif_label = QLabel() + pixmap = QPixmap('src/assets/audio.png') + self.gif_label.setFixedSize(240, 180) + self.gif_label.setPixmap(pixmap) self.gif_label.setScaledContents(True) - self.movie.start() + + self.tts_selector = QComboBox() self.tts_selector.addItems(["pyttsx3", "gTTS"]) - self.tts_selector.setStyleSheet(combo_sheet) + self.tts_selector.setStyleSheet(""" + QComboBox { + background-color: #3B3B3B; + color: white; + border: 1px solid #555555; + border-radius: 4px; + padding: 4px; + } + QComboBox::drop-down { + border: none; + background: transparent; + } + """) + right_layout.addWidget(self.gif_label, alignment=Qt.AlignCenter) - right_layout.addWidget(self.tts_selector) + # right_layout.addWidget(self.tts_selector) right_layout.addStretch() - top_layout.addLayout(left_layout) - top_layout.addLayout(right_layout) - top_half.setLayout(top_layout) + + # Add sections to top layout + top_layout.addLayout(left_layout, 2) + top_layout.addLayout(right_layout, 1) # === BOTTOM HALF === bottom_half = QWidget() - bottom_layout = QVBoxLayout() + bottom_layout = QVBoxLayout(bottom_half) + bottom_layout.setSpacing(10) + self.bottom_label = QLabel("Temporary Area") self.bottom_label.setAlignment(Qt.AlignCenter) + self.bottom_label.setStyleSheet(label_style) + bottom_layout.addWidget(self.bottom_label) bottom_half.setLayout(bottom_layout) @@ -419,28 +672,28 @@ def use_page(self): main_layout.addWidget(top_half, 1) main_layout.addWidget(bottom_half, 1) - self.E_page.setLayout(main_layout) return self.E_page - # #save device function called from config and edit pages def save_device(self): dev_name = self.input_name.text().strip() dev_ip = self.input_ip.text().strip() dev_port = self.input_port.text().strip() - dev_dlt = self.input_dlt.text().strip() - dev_adb = self.input_adb.text().strip() - print(dev_name,dev_ip,dev_dlt,dev_adb,dev_port) + if dev_name.strip() == "" or dev_ip.strip() =="": + QMessageBox.warning(self, "Invalid Time", "Please enter time as HH:MM") + return + + if not os.path.exists(DEVICE_FILE) or os.stat(DEVICE_FILE).st_size == 0: with open(DEVICE_FILE, 'w') as f: f.write('[]') - if dev_name and dev_ip : + print(dev_name) + print(dev_ip) + if dev_name and dev_ip : device_data = { "name": dev_name, "ip": dev_ip, "port": dev_port, - "dlt_path": dev_dlt, - "adb_path" : dev_adb } #device data holds each dict #devices hold the whole list @@ -480,8 +733,8 @@ def file(self,event,input): def start_speak(self): text = self.Input_words.text() - if text == '': - self.tts.warn(mesg="Nothing to speak") + if text.strip() == '': + QMessageBox.critical(self.E_page, "Empty Input Error", "Empty input exception occurred") return else : # self.movie.start() @@ -491,14 +744,14 @@ def start_speak(self): def start_file(self): file_path = self.Input_excel.text() if file_path == '': - self.tts.warn(mesg="Give something to begin with") + QMessageBox.critical(self.E_page, "Empty file Error", "Could not find file") return else: if file_path.endswith('xlsx' or 'xls'): print("excel file found") self.tts.file_iter(file_path=file_path) else: - self.tts.warn(mesg="Give Correct *excel file") + QMessageBox.critical(self.E_page, "File Error","Could not find file") def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate @@ -510,7 +763,9 @@ def retranslateUi(self, MainWindow): self.btn_sched_page.setText(_translate('MainWindow','Test/Schedule')) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() + app.setStyle("fusion") + MainWindow = QtWidgets.QMainWindow() + MainWindow.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowCloseButtonHint) ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.setWindowTitle("Test Automation Runner") diff --git a/src/Update_Excel.py b/src/Update_Excel.py index 814f769..8e7c40c 100644 --- a/src/Update_Excel.py +++ b/src/Update_Excel.py @@ -1,14 +1,16 @@ from openpyxl import Workbook, load_workbook import os from datetime import datetime - +from email_service import send_with_outlook FIELDS = [ "timestamp", "wake_word", "utterance", "recognized_text", "intent", "is_final_asr","cpu_usage" ,"prompt_text", "confidence","retry_count", "error_code" ] - -EXCEL_FILE = f"session_log_{datetime.now().strftime('%Y-%m-%d_%H_%M_%S')}.xlsx" +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # folder of this script (src/) +FILES_DIR = os.path.join(BASE_DIR, "..", "files") # ../files +os.makedirs(FILES_DIR, exist_ok=True) +EXCEL_FILE = os.path.join(FILES_DIR,f"session_log_{datetime.now().strftime('%Y-%m-%d_%H_%M_%S')}.xlsx") class Update_Excel(): _instance = None @@ -40,6 +42,10 @@ def reset(self): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.data = {key: "" for key in FIELDS} self.data["timestamp"] = timestamp + def send_mail(self): + print("sending mail through win32 client after tts") + print("Sending excel file",EXCEL_FILE) + send_with_outlook(EXCEL_FILE) if __name__ == "__main__": session = Update_Excel() # Wake word detected @@ -54,3 +60,5 @@ def reset(self): session.write() # Start next session session.reset() + + session.send_mail() diff --git a/src/assets/audio.png b/src/assets/audio.png new file mode 100644 index 0000000..0288a29 Binary files /dev/null and b/src/assets/audio.png differ diff --git a/src/assets/bck.jpg b/src/assets/bck.jpg new file mode 100644 index 0000000..cf56bf8 Binary files /dev/null and b/src/assets/bck.jpg differ diff --git a/src/assets/bck1.jpg b/src/assets/bck1.jpg new file mode 100644 index 0000000..7211228 Binary files /dev/null and b/src/assets/bck1.jpg differ diff --git a/src/assets/bck2.jpg b/src/assets/bck2.jpg new file mode 100644 index 0000000..a3e3c68 Binary files /dev/null and b/src/assets/bck2.jpg differ diff --git a/src/assets/bck3.jpg b/src/assets/bck3.jpg new file mode 100644 index 0000000..b23e9b3 Binary files /dev/null and b/src/assets/bck3.jpg differ diff --git a/src/assets/download.png b/src/assets/download.png index 44358a2..c6b0d25 100644 Binary files a/src/assets/download.png and b/src/assets/download.png differ diff --git a/src/device_card.py b/src/device_card.py index 5d0deda..b870fb9 100644 --- a/src/device_card.py +++ b/src/device_card.py @@ -5,107 +5,97 @@ ) from PyQt5.QtGui import QPainter,QFont,QPixmap,QPainterPath from PyQt5.QtCore import Qt -import json from PyQt5.QtCore import pyqtSignal -import Test_runner_GUI + class DeviceCard(QWidget): config_signal = pyqtSignal(dict) use_signal = pyqtSignal(dict) + def __init__(self, device): super().__init__() self.device = device - self.sig = pyqtSignal() + # === Dark themed style === self.setStyleSheet(""" QWidget { - border: 1px solid #ccc; - border-radius: 10px; - background-color: #fefefe; + border: 1px ; + border-radius: 5px; + background: transparent; } QLabel { - color: #333; - border-radius:100px; + color: ffffff; } QPushButton { - padding: 5px 10px; - border-radius: 5px; + padding: 6px 12px; + border-radius: 6px; + font-weight: bold; } QPushButton#primary { - background-color: #4CAF50; + background-color: #007ACC; color: white; } + QPushButton#primary:hover { background-color: #005A99; } + QPushButton#primary:pressed { background-color: #2E7D32; } + QPushButton#secondary { - background-color: #e0e0e0; - color: black; + background-color: #007ACC; + color: white; } + QPushButton#secondary:hover { background-color: #005A99; } + QPushButton#secondary:pressed { background-color: #005A99; } """) - self.setFixedSize(240, 320) - def make_round_pixmap(pixmap): - size = min(pixmap.width(), pixmap.height()) - - # Center crop manually - x = (pixmap.width() - size) // 2 - y = (pixmap.height() - size) // 2 - cropped = pixmap.copy(x, y, size, size) - cropped = cropped.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation) - - rounded = QPixmap(size, size) - rounded.fill(Qt.transparent) - - path = QPainterPath() - path.addEllipse(0, 0, size, size) - painter = QPainter(rounded) - painter.setRenderHint(QPainter.Antialiasing) - painter.setClipPath(path) - painter.drawPixmap(0, 0, cropped) - painter.end() + # self.setFixedSize(240, 320) - return rounded - -# Apply to QLabel + image = QLabel(self) pixmap = QPixmap('src/assets/download.png') - pixmap1 = QPixmap(r'c:\Users\Adin N S\Downloads\256px-MINI_logo.svg.png') - round_pixmap = make_round_pixmap(pixmap) - image.setPixmap(round_pixmap) - image.setScaledContents(True) - # Device Title - # image = QLabel(self) - # pixmap = QPixmap('src/assets/download.jpg') - # image.setPixmap(pixmap) - # image.setScaledContents(True) + image.setPixmap(pixmap) + image.setFixedSize(250, 120) + + + # === Device Title === title = QLabel(device["name"]) - title.setFont(QFont("Arial", 12, QFont.Bold)) + title.setFont(QFont("Arial", 14, QFont.Bold)) + title.setStyleSheet("color: #ffffff; font-size: 14px; font-weight : bold") title.setAlignment(Qt.AlignCenter) - # Device Info + # === Device Info === info = QLabel(device["ip"]) + info.setStyleSheet("color: #ffffff; font-size: 12px; font-weight : bold") info.setAlignment(Qt.AlignCenter) - # Buttons + + # === Buttons === btn_use = QPushButton("Use") btn_use.setObjectName("primary") btn_use.clicked.connect(self.emit_use) + btn_config = QPushButton("Configure") btn_config.setObjectName("secondary") btn_config.clicked.connect(self.emit_config) - + btns = QHBoxLayout() + btns.addStretch() btns.addWidget(btn_use) btns.addWidget(btn_config) + btns.addStretch() + + # === Layout === layout = QVBoxLayout() layout.addStretch() - layout.addWidget(image) + layout.addWidget(image, alignment=Qt.AlignCenter) + layout.addSpacing(8) layout.addWidget(title) layout.addWidget(info) + layout.addSpacing(12) layout.addLayout(btns) layout.addStretch() self.setLayout(layout) + def emit_config(self): - # print("emitting config signal") self.config_signal.emit(self.device) + def emit_use(self): - # print("emitting use signal") - self.use_signal.emit(self.device) \ No newline at end of file + self.use_signal.emit(self.device) diff --git a/src/dj.gif b/src/dj.gif deleted file mode 100644 index 9a4af1f..0000000 Binary files a/src/dj.gif and /dev/null differ diff --git a/src/email_service.py b/src/email_service.py new file mode 100644 index 0000000..6948c75 --- /dev/null +++ b/src/email_service.py @@ -0,0 +1,43 @@ +import win32com.client as win32com +import os +import psutil +import time as t + +def send_with_outlook(file_path): + # Open Outlook + os.startfile('outlook') + outlook = win32com.Dispatch('outlook.application') + # Create a new mail item + accounts = win32com.Dispatch("outlook.application").Session.Accounts + print(accounts[0]) + # mail = outlook.CreateItem(0) + mail = outlook.CreateItemFromTemplate(r"c:\Users\jithin.sreekala\OneDrive - Acsia Technologies Private Limited\Pictures\mail.msg") + # 0 = Mail item + mail.SendUsingAccount = accounts[0] + mail.To = "adin.n@acsiatech.com" + mail.Subject = "Test Report" + mail.Body = "Hi,\n\nPlease find the attached test report.\n\nRegards" + # Attach the file + # mail.Sensitivity = 1 + if os.path.exists(file_path): + mail.Attachments.Add(file_path) + else: + print("File not found:", file_path) + mail.display(False) + try: # opens Outlook draft window + mail.Send() + print("sucessfully send mail") + except Exception as e: + print(e) + + t.sleep(5) + + for P in psutil.process_iter(): + if "OUTLOOK.EXE" in P.name().upper(): + P.kill() + +# Test run +if __name__ == "__main__": + test_file = r"c:\Users\jithin.sreekala\Downloads\IDCEVO_IPA_BCA_STS_Suite _Analyised.zip" #for testing + send_with_outlook(test_file) + diff --git a/src/new_core.py b/src/new_core.py deleted file mode 100755 index 61f4572..0000000 --- a/src/new_core.py +++ /dev/null @@ -1,186 +0,0 @@ -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtWidgets import ( - QApplication, QMainWindow, QWidget, QPushButton, QLabel, - QVBoxLayout, QHBoxLayout, QStackedWidget, QLineEdit, QTextEdit, - QFrame, QScrollArea,QComboBox,QRadioButton,QFileDialog,QMessageBox,QCheckBox -) -from PyQt5.QtGui import QIcon,QFont,QPixmap,QMovie -from PyQt5.QtCore import Qt -import json -from PyQt5.QtCore import pyqtSignal -import new_ui -from styles import * -import subprocess -import os -from TTS_main import Test_begin -class Main_utils_page(QWidget): - def __init__(self): - super().__init__() - self.sig_use = pyqtSignal() - self.page = self.main_page() - - def main_page(self): - page = self.create_card() - main_layout = QHBoxLayout() - main_layout.setAlignment(Qt.AlignCenter) - main_layout.addWidget(page) - page.setLayout(main_layout) - return page - - def create_card(self): - card = QWidget() - card.setStyleSheet("background-color: #272757; border-radius: 12px; padding: 2px;") - vbox = QVBoxLayout() - vbox.setAlignment(Qt.AlignTop) - vbox.setSpacing(15) - - label = QLabel("Start A Task or Schedule One") - label.setStyleSheet(my_style) - label.setAlignment(Qt.AlignCenter) - vbox.addWidget(label) - # ---------- IP Address Input ---------- - ip_path_edit = QLineEdit() - ip_path_edit.setPlaceholderText("IP Address") - ip_path_edit.setStyleSheet(my_style) - ip_path_edit.setText('169.254.80.') - vbox.addWidget(ip_path_edit) - - # ---------- Excel File Input ---------- - exe_path_edit = QLineEdit() - exe_path_edit.setPlaceholderText("Path to Excel") - exe_path_edit.setStyleSheet(my_style) - browse_btn = QPushButton("Browse") - browse_btn.setStyleSheet(my_style) - browse_btn.setFixedSize(100,40) - browse_btn.clicked.connect(lambda: exe_path_edit.setText( - QFileDialog.getOpenFileName(None, "Select Excel", "", "Excel Files (*.xlsx)")[0] - )) - - exe_hbox = QHBoxLayout() - exe_hbox.addWidget(exe_path_edit) - exe_hbox.addWidget(browse_btn) - vbox.addLayout(exe_hbox) - - # ---------- Log Folder Input ---------- - log_path_edit = QLineEdit() - log_path_edit.setPlaceholderText("Path to Log Folder") - log_path_edit.setStyleSheet(my_style) - log_browse_btn = QPushButton("Browse") - log_browse_btn.setStyleSheet(my_style) - log_browse_btn.setFixedSize(100,40) - log_browse_btn.clicked.connect(lambda: log_path_edit.setText( - QFileDialog.getExistingDirectory(self, 'Select Log Folder') - )) - - log_hbox = QHBoxLayout() - log_hbox.addWidget(log_path_edit) - log_hbox.addWidget(log_browse_btn) - vbox.addLayout(log_hbox) - - # ---------- DLP Project File ---------- - fp_path_edit = QLineEdit() - fp_path_edit.setPlaceholderText("Project file for DLT ECU Conf") - fp_path_edit.setStyleSheet(my_style) - fp_browse_btn = QPushButton("Browse") - fp_browse_btn.setStyleSheet(my_style) - fp_browse_btn.setFixedSize(100,40) - fp_browse_btn.clicked.connect(lambda: fp_path_edit.setText( - QFileDialog.getOpenFileName(None, "Select DLP File", "", "DLP Files (*.DLP)")[0] - )) - - fp_hbox = QHBoxLayout() - fp_hbox.addWidget(fp_path_edit) - fp_hbox.addWidget(fp_browse_btn) - vbox.addLayout(fp_hbox) - - # ---------- Time Input ---------- - time_input = QLineEdit() - time_input.setStyleSheet(my_style) - time_input.setPlaceholderText("Schedule Time (HH:MM, e.g., 14:30) optional IN DEVLOPMENT") - vbox.addWidget(time_input) - - # ---------- Buttons ---------- - btn_hbox = QHBoxLayout() - - test_btn = QPushButton("Start Test") - test_btn.setStyleSheet(my_style) - test_btn.setFixedSize(100,60) - test_btn.clicked.connect(lambda: Test_begin( - mcu_ip=ip_path_edit.text(), - input_excel=exe_path_edit.text(), - directory=log_path_edit.text(), - dlp_file=fp_path_edit.text(), - load=Give_load.isChecked(), - stack=tech_stack.currentText() - )) - - schedule_btn = QPushButton("Schedule") - schedule_btn.setStyleSheet(my_style) - schedule_btn.setFixedSize(100,60) - schedule_btn.clicked.connect(lambda: self.create_and_schedule_task( - exe_path_edit.text(), - "MyApp_Task", - time_input.text() - )) - checkbox_layout = QVBoxLayout() - checkbox_label = QLabel("Give load to system?") - checkbox_label.setStyleSheet(my_style) - Give_load = QRadioButton("Yes (ACA ONLY)") - Give_no_load = QRadioButton("No") - Give_load.setStyleSheet("color: white;") - Give_no_load.setStyleSheet("color: white;") - checkbox_layout.addWidget(checkbox_label) - checkbox_layout.addWidget(Give_load) - checkbox_layout.addWidget(Give_no_load) - tech_stack = QComboBox() - tech_stack.addItem("BCA") - tech_stack.addItem("Cerance") - tech_stack.setStyleSheet(combo_sheet) - checkbox_layout.addWidget(tech_stack) - vbox.addLayout(checkbox_layout) - btn_hbox.addWidget(test_btn) - btn_hbox.addWidget(schedule_btn) - vbox.addLayout(btn_hbox) - # ---------- Final Card Layout ---------- - card.setLayout(vbox) - return card - - def printer(self): - print("god") - print(self.time_input.text()) - print(self.exe_input.text()) - - def create_and_schedule_task(self, exe_path, task_name, time_str): - print(exe_path) - print(task_name) - print(time_str) - cwd = os.getcwd()+'/bats' - #we Create .bat file (i dont know how much safe is this one) - os.makedirs(cwd, exist_ok=True) # Create the directory if it doesn't exist - bat_path = os.path.join(cwd, f"{task_name}.bat") - # bat_path = os.path.join(cwd , f"{task_name}.bat") - with open(bat_path, 'w') as f: - f.write(f'start "" "{exe_path}"\n') - - # Schedule task using schtasks , like running a command in linux (can bring improvements) - hour, minute = time_str.split(":") - # https://learn.microsoft.com/en-us/windows/win32/taskschd/schtasks for your reference - # this is definetley gonna break the system - command = [ - "schtasks", - "/Create", - "/SC", "DAILY", - "/TN", task_name, - "/TR", f'"{bat_path}"', - "/ST", f"{hour}:{minute}", - "/F" - ] - - try: - subprocess.run(command, check=True) - QMessageBox.information(self, "Scheduled", f"Task '{task_name}' scheduled at {time_str}") - except subprocess.CalledProcessError as e: - QMessageBox.critical(self, "Error", f"Failed to schedule task:\n{str(e)}") - - - diff --git a/src/new_ui.py b/src/new_ui.py deleted file mode 100755 index fe6087a..0000000 --- a/src/new_ui.py +++ /dev/null @@ -1,502 +0,0 @@ - -# Form implementation generated from reading ui file 'tt.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. - - -from PyQt5 import QtCore, QtGui, QtWidgets -import sys -from PyQt5.QtWidgets import ( - QApplication, QMainWindow, QWidget, QPushButton, QLabel, - QVBoxLayout, QHBoxLayout, QStackedWidget, QLineEdit, QTextEdit, - QFrame, QScrollArea,QSizePolicy,QGridLayout,QFileDialog,QMessageBox,QComboBox -) -from PyQt5.QtGui import QIcon,QFont,QPixmap,QMovie -from PyQt5.QtCore import Qt -import json -import os -from PyQt5.QtCore import pyqtSignal -import time as t -import utils -from new_core import Main_utils_page -from device_card import DeviceCard -from rack_control_ui import Main_rack_page -from styles import * - -DEVICE_FILE = "devices.json" -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - self.tts = utils.tts_main() - self.isEditing = False - self.isEditingDevName = '' - self.my_style = """ - - QLineEdit { - border: 1px solid #ccc; - border-radius: 6px; - padding: 6px 10px; - background-color:#008a91; - color: #333; - font-size: 14px; - } - - QLineEdit:focus { - border: 1px solid #0078d7; /* Blue border on focus */ - background-color: #ffffff; - } - - QLineEdit::placeholder { - color: #999; - } - QPushButton { - padding: 5px 10px; - border-radius: 5px; - background-color: #4CAF50; - color: white; - } - QLabel{ - color: white; - - } - -""" - self.btn_sheet=''' -QPushButton { - color: rgb(255, 255, 255); - background-color: #272757 ; - border: 0px solid; - text-align:center; - border-radius : 10px -} -QPushButton:hover { - background-color: #9575cd; - font-size:17px; - border-radius : 10px; - margin : 5px; -} -''' - MainWindow.setObjectName("MainWindow") - MainWindow.resize(1100, 600) - MainWindow.setMinimumSize(QtCore.QSize(1000, 500)) - MainWindow.setStyleSheet("background-color: #241A42;") - self.centralwidget = QtWidgets.QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - #self.centralwidget.setStyleSheet() - self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.verticalLayout.setSpacing(0) - self.verticalLayout.setObjectName("verticalLayout") - self.Top_Bar = QtWidgets.QFrame(self.centralwidget) - self.Top_Bar.setMaximumSize(QtCore.QSize(16777215, 30)) - self.Top_Bar.setStyleSheet("background-color:#2C224D;") - self.Top_Bar.setFrameShape(QtWidgets.QFrame.NoFrame) - self.Top_Bar.setFrameShadow(QtWidgets.QFrame.Raised) - self.Top_Bar.setObjectName("Top_Bar") - self.horizontalLayout = QtWidgets.QHBoxLayout(self.Top_Bar) - self.horizontalLayout.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout.setSpacing(0) - self.horizontalLayout.setObjectName("horizontalLayout") - self.frame_toggle = QtWidgets.QFrame(self.Top_Bar) - self.frame_toggle.setMaximumSize(QtCore.QSize(100, 30)) - - self.frame_toggle.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_toggle.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_toggle.setObjectName("frame_toggle") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_toggle) - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_2.setSpacing(0) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.Btn_Toggle = QtWidgets.QLabel(self.frame_toggle) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.Btn_Toggle.sizePolicy().hasHeightForWidth()) - self.Btn_Toggle.setSizePolicy(sizePolicy) - - self.pixmap1 = QPixmap('src/assets/logo.png') - self.Btn_Toggle.setPixmap(self.pixmap1) - self.Btn_Toggle.setScaledContents(True) - self.Btn_Toggle.setStyleSheet("background-color: #272757;") - - self.Btn_Toggle.setObjectName("Btn_Toggle") - self.verticalLayout_2.addWidget(self.Btn_Toggle) - self.horizontalLayout.addWidget(self.frame_toggle) - self.frame_top = QtWidgets.QFrame(self.Top_Bar) - self.frame_top.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_top.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_top.setObjectName("frame_top") - self.horizontalLayout.addWidget(self.frame_top) - self.verticalLayout.addWidget(self.Top_Bar) - self.Content = QtWidgets.QFrame(self.centralwidget) - self.Content.setFrameShape(QtWidgets.QFrame.NoFrame) - self.Content.setFrameShadow(QtWidgets.QFrame.Raised) - self.Content.setObjectName("Content") - self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.Content) - self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_2.setSpacing(0) - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.frame_left_menu = QtWidgets.QFrame(self.Content) - self.frame_left_menu.setMinimumSize(QtCore.QSize(150, 0)) - self.frame_left_menu.setMaximumSize(QtCore.QSize(150, 16777215)) - # self.frame_left_menu.setStyleSheet("background-color: rgb(35, 35, 35);") - self.frame_left_menu.setStyleSheet("background-color: #272757;") - self.frame_left_menu.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_left_menu.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_left_menu.setObjectName("frame_left_menu") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_left_menu) - self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_3.setObjectName("verticalLayout_3") - self.frame_top_menus = QtWidgets.QFrame(self.frame_left_menu) - self.frame_top_menus.setFrameShape(QtWidgets.QFrame.NoFrame) - self.frame_top_menus.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_top_menus.setObjectName("frame_top_menus") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_top_menus) - self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_4.setSpacing(0) - self.verticalLayout_4.setObjectName("verticalLayout_4") - self.btn_home_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_home_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_home_page.setStyleSheet(self.btn_sheet) - self.btn_home_page.setObjectName("btn_home_page") - self.btn_home_page.setIcon(QIcon('src/assets/list.svg')) - - self.btn_new_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_new_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_new_page.setStyleSheet(self.btn_sheet) - self.btn_new_page.setObjectName("btn_new_page") - self.btn_new_page.setIcon(QIcon('src/assets/add.svg')) - - self.btn_sttings_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_sttings_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_sttings_page.setStyleSheet(self.btn_sheet) - self.btn_sttings_page.setObjectName("Rack_sttings_page") - self.btn_sttings_page.setIcon(QIcon('src/assets/settings.svg')) - - self.btn_general_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_general_page.setMinimumSize(QtCore.QSize(0, 40)) - self.btn_general_page.setStyleSheet(self.btn_sheet) - self.btn_general_page.setObjectName("btn_general_page") - self.btn_general_page.setIcon(QIcon('src/assets/speak.svg')) - - self.btn_sched_page = QtWidgets.QPushButton(self.frame_top_menus) - self.btn_sched_page.setMinimumSize(QtCore.QSize(0,40)) - self.btn_sched_page.setStyleSheet(self.btn_sheet) - self.btn_sched_page.setIcon(QIcon('src/assets/Timer.svg')) - for widget in [self.btn_home_page,self.btn_new_page,self.btn_general_page,self.btn_sched_page,self.btn_sttings_page]: - self.verticalLayout_4.addWidget(widget) - self.verticalLayout_3.addWidget(self.frame_top_menus, 0, QtCore.Qt.AlignTop) - self.horizontalLayout_2.addWidget(self.frame_left_menu) - self.frame_pages = QtWidgets.QFrame(self.Content) - self.frame_pages.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_pages.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_pages.setObjectName("frame_pages") - self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.frame_pages) - self.verticalLayout_5.setObjectName("verticalLayout_5") - - self.stackedWidget = QtWidgets.QStackedWidget(self.frame_pages) - self.stackedWidget.setObjectName("stackedWidget") - self.stackedWidget.setStyleSheet('background-color : #120C26 ;') - self.page1 = self.home_page() - self.page2 = self.add_page() - self.page3 = self.sched_page() - self.page4 = self.use_page() - self.page5 = self.rack_page() - self.stackedWidget.addWidget(self.page1) - self.stackedWidget.addWidget(self.page2) - self.stackedWidget.addWidget(self.page3) - self.stackedWidget.addWidget(self.page4) - self.stackedWidget.addWidget(self.page5) - self.verticalLayout_5.addWidget(self.stackedWidget) - self.horizontalLayout_2.addWidget(self.frame_pages) - self.verticalLayout.addWidget(self.Content) - MainWindow.setCentralWidget(self.centralwidget) - self.retranslateUi(MainWindow) - self.stackedWidget.setCurrentIndex(0) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - self.btn_home_page.clicked.connect(lambda:self.stackedWidget.setCurrentWidget(self.page1)) - self.btn_new_page.clicked.connect(lambda:self.stackedWidget.setCurrentWidget(self.page2)) - self.btn_sched_page.clicked.connect(lambda:self.stackedWidget.setCurrentWidget(self.page3)) - self.btn_general_page.clicked.connect(lambda:self.stackedWidget.setCurrentWidget(self.page4)) - self.btn_sttings_page.clicked.connect(lambda:self.stackedWidget.setCurrentWidget(self.page5)) -# home page - def rack_page(self): - page = QWidget() - h_box = QHBoxLayout() - self.card = Main_rack_page().page - h_box.addWidget(self.card) - page.setLayout(h_box) - return page - - def home_page(self): - page = QWidget() - scroll = QScrollArea() - scroll.setWidgetResizable(True) - container = QWidget() - grid_layout = QGridLayout() - try: - with open (DEVICE_FILE , "r") as file: - devices = json.load(file) - # print("json document parsing") - except Exception as e: - devices = [] - print(e) - row = 0 - col = 0 - for i, device in enumerate(devices): - card = DeviceCard(device) - card.config_signal.connect(self.edit_page) - card.use_signal.connect(self.sched_page) - grid_layout.addWidget(card, row, col) - - col += 1 - if col == 3: # 3 cards per row, change if you want more or fewer - col = 0 - row += 1 - - container.setLayout(grid_layout) - layout = QVBoxLayout() - scroll.setWidget(container ) - layout.addWidget(scroll) - page.setLayout(layout) - return page -#config page - def add_page(self): - page = QWidget() - layout = QVBoxLayout() - layout.setSpacing(20) - layout.setContentsMargins(0, 0, 0, 0) - self.input_name = QLineEdit() - self.input_name.setPlaceholderText("Device Name") - self.input_ip = QLineEdit() - self.input_ip.setPlaceholderText("IP Address") - self.input_port = QLineEdit() - self.input_port.setPlaceholderText("Port") - self.input_dlt = QLineEdit() - self.input_dlt.setPlaceholderText("input DLT path") - self.input_dlt.mousePressEvent =lambda event , input=self.input_dlt:self.file(event,self.input_dlt) - self.input_adb = QLineEdit() - self.input_adb.setPlaceholderText("input ADB path") - self.input_adb.mousePressEvent = lambda event , input=self.input_adb:self.file(event,self.input_adb) - self.save_btn = QPushButton("Save Device") - self.save_btn.setFixedHeight(36) - self.save_btn.setStyleSheet(self.my_style) - self.save_btn.setFixedWidth(150) - self.save_btn.clicked.connect(self.save_device) - for widget in [self.input_name, self.input_ip, self.input_port, self.input_dlt,self.input_adb, self.save_btn]: - widget.setStyleSheet(self.my_style) - layout.addWidget(widget) - layout.addStretch() - page.setLayout(layout) - return page - #edit page will be loaded after this - def edit_page(self,device): - self.isEditing = True - self.isEditingDevName = device["name"] - # print("Editing device:", device) - self.E_page = QWidget() - layout = QVBoxLayout() - layout.setSpacing(20) - layout.setContentsMargins(0, 0, 0, 0) - - self.input_name = QLineEdit(device.get("name", "")) - self.input_ip = QLineEdit(device.get("ip", "")) - self.input_port = QLineEdit(device.get("port", "")) - self.input_dlt = QLineEdit(device.get("dlt_path", "")) - self.input_adb = QLineEdit(device.get("adb_path", "")) - - for input_field in [self.input_dlt, self.input_adb]: - input_field.mousePressEvent = lambda event, input=input_field: self.file(event, input) - - for field in [self.input_name, self.input_ip, self.input_port, self.input_dlt, self.input_adb]: - field.setStyleSheet(self.my_style) - - self.save_btn = QPushButton("Save Device") - self.save_btn.setFixedWidth(100) - self.save_btn.setStyleSheet(self.my_style) - self.save_btn.clicked.connect(self.save_device) - - for widget in [self.input_name, self.input_ip, self.input_port, self.input_dlt, self.input_adb, self.save_btn]: - layout.addWidget(widget) - - layout.addStretch() - self.E_page.setLayout(layout) - - self.stackedWidget.addWidget(self.E_page) - self.stackedWidget.setCurrentWidget(self.E_page) - - def clear_form(self): - self.input_name.clear() - self.input_ip.clear() - self.input_port.clear() - self.input_adb.clear() - self.input_dlt.clear() -#settings page - def sched_page(self): - page = Main_utils_page().page - self.stackedWidget.addWidget(page) - self.stackedWidget.setCurrentWidget(page) - return page - def use_page(self): - self.E_page = QWidget() - main_layout = QVBoxLayout() - main_layout.setSpacing(0) - main_layout.setContentsMargins(0, 0, 0, 0) - # === TOP HALF === - top_half = QWidget() - top_layout = QHBoxLayout() - top_layout.setSpacing(20) - # --- LEFT - left_layout = QVBoxLayout() - left_layout.setSpacing(10) - self.label = QLabel("Input Custom Words to Speak") - self.Input_words = QLineEdit() - self.Input_words.setPlaceholderText("Input words to speak") - self.btn_speak = QPushButton("Speak") - self.btn_speak.setFixedWidth(100) - self.btn_speak.clicked.connect(self.start_speak) - - self.label_excel = QLabel("Use Custom Excel File") - self.Input_excel = QLineEdit() - self.Input_excel.setPlaceholderText("Input Excel file path") - self.Input_excel.mousePressEvent= lambda event, input=self.Input_excel: self.file(event, input) - self.btn_speak_excel = QPushButton("Start") - self.btn_speak_excel.setFixedWidth(100) - self.btn_speak_excel.clicked.connect(self.start_file) - - for field in [self.label, self.Input_words, self.btn_speak, - self.label_excel, self.Input_excel, self.btn_speak_excel]: - field.setStyleSheet(self.my_style) - left_layout.addWidget(field) - left_layout.addStretch() - - # --- RIGHT (30%) - right_layout = QVBoxLayout() - self.movie = QMovie('/home/adin/Desktop/p3V1/Python_testing/src/dj.gif') - self.gif_label = QLabel("Music GIF here") - self.gif_label.setFixedSize(200, 150) - #self.gif_label.setStyleSheet("border: 1px solid gray;") - self.gif_label.setMovie(self.movie) - self.gif_label.setScaledContents(True) - self.movie.start() - self.tts_selector = QComboBox() - self.tts_selector.addItems(["pyttsx3", "gTTS"]) - self.tts_selector.setStyleSheet(combo_sheet) - right_layout.addWidget(self.gif_label, alignment=Qt.AlignCenter) - right_layout.addWidget(self.tts_selector) - right_layout.addStretch() - top_layout.addLayout(left_layout) - top_layout.addLayout(right_layout) - top_half.setLayout(top_layout) - - # === BOTTOM HALF === - bottom_half = QWidget() - bottom_layout = QVBoxLayout() - self.bottom_label = QLabel("Temporary Area") - self.bottom_label.setAlignment(Qt.AlignCenter) - bottom_layout.addWidget(self.bottom_label) - bottom_half.setLayout(bottom_layout) - - # === Final Composition === - main_layout.addWidget(top_half, 1) - main_layout.addWidget(bottom_half, 1) - - self.E_page.setLayout(main_layout) - return self.E_page - - -# #save device function called from config and edit pages - def save_device(self): - dev_name = self.input_name.text().strip() - dev_ip = self.input_ip.text().strip() - dev_port = self.input_port.text().strip() - dev_dlt = self.input_dlt.text().strip() - dev_adb = self.input_adb.text().strip() - print(dev_name,dev_ip,dev_dlt,dev_adb,dev_port) - if not os.path.exists(DEVICE_FILE) or os.stat(DEVICE_FILE).st_size == 0: - with open(DEVICE_FILE, 'w') as f: - f.write('[]') - if dev_name and dev_ip : - device_data = { - "name": dev_name, - "ip": dev_ip, - "port": dev_port, - "dlt_path": dev_dlt, - "adb_path" : dev_adb - } - #device data holds each dict - #devices hold the whole list - - with open(DEVICE_FILE , "r") as device_file: - try: - devices = json.load(device_file) - except json.JSONDecodeError: - devices = [] - - #devices.append(device_data) #removing beacuse we dont want duplicates due to editing - if self.isEditing : - for index,dev in enumerate(devices): - if dev["name"] == self.isEditingDevName: - devices[index] = device_data - break - else: - devices.append(device_data) - with open(DEVICE_FILE , "w") as file: - json.dump(devices,file,indent=4) - # print("saving to json file") - - self.clear_form() - self.new_page = self.home_page() - self.stackedWidget.addWidget(self.new_page) - self.stackedWidget.setCurrentWidget(self.new_page) - - def file(self,event,input): - file_dialog = QFileDialog() - file_dialog.setWindowTitle("Open File") - file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile) - file_dialog.setViewMode(QFileDialog.ViewMode.Detail) - if file_dialog.exec(): - selected_files = file_dialog.selectedFiles() - print("Selected File:", selected_files[0]) - input.setText(selected_files[0]) - - def start_speak(self): - text = self.Input_words.text() - if text == '': - self.tts.warn(mesg="เดธเด‚เดธเดพเดฐเดฟเด•เตเด•เดพเตป เดŽเดจเตเดคเต†เด™เตเด•เดฟเดฒเตเด‚ เดŸเต†เด•เตเดธเตเดฑเตเดฑเต เดจเตฝเด•เตเด•") - return - else : - # self.movie.start() - self.tts.tts_converter(text) - t.sleep(3) - # self.movie.stop() - def start_file(self): - file_path = self.Input_excel.text() - if file_path == '': - self.tts.warn(mesg="เดคเตเดŸเด™เตเด™เดพเตป เดŽเดจเตเดคเต†เด™เตเด•เดฟเดฒเตเด‚ เด•เตŠเดŸเตเด•เตเด•เต‚. เดฌเดพเด•เตเด•เดฟ เดจเดฎเตเด•เตเด•เต เดชเดฟเดจเตเดจเต€เดŸเต เดšเต†เดฏเตเดฏเดพเด‚") - return - else: - if file_path.endswith('xlsx' or 'xls'): - print("excel file found") - self.tts.file_iter(file_path=file_path) - else: - self.tts.warn(mesg="เดถเดฐเดฟเดฏเดพเดฏ เดŽเด•เตเดธเตฝ เดซเดฏเตฝ เดจเตฝเด•เตเด•") - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - self.btn_new_page.setText(_translate("MainWindow", "Add a Device")) - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.btn_home_page.setText(_translate("MainWindow", "Home")) - self.btn_sttings_page.setText(_translate("MainWindow", "Settings")) - self.btn_general_page.setText(_translate("MainWindow", " TTS Speech")) - self.btn_sched_page.setText(_translate('MainWindow','Test/Schedule')) -if __name__ == "__main__": - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - - sys.exit(app.exec_()) diff --git a/src/rack_control_ui.py b/src/rack_control_ui.py index 6e1f644..f95238c 100644 --- a/src/rack_control_ui.py +++ b/src/rack_control_ui.py @@ -1,11 +1,12 @@ import sys from PyQt5.QtWidgets import ( QApplication, - QMainWindow, + QGridLayout, QWidget, QVBoxLayout, QPushButton, - QLabel + QLabel, + QHBoxLayout ) from PyQt5.QtCore import Qt import serial @@ -30,78 +31,145 @@ def __init__(self): self.connect() self.init_ui() def connect(self): + # Close existing connection if open + if hasattr(self, "ser") and self.ser.is_open: + print('self.ser.close()') + try: - self.ser = serial.Serial(port='COM3', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1) - self.st_msg = "Rack Connected" - print('connected') - # self.init_ui() + self.ser = serial.Serial( + port='COM3', + baudrate=115200, + bytesize=8, + parity='N', + stopbits=1, + timeout=1 + ) + self.st_msg = "Rack Connected" + print("connected") + if hasattr(self, "rack_status"): + self.rack_status.setText(self.st_msg) + self.rack_status.setStyleSheet("font-size: 22px; font-weight: bold; color: lime;") + except serial.SerialException: - print('disconnected') self.st_msg = "Rack disconnected" - # self.init_ui() + print(" serial.SerialException disconnected") + if hasattr(self, "rack_status"): + self.rack_status.setText(self.st_msg) + self.rack_status.setStyleSheet("font-size: 22px; font-weight: bold; color: red;") + + except Exception: + print( ' Exception disconnected') + self.st_msg = "Rack Disconnected" + if hasattr(self, "rack_status"): + self.rack_status.setText(self.st_msg) + self.rack_status.setStyleSheet("font-size: 22px; font-weight: bold; color: red;") + def init_ui(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignCenter) - layout.setSpacing(10) - # Title + layout.setSpacing(20) + + # === Title === title = QLabel("Device Control Panel") title.setAlignment(Qt.AlignCenter) + title.setStyleSheet("font-size: 26px; font-weight: bold; color: white;") + layout.addWidget(title) + + # === Rack Status === self.rack_status = QLabel(self.st_msg) - self.rack_status.setStyleSheet("font-size: 24px; font-weight: bold;color:red;") self.rack_status.setAlignment(Qt.AlignCenter) - self.warning = QLabel("*dont use or press the buttons unless you have a HOST PC connnection through serial otherwise it'll crash") - self.warning.setStyleSheet("font-weight: bold;color:white;") - self.warning.setAlignment(Qt.AlignCenter) - title.setStyleSheet("font-size: 24px; font-weight: bold;color:white;") - layout.addWidget(title) - layout.addWidget(self.warning) + self.rack_status.setStyleSheet("font-size: 22px; font-weight: bold; color: red;") layout.addWidget(self.rack_status) - - # Button names + + # === Button Styles === + btn_style_on = """ + QPushButton { + background-color: #4CAF50; + color: white; + font-size: 16px; + font-weight: bold; + padding: 8px 16px; + border-radius: 6px; + min-width: 100px; + min-height: 40px; + } + QPushButton:hover { background-color: #45A049; } + QPushButton:pressed { background-color: #2E7D32; } + """ + btn_style_off = """ + QPushButton { + background-color: #F44336; + color: white; + font-size: 16px; + font-weight: bold; + padding: 8px 16px; + border-radius: 6px; + min-width: 100px; + min-height: 40px; + } + QPushButton:hover { background-color: #E53935; } + QPushButton:pressed { background-color: #B71C1C; } + """ + + # === Grid Layout for Controls === + grid = QGridLayout() + grid.setSpacing(15) + button_names = ['Mute', 'OBD', 'CL30', 'CL30F', 'CL30B'] - # Create buttons - self.buttons = [] - for i, name in enumerate(button_names): - btn = QPushButton(f"{name} ") - btn.setFixedSize(200, 50) - btn.setCheckable(True) - btn.setStyleSheet( - """ - QPushButton { - background-color: #f0f0f0; - border: 2px solid #333; - border-radius: 10px; - font-size: 16px; - } - QPushButton:checked { - background-color: #66bb6a; - color: white; - } - """ - ) - btn.clicked.connect(lambda _, idx=i: self.toggle_button(idx)) - layout.addWidget(btn, alignment=Qt.AlignCenter) - self.buttons.append(btn) - ref_btn = QPushButton('Refresh') - ref_btn.setFixedSize(250, 30) - ref_btn.setStyleSheet( - """ - QPushButton { - background-color: #f0f0f0; - border: 2px solid #333; - border-radius: 10px; - font-size: 10px; - } - QPushButton:pressed { - background-color: #66bb6a; - color: white; - } """ - ) + for row, name in enumerate(button_names): + label = QLabel(name) + label.setStyleSheet("color: white; font-size: 14px; font-weight: bold;") + + btn_on = QPushButton("ON") + btn_on.setStyleSheet(btn_style_on) + btn_on.clicked.connect(lambda _, idx=row: self.send_command(idx, True)) + grid.addWidget(label, row, 1, alignment=Qt.AlignRight) + + grid.addWidget(btn_on, row, 0) + + btn_off = QPushButton("OFF") + btn_off.setStyleSheet(btn_style_off) + btn_off.clicked.connect(lambda _, idx=row: self.send_command(idx, False)) + grid.addWidget(btn_off, row, 2) + + # === Wrap grid in a centered container === + grid_container = QWidget() + grid_container.setLayout(grid) + grid_layout = QHBoxLayout() + grid_layout.addStretch() + grid_layout.addWidget(grid_container) + grid_layout.addStretch() + layout.addLayout(grid_layout) + + # === Refresh Button Centered === + ref_btn = QPushButton("๐Ÿ”„ Refresh") + ref_btn.setFixedHeight(40) + ref_btn.setStyleSheet(""" + QPushButton { + background-color: #007ACC; + color: white; + border-radius: 6px; + font-size: 14px; + font-weight: bold; + padding: 6px 12px; + min-width: 50px; + } + QPushButton:hover { background-color: #005A99; } + QPushButton:pressed { background-color: #004C80; } + """) ref_btn.clicked.connect(self.connect) - layout.addWidget(ref_btn,alignment=Qt.AlignCenter) + layout.addWidget(ref_btn, alignment=Qt.AlignCenter) + self.setLayout(layout) + + def send_command(self, button_idx, turn_on): + """Send ON or OFF command directly .""" + cmd = self.button_commands[button_idx][0] if turn_on else self.button_commands[button_idx][1] + self.ser.write(cmd.encode() + b'\n') + + def toggle_button(self, button_idx): is_on = self.button_states[button_idx] diff --git a/src/testui.py b/src/testui.py deleted file mode 100755 index c7a5272..0000000 --- a/src/testui.py +++ /dev/null @@ -1,265 +0,0 @@ - -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtWidgets import * -from PyQt5.QtGui import QMovie -import os -import sys -from gtts import gTTS -import speech_recognition as sr -import pandas as pd -import subprocess -import signal -import platform -import time as t -import pyttsx3 -import TTS_main - - -cols = [0] -filename = '' -class Ui_MainWindow(object): - filename = '' - def setupUi(self, MainWindow): - MainWindow.setObjectName("MainWindow") - MainWindow.resize(446, 423) - self.centralwidget = QtWidgets.QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - self.centralwidget.setStyleSheet("background-color: #272e2a") - self.Speak_button = QtWidgets.QPushButton(self.centralwidget) - self.Speak_button.setGeometry(QtCore.QRect(360, 330, 81, 31)) - self.Speak_button.setObjectName("Speak_button") - self.Speak_button.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#01ff01")) - self.Input = QtWidgets.QPlainTextEdit(self.centralwidget) - self.Input.setGeometry(QtCore.QRect(0, 330, 351, 31)) - self.Input.setPlaceholderText("") - self.Input.setObjectName("Input") - self.Input.setStyleSheet("background-color: #545755") - self.anim = QtWidgets.QLabel(self.centralwidget) - self.anim.setGeometry(QtCore.QRect(70, 10, 431, 231)) - self.anim.setObjectName("anim") - self.movie = QMovie("ld.gif") - self.anim.setMovie(self.movie) - self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_2.setGeometry(QtCore.QRect(0, 270, 191, 27)) - self.pushButton_2.setObjectName("FileSlector") - self.pushButton_2.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#08c6f5")) - self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_3.setGeometry(QtCore.QRect(250, 270, 91, 27)) - self.pushButton_3.setObjectName("pushButton_3") - self.pushButton_3.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#01ff01")) - self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_4.setGeometry(QtCore.QRect(350, 270, 91, 27)) - self.pushButton_4.setObjectName("pushButton_4") - self.pushButton_4.setStyleSheet(""" - background-color: %s; - padding: 1px; - margin: 4px; - border-radius: 6px; - """ % ("#ff0000")) - self.label = QtWidgets.QLabel(self.centralwidget) - self.label.setGeometry(QtCore.QRect(0, 300, 431, 20)) - self.label.setStyleSheet("color :#ffffff") - font = QtGui.QFont() - font.setPointSize(11) - self.label.setFont(font) - self.label.setObjectName("label") - MainWindow.setCentralWidget(self.centralwidget) - self.statusbar = QtWidgets.QStatusBar(MainWindow) - self.statusbar.setObjectName("statusbar") - MainWindow.setStatusBar(self.statusbar) - self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 24)) - self.menubar.setObjectName("menubar") - MainWindow.setMenuBar(self.menubar) - self.retranslateUi(MainWindow) - self.pushButton_2.clicked.connect(self.file) - self.Speak_button.clicked.connect(self.speak) - self.pushButton_3.clicked.connect(self.start_btn) - self.pushButton_4.clicked.connect(self.exit) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.Speak_button.setText(_translate("MainWindow", "Speak")) - self.pushButton_2.setText(_translate("MainWindow", "Select File")) - self.pushButton_3.setText(_translate("MainWindow", "Start")) - self.pushButton_4.setText(_translate("MainWindow", "stop")) - self.label.setText(_translate("MainWindow", "selected file:")) - - def animation_area(self): - self.movie.start() - - def file(self): - file_dialog = QFileDialog() - file_dialog.setWindowTitle("Open File") - file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile) - file_dialog.setViewMode(QFileDialog.ViewMode.Detail) - if file_dialog.exec(): - selected_files = file_dialog.selectedFiles() - print("Selected File:", selected_files[0]) - self.filename = selected_files[0] - self.label.setText(selected_files[0]) - print(self.filename) - def start_btn(self): - if self.filename.endswith('xlsx' or 'xls'): - print("excel file found") - else: - self.warn(mesg="No file selected") - return - syestem = platform.system() - print(syestem) - # try: - # while subprocess.check_output(["fuser",self.filename], text=True): - # check_st(filename=self.filename,system=syestem) - # except subprocess.CalledProcessError: - # print("File is not open by any process. Proceeding.") - - file_iteration(filename=self.filename) - def exit(self): - sys.exit() - def speak(self): - text = self.Input.toPlainText() - if text == '': - self.warn(mesg="Enter some text to continue") - return - self.animation_area() - tts_converter(text) - self.Input.clear() - # listen() - def warn(self,mesg): - msg = QMessageBox() - msg.setIcon(QMessageBox.Warning) - msg.setText(mesg) - msg.setWindowTitle('Warning') - msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) - msg.exec_() - -def tts_converter(command): - engine = pyttsx3.init() - engine.setProperty("rate", 150) - engine.say(command) - engine.runAndWait() - - -def listen(): - print("\033[1m\033[33;32m[-]audio played , listening now . . .") - recognizer = sr.Recognizer() - converted_text = "Empty" - # for index,name in enumerate(sr.Microphone.list_microphone_names()): - # print(f"{index} , {name}") - with sr.Microphone(device_index=4)as inputsource: - print("\033[1m\033[33;32m[+]listening for audio...") - recognizer.adjust_for_ambient_noise(inputsource,duration=.5) - voiceinput = recognizer.record(inputsource,duration=10) - try: - converted_text = recognizer.recognize_google(voiceinput) - print("\033[1m\033[33;32m[+]user said ,",converted_text) - except KeyboardInterrupt: - print("\033[1m\033[33;32mKeyboard : interupt happened") - exit(0) - except sr.exceptions.UnknownValueError: - print("\033[1m\033[33;32m[*]exception : user said nothing") - print(f'User said {converted_text}') - return converted_text - -def check_st(filename,system): - if system == 'Linux': - try: - output = subprocess.check_output(["fuser",filename], text=True) - #print(output) - lines = output.strip().split("/") # Skip the header - for line in lines: - print(line) - parts = line.split() - pid = int(parts[0]) - print(f"File is open by PID {pid}, killing it...") - os.kill(pid, signal.SIGKILL) - print(f"Process {pid} killed.") - except subprocess.CalledProcessError: - print("File is not open by any process. Proceeding.") - file_iteration(filename=filename) - elif system == 'Windows': - print('windows') - -def file_iteration(filename): - print(filename) - data = pd.read_excel(filename,usecols=cols) - print(data) - for index,row in data.iterrows(): - tts_converter("Hey Mini") - tts_converter(row['commands']) - TTS_main.print_fun() - t.sleep(5) - # result = listen() - # data.at[index,'Results'] = f'{result}' - # data.to_excel('words.xlsx',index=False,engine='openpyxl') - # print(result) - -if __name__ == "__main__": - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # self.Chat_scrollArea = QtWidgets.QScrollArea(self.centralwidget) - # self.Chat_scrollArea.setGeometry(QtCore.QRect(0, 0, 441, 261)) - # self.Chat_scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) - # self.Chat_scrollArea.setWidgetResizable(True) - # self.Chat_scrollArea.setObjectName("Chat_scrollArea") - # self.Chat_container = QtWidgets.QWidget() - # self.Chat_container.setGeometry(QtCore.QRect(0, 0, 439, 259)) - # self.Chat_container.setObjectName("Chat_container") - # self.verticalLayoutWidget = QtWidgets.QWidget(self.Chat_container) - # self.verticalLayoutWidget.setGeometry(QtCore.QRect(-1, -1, 441, 261)) - # self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - # self.caht_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) - # self.caht_layout.setContentsMargins(0, 0, 0, 0) - # self.caht_layout.setObjectName("caht_layout") - # self.caht_layout.addStretch() - # self.Chat_scrollArea.setWidget(self.Chat_container) \ No newline at end of file diff --git a/src/words.xlsx b/src/words.xlsx deleted file mode 100755 index 991d3d8..0000000 Binary files a/src/words.xlsx and /dev/null differ diff --git a/test/logger.py b/test/logger.py index 959ab41..4a93ceb 100644 --- a/test/logger.py +++ b/test/logger.py @@ -1,67 +1,140 @@ -import subprocess +import sys import os -import time +from PyQt5.QtWidgets import ( + QApplication, QWidget, QLabel, QLineEdit, QPushButton, + QVBoxLayout, QHBoxLayout, QFileDialog, QComboBox, QRadioButton, QButtonGroup +) +from PyQt5.QtGui import QIcon from datetime import datetime -# Configuration -device_id = 'J7S8WCZTROEQ8L9D' # Replace with your device ID or IP -log_file = "adb_logs.log" # Output log file name -duration = 3 # Duration in seconds - -def collect_logs(): - try: - print(f"Starting ADB log collection for {device_id} (duration: {duration} seconds)") - - # Get current timestamp for the log file header - timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - # Open log file with proper encoding - with open(log_file, "w", encoding='ISO-8859-1') as file: - file.write(f"ADB Log Collection - Device: {device_id} - Started at {timestamp}\n") - file.write("="*60 + "\n\n") - - # Start the ADB logcat process - process = subprocess.Popen( - ["adb", "-s", device_id, "logcat"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - bufsize=1, - encoding='ISO-8859-1' - ) - - # Record start time - start_time = time.time() - - try: - # Read lines for the specified duration - while time.time() - start_time < duration: - line = process.stdout.readline() - if line: - file.write(line) - file.flush() - else: - break # Exit if process ended - - except KeyboardInterrupt: - print("\nLog collection interrupted by user") - - finally: - # Clean up the process - process.terminate() - try: - process.wait(timeout=1) - except subprocess.TimeoutExpired: - process.kill() - - # Add footer information - file.write(f"\n\nLog collection completed after {duration} seconds") - print(f"\nLogs saved to {os.path.abspath(log_file)}") - - except Exception as e: - print(f"Error occurred: {str(e)}") - if 'process' in locals(): - process.terminate() + +class IPATestUI(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle("IPA Test Automation Runner") + self.setWindowIcon(QIcon(":/icons/IAV_Logo.ico")) + self.setGeometry(200, 200, 500, 350) + + # Store values + self.ip = "" + self.excel_file = "" + self.config_file = "" + self.system_load = False + self.iterations = 1 + + # Timestamped run directory + self.timenow = datetime.now() + self.rundirectoryname = "IPA_Testrun_" + self.timenow.strftime("%d_%m_%H_%M") + self.rundirectory = "" + + self.initUI() + + def initUI(self): + layout = QVBoxLayout() + + # IP Address + ip_label = QLabel("IP Address:") + self.ip_entry = QLineEdit() + layout.addWidget(ip_label) + layout.addWidget(self.ip_entry) + + # Excel File + excel_label = QLabel("Excel File:") + excel_layout = QHBoxLayout() + self.excel_entry = QLineEdit() + excel_button = QPushButton("Browse") + excel_button.clicked.connect(self.browse_excel) + excel_layout.addWidget(self.excel_entry) + excel_layout.addWidget(excel_button) + layout.addWidget(excel_label) + layout.addLayout(excel_layout) + + # Config File + config_label = QLabel("Configuration File:") + config_layout = QHBoxLayout() + self.config_entry = QLineEdit() + config_button = QPushButton("Browse") + config_button.clicked.connect(self.browse_config) + config_layout.addWidget(self.config_entry) + config_layout.addWidget(config_button) + layout.addWidget(config_label) + layout.addLayout(config_layout) + + # System Load (Yes/No) + sysload_label = QLabel("Give System Load?") + sysload_layout = QHBoxLayout() + self.radio_yes = QRadioButton("Yes") + self.radio_no = QRadioButton("No") + self.radio_no.setChecked(True) + sysload_group = QButtonGroup(self) + sysload_group.addButton(self.radio_yes) + sysload_group.addButton(self.radio_no) + sysload_layout.addWidget(self.radio_yes) + sysload_layout.addWidget(self.radio_no) + layout.addWidget(sysload_label) + layout.addLayout(sysload_layout) + + # Iteration Count + iter_layout = QHBoxLayout() + iter_label = QLabel("Iteration Count:") + self.iter_combo = QComboBox() + self.iter_combo.addItems([str(i) for i in range(1, 6)]) + iter_layout.addWidget(iter_label) + iter_layout.addWidget(self.iter_combo) + layout.addLayout(iter_layout) + + # Start Button + start_button = QPushButton("Start Test") + start_button.clicked.connect(self.start_test) + layout.addWidget(start_button) + + # Status labels + self.status_total = QLabel("Total / Played: 0 / 0") + self.status_current = QLabel("Current Utterance: None") + layout.addWidget(self.status_total) + layout.addWidget(self.status_current) + + self.setLayout(layout) + + def browse_excel(self): + file_name, _ = QFileDialog.getOpenFileName(self, "Select Excel File", "", "Excel Files (*.xlsx *.xls)") + if file_name: + self.excel_entry.setText(file_name) + self.excel_file = file_name + + def browse_config(self): + file_name, _ = QFileDialog.getOpenFileName(self, "Select Configuration File", "", "Config Files (*.txt *.cfg *.ini);;All Files (*)") + if file_name: + self.config_entry.setText(file_name) + self.config_file = file_name + + def start_test(self): + self.ip = self.ip_entry.text() + self.system_load = self.radio_yes.isChecked() + self.iterations = int(self.iter_combo.currentText()) + + # Check inputs + if not self.ip or not self.excel_file or not self.config_file: + self.update_status("Please provide all required inputs.", error=True) + return + + # Create run directory + self.rundirectory = os.path.join(os.getcwd(), self.rundirectoryname) + os.makedirs(self.rundirectory, exist_ok=True) + + self.update_status(f"Starting IPA Test on {self.ip}...", error=False) + + # TODO: Replace with your actual test runner logic + print(f"Running with: IP={self.ip}, Excel={self.excel_file}, Config={self.config_file}, " + f"SystemLoad={self.system_load}, Iterations={self.iterations}") + + def update_status(self, message, error=False): + color = "red" if error else "green" + self.status_total.setText(f'{message}') + if __name__ == "__main__": - collect_logs() + app = QApplication(sys.argv) + win = IPATestUI() + win.show() + sys.exit(app.exec_())