Merge remote-tracking branch 'origin/master'

This commit is contained in:
Eduardo 2024-01-23 12:48:13 +01:00
commit 1a258632af
6 changed files with 162 additions and 8615 deletions

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# ST-TEN-1
CONTROL SOFTWARE FOR ERRECINQUE LEAK TEST SYSTEMS
## Getting started
This software is deployed on many different systems, each using one of the following leak test instruments:
-Tecna T3L
-Tecna T3P
-Furness controls FCO730
In addition to leak testing, the software supports many other functions, depending on which system is deployed:
-electrical resistance measurement
-vision test
-fixture digital I/O management
## Setup
-Clone the repository
-On Windows: ./init_win.bat
-On Linux: ./init.sh

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 642 KiB

After

Width:  |  Height:  |  Size: 642 KiB

View File

@ -125,7 +125,7 @@ pid_mode: 0 # 0=FAST 1=MEDIUM 2=SLOW 4 = FIXED 5 = AUTOMATIC 6 = FLOW 7 = LEAK W
pid_level: 1 pid_level: 1
pid_speed: 1 pid_speed: 1
tester_discharge_enable: no tester_discharge_enable: no
pid_pressure_correction: 110 pid_pressure_correction: 100
tempo_pre_riempimento: 0 tempo_pre_riempimento: 0
pressione_pre_riempimento: 1000 pressione_pre_riempimento: 1000

View File

@ -9,10 +9,9 @@ import nfc
from nfc.clf import RemoteTarget from nfc.clf import RemoteTarget
class RFID_PN532(Component): class RFID_PN532(Component):
new_id_signal = pyqtSignal(str) new_id_signal = pyqtSignal(str)
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True):
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
self.data_to_write = None self.data_to_write = None

View File

