2022-06-01 16:37:19 +00:00
import logging
import os
import sys
from datetime import datetime
2022-07-19 09:59:00 +00:00
from lib . db import Archive , Steps , Users
2022-07-26 14:18:44 +00:00
from lib . helpers import get_shift
from playhouse . shortcuts import model_to_dict
2022-06-28 10:31:27 +00:00
from PyQt5 . QtCore import QTimer
2022-06-01 16:37:19 +00:00
from ui . helpers import replace_widget
from ui . recipe_selection import Recipe_Selection
from ui . test_assembly import Test_Assembly
from ui . test_autotest import Test_Autotest
2022-07-25 13:36:42 +00:00
from ui . test_barcodes import Test_Barcodes
2022-07-12 08:48:04 +00:00
from ui . test_leak import Test_Leak
2022-06-22 15:18:29 +00:00
from ui . test_vision import Test_Vision
2022-06-01 16:37:19 +00:00
from ui . widget import Widget
class Test ( Widget ) :
2022-07-26 14:18:44 +00:00
def __init__ ( self , machine_id = None , components = None ) :
2022-06-01 16:37:19 +00:00
super ( ) . __init__ ( )
2022-07-26 14:18:44 +00:00
self . machine_id = machine_id
2022-06-22 15:18:29 +00:00
self . components = components
2022-06-01 16:37:19 +00:00
# GET LOGGER
self . log = logging . getLogger ( " Test " )
# SHOW USERNAME
session = Users . get_session ( )
self . user_l . setText ( session . username )
if session . is_admin :
self . user_l . setStyleSheet ( " QLabel { color: red; } " )
else :
self . user_l . setStyleSheet ( " " )
# SHOW AND UPDATE TIME CLOCK
self . refresh_time ( init = True )
# INIT RECIPE
self . recipe = None
2022-07-19 09:59:00 +00:00
self . step = None
2022-06-01 16:37:19 +00:00
# INIT CYCLE STATES
2022-07-19 09:59:00 +00:00
self . cycle_available_steps = {
2022-08-02 16:15:30 +00:00
# "assembly_1": Test_Assembly(img_path=self.select_step_img("assembly_1"), text=u"INSERIRE SENSORE", widget=None),
" autotest " : Test_Assembly ( img_path = None , text = u " ESEGUIRE PROCEDURA DI AUTOTEST " , widget = Test_Autotest ( ) ) ,
" barcodes " : Test_Assembly ( img_path = self . select_step_img ( " scan " ) , text = u " LEGGERE IL BARCODE DEL PEZZO DA COLLAUDARE " , widget = Test_Barcodes ( ) ) ,
" 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 ) ,
" fail " : Test_Assembly ( img_path = self . select_step_img ( " fail " ) , text = u " CICLO INTERROTTO " , widget = None ) ,
" leak " : Test_Assembly ( img_path = None , text = None , widget = Test_Leak ( components = self . components , recipe = self . recipe , step = self . step ) ) ,
" print " : Test_Assembly ( img_path = self . select_step_img ( " print " ) , text = u " STAMPA ETICHETTA IN CORSO " , widget = None ) ,
" select_recipe " : Test_Assembly ( img_path = None , text = u " SELEZIONARE IL CODICE DA COLLAUDARE " , widget = Recipe_Selection ( ) ) ,
" vision " : Test_Assembly ( img_path = None , text = u " VERIFICARE CONTROLLO CON TELECAMERA " , widget = Test_Vision ( components = self . components , recipe = self . recipe , step = self . step ) ) ,
" 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 ) ,
2022-06-01 16:37:19 +00:00
}
2022-07-19 09:59:00 +00:00
self . cycle_steps = None
2022-06-28 10:31:27 +00:00
self . cycle_index = - 1
2022-06-01 16:37:19 +00:00
# SETUP AUTOTEST
self . autotest_request = False
2022-07-19 09:59:00 +00:00
# if "--no-autotest" not in sys.argv:
# self.autotest_period = 12 * 60 * 60 * 1000
# self.request_autotest("init")
# else:
self . autotest_period = None
2022-06-28 10:31:27 +00:00
# INIT TEST DATA
2022-07-26 10:24:53 +00:00
self . data = { " ok " : True , " overridden " : False }
self . archived = None
2022-06-01 16:37:19 +00:00
# INIT PIECES COUNTER ([pieces_ok, pieces_failed])
self . pieces = [ 0 , 0 ]
# CONNECT CYCLE CONTROLS
self . cancel_b . clicked . connect ( self . fail_cycle )
self . change_recipe_b . clicked . connect ( self . change_recipe )
2022-07-19 09:59:00 +00:00
for w in self . cycle_available_steps . values ( ) :
2022-06-01 16:37:19 +00:00
if hasattr ( w , " ok " ) :
# custom ok handlers should call next again
if type ( w . widget ) is Recipe_Selection :
w . ok . connect ( self . set_recipe )
2022-07-25 13:36:42 +00:00
elif type ( w . widget ) is Test_Barcodes :
w . ok . connect ( self . set_barcodes )
2022-07-12 08:48:04 +00:00
elif type ( w . widget ) is Test_Leak :
w . ok . connect ( self . set_leak )
2022-06-28 10:31:27 +00:00
elif type ( w . widget ) is Test_Vision :
w . ok . connect ( self . set_vision )
2022-06-01 16:37:19 +00:00
else :
w . ok . connect ( self . next )
2022-07-12 08:48:04 +00:00
if hasattr ( w , " ko " ) :
w . ko . connect ( self . fail_cycle )
2022-06-01 16:37:19 +00:00
# TESTING
if " --test " in sys . argv :
self . testing = True
else :
self . testing = False
# /TESTING
# START CYCLE
2022-07-12 08:48:04 +00:00
self . next_timer = QTimer ( )
self . next_timer . setSingleShot ( True )
self . next_timer . timeout . connect ( self . next )
2022-06-01 16:37:19 +00:00
self . next ( )
def refresh_time ( self , init = False ) :
if init :
self . time_timer = QTimer ( )
self . time_timer . setSingleShot ( True )
self . time_timer . timeout . connect ( self . refresh_time )
t = datetime . now ( )
self . time_l . setText ( " {d} / {mo} / {y} \n {h} : {m} " . format ( y = t . year , mo = t . month , d = t . day , h = t . hour , m = t . minute ) )
self . time_timer . start ( 60 - t . second )
def select_step_img ( self , step , suffix = None ) :
img_path = " ./src/ui/imgs "
names = [ ]
if suffix is not None :
2022-07-26 14:18:44 +00:00
names . append ( f " { step } _ { suffix } _ { self . machine_id } " )
2022-06-01 16:37:19 +00:00
names . append ( f " { step } _ { suffix } " )
2022-07-26 14:18:44 +00:00
names . append ( f " { step } _ { self . machine_id } " )
2022-06-01 16:37:19 +00:00
names . append ( f " { step } " )
for name in names :
for ext in [ " png " , " jpg " ] :
path = f " { img_path } / { name } . { ext } "
if os . path . isfile ( path ) :
return path
raise FileNotFoundError ( f " No image was found for step { step } " )
def change_recipe ( self ) :
self . next ( action = " change_recipe " )
def fail_cycle ( self ) :
self . next ( action = " fail " )
def setCentralWidget ( self , widget ) :
replace_widget ( self , " centralWidget " , widget )
def request_autotest ( self , reason ) : # you can cancel the request calling request_autotest(False)
self . log . info ( f " cycle request autotest: reason: { reason !r} autotest_request: { self . autotest_request !r} " )
if reason == " init " :
self . autotest_timer = QTimer ( )
self . autotest_timer . setSingleShot ( False )
self . autotest_timer . timeout . connect ( self . request_periodic_autotest )
self . time_timer . start ( self . autotest_period )
reason = " boot "
self . autotest_request = reason
2022-07-19 09:59:00 +00:00
self . cycle_available_steps [ " autotest " ] . widget . set_reason ( reason )
2022-06-01 16:37:19 +00:00
def request_periodic_autotest ( self ) :
self . request_autotest ( " periodic " )
def next ( self , action = None ) :
2022-07-19 09:59:00 +00:00
self . log . debug ( f " cycle next: cycle step: { self . step !r} action: { action !r} " )
2022-07-25 09:16:14 +00:00
current_w = self . centralWidget
if hasattr ( current_w , " stop " ) :
current_w . stop ( )
2022-06-01 16:37:19 +00:00
if action == " change_recipe " :
self . log . info ( f " cycle next: action: { action !r} " )
self . set_recipe ( recipe = None )
2022-07-19 09:59:00 +00:00
self . step = Steps ( type = " select_recipe " )
2022-06-28 10:31:27 +00:00
self . cycle_index = - 1
# RESET TEST DATA
2022-07-26 10:24:53 +00:00
self . data = { " ok " : True , " overridden " : False }
self . archived = None
2022-08-02 16:15:30 +00:00
# COUNT RESET
self . pieces [ 0 ] = 0
self . pieces [ 1 ] = 0
2022-06-01 16:37:19 +00:00
elif action == " fail " :
self . log . info ( f " cycle next: action: { action !r} " )
# FAIL AND RESTART TEST
2022-07-19 09:59:00 +00:00
self . step = Steps ( type = " fail " )
2022-06-28 10:31:27 +00:00
self . cycle_index = - 1
# RESET TEST DATA
2022-07-26 10:24:53 +00:00
self . data = { " ok " : True , " overridden " : False }
self . archived = None
2022-08-02 16:15:30 +00:00
# COUNT FAIL
self . pieces [ 1 ] + = 1
2022-06-01 16:37:19 +00:00
elif action is not None :
raise NotImplementedError ( f " cycle next: action { action !r} is not a valid action " )
2022-07-19 09:59:00 +00:00
# if action did not set the next cycle step
# set next cycle step normally
if self . recipe is None or self . cycle_steps is None :
2022-07-12 08:48:04 +00:00
# if recipe not set: select_recipe
2022-07-19 09:59:00 +00:00
self . step = Steps ( type = " select_recipe " )
elif action is None :
2022-07-12 08:48:04 +00:00
if self . cycle_index == - 1 and self . autotest_request is not False :
2022-07-19 09:59:00 +00:00
# if cycle_steps is not started or has ended
2022-07-12 08:48:04 +00:00
# and autotest was requested
self . autotest_request = False
2022-07-19 09:59:00 +00:00
self . step = Steps ( type = " autotest " )
2022-07-12 08:48:04 +00:00
if self . autotest_period is not None : # reset periodic autotest timer
self . time_timer . start ( self . autotest_period )
2022-07-19 09:59:00 +00:00
elif len ( self . cycle_steps ) :
# goto next step in cycle_steps
self . cycle_index = ( self . cycle_index + 1 ) % len ( self . cycle_steps )
self . step = self . cycle_steps [ self . cycle_index ]
2022-06-01 16:37:19 +00:00
else :
2022-07-19 09:59:00 +00:00
self . cycle_index = - 1
2022-07-26 10:24:53 +00:00
self . archived = None
2022-07-19 09:59:00 +00:00
self . step = Steps ( type = None )
2022-06-01 16:37:19 +00:00
# enable/disable cycle controls
self . change_recipe_b . setEnabled ( self . recipe is not None )
2022-07-19 09:59:00 +00:00
self . cancel_b . setEnabled ( self . step . type is not None and self . step . type not in {
2022-06-01 16:37:19 +00:00
" emergency " ,
" fail " ,
" select_recipe " ,
" wait " ,
} )
2022-07-19 09:59:00 +00:00
self . log . info ( f " cycle next: next cycle step: { self . step !r} " )
2022-06-28 10:31:27 +00:00
# INIT TEST DATA IF STARTING CYCLE LOOP
if self . cycle_index == 0 :
2022-07-26 10:24:53 +00:00
self . data = { " ok " : True , " overridden " : False }
self . archived = None
2022-07-19 09:59:00 +00:00
w = self . cycle_available_steps [ self . step . type ]
2022-06-22 15:18:29 +00:00
if hasattr ( w , " start " ) :
2022-07-19 09:59:00 +00:00
w . start ( recipe = self . recipe , step = self . cycle_steps [ self . cycle_index ] )
2022-07-25 09:16:14 +00:00
if w is not current_w :
self . setCentralWidget ( w )
2022-07-19 09:59:00 +00:00
if self . step . type == " done " :
2022-07-26 10:24:53 +00:00
self . archived = self . done ( )
self . next_timer . start ( 2000 )
elif self . step . type == " print " :
self . print ( self . archived )
2022-07-12 08:48:04 +00:00
self . next_timer . start ( 2000 )
2022-07-19 09:59:00 +00:00
elif self . step . type == " fail " :
self . next_timer . start ( 2000 )
elif self . step . type == " wait " :
2022-07-12 08:48:04 +00:00
self . next_timer . start ( 6000 )
2022-06-01 16:37:19 +00:00
# UPDATE PIECES DISPLAY
self . pieces_count_l . setText ( f " { self . pieces [ 0 ] } OK / { self . pieces [ 1 ] } NOK / { sum ( self . pieces ) } TOT " )
def set_recipe ( self , recipe = None ) :
self . recipe = recipe
2022-07-19 09:59:00 +00:00
if self . recipe is None :
self . cycle_steps = None
else :
2022-07-26 10:24:53 +00:00
steps = self . recipe . get_steps ( )
print_found = False
for i , step in enumerate ( steps ) :
if step . type == " print " :
steps . insert ( i , Steps ( type = " done " ) )
print_found = True
break
if not print_found :
steps . append ( Steps ( type = " done " ) )
steps . append ( Steps ( type = " wait " ) )
self . cycle_steps = steps
2022-06-01 16:37:19 +00:00
# UPDATE RECIPE DISPLAY
if self . recipe is not None :
self . recipe_l . setText ( self . recipe . name )
self . recipe_l . setStyleSheet ( " " )
self . next ( )
else :
self . recipe_l . setText ( " NON SELEZIONATA " )
self . recipe_l . setStyleSheet ( " QLabel { color: red; } " )
2022-07-25 13:36:42 +00:00
def set_barcodes ( self , barcodes = None ) :
if " barcodes " not in self . data :
self . data [ " barcodes " ] = { }
self . data [ " barcodes " ] . update ( barcodes )
2022-06-28 10:31:27 +00:00
self . next ( )
2022-07-12 08:48:04 +00:00
def set_leak ( self , leak = None ) :
2022-07-25 13:36:42 +00:00
if " leak " not in self . data :
2022-08-01 11:29:12 +00:00
self . data [ " leak " ] = { }
2022-07-26 14:18:44 +00:00
leak [ " step " ] = model_to_dict ( self . step )
2022-08-01 11:29:12 +00:00
self . data [ " leak " ] [ len ( self . data [ " leak " ] ) ] = leak
2022-07-26 10:24:53 +00:00
self . data [ " overridden " ] = self . data [ " overridden " ] or leak . get ( " overridden " , False )
self . data [ " ok " ] = self . data [ " ok " ] and leak . get ( " ok " , False )
2022-07-25 13:36:42 +00:00
self . next ( )
def set_vision ( self , vision = None ) :
if " vision " not in self . data :
2022-08-01 11:29:12 +00:00
self . data [ " vision " ] = { }
2022-07-26 14:18:44 +00:00
vision [ " step " ] = model_to_dict ( self . step )
2022-08-01 11:29:12 +00:00
self . data [ " vision " ] [ len ( self . data [ " vision " ] ) ] = vision
2022-07-26 10:24:53 +00:00
self . data [ " overridden " ] = self . data [ " overridden " ] or vision . get ( " overridden " , False )
self . data [ " ok " ] = self . data [ " ok " ] and vision . get ( " ok " , False )
2022-07-12 08:48:04 +00:00
self . next ( )
2022-07-19 09:59:00 +00:00
def done ( self , ok = True ) :
2022-06-01 16:37:19 +00:00
self . log . info ( " cycle done " )
2022-08-02 16:15:30 +00:00
vision_test_1 = self . data . get ( " vision " , { } ) . get ( 0 , { } )
out_paths = self . components [ " vision_saver " ] . save (
save_time = vision_test_1 . get ( " time " , None ) ,
frame = vision_test_1 . get ( " frame " , None ) ,
# vision=vision_test_1.get("detections", None),
)
self . log . info ( f " cycle vision saved locally: { out_paths !r} " )
2022-08-01 11:29:12 +00:00
for vision in self . data [ " vision " ] . values ( ) :
vision . pop ( " frame " , None )
vision . pop ( " render " , None )
2022-06-28 10:31:27 +00:00
archived = Archive . archive ( self . recipe , self . data , ok and self . data [ " ok " ] , overridden = self . data [ " overridden " ] )
2022-06-01 16:37:19 +00:00
self . log . info ( f " cycle archived locally: { archived !r} " )
2022-07-26 10:24:53 +00:00
# COUNT OK
self . pieces [ 0 ] + = 1
return archived
def print ( self , archived = None ) :
self . log . info ( " cycle print " )
2022-06-01 16:37:19 +00:00
# LABEL PRINT
2022-08-02 16:15:30 +00:00
leak_test_1 = self . data . get ( " leak " , { } ) . get ( 0 , { } )
leak_test_1_step_spec = leak_test_1 . get ( " step " , { } ) . get ( " spec " , { } )
leak_test_1_results = leak_test_1 . get ( " results " , { } )
leak_test_1_results_data = leak_test_1_results . get ( " data " , { } )
2022-08-01 11:29:12 +00:00
datamatrix = str ( archived . recipe . part_number ) + archived . time . strftime ( " % m % y " ) + f " { archived . id : 0>5 } "
2022-08-02 16:15:30 +00:00
pmax = leak_test_1_step_spec . get ( " test_pressure " , " - " )
pmin = leak_test_1_results_data . get ( " Running test: pressure at the end of settling " , " - " )
leak = leak_test_1_results_data . get ( " Running test: measured leak " , " - " )
2022-07-26 10:24:53 +00:00
context = {
2022-08-01 11:29:12 +00:00
" DATAMATRIX " : datamatrix ,
" DATAMATRIX_TEXT " : datamatrix ,
" PIECE_NUM " : str ( archived . id ) ,
" DATETIME " : archived . time . strftime ( " %d / % m/ % Y % H: % M: % S " ) ,
2022-07-26 14:18:44 +00:00
" SHIFT " : str ( get_shift ( archived . time ) ) ,
2022-07-26 14:46:27 +00:00
" STATION " : str ( self . machine_id ) ,
2022-07-25 13:36:42 +00:00
" OPERATOR " : str ( Users . get_session ( ) . user . username ) ,
2022-08-01 11:29:12 +00:00
" PMAX " : f " { pmax : .3f } " if type ( pmax ) is not str else pmax ,
" PMIN " : f " { pmin : .3f } " if type ( pmin ) is not str else pmin ,
" LEAK " : f " { leak : .3f } " if type ( leak ) is not str else leak ,
2022-08-02 16:15:30 +00:00
" TFILL " : str ( leak_test_1_step_spec . get ( " filling_time " , " - " ) ) ,
" TSTAB " : str ( leak_test_1_step_spec . get ( " settling_time " , " - " ) ) ,
" TTEST " : str ( leak_test_1_step_spec . get ( " test_time " , " - " ) ) ,
" MAXLEAK " : str ( leak_test_1_step_spec . get ( " test_pressure_max_delta " , " - " ) ) ,
" PTESTMIN " : str ( leak_test_1_step_spec . get ( " test_pressure_min_delta " , " - " ) ) ,
2022-07-27 12:54:19 +00:00
" RESULT_L1 " : " ESITO " + str ( " FORZATO " if self . data . get ( " overridden " , False ) else " " ) ,
2022-08-02 16:15:30 +00:00
" RESULT_L2 " : str ( " CONFORME " if leak_test_1_results . get ( " ok " , False ) else " SCARTO " ) ,
2022-07-26 10:24:53 +00:00
}
self . components [ " label_printer " ] . print_label ( " EtichettaR5 " , context = context )
self . log . info ( f " cycle printed: { context !r} " )