diff --git a/config/label_templates/ETA013.prn b/config/label_templates/ETA013.prn new file mode 100644 index 0000000..4c3f6ea Binary files /dev/null and b/config/label_templates/ETA013.prn differ diff --git a/config/label_templates/EtichettaR5.prn b/config/label_templates/EtichettaR5.prn index b133511..3924cc2 100644 --- a/config/label_templates/EtichettaR5.prn +++ b/config/label_templates/EtichettaR5.prn @@ -7,7 +7,7 @@ ^LL1071 ^LS0 ^FT32,94^A0N,23,24^FH\^FDNumero Disegno^FS -^FT39,240^A0N,20,19^FH\^FD{DATAMATRIX_TEXT}^FS +^FT39,240^A0N,20,19^FH\^FD{PART}{MO}{YY}{SN5}^FS ^FT39,291^A0N,20,19^FH\^FDN. Pezzo:^FS ^FT36,318^A0N,20,19^FH\^FD{DATETIME}^FS ^FT42,359^A0N,20,19^FH\^FDTurno:^FS @@ -22,20 +22,20 @@ ^FT34,709^A0N,20,19^FH\^FDCaduta Tollerata^FS ^FT34,736^A0N,20,19^FH\^FDmax (Bar)^FS ^FT34,763^A0N,20,19^FH\^FDPress Min Prova (Bar)^FS -^FT136,291^A0N,20,19^FH\^FD{PIECE_NUM}^FS +^FT136,291^A0N,20,19^FH\^FD{SN}^FS ^FT145,359^A0N,20,19^FH\^FD{SHIFT}^FS ^FT138,413^A0N,20,19^FH\^FD{OPERATOR}^FS ^FT184,520^A0N,20,19^FH\^FD{PMAX}^FS ^FT184,547^A0N,20,19^FH\^FD{PMIN}^FS -^FT185,574^A0N,20,19^FH\^FD{LEAK}^FS +^FT185,574^A0N,20,19^FH\^FD{RESLEAK}^FS ^FT257,628^A0N,20,19^FH\^FD{TFILL}^FS -^FT257,655^A0N,20,19^FH\^FD{TSTAB}^FS +^FT257,655^A0N,20,19^FH\^FD{TSET}^FS ^FT257,682^A0N,20,19^FH\^FD{TTEST}^FS -^FT257,736^A0N,20,19^FH\^FD{MAXLEAK}^FS -^FT257,763^A0N,20,19^FH\^FD{PTESTMIN}^FS +^FT257,736^A0N,20,19^FH\^FD{PMAX}^FS +^FT257,763^A0N,20,19^FH\^FD{PMIN}^FS ^FT138,386^A0N,20,19^FH\^FD{STATION}^FS ^BY80,80^FT42,196^BXN,5,200,0,0,1,~ -^FH\^FD{DATAMATRIX}^FS +^FH\^FD{PART}{MO}{YY}{SN5}^FS ^FT56,906^A0N,36,36^FH\^FD{RESULT_L2}^FS ^FT56,868^A0N,36,36^FH\^FD{RESULT_L1}^FS ^FO32,454^GB292,0,8^FS diff --git a/runme.sh b/runme.sh index c707543..bd9a5cb 100755 --- a/runme.sh +++ b/runme.sh @@ -1,4 +1,4 @@ #!/bin/bash -e cd "$(dirname "$0")" source "./venv/bin/activate" || source "./venv/Scripts/activate" || : -python -O "./src/main.py" --no-edgetpu --no-tflite +python -O "./src/main.py" --no-edgetpu --no-tflite $* diff --git a/src/components/os_label_printer.py b/src/components/os_label_printer.py index eb50130..279afad 100644 --- a/src/components/os_label_printer.py +++ b/src/components/os_label_printer.py @@ -39,31 +39,49 @@ class Os_Label_Printer(Component): # LABEL PRINT label = label.format(**context) if platform.system() == "Windows": - printer = win32print.OpenPrinter(self.printer) - job = win32print.StartDocPrinter(printer, 1, ("label", None, "RAW")) - win32print.WritePrinter(printer, bytes(label, encoding="utf8", errors="surrogateescape")) - win32print.EndPagePrinter(printer) - return True + try: + printer = win32print.OpenPrinter(self.printer) + job = win32print.StartDocPrinter(printer, 1, ("label", None, "RAW")) + win32print.WritePrinter(printer, bytes(label, encoding="utf8", errors="surrogateescape")) + win32print.EndPagePrinter(printer) + return label + except Exception as e: + self.log.exception(traceback.format_exc()) + QMessageBox.critical( + None, + "Errore Stampante", + f"Non e stato possibile stampare l'etichetta.\n\nErrore:\n{e}" + ) + return None else: - os.makedirs("tmp", exist_ok=True) - label_file = "tmp/label.prn" - with open(label_file, "w", errors="surrogateescape") as f: - label = f.write(label) - if self.platform == "windows": - cmd = f'print /d:"{self.printer}" "{label_file}"' - elif self.platform == "cups": - cmd = f'lp -d "{self.printer}" "{label_file}"' - else: - raise NotImplementedError(f"platform {self.platform!r} is not supported") - if not self.simulate: - p = subprocess.run(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) # unsafe - if p.returncode != 0: - self.log.exception(f"failed to print: returncode: {p.returncode}\noutput:\n{p.stdout}") - QMessageBox.critical( - None, - "Errore Stampante", - f"Non e stato possibile stampare l'etichetta.\n\nErrore:\nreturncode: {p.returncode}\noutput:\n{p.stdout}" - ) - return False - return True - return False + try: + os.makedirs("tmp", exist_ok=True) + label_file = "tmp/label.prn" + with open(label_file, "w", errors="surrogateescape") as f: + label = f.write(label) + if self.platform == "windows": + cmd = f'print /d:"{self.printer}" "{label_file}"' + elif self.platform == "cups": + cmd = f'lp -d "{self.printer}" "{label_file}"' + else: + raise NotImplementedError(f"platform {self.platform!r} is not supported") + if not self.simulate: + p = subprocess.run(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) # unsafe + if p.returncode != 0: + self.log.exception(f"failed to print: returncode: {p.returncode}\noutput:\n{p.stdout}") + QMessageBox.critical( + None, + "Errore Stampante", + f"Non e stato possibile stampare l'etichetta.\n\nErrore:\nreturncode: {p.returncode}\noutput:\n{p.stdout}" + ) + return None + return label + except Exception as e: + self.log.exception(traceback.format_exc()) + QMessageBox.critical( + None, + "Errore Stampante", + f"Non e stato possibile stampare l'etichetta.\n\nErrore:\n{e}" + ) + return None + return None diff --git a/src/components/serial_label_printer.py b/src/components/serial_label_printer.py index 12b819e..19c66cf 100644 --- a/src/components/serial_label_printer.py +++ b/src/components/serial_label_printer.py @@ -48,9 +48,18 @@ class Serial_Label_Printer(Component): ) conn.write(label.encode(errors="surrogateescape")) conn.close() + return label except serial.serialutil.SerialException as e: QMessageBox.critical( None, "Errore Connessione Stampante", "Non e stato possibile connettersi alla stampante di etichette\nL'etichetta non verra stampata.\n\nErrore:\n" + str(e) ) + return None + except Exception as e: + QMessageBox.critical( + None, + "Errore Stampante", + f"Non e stato possibile stampare l'etichetta.\n\nErrore:\n{e}" + ) + return None diff --git a/src/lib/db/models/archive.py b/src/lib/db/models/archive.py index 8f85419..85ceba7 100644 --- a/src/lib/db/models/archive.py +++ b/src/lib/db/models/archive.py @@ -1,6 +1,6 @@ from datetime import datetime -from peewee import AutoField, BooleanField, DateTimeField, ForeignKeyField +from peewee import AutoField, BooleanField, DateTimeField, ForeignKeyField, TextField from playhouse.sqlite_ext import JSONField from .base_model import BaseModel, db @@ -12,46 +12,47 @@ class Archive(BaseModel): id = AutoField(primary_key=True, unique=True, null=False) time = DateTimeField(unique=True, null=False, default=datetime.now) user = ForeignKeyField(Users, Users.username, null=False) - recipe = ForeignKeyField(Recipes, null=False) result = BooleanField(null=False) overridden = BooleanField(null=False) test_data = JSONField(null=False) + label = TextField(null=True) archived = BooleanField(null=False, default=False) uploaded = BooleanField(null=False, default=False) @classmethod @db.atomic() def archive(cls, recipe, test_data, result, overridden): - parsed_test_data = { - "ESITO GLOBALE COLLAUDO": "OK" if test_data.get("ok", None) else "KO", - } - total_duration = 0 - for step_name in [ - "autotest", - "barcodes", - "connector", - "leak", - "print", - "resistance", - "vision", - ]: - for k, v in test_data.get(step_name, {}).items(): - if step_name not in parsed_test_data: - parsed_test_data[step_name] = {} - parsed_test_data[step_name][k] = { - f"ESITO {step_name}": "OK" if v.get("ok", None) else "KO", - "result": v.get("results", {}).get("result", None), - "data": v.get("results", {}).get("data", None), - "spec": v.get("step", {}).get("spec", None), - "duration": v.get("duration", None), - } - if parsed_test_data[step_name][k]["duration"] is not None: - total_duration += parsed_test_data[step_name][k]["duration"] - parsed_test_data["DURATA TOTALE COLLAUDO"] = total_duration + # parsed_test_data = { + # "ESITO GLOBALE COLLAUDO": "OK" if test_data.get("ok", None) else "KO", + # "recipe": test_data.get("recipe", None), + # } + # total_duration = 0 + # for step_name in [ + # "autotest", + # "barcodes", + # "connector", + # "leak", + # "print", + # "resistance", + # "vision", + # ]: + # for k, v in test_data.get(step_name, {}).items(): + # if step_name not in parsed_test_data: + # parsed_test_data[step_name] = {} + # parsed_test_data[step_name][k] = { + # f"ESITO {step_name}": "OK" if v.get("ok", None) else "KO", + # "result": v.get("results", {}).get("result", None), + # "data": v.get("results", {}).get("data", None), + # "step": v.get("step", None), + # "duration": v.get("duration", None), + # } + # if parsed_test_data[step_name][k]["duration"] is not None: + # total_duration += parsed_test_data[step_name][k]["duration"] + # parsed_test_data["DURATA TOTALE COLLAUDO"] = total_duration return cls.create( user=Users.get_session().user, recipe=recipe, - test_data=parsed_test_data, + test_data=test_data, result=result, overridden=overridden, ) diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 3007f83..496c3c3 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -213,6 +213,8 @@ class Test(Widget): }) self.log.info(f"cycle next: next cycle step: {self.step!r}") # INIT TEST DATA IF STARTING CYCLE LOOP + if self.recipe is not None and "recipe" not in self.data: + self.data["recipe"] = model_to_dict(self.recipe) if self.cycle_index == 0: self.data = {"ok": True, "overridden": False} self.archived = None @@ -225,7 +227,9 @@ class Test(Widget): self.archived = self.done() self.next_timer.start(2000) elif self.step.type == "print": - self.print(self.archived, self.step.spec.get("template", "EtichettaR5")) + compiled_label = self.print(self.archived, self.step.spec.get("template", "EtichettaR5")) + self.archived.label = compiled_label + self.archived.save() self.next_timer.start(2000) elif self.step.type == "fail": self.next_timer.start(2000) @@ -324,35 +328,74 @@ class Test(Widget): self.pieces[0] += 1 return archived + @staticmethod + def labellify(v): + if not isinstance(v, str): + v = f"{v:.3f}" + return v + def print(self, archived, label): self.log.info("cycle print") + if archived.label is not None: + raise AssertionErrror("this should never happen") + self.components["label_printer"].print_label(archived.label, context=None) + self.log.info("cycle printed already compiled label") # LABEL PRINT - leak_test_1 = self.data.get("leak", {}).get(0, {}) - leak_test_1_step_spec = leak_test_1.get("step", {}).get("spec", {}) + recipe = archived.test_data.get("recipe", {}) + leak_test_1 = archived.test_data.get("leak", {}).get(0, {}) + leak_test_1_step = leak_test_1.get("step", {}) + leak_test_1_step_spec = leak_test_1_step.get("spec", {}) leak_test_1_results = leak_test_1.get("results", {}) leak_test_1_results_data = leak_test_1_results.get("data", {}) - datamatrix = str(archived.recipe.part_number) + archived.time.strftime("%m%y") + f"{archived.id:0>5}" - 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", "-") context = { - "DATAMATRIX": datamatrix, - "DATAMATRIX_TEXT": datamatrix, - "PIECE_NUM": str(archived.id), + # RECIPE DATA + "RECIPE": self.labellify(recipe.get("name", "-")), + "CLIENT": self.labellify(recipe.get("client", "-")), + "PART": self.labellify(recipe.get("part_number", "-")), + # STEP SPEC + "TPREFILL": self.labellify(leak_test_1_step_spec.get("pre_filling_time", "-")), + "PPREFILL": self.labellify(leak_test_1_step_spec.get("pre_filling_pressure", "-")), + "TFILL": self.labellify(leak_test_1_step_spec.get("filling_time", "-")), + "TSET": self.labellify(leak_test_1_step_spec.get("settling_time", "-")), + "PSETMINP": self.labellify(leak_test_1_step_spec.get("settling_pressure_min_percent", " -")), + "PSETMAXP": self.labellify(leak_test_1_step_spec.get("settling_pressure_max_percent", " -")), + "TTEST": self.labellify(leak_test_1_step_spec.get("test_time", "-")), + "PMIN": self.labellify(leak_test_1_step_spec.get("test_pressure_min_delta", "-")), + "PTEST": self.labellify(leak_test_1_step_spec.get("test_pressure", "-")), + "PMAX": self.labellify(leak_test_1_step_spec.get("test_pressure_max_delta", "-")), + "TFLUSH": self.labellify(leak_test_1_step_spec.get("flush_time", "-")), + "PFLUSH": self.labellify(leak_test_1_step_spec.get("flush_pressure", "-")), + # ACTUAL TESTED VALUES + "RESTPB": self.labellify(leak_test_1_results_data.get("Running test: phase backwards time", "-")), + "RESPFILL": self.labellify(leak_test_1_results_data.get("Running test: filling pressure", "-")), + "RESPSET": self.labellify(leak_test_1_results_data.get("Running test: pressure at the end of settling", "-")), + "RESPB": self.labellify(leak_test_1_results_data.get("Running test: burst pressure", "-")), + "RESLEAK": self.labellify(leak_test_1_results_data.get("Running test: measured leak", "-")), + "RESFLOW": self.labellify(leak_test_1_results_data.get("Running test: calculated leak flow rate", "-")), + "RESRVP": self.labellify(leak_test_1_results_data.get("Running test: calculate RVP%", "-")), + "RESRES": self.labellify(leak_test_1_results_data.get("Running test: result", "-")), + # SERIAL DEFINITION + "SN": str(archived.id), + "SN5": f"{archived.id:0>5}", + "SN6": f"{archived.id:0>6}", + # TIME DEFINITION "DATETIME": archived.time.strftime("%d/%m/%Y %H:%M:%S"), + "YYYY": archived.time.strftime("%Y"), + "YY": archived.time.strftime("%y"), + "MO": archived.time.strftime("%m"), + "DD": archived.time.strftime("%d"), + "HH": archived.time.strftime("%H"), + "MI": archived.time.strftime("%M"), + "SS": archived.time.strftime("%S"), + # EXTRA DATA "SHIFT": str(get_shift(archived.time)), "STATION": str(self.machine_id), - "OPERATOR": str(Users.get_session().user.username), - "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, - "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", "-")), + "OPERATOR": str(archived.user.username), + # RESULT + "RESULT": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO") + str(" FORZATO" if self.data.get("overridden", False) else ""), "RESULT_L1": "ESITO" + str(" FORZATO" if self.data.get("overridden", False) else ""), "RESULT_L2": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO"), } - self.components["label_printer"].print_label(label, context=context) + compiled_label = self.components["label_printer"].print_label(label, context=context) self.log.info(f"cycle printed: {context!r}") + return compiled_label