2022-06-01 16:37:19 +00:00
import logging
import os
import sys
from datetime import datetime
2022-06-28 10:31:27 +00:00
from lib . db import Archive , Users
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-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-06-22 15:18:29 +00:00
def __init__ ( self , system_name = None , components = None ) :
2022-06-01 16:37:19 +00:00
super ( ) . __init__ ( )
self . system_name = system_name
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
# INIT CYCLE STATES
self . cycle_state = None
self . cycle_states = {
2022-06-22 15:18:29 +00:00
# "assembly_1": Test_Assembly(self.select_step_img("assembly_1"), u"INSERIRE SENSORE"),
2022-06-01 16:37:19 +00:00
" autotest " : Test_Assembly ( None , u " ESEGUIRE PROCEDURA DI AUTOTEST " , Test_Autotest ( ) ) ,
" done " : Test_Assembly ( self . select_step_img ( " success " ) , u " COLLAUDO COMPLETATO - RIMUOVERE IL SENSORE " ) ,
" emergency " : Test_Assembly ( self . select_step_img ( " reset_emergency " ) , u " EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \" RESET EMERGENZA \" DAL MEN \u00d9 \" STRUMENTI \" " ) ,
2022-06-22 15:18:29 +00:00
" fail " : Test_Assembly ( self . select_step_img ( " fail " ) , u " CICLO INTERROTTO - RIMUOVERE IL SENSORE " ) ,
2022-07-12 08:48:04 +00:00
" run_test " : Test_Assembly ( self . select_step_img ( " wait " ) , u " ESECUZIONE TEST IN CORSO - ATTENDERE " , Test_Leak ( components = self . components , recipe = self . recipe ) ) ,
2022-06-22 15:18:29 +00:00
" select_recipe " : Test_Assembly ( None , u " SELEZIONARE IL CODICE DA COLLAUDARE " , Recipe_Selection ( ) ) ,
2022-07-12 08:48:04 +00:00
" vision " : Test_Assembly ( None , u " ESEGUIRE PROCEDURA DI AUTOTEST " , Test_Vision ( components = self . components , recipe = self . recipe ) ) ,
2022-06-22 15:18:29 +00:00
" wait " : Test_Assembly ( self . select_step_img ( " wait " ) , u " ATTENDERE - PAUSA INTER CICLO " ) ,
2022-06-01 16:37:19 +00:00
}
2022-07-12 08:48:04 +00:00
self . cycle_loop = [ " run_test " , " vision " , " done " , " wait " ]
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
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-12 08:48:04 +00:00
self . data = { }
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 )
for w in self . cycle_states . values ( ) :
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-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 :
names . append ( f " { step } _ { suffix } _ { self . system_name } " )
names . append ( f " { step } _ { suffix } " )
names . append ( f " { step } _ { self . system_name } " )
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
self . cycle_states [ " autotest " ] . widget . set_reason ( reason )
def request_periodic_autotest ( self ) :
self . request_autotest ( " periodic " )
def next ( self , action = None ) :
self . log . debug ( f " cycle next: cycle_state: { self . cycle_state !r} action: { action !r} " )
2022-06-28 10:31:27 +00:00
current_w = self . cycle_states . get ( self . cycle_state , None )
if current_w is not None and 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 )
self . cycle_state = " select_recipe "
2022-06-28 10:31:27 +00:00
self . cycle_index = - 1
# RESET TEST DATA
2022-07-12 08:48:04 +00:00
self . data . clear ( )
2022-06-01 16:37:19 +00:00
elif action == " fail " :
self . log . info ( f " cycle next: action: { action !r} " )
if self . cycle_state in self . cycle_loop :
pass
# COUNT FAIL
self . pieces [ 1 ] + = 1
# FAIL AND RESTART TEST
self . cycle_state = " fail "
2022-06-28 10:31:27 +00:00
self . cycle_index = - 1
# RESET TEST DATA
2022-07-12 08:48:04 +00:00
self . data . clear ( )
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 " )
# if action did not set the next cycle_state
# set next cycle_state normally
2022-07-12 08:48:04 +00:00
if self . recipe is None :
# if recipe not set: select_recipe
self . cycle_state = " select_recipe "
else :
if self . cycle_index == - 1 and self . autotest_request is not False :
# if cycle_loop is not started or has ended
# and autotest was requested
self . autotest_request = False
self . cycle_state = " autotest "
if self . autotest_period is not None : # reset periodic autotest timer
self . time_timer . start ( self . autotest_period )
2022-06-01 16:37:19 +00:00
else :
2022-07-12 08:48:04 +00:00
# goto next step in cycle_loop
self . cycle_index = ( self . cycle_index + 1 ) % len ( self . cycle_loop )
self . cycle_state = self . cycle_loop [ self . cycle_index ]
2022-06-01 16:37:19 +00:00
# enable/disable cycle controls
self . change_recipe_b . setEnabled ( self . recipe is not None )
self . cancel_b . setEnabled ( self . cycle_state not in {
" emergency " ,
" fail " ,
" select_recipe " ,
" wait " ,
} )
self . log . info ( f " cycle next: next cycle_state: { self . cycle_state !r} " )
2022-06-28 10:31:27 +00:00
# INIT TEST DATA IF STARTING CYCLE LOOP
if self . cycle_index == 0 :
2022-07-12 08:48:04 +00:00
self . data . clear ( )
2022-06-01 16:37:19 +00:00
w = self . cycle_states [ self . cycle_state ]
2022-06-22 15:18:29 +00:00
if hasattr ( w , " start " ) :
2022-07-12 08:48:04 +00:00
w . start ( recipe = self . recipe )
self . setCentralWidget ( w )
if self . cycle_state == " done " :
self . done ( )
self . next_timer . start ( 2000 )
elif self . cycle_state == " wait " :
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
# 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-06-28 10:31:27 +00:00
def set_vision ( self , vision = None ) :
self . data [ " vision " ] = vision
self . data [ " overridden " ] = self . data . get ( " overridden " , False ) or self . data [ " vision " ] . get ( " overridden " , False )
self . data [ " ok " ] = self . data . get ( " ok " , True ) and self . data [ " vision " ] . get ( " ok " , False )
self . next ( )
2022-07-12 08:48:04 +00:00
def set_leak ( self , leak = None ) :
self . data [ " leak " ] = leak
self . data [ " overridden " ] = self . data . get ( " overridden " , False ) or self . data [ " leak " ] . get ( " overridden " , False )
self . data [ " ok " ] = self . data . get ( " ok " , True ) and self . data [ " leak " ] . get ( " ok " , False )
self . next ( )
def done ( self , ok = False , next = False ) :
2022-06-01 16:37:19 +00:00
self . log . info ( " cycle done " )
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} " )
# LABEL PRINT
# self.printer.print_label("1", archived)
# self.log.info(f"cycle printed: {archived!r}")
# COUNT OK
self . pieces [ 0 ] + = 1