@ -22,7 +22,8 @@ app = None
parser = argparse.ArgumentParser(prog='ST-TEN', description='Leak test system') parser = argparse.ArgumentParser(prog='ST-TEN', description='Leak test system')
parser.add_argument('-s', '--system-id') parser.add_argument('-s', '--system-id')
args,unspec = parser.parse_known_args() args, unspec = parser.parse_known_args()
def quit_app(signalnum=None, handler=None): def quit_app(signalnum=None, handler=None):
logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}") logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}")
@ -65,7 +66,7 @@ try:
# IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGING # IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGING
from components import (ArchiveSynchronizer, Multicomp730424, from components import (ArchiveSynchronizer, Multicomp730424,
Os_Label_Printer, RemoteAPI, Os_Label_Printer, RemoteAPI,
TecnaMarpossProvasetT3,FurnessControlsLeakTester, TecnaScrewdriver, USB_586x,RFID_PN532) TecnaMarpossProvasetT3, FurnessControlsLeakTester, TecnaScrewdriver, USB_586x, RFID_PN532)
from lib.db import Users from lib.db import Users
from lib.helpers import ConfigReader from lib.helpers import ConfigReader
from PyQt5.QtCore import QObject, QThread, pyqtSignal from PyQt5.QtCore import QObject, QThread, pyqtSignal
@ -106,9 +107,9 @@ try:
"screwdriver": {"c": TecnaScrewdriver, "k": {"paused": True}}, "screwdriver": {"c": TecnaScrewdriver, "k": {"paused": True}},
"tecna_t3": {"c": TecnaMarpossProvasetT3, "k": {"paused": True}}, "tecna_t3": {"c": TecnaMarpossProvasetT3, "k": {"paused": True}},
"furness_controls": {"c": FurnessControlsLeakTester, "k": {"paused": True}}, "furness_controls": {"c": FurnessControlsLeakTester, "k": {"paused": True}},
"digital_io":{"c":USB_586x,"k":{"paused":True}}, "digital_io": {"c": USB_586x, "k": {"paused": True}},
"digital_io_flush_blow":{"c":USB_586x,"k":{"paused":True}}, "digital_io_flush_blow": {"c": USB_586x, "k": {"paused": True}},
"fixture_id":{"c":RFID_PN532,"k":{"paused":False, "lazy":False}}, "fixture_id": {"c": RFID_PN532, "k": {"paused": False, "lazy": False}},
} }
# VISION COMPONENT IS OPTIONAL AND DISABLED BY DEFAULT # VISION COMPONENT IS OPTIONAL AND DISABLED BY DEFAULT
if "--vision" in sys.argv: if "--vision" in sys.argv:
@ -170,10 +171,10 @@ try:
# self.main_window = Main_Window(self.bench) # self.main_window = Main_Window(self.bench)
self.main_window = Main_Window() self.main_window = Main_Window()
# CONNECT MAIN WINDOW ACTIONS # CONNECT MAIN WINDOW ACTIONS
self.main_window.logout_a.triggered.connect(lambda checked, self=weakref.ref(self): self().logout()) self.main_window.logout_a.triggered.connect(lambda checked, selfie=weakref.ref(self): selfie().logout())
self.main_window.archive_a.triggered.connect( self.main_window.archive_a.triggered.connect(
lambda checked, self=weakref.ref(self): self().main_window.open_dialog( lambda checked, selfie=weakref.ref(self): selfie().main_window.open_dialog(
Archive(hide_cloud_image="vision_saver" not in self().components))) Archive(hide_cloud_image="vision_saver" not in selfie().components)))
if "--archive" in sys.argv: if "--archive" in sys.argv:
self.main_window.archive_a.trigger() self.main_window.archive_a.trigger()
if "--about" in sys.argv: if "--about" in sys.argv:
@ -182,9 +183,11 @@ try:
# admin menu should not be visible before an admin logs in # admin menu should not be visible before an admin logs in
self.main_window.admin_m.menuAction().setVisible(False) self.main_window.admin_m.menuAction().setVisible(False)
self.main_window.about_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(About())) self.main_window.about_a.triggered.connect(
lambda checked, selfie=weakref.ref(self): selfie().main_window.open_dialog(About()))
self.main_window.quit_a.triggered.connect(quit_app) self.main_window.quit_a.triggered.connect(quit_app)
self.main_window.users_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Users_Management())) self.main_window.users_management_a.triggered.connect(
lambda checked, selfie=weakref.ref(self): selfie().main_window.open_dialog(Users_Management()))
self.main_window.table_selection_a.triggered.connect(self.set_recipe_mode_table) self.main_window.table_selection_a.triggered.connect(self.set_recipe_mode_table)
self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode) self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode)
self.main_window.ristampa_etichetta_a.triggered.connect(self.reprint_label) self.main_window.ristampa_etichetta_a.triggered.connect(self.reprint_label)
@ -201,7 +204,8 @@ try:
self.main_window.save_tecna_recipes_a.trigger() self.main_window.save_tecna_recipes_a.trigger()
else: else:
self.main_window.save_tecna_recipes_a.setVisible(False) self.main_window.save_tecna_recipes_a.setVisible(False)
self.main_window.barcode_selection_a.setVisible(self.config["hardware_config"]["barcode_recipe_selection"] == "present") self.main_window.barcode_selection_a.setVisible(
self.config["hardware_config"]["barcode_recipe_selection"] == "present")
# OPEN LOGIN TAB # OPEN LOGIN TAB
self.open_login() self.open_login()
@ -228,15 +232,16 @@ try:
else: else:
self.main_window.admin_m.menuAction().setVisible(False) self.main_window.admin_m.menuAction().setVisible(False)
# open test # open test
self.main_window.open_tab(Test(self.config, self.components,self)) self.main_window.open_tab(Test(self.config, self.components, self))
self.main_window.centralWidget().request_autotest("login") self.main_window.centralWidget().request_autotest("login")
else: else:
self.main_window.admin_m.menuAction().setVisible(False) self.main_window.admin_m.menuAction().setVisible(False)
def logout(self): def logout(self):
#Users.logout() # Users.logout()
self.main_window.admin_m.menuAction().setVisible(False) self.main_window.admin_m.menuAction().setVisible(False)
if type(self.main_window.centralWidget().centralWidget.widget) in (Recipe_Selection,Barcode_Recipe_Selection): if type(self.main_window.centralWidget().centralWidget.widget) in (
Recipe_Selection, Barcode_Recipe_Selection):
# LOGOUT IMMEDIATELY IF NOT TESTING # LOGOUT IMMEDIATELY IF NOT TESTING
Users.logout() Users.logout()
self.open_login() self.open_login()
@ -254,8 +259,11 @@ try:
def set_recipe_mode_barcode(self): def set_recipe_mode_barcode(self):
self.main_window.centralWidget().set_recipe_mode_barcode() self.main_window.centralWidget().set_recipe_mode_barcode()
def reprint_label(self): def reprint_label(self):
self.main_window.centralWidget().reprint_label() self.main_window.centralWidget().reprint_label()
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)

View File

@ -5,33 +5,34 @@ import sys
import weakref import weakref
from datetime import datetime, timedelta from datetime import datetime, timedelta
from PyQt5.QtCore import QTimer, pyqtSlot
from PyQt5.QtWidgets import QMessageBox
from lib.db import Archive, Steps, Users from lib.db import Archive, Steps, Users
from lib.helpers import get_shift from lib.helpers import get_shift
from playhouse.shortcuts import model_to_dict from playhouse.shortcuts import model_to_dict
from PyQt5.QtCore import QTimer, pyqtSlot from ui.barcode_recipe_selection import Barcode_Recipe_Selection
from PyQt5.QtWidgets import QMessageBox
from ui.helpers import replace_widget from ui.helpers import replace_widget
from ui.recipe_selection import Recipe_Selection from ui.recipe_selection import Recipe_Selection
from ui.barcode_recipe_selection import Barcode_Recipe_Selection
from ui.test_assembly import Test_Assembly from ui.test_assembly import Test_Assembly
from ui.test_barcodes import Test_Barcodes from ui.test_barcodes import Test_Barcodes
from ui.test_connector import Test_Connector from ui.test_connector import Test_Connector
from ui.test_count import Test_Count from ui.test_count import Test_Count
from ui.test_count_end import Test_Count_End from ui.test_count_end import Test_Count_End
from ui.test_warning_img import Test_Warning_Img
from ui.test_instructions import Test_Instructions
from ui.test_fail import Test_Fail from ui.test_fail import Test_Fail
from ui.test_instructions import Test_Instructions
from ui.test_leak import Test_Leak from ui.test_leak import Test_Leak
from ui.test_resistance import Test_Resistance from ui.test_resistance import Test_Resistance
from ui.test_screws import Test_Screws from ui.test_screws import Test_Screws
from ui.test_vision import Test_Vision from ui.test_vision import Test_Vision
from ui.test_warning_img import Test_Warning_Img
from ui.widget import Widget from ui.widget import Widget
class Test(Widget): class Test(Widget):
def __init__(self, config, components=None,main_window=None): def __init__(self, config, components=None, main_window=None):
super().__init__() super().__init__()
self.main_window=main_window self.autotest_timer = None
self.main_window = main_window
self.config = config self.config = config
self.components = components self.components = components
# GET LOGGER # GET LOGGER
@ -50,7 +51,7 @@ class Test(Widget):
# INIT RECIPE # INIT RECIPE
self.recipe = None self.recipe = None
if self.config["hardware_config"]["barcode_recipe_selection"]=="present": if self.config["hardware_config"]["barcode_recipe_selection"] == "present":
self.recipe_selection_mode = "barcode" self.recipe_selection_mode = "barcode"
else: else:
self.recipe_selection_mode = "table" self.recipe_selection_mode = "table"
@ -60,12 +61,12 @@ class Test(Widget):
self.steps_dependencies = { self.steps_dependencies = {
"count": set(), "count": set(),
"connector": {"multicomp", }, "connector": {"multicomp", },
"instruction":{"digital_io"}, "instruction": {"digital_io"},
"screws": {"screwdriver", "tecna_t3", }, "screws": {"screwdriver", "tecna_t3", },
"resistance": {"multicomp", }, "resistance": {"multicomp", },
"leak_1": {self.tester_component, }, "leak_1": {self.tester_component, },
"leak_2": {self.tester_component, }, "leak_2": {self.tester_component, },
"vision": {("uvc_camera", "galaxy_camera", ), "vision", "vision_saver", }, # "neo_pixels", }, "vision": {("uvc_camera", "galaxy_camera",), "vision", "vision_saver", }, # "neo_pixels", },
"print": {"label_printer", }, "print": {"label_printer", },
} }
self.unsupported_steps = set() self.unsupported_steps = set()
@ -86,23 +87,31 @@ class Test(Widget):
# "assembly_1": Test_Assembly(img_path=self.select_step_img("assembly_1"), text=u"INSERIRE SENSORE", widget=None), # "assembly_1": Test_Assembly(img_path=self.select_step_img("assembly_1"), text=u"INSERIRE SENSORE", widget=None),
"barcodes": Test_Assembly(img_path=self.select_step_img("scan"), text=u"LEGGERE IL BARCODE DEL PEZZO DA COLLAUDARE", widget=Test_Barcodes()), "barcodes": Test_Assembly(img_path=self.select_step_img("scan"), text=u"LEGGERE IL BARCODE DEL PEZZO DA COLLAUDARE", widget=Test_Barcodes()),
"connector": Test_Assembly(img_path=self.select_step_img("scan"), text=u"COLLEGARE IL CONNETTORE INDICATO AL PEZZO E LEGGERE IL SUO BARCODE", widget=Test_Connector(run_once=True)), "connector": Test_Assembly(img_path=self.select_step_img("scan"), text=u"COLLEGARE IL CONNETTORE INDICATO AL PEZZO E LEGGERE IL SUO BARCODE", widget=Test_Connector(run_once=True)),
"count": Test_Assembly(img_path=None, text=u"INSERIRE IL NUMERO DI PEZZI ATTESI PER IL LOTTO", widget=Test_Count(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, run_once=True)), "count": Test_Assembly(img_path=None, text=u"INSERIRE IL NUMERO DI PEZZI ATTESI PER IL LOTTO",
"warning_img": Test_Assembly(img_path=None, text=u"ATTENZIONE - PER QUESTO CODICE ESEGUIRE LE OPERAZIONI INDICATE IN FIGURA", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step,run_once=True)), widget=Test_Count(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, run_once=True)),
"count_end": Test_Assembly(img_path=None, text=u"LOTTO TERMINATO, PREMERE CONTINUA PERCOMINCIARNE UNO NUOVO", widget=Test_Count_End(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), "warning_img": Test_Assembly(img_path=None, text=u"ATTENZIONE - PER QUESTO CODICE ESEGUIRE LE OPERAZIONI INDICATE IN FIGURA",
widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step, run_once=True)),
"count_end": Test_Assembly(img_path=None, text=u"LOTTO TERMINATO, PREMERE CONTINUA PERCOMINCIARNE UNO NUOVO",
widget=Test_Count_End(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)),
"done": Test_Assembly(img_path=self.select_step_img("success"), text=u"COLLAUDO COMPLETATO", widget=None), "done": Test_Assembly(img_path=self.select_step_img("success"), text=u"COLLAUDO COMPLETATO", widget=None),
"emergency": Test_Assembly(img_path=self.select_step_img("reset_emergency"), text=u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\"", widget=None), "emergency": Test_Assembly(img_path=self.select_step_img("reset_emergency"),
text=u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\"", widget=None),
"fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO, PREMERE CONTINUA PER COMINCIARE UN NUOVO CICLO", widget=Test_Fail(parent=self)), "fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO, PREMERE CONTINUA PER COMINCIARE UN NUOVO CICLO", widget=Test_Fail(parent=self)),
"blow": Test_Assembly(img_path=None, text=u"SOFFIAGGIO TUBO IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)), "blow": Test_Assembly(img_path=None, text=u"SOFFIAGGIO TUBO IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)),
"leak_1": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces,parent=self)), "leak_1": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)),
"leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces,parent=self)), "leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)),
"flush": Test_Assembly(img_path=None, text=u"SCARICO ARIA IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)), "flush": Test_Assembly(img_path=None, text=u"SCARICO ARIA IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)),
"instruction": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", widget=Test_Instructions(components=self.components, recipe=self.recipe,bench_name=self.config.machine_id, step=self.step)), "instruction": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA",
"piece_removal": Test_Assembly(img_path=None, text=u"RIMUOVERE IL PEZZO APRENDO TUTTE LE CHIUSURE", widget=Test_Instructions(components=self.components, recipe=self.recipe,bench_name=self.config.machine_id, step=self.step)), widget=Test_Instructions(components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)),
"piece_removal": Test_Assembly(img_path=None, text=u"RIMUOVERE IL PEZZO APRENDO TUTTE LE CHIUSURE",
widget=Test_Instructions(components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)),
"print": Test_Assembly(img_path=self.select_step_img("print"), text=u"STAMPA ETICHETTA IN CORSO", widget=None), "print": Test_Assembly(img_path=self.select_step_img("print"), text=u"STAMPA ETICHETTA IN CORSO", widget=None),
"resistance": Test_Assembly(img_path=None, text=u"COLLEGARE CONNETTORE ELETTRICO PER EFFETTUARE PROVA RESISTENZA", widget=Test_Resistance(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), "resistance": Test_Assembly(img_path=None, text=u"COLLEGARE CONNETTORE ELETTRICO PER EFFETTUARE PROVA RESISTENZA",
widget=Test_Resistance(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)),
"screws": Test_Assembly(img_path=None, text=u"AVVITARE TUTE LE VITI COME INDICATO", widget=Test_Screws(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), "screws": Test_Assembly(img_path=None, text=u"AVVITARE TUTE LE VITI COME INDICATO", widget=Test_Screws(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)),
"select_recipe": Test_Assembly(img_path=None, text=u"SELEZIONARE IL CODICE DA COLLAUDARE", widget=Recipe_Selection(config=self.config, unsupported_steps=self.unsupported_steps)), "select_recipe": Test_Assembly(img_path=None, text=u"SELEZIONARE IL CODICE DA COLLAUDARE", widget=Recipe_Selection(config=self.config, unsupported_steps=self.unsupported_steps)),
"barcode_recipe_selection": Test_Assembly(img_path=self.select_step_img("scan"), text=u"LEGGERE IL BARCODE SULLA DIMA DEL COMPONENTE DA COLLAUDARE", widget=Barcode_Recipe_Selection(parent=self)), "barcode_recipe_selection": Test_Assembly(img_path=self.select_step_img("scan"), text=u"LEGGERE IL BARCODE SULLA DIMA DEL COMPONENTE DA COLLAUDARE",
widget=Barcode_Recipe_Selection(parent=self)),
"vision": Test_Assembly(img_path=None, text=u"VERIFICARE CONTROLLO CON TELECAMERA", widget=Test_Vision(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), "vision": Test_Assembly(img_path=None, text=u"VERIFICARE CONTROLLO CON TELECAMERA", widget=Test_Vision(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)),
"wait": Test_Assembly(img_path=self.select_step_img("wait"), text=u"ATTENDERE - PAUSA INTER CICLO", widget=None), "wait": Test_Assembly(img_path=self.select_step_img("wait"), text=u"ATTENDERE - PAUSA INTER CICLO", widget=None),
None: Test_Assembly(img_path=self.select_step_img("warning"), text=u"ATTENZIONE - LA RICETTA SELEZIONATA NON CONTIENE FASI DI TEST", widget=None), None: Test_Assembly(img_path=self.select_step_img("warning"), text=u"ATTENZIONE - LA RICETTA SELEZIONATA NON CONTIENE FASI DI TEST", widget=None),
@ -120,7 +129,7 @@ class Test(Widget):
if "--no-autotest" not in sys.argv: if "--no-autotest" not in sys.argv:
self.autotest_period = int(8.5 * 60 * 60 * 1000) # 8.5 HOURS self.autotest_period = int(8.5 * 60 * 60 * 1000) # 8.5 HOURS
# self.autotest_period = 12 * 60 * 60 * 1000 # 12 HOURS # self.autotest_period = 12 * 60 * 60 * 1000 # 12 HOURS
#if not self.config["autotest_done"]: # if not self.config["autotest_done"]:
# self.request_autotest("init") # self.request_autotest("init")
else: else:
self.autotest_period = None self.autotest_period = None
@ -134,15 +143,15 @@ class Test(Widget):
for step_name, w in self.cycle_available_steps.items(): for step_name, w in self.cycle_available_steps.items():
if hasattr(w, "ok"): if hasattr(w, "ok"):
# custom ok handlers should call next again # custom ok handlers should call next again
if isinstance(w.widget, (Recipe_Selection)): if isinstance(w.widget, Recipe_Selection):
w.ok.connect(self.set_recipe) w.ok.connect(self.set_recipe)
else: else:
w.ok.connect(lambda data=None, step_name=step_name, self=weakref.ref(self): self().set_step(step_name, data)) w.ok.connect(lambda data=None, step_namel=step_name, selfie=weakref.ref(self): selfie().set_step(step_namel, data))
if hasattr(w, "ko"): if hasattr(w, "ko"):
w.ko.connect(self.fail_cycle) w.ko.connect(self.fail_cycle)
# CUSTOM STEP CONNECTIONS # CUSTOM STEP CONNECTIONS
self.cycle_available_steps["count"].ok.connect(self.cycle_available_steps["count_end"].widget.set_amount) self.cycle_available_steps["count"].ok.connect(self.cycle_available_steps["count_end"].widget.set_amount)
#self.cycle_available_steps["warning_img"].ok.connect(self.cycle_available_steps["warning_img"].widget.set_done) # self.cycle_available_steps["warning_img"].ok.connect(self.cycle_available_steps["warning_img"].widget.set_done)
if "fixture_id" in self.components.keys(): if "fixture_id" in self.components.keys():
self.components["fixture_id"].new_id_signal.connect(self.load_recipe_from_rfid) self.components["fixture_id"].new_id_signal.connect(self.load_recipe_from_rfid)
@ -193,6 +202,7 @@ class Test(Widget):
def set_recipe_mode_barcode(self): def set_recipe_mode_barcode(self):
self.recipe_selection_mode = "barcode" self.recipe_selection_mode = "barcode"
self.change_recipe() self.change_recipe()
def reprint_label(self): def reprint_label(self):
self.print(self.last_label, self.print_step.spec.get("template", "EtichettaR5")) self.print(self.last_label, self.print_step.spec.get("template", "EtichettaR5"))
@ -206,7 +216,7 @@ class Test(Widget):
if "--no-autotest" not in sys.argv: if "--no-autotest" not in sys.argv:
self.log.info(f"cycle request autotest: reason: {reason!r} autotest_request: {self.autotest_request!r}") self.log.info(f"cycle request autotest: reason: {reason!r} autotest_request: {self.autotest_request!r}")
if reason in ("init","login"): if reason in ("init", "login"):
self.autotest_timer = QTimer() self.autotest_timer = QTimer()
self.autotest_timer.setSingleShot(False) self.autotest_timer.setSingleShot(False)
self.autotest_timer.timeout.connect(self.request_periodic_autotest) self.autotest_timer.timeout.connect(self.request_periodic_autotest)
@ -217,7 +227,6 @@ class Test(Widget):
if reason == "logout": if reason == "logout":
self.next(action="abort") self.next(action="abort")
def request_periodic_autotest(self): def request_periodic_autotest(self):
self.request_autotest("periodic") self.request_autotest("periodic")
@ -236,12 +245,12 @@ class Test(Widget):
self.cycle_available_steps["leak_2"].widget.recipe_written = False self.cycle_available_steps["leak_2"].widget.recipe_written = False
self.step = Steps(type="select_recipe") self.step = Steps(type="select_recipe")
self.cycle_index = -1 self.cycle_index = -1
self.recipe=None self.recipe = None
self.cycle_steps=None self.cycle_steps = None
# COUNT RESET # COUNT RESET
self.pieces["ok"] = 0 self.pieces["ok"] = 0
self.pieces["ko"] = 0 self.pieces["ko"] = 0
elif action in ("fail","abort"): elif action in ("fail", "abort"):
self.log.info(f"cycle next: action: {action!r}") self.log.info(f"cycle next: action: {action!r}")
# FAIL AND RESTART TEST # FAIL AND RESTART TEST
self.step = Steps(type="fail") self.step = Steps(type="fail")
@ -286,7 +295,7 @@ class Test(Widget):
else: else:
t = datetime.now() t = datetime.now()
self.last_at_l.setText("{d}/{mo}/{y} {h}:{m}".format(y=t.year, mo=t.month, d=t.day, h=t.hour, m=t.minute)) self.last_at_l.setText("{d}/{mo}/{y} {h}:{m}".format(y=t.year, mo=t.month, d=t.day, h=t.hour, m=t.minute))
t+=timedelta(seconds=int(self.autotest_period/1000)) t += timedelta(seconds=int(self.autotest_period / 1000))
self.next_at_l.setText("{d}/{mo}/{y} {h}:{m}".format(y=t.year, mo=t.month, d=t.day, h=t.hour, m=t.minute)) self.next_at_l.setText("{d}/{mo}/{y} {h}:{m}".format(y=t.year, mo=t.month, d=t.day, h=t.hour, m=t.minute))
self.autotesting_reason = None self.autotesting_reason = None
self.cycle_index = -1 self.cycle_index = -1
@ -317,8 +326,8 @@ class Test(Widget):
self.data["recipe"] = model_to_dict(self.recipe) self.data["recipe"] = model_to_dict(self.recipe)
w = self.cycle_available_steps[self.step.type] w = self.cycle_available_steps[self.step.type]
show = None show = None
if self.step.type=="leak_2": if self.step.type == "leak_2":
self.setCentralWidget(w) # NEED TO PRESHOW UI self.setCentralWidget(w) # NEED TO PRESHOW UI
if hasattr(w, "start"): if hasattr(w, "start"):
show = w.start(recipe=self.recipe, step=self.step, pieces=self.pieces) show = w.start(recipe=self.recipe, step=self.step, pieces=self.pieces)
if show is not False and w is not current_w: if show is not False and w is not current_w:
@ -327,7 +336,7 @@ class Test(Widget):
self.next_timer.start(0) self.next_timer.start(0)
if self.step.type == "done": if self.step.type == "done":
self.archived = self.done() self.archived = self.done()
self.last_label=copy.deepcopy(self.archived) self.last_label = copy.deepcopy(self.archived)
self.next_timer.start(500) self.next_timer.start(500)
elif self.step.type == "print": elif self.step.type == "print":
compiled_label = self.print(self.archived, self.step.spec.get("template", "EtichettaR5")) compiled_label = self.print(self.archived, self.step.spec.get("template", "EtichettaR5"))
@ -369,7 +378,7 @@ class Test(Widget):
count_found = True count_found = True
if "warning_img" in step.spec: if "warning_img" in step.spec:
if step.spec["warning_img"]: if step.spec["warning_img"]:
steps.insert(i,Steps(type="warning_img", spec={"warning_img":step.spec["warning_img"]})) steps.insert(i, Steps(type="warning_img", spec={"warning_img": step.spec["warning_img"]}))
skip.add(i + 1) skip.add(i + 1)
if "assembly" in step.spec: if "assembly" in step.spec:
if step.spec["assembly"]: if step.spec["assembly"]:
@ -378,7 +387,7 @@ class Test(Widget):
if "require_discard_piece" in step.spec: if "require_discard_piece" in step.spec:
if step.spec["require_discard_piece"]: if step.spec["require_discard_piece"]:
self.require_discard_piece = True self.require_discard_piece = True
if step.type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR if step.type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR
steps.insert(i + 1, Steps(type="resistance", spec={ steps.insert(i + 1, Steps(type="resistance", spec={
"scale": 500, "scale": 500,
"expected": float("+inf"), "expected": float("+inf"),
@ -396,7 +405,7 @@ class Test(Widget):
steps.append(Steps(type="piece_removal")) steps.append(Steps(type="piece_removal"))
if count_found: if count_found:
steps.append(Steps(type="count_end")) steps.append(Steps(type="count_end"))
if step.type in ("leak_1","leak_2"): if step.type in ("leak_1", "leak_2"):
self.leak_step = step self.leak_step = step
if not print_found: if not print_found:
@ -406,52 +415,52 @@ class Test(Widget):
steps.append(Steps(type="wait")) steps.append(Steps(type="wait"))
self.cycle_steps = steps self.cycle_steps = steps
self.check_steps_dependencies(self.cycle_steps) self.check_steps_dependencies(self.cycle_steps)
leak_autotest_steps=[] leak_autotest_steps = []
# CONFIGURE LEAK AUTOTEST PARAMETERS # CONFIGURE LEAK AUTOTEST PARAMETERS
if self.config["autotest_leak"]["enabled"]=="true": if self.config["autotest_leak"]["enabled"] == "true":
l_at_1=copy.deepcopy(self.config["autotest_leak"]) l_at_1 = copy.deepcopy(self.config["autotest_leak"])
l_at_1.pop("enabled") l_at_1.pop("enabled")
l_at_1={a: float(x) for a, x in l_at_1.items()} l_at_1 = {a: float(x) for a, x in l_at_1.items()}
l_at_1["autotest"]="ko_check" l_at_1["autotest"] = "ko_check"
l_at_2=copy.deepcopy(self.config["autotest_leak"]) l_at_2 = copy.deepcopy(self.config["autotest_leak"])
l_at_2.pop("enabled") l_at_2.pop("enabled")
l_at_2={a: float(x) for a, x in l_at_2.items()} l_at_2 = {a: float(x) for a, x in l_at_2.items()}
l_at_2["test_pressure_qneg"]=l_at_2["test_pressure_tt_qneg"] l_at_2["test_pressure_qneg"] = l_at_2["test_pressure_tt_qneg"]
l_at_2["test_pressure_qpos"]=l_at_2["test_pressure_tt_qpos"] l_at_2["test_pressure_qpos"] = l_at_2["test_pressure_tt_qpos"]
l_at_2["autotest"]="ok_check" l_at_2["autotest"] = "ok_check"
leak_autotest_steps=[Steps(type="leak_1",spec=l_at_1),Steps(type="leak_1",spec=l_at_2)] leak_autotest_steps = [Steps(type="leak_1", spec=l_at_1), Steps(type="leak_1", spec=l_at_2)]
self.autotest_cycle_steps = [ self.autotest_cycle_steps = [
*([ *([
Steps(type="resistance", spec={ Steps(type="resistance", spec={
"scale": 500, "scale": 500,
"expected": 1, "expected": 1,
"tolerance_pos": 5, "tolerance_pos": 5,
"tolerance_neg": 5, "tolerance_neg": 5,
"autotest": True, "autotest": True,
}), }),
Steps(type="resistance", spec={ Steps(type="resistance", spec={
"scale": 500, "scale": 500,
"expected": float("+inf"), "expected": float("+inf"),
"tolerance_pos": 0, "tolerance_pos": 0,
"tolerance_neg": 0, "tolerance_neg": 0,
"autotest": True, "autotest": True,
}), }),
Steps(type="resistance", spec={ Steps(type="resistance", spec={
"scale": 500, "scale": 500,
"expected": 10, "expected": 10,
"tolerance_pos": 1, "tolerance_pos": 1,
"tolerance_neg": 1, "tolerance_neg": 1,
"autotest": True, "autotest": True,
}), }),
Steps(type="resistance", spec={ Steps(type="resistance", spec={
"scale": 500, "scale": 500,
"expected": float("+inf"), "expected": float("+inf"),
"tolerance_pos": 0, "tolerance_pos": 0,
"tolerance_neg": 0, "tolerance_neg": 0,
"autotest": True, "autotest": True,
}), }),
] if "resistance" not in self.unsupported_steps else []), ] if "resistance" not in self.unsupported_steps else []),
*(leak_autotest_steps), *(leak_autotest_steps),
Steps(type="done"), Steps(type="done"),
Steps(type="wait"), Steps(type="wait"),
@ -503,9 +512,11 @@ class Test(Widget):
if not self.components[dependency].ready: if not self.components[dependency].ready:
missing_components.add(dependency) missing_components.add(dependency)
if len(unsupported_steps): if len(unsupported_steps):
QMessageBox.critical(None, "Errore Ricetta", f"Questa ricetta contiene uno o piu step non supportati da questo banco:\n{', '.join(sorted(unsupported_steps))}\nModificare la ricetta adeguatamente.") QMessageBox.critical(None, "Errore Ricetta",
f"Questa ricetta contiene uno o piu step non supportati da questo banco:\n{', '.join(sorted(unsupported_steps))}\nModificare la ricetta adeguatamente.")
if len(missing_components): if len(missing_components):
QMessageBox.critical(None, "Errore Componenti Ricetta", f"Questa ricetta richiede i seguenti componenti per essere eseguita:\n{', '.join(sorted(missing_components))}\nModificare la ricetta adeguatamente o collegare i componenti elencati.") QMessageBox.critical(None, "Errore Componenti Ricetta",
f"Questa ricetta richiede i seguenti componenti per essere eseguita:\n{', '.join(sorted(missing_components))}\nModificare la ricetta adeguatamente o collegare i componenti elencati.")
if len(unsupported_steps) or len(missing_components): if len(unsupported_steps) or len(missing_components):
self.change_recipe() self.change_recipe()
@ -514,10 +525,10 @@ class Test(Widget):
self.data[step_name] = {} self.data[step_name] = {}
if data is not None: if data is not None:
data["step"] = model_to_dict(self.step) data["step"] = model_to_dict(self.step)
data["step"].pop("name",None) data["step"].pop("name", None)
# MAKE ARRAY ONLY IF MORE THAN ONE TEST OF SAME TYPE # MAKE ARRAY ONLY IF MORE THAN ONE TEST OF SAME TYPE
if len(self.data[step_name])>1: if len(self.data[step_name]) > 1:
self.data[step_name][str(len(self.data[step_name]))] = data self.data[step_name][str(len(self.data[step_name]))] = data
else: else:
self.data[step_name] = data self.data[step_name] = data
@ -530,17 +541,17 @@ class Test(Widget):
self.log.info("cycle done, saving data...") self.log.info("cycle done, saving data...")
# remove useless info # remove useless info
self.data.get("recipe",{}).get("spec",{}).pop("steps",None) self.data.get("recipe", {}).get("spec", {}).pop("steps", None)
self.data.get("recipe",{}).get("spec",{}).pop("available_steps",None) self.data.get("recipe", {}).get("spec", {}).pop("available_steps", None)
for leak in ["leak_1","leak_2"]: for leak in ["leak_1", "leak_2"]:
if leak in self.data.keys(): if leak in self.data.keys():
results={k:self.data[leak]["results"][self.tester_component][k] for k in ["Running test: result"]} results = {k: self.data[leak]["results"][self.tester_component][k] for k in ["Running test: result"]}
results.update({k:round(float(self.data[leak]["results"][self.tester_component][k]),2) for k in ["Running test: filling pressure", results.update({k: round(float(self.data[leak]["results"][self.tester_component][k]), 2) for k in ["Running test: filling pressure",
"Running test: measured leak", "Running test: measured leak",
"Running test: pressure at the end of settling"]} "Running test: pressure at the end of settling"]}
) )
self.data[leak]["results"]=results self.data[leak]["results"] = results
if "vision" in self.data: if "vision" in self.data:
vision_test_1 = self.data.get("vision", {}).get("0", {}) vision_test_1 = self.data.get("vision", {}).get("0", {})
@ -607,10 +618,10 @@ class Test(Widget):
leak_test_2_step_spec = leak_test_2_step.get("spec", {}) leak_test_2_step_spec = leak_test_2_step.get("spec", {})
leak_test_2_results = leak_test_2.get("results", {}) leak_test_2_results = leak_test_2.get("results", {})
psetminp_a = leak_test_1_step_spec.get("test_pressure", 0) * (100+leak_test_1_step_spec.get("test_pressure_qneg", 0)/100) psetminp_a = leak_test_1_step_spec.get("test_pressure", 0) * (100 + leak_test_1_step_spec.get("test_pressure_qneg", 0) / 100)
psetmaxp_a = leak_test_1_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_1_step_spec.get("test_pressure_qpos", 0)/100) psetmaxp_a = leak_test_1_step_spec.get("settling_pressure_max_percent", 0) * (100 + leak_test_1_step_spec.get("test_pressure_qpos", 0) / 100)
psetminp2_a = leak_test_2_step_spec.get("settling_pressure_min_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_qneg", 0)/100) psetminp2_a = leak_test_2_step_spec.get("settling_pressure_min_percent", 0) * (100 + leak_test_2_step_spec.get("test_pressure_qneg", 0) / 100)
psetmaxp2_a = leak_test_2_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_qpos", 0)/100) psetmaxp2_a = leak_test_2_step_spec.get("settling_pressure_max_percent", 0) * (100 + leak_test_2_step_spec.get("test_pressure_qpos", 0) / 100)
leak_test_1_results["Running test: pressure at the end of measure"] = leak_test_1_results["Running test: pressure at the end of settling"] - leak_test_1_results["Running test: measured leak"] leak_test_1_results["Running test: pressure at the end of measure"] = leak_test_1_results["Running test: pressure at the end of settling"] - leak_test_1_results["Running test: measured leak"]
printer_fields = self.print_step.spec printer_fields = self.print_step.spec
context = { context = {
@ -685,10 +696,10 @@ class Test(Widget):
"RESULT_L2": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO"), "RESULT_L2": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO"),
} }
for n in range(5): for n in range(5):
field=f"labeltxt_{n+1}" field = f"labeltxt_{n + 1}"
if field in printer_fields.keys(): if field in printer_fields.keys():
if printer_fields[field] !="": if printer_fields[field] != "":
context[field.upper()]=printer_fields[field] context[field.upper()] = printer_fields[field]
# PRINT MAIN PRODUCT LABEL # PRINT MAIN PRODUCT LABEL
compiled_label = self.components["label_printer"].print_label(label, context=context) compiled_label = self.components["label_printer"].print_label(label, context=context)
@ -705,7 +716,7 @@ class Test(Widget):
self.components["extra_label_printer"].print_label(f"{label}.prn", context=None) self.components["extra_label_printer"].print_label(f"{label}.prn", context=None)
@pyqtSlot(str) @pyqtSlot(str)
def load_recipe_from_rfid(self,data): def load_recipe_from_rfid(self, data):
if self.step.type == "barcode_recipe_selection": if self.step.type == "barcode_recipe_selection":
if data is not None: if data is not None:
self.cycle_available_steps["barcode_recipe_selection"].widget.get(data) self.cycle_available_steps["barcode_recipe_selection"].widget.get(data)