st-ten-1/src/ui/test/test.py

234 lines
9.8 KiB
Python
Raw Normal View History

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