Merge remote-tracking branch 'origin/master'

# Conflicts:
#	config/machine_settings/hostnames.ini
This commit is contained in:
stres1 2022-08-02 17:33:02 +02:00
commit fca98bdd0f
17 changed files with 134 additions and 138 deletions

View File

@ -17,6 +17,7 @@ balance_blue: 1.5
time_format: %Y-%m-%d_%H-%M-%S
path: ./data/images
minimum_disk_free_space_gb: 20
resize_resolution: 612x512
[archive_synchronizer]
archive_endpoint: https://r5portal.it/api/echo/

View File

@ -1,7 +1,8 @@
import sys
import time
import traceback
from PyQt5.QtCore import QThread
if "--sim-serial" in sys.argv:
from components.dummies.serial import serial
else:
@ -16,16 +17,8 @@ C_UINT32_MAX = c_uint32(-1).value
class NeoPixels(Component):
def __init__(self, config=None, name=None):
self.conn = None
super().__init__(config=config, name=name, threaded=False)
self.conn = serial.Serial(
self.port,
baudrate=self.baudrate,
stopbits=self.stopbits,
parity=self.parity,
bytesize=self.bytesize,
)
time.sleep(5)
self.set_all_pixel_color("#000000")
def config_changed(self):
self.port = self.config[self.name]["port"]
@ -33,6 +26,17 @@ class NeoPixels(Component):
self.stopbits = getattr(serial, self.config[self.name].get("stopbits", "stopbits_one").upper())
self.parity = getattr(serial, self.config[self.name].get("parity", "parity_none").upper())
self.bytesize = getattr(serial, self.config[self.name].get("bytesize", "eightbits").upper())
if self.conn is not None:
self.conn.close()
self.conn = serial.Serial(
self.port,
baudrate=self.baudrate,
stopbits=self.stopbits,
parity=self.parity,
bytesize=self.bytesize,
)
QThread.msleep(5000)
self.set_all_pixel_color("#000000")
def set(self, pixel, color):
if type(pixel) is not int or pixel < 0 or pixel > C_UINT32_MAX:
@ -44,7 +48,7 @@ class NeoPixels(Component):
response = self.conn.readline()
if response != b"ok\n":
self.log.error(response.strip())
# conn.close()
# self.conn.close()
except serial.serialutil.SerialException:
self.log.exception(traceback.format_exc())

View File

@ -180,7 +180,7 @@ class TecnaMarpossProvasetT3P(ModbusComponent):
"Running test: test type",
"Running test: sequence index",
]}
if info["Running test: active phase"] == "FINE TEST":
if info["Running test: active phase"] == "FINE TEST": # "END TEST, WAITING THE START OF A NEW TEST":
info.update(self.get_test_results())
self.log.debug(str(info))
super()._get([info])

View File

@ -7,7 +7,7 @@ registers = {
"Life counter: TOTAL TESTS": [8 - 1, {"dt": "32bit_uint", }],
"Real time test pressure output": [11 - 1, {"dt": "32bit_int", "f": 21, }],
"Real time differential pressure output": [13 - 1, {"dt": "32bit_int", "f": 22, }],
"Real time pressure line regulator": [15 - 1, {"dt": "16bit_int", "f": 23,"g":0.1 }],
"Real time pressure line regulator": [15 - 1, {"dt": "16bit_int", "f": 23, "g": 0.1}], # TODO: REMOVE "g"
"Active alarm flags": [16 - 1, {"dt": "16bit_uint", }],
# | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
# | | | | A5 | A4 | A3 | A2 | A1 | | | | | | E3 | E2 | E1 |
@ -28,9 +28,9 @@ registers = {
"Running test: flow rate format": [27 - 1, {"dt": "16bit_uint", }], # white
"Active test program number": [31 - 1, {"dt": "16bit_uint", }],
"Running test: active phase": [32 - 1, {"dt": "16bit_uint", "decoding": {
0: "ATTESA START",
10: "CONTROLLO BARCODE",
20: "ATTESA BARCODE",
0: "ATTESA START", # "WAITING START",
10: "CONTROLLO BARCODE", # "CHECK BARCODE",
20: "ATTESA BARCODE", # "WAITING BARCODE",
30: "START TEST",
40: "START CAGE",
50: "START PLUG",
@ -38,10 +38,10 @@ registers = {
70: "WAIT DELAY ACKNOWLEDGE COMMAND",
80: "WAIT DELAY",
90: "WAIT ACKNOWLEDGE",
100: "T0 PRE-RIEMPIMENTO",
110: "T1 RIEMPIMENTO",
120: "T2 ASSESTAMENTO",
130: "T3 MISURA",
100: "T0 PRE-RIEMPIMENTO", # "T0 PRE-FILL",
110: "T1 RIEMPIMENTO", # "T1 FILLING",
120: "T2 ASSESTAMENTO", # "T2 SETTLING",
130: "T3 MISURA", # "T3 MEASURE",
140: "WAITING OPERATOR RESULT ACKNOWLEDGE",
150: "RESULT PRESENT",
160: "MARKING",
@ -49,7 +49,7 @@ registers = {
180: "END SEQUENCE PROGRAM",
190: "END PLUG",
200: "END CAGE",
210: "FINE TEST",
210: "FINE TEST", # WAITING THE START OF A NEW TEST",
}, }],
"Running test: phase backwards time": [33 - 1, {"dt": "16bit_uint", "f": 26, }],
"Running test: filling pressure": [34 - 1, {"dt": "32bit_int", "f": 21, }],

View File

@ -1,29 +1,26 @@
import logging
import os
import sys
import time
import traceback
from configparser import ConfigParser
from pathlib import Path
import cv2
import numpy as np
from PyQt5.QtCore import (QFileSystemWatcher, QLineF, QMutex, QPointF, QRectF,
Qt, QThread, pyqtSignal)
from PyQt5.QtGui import (QBrush, QColor, QFont, QImage, QPainter, QPainterPath,
QPen, QPixmap)
from PyQt5.QtWidgets import QApplication
from lib.helpers import time_this
from .component import Component
from .consumer import Consumer
if "--no-gpu" in sys.argv:
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
import tensorflow as tf
from lib.helpers.object_detection.utils import label_map_util
from PyQt5.QtCore import (QFileSystemWatcher, QLineF, QMutex, QPointF, QRectF,
Qt, QThread, pyqtSignal)
from PyQt5.QtGui import (QBrush, QColor, QFont, QImage, QPainter, QPainterPath,
QPen, QPixmap)
from .component import Component
from .consumer import Consumer
if "--no-edgetpu" not in sys.argv:
try:
@ -317,8 +314,7 @@ class Vision(Component):
if tf_mode is None and "normal" in self.allowed_modes:
try:
# create tensorflow model
model = tf.saved_model.load(str(self.models_dir / model_name))
model = model.signatures['serving_default']
model = tf.saved_model.load(str(self.models_dir / model_name)).signatures["serving_default"]
tf_mode = "normal"
except Exception:
self.log.exception(traceback.format_exc())
@ -339,14 +335,14 @@ class Vision(Component):
self.log.info(f"initialized model {self.model!r} with mode {self.tf_mode!r}")
self.loading_model_signal.emit({"status": "done"})
@time_this
def check_features(self, frame, lock=True):
if self.interpreter is not None and frame.shape != self.interpreter.get_input_details()[0]["shape"][1:3]:
tensor = np.expand_dims(cv2.resize(frame, self.interpreter.get_input_details()[0]["shape"][1:3], interpolation=cv2.INTER_LINEAR), axis=0)
else:
frame_resized=cv2.resize(frame, (256,256), interpolation=cv2.INTER_LINEAR)
frame_resized = cv2.resize(frame, (256, 256), interpolation=cv2.INTER_LINEAR)
tensor = tf.convert_to_tensor(np.asarray(frame_resized))
tensor = tensor[tf.newaxis, ...]
# tensor = np.expand_dims(frame, axis=0)
# Run inference
if lock:
self.lock.lock()
@ -388,33 +384,36 @@ class Vision(Component):
if lock:
self.lock.unlock()
detections = {
"detection_scores": [scores][0:1],
"detection_boxes": [boxes][0:1],
"detection_classes": [map(lambda class_id: class_id + 1, class_ids)][0:1],
"detection_scores": [scores],
"detection_boxes": [boxes],
"detection_classes": [map(lambda class_id: class_id + 1, class_ids)],
}
else:
detections = self.model(tensor)
if lock:
self.lock.unlock()
detections = {
"detection_scores": detections["detection_scores"].numpy().tolist(),
"detection_boxes": detections["detection_boxes"].numpy().tolist(),
"detection_classes": detections["detection_classes"],
}
# WARNING: results other than the ones related to tensor[-1] will be discarded
parsed_detections = []
for d_box, d_class, d_score in zip( # , d_mask in zip(
for d_score, d_box, d_class in zip( # , d_mask in zip(
detections["detection_scores"][-1],
detections["detection_boxes"][-1],
detections["detection_classes"][-1],
detections["detection_scores"][-1],
# detections["detection_masks"][-1],
):
if d_score < self.detection_threshold:
continue
box = list(d_box)
# box = d_box.numpy().tolist()
box = [i * s for i, s in zip(box, frame.shape[:2] * 2)] # rescale detection to frame size
detection = {
"class": self.category_index[int(d_class)],
"score": float(d_score),
# "score": d_score.numpy().tolist(),
# "mask": d_mask.numpy().tolist(),
"score": d_score,
"box": box,
"class": self.category_index[int(d_class)],
# "mask": d_mask,
"center": self.get_center(box),
"size": self.get_size(box),
}
@ -477,7 +476,6 @@ class Vision(Component):
else:
raise NotImplementedError(f"invalid zone_detection_filter_mode: {self.zone_detection_filter_mode!r}")
elif zone["shape"] == "ellipse": # it's a circle
distance = self.get_distance(detection["center"], zone["center"])
if self.zone_detection_filter_mode == "center_inside":
outside_zone = distance > zone["size"][0] / 2
elif self.zone_detection_filter_mode == "box_inside":

View File

@ -17,19 +17,30 @@ class VisionSaver(Component):
def config_changed(self):
self.location = Path(self.config[self.name]["path"])
os.makedirs(self.location, exist_ok=True)
self.resize_resolution = self.config[self.name].get("resize_resolution", None)
if self.resize_resolution is not None:
self.resize_resolution = list(map(int, self.resize_resolution.split("x")))
self.mask_zones = self.config[self.name].get("mask_zones", None)
self.minimum_disk_free_space_gb = self.config[self.name].get("minimum_disk_free_space_gb", None)
if self.minimum_disk_free_space_gb is not None:
self.minimum_disk_free_space_gb = float(self.minimum_disk_free_space_gb)
self.time_format = self.config[self.name]["time_format"]
def save(self, save_time, img, mask=True):
timestamp = datetime.fromtimestamp(save_time).strftime(self.time_format)
def save(self, save_time, img, mask=True, resize=True):
if type(save_time) is float:
save_time = int(save_time)
if type(save_time) is int:
save_time = datetime.fromtimestamp(save_time)
if type(save_time) is not datetime:
raise ValueError(f"save_time must be float int or datetime, not {type(save_time)}")
timestamp = save_time.strftime(self.time_format)
save_dir = self.location / save_time.strftime("%Y") / save_time.strftime("%m")
os.makedirs(save_dir, exist_ok=True)
out_path = save_dir / f"{timestamp}.png"
self.log.info(f"saving {out_path}")
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
if resize and self.resize_resolution is not None:
img = cv2.resize(img, self.resize_resolution, interpolation=cv2.INTER_LINEAR)
if mask and self.mask_zones is not None:
height, width, channels = img.shape
out = np.full(
@ -41,7 +52,7 @@ class VisionSaver(Component):
out[zone[1]:zone[3], zone[0]:zone[2]] = img[zone[1]:zone[3], zone[0]:zone[2]]
else:
out = img
cv2.imwrite(out_path, out)
cv2.imwrite(str(out_path), out)
return out_path
def remove_older_images_if_needed(self):

View File

@ -2,8 +2,8 @@ import time
import serial
#tester_port="/dev/ttyUSB0"
tester_port="COM1"
# tester_port="/dev/ttyUSB0"
tester_port = "COM1"
conn = serial.Serial(
tester_port,

View File

@ -15,7 +15,7 @@ conn = serial.Serial(
)
pixel = C_UINT32_MAX
time.sleep(5)
color = "#000000"
color = "#ff00ff"
conn.write(int.to_bytes(pixel, length=4, byteorder="big") + bytes.fromhex(color[1:7]) + b"\n")
response = conn.readline()
print(response)

View File

@ -46,19 +46,19 @@ class Archive(Widget):
replace_widget(self, "crud_w", self.crud)
self.selected = None
self.print_b.setEnabled(False)
self.crud.db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
self.crud.db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
self.crud.db_tw.itemSelectionChanged.connect(self.check)
self.crud().db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
self.crud().db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
self.crud().db_tw.itemSelectionChanged.connect(self.check)
self.print_b.clicked.connect(self.print_label)
def check(self):
if not self.crud.modified:
selected = self.crud.get_selected_rows()
if not self.crud().modified:
selected = self.crud().get_selected_rows()
if len(selected) == 1:
selected = selected[0] - 1 # - 1 because rn starts from 1 (filters line)
if selected >= 0 and selected < len(self.crud.data_index):
selected = self.crud.data_index[selected]
self.selected = self.crud.db.table_model.get_by_id(selected)
if selected >= 0 and selected < len(self.crud().data_index):
selected = self.crud().data_index[selected]
self.selected = self.crud().db.table_model.get_by_id(selected)
self.print_b.setEnabled(True)
return
self.selected = None

View File

@ -46,19 +46,19 @@ class Autotests_Archive(Widget):
replace_widget(self, "crud_w", self.crud)
self.selected = None
self.print_b.setEnabled(False)
self.crud.db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
self.crud.db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
self.crud.db_tw.itemSelectionChanged.connect(self.check)
self.crud().db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
self.crud().db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
self.crud().db_tw.itemSelectionChanged.connect(self.check)
self.print_b.clicked.connect(self.print_label)
def check(self):
if not self.crud.modified:
selected = self.crud.get_selected_rows()
if not self.crud().modified:
selected = self.crud().get_selected_rows()
if len(selected) == 1:
selected = selected[0] - 1 # - 1 because rn starts from 1 (filters line)
if selected >= 0 and selected < len(self.crud.data_index):
selected = self.crud.data_index[selected]
self.selected = self.crud.db.table_model.get_by_id(selected)
if selected >= 0 and selected < len(self.crud().data_index):
selected = self.crud().data_index[selected]
self.selected = self.crud().db.table_model.get_by_id(selected)
self.print_b.setEnabled(True)
return
self.selected = None

View File

@ -1,4 +1,5 @@
import sys
import weakref
from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtWidgets import QApplication, QTableWidget
@ -28,7 +29,7 @@ class CopyPastableCrudQTableWidget(QTableWidget):
copy_sparse[row] = {}
cell = self.cellWidget(row, col)
if cell is not None:
copy_sparse[row][col] = cell.parse(row_number=row, crud=self.crud)
copy_sparse[row][col] = cell.parse(row_number=row, crud=weakref.ref(self.crud))
copy_dense = [["" for col in range(max_col - min_col + 1)] for row in range(max_row - min_row + 1)]
for row, row_cells in copy_sparse.items():
for col, cell_text in row_cells.items():
@ -54,7 +55,7 @@ class CopyPastableCrudQTableWidget(QTableWidget):
c = min_col + col
cell = self.cellWidget(r, c)
if cell is not None:
cell.render(cell_text, field_name=self.crud.select[c] if self.crud is not None else None, row_number=r, crud=self.crud)
cell.render(cell_text, field_name=self.crud.select[c] if self.crud is not None else None, row_number=r, crud=weakref.ref(self.crud))
super().keyPressEvent(event)
QApplication.sendEvent(self, event)
return True

View File

@ -6,7 +6,7 @@ from datetime import datetime
from lib.db import Crud_DB
from peewee import TextField
from PyQt5.QtCore import QObject, Qt, pyqtSignal
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import (QAbstractItemView, QComboBox, QDialog,
QGridLayout, QHeaderView, QLineEdit, QMessageBox,
QPlainTextEdit, QPushButton)
@ -46,7 +46,12 @@ class Cell:
self.field_alias = field_alias
self.field = field
self.row_number = row_number
self.crud = crud
if crud is None:
self.crud = None
elif type(crud) is weakref.ReferenceType:
self.crud = crud
else:
self.crud = weakref.ref(crud)
self.value = None
self.is_modified = False
self.connected_modified = False
@ -181,7 +186,7 @@ class Json_External_Dialog_Editor_Cell_Widget(QPushButton, Cell):
def __init__(self, editor_widget_class, *args, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None, **kwargs):
if not issubclass(editor_widget_class, Editor):
raise AssertionError(f"editor_widget_class {editor_widget_class!r} must be a subclass of {Editor!r}")
self.editor = editor_widget_class(*args, cell_widget=self, **kwargs)
self.editor = editor_widget_class(*args, cell_widget=weakref.ref(self), **kwargs)
super().__init__(u"\u238B modifica")
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
self.dialog = Dialog()
@ -335,7 +340,7 @@ class Crud(Widget):
for fn, cn in self.select_index.items():
w = self.db_tw.cellWidget(rn, cn)
try:
r[fn] = w._parse(row_number=rn, crud=self)
r[fn] = w._parse(row_number=rn, crud=weakref.ref(self))
except Exception as e:
self.log.exception(traceback.format_exc())
self.set_row_color(rn, "red")
@ -427,12 +432,12 @@ class Crud(Widget):
r = self.row_upgrader(r, rn, self)
for fn, cn in self.select_index.items():
readonly = self.readonly is None or self.readonly is True or (self.readonly is not False and fn in self.readonly)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=self)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=weakref.ref(self))
w.set_readonly(readonly=w.readonly)
w.do_autocomplete(w.autocomplete)
w.modified.connect(self.set_modified)
if fn in r:
w._render(data=r[fn], row_number=rn, crud=self)
w._render(data=r[fn], row_number=rn, crud=weakref.ref(self))
self.db_tw.setCellWidget(rn, cn, w)
# REENABLE EVENTS AFTER UPDATE
self.db_tw.blockSignals(False)
@ -452,7 +457,7 @@ class Crud(Widget):
self.db_tw.setRowCount(rn + 1)
for fn, cn in self.select_index.items():
readonly = self.readonly is None or self.readonly is True or (self.readonly is not False and fn in self.readonly)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=self)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=weakref.ref(self))
w.set_readonly(readonly=w.readonly)
w.do_autocomplete(w.autocomplete)
w.modified.connect(self.set_modified)

View File

@ -1,3 +1,5 @@
import weakref
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit,
QListWidget, QPlainTextEdit, QRadioButton,
@ -8,7 +10,12 @@ from ui.widget import Widget
class Editor(Widget):
def __init__(self, cell_widget=None):
super().__init__()
self.cell_widget = cell_widget
if cell_widget is None:
self.cell_widget = None
elif type(cell_widget) is weakref.ReferenceType:
self.cell_widget = cell_widget
else:
self.cell_widget = weakref.ref(cell_widget)
self.spec = {}
def set_readonly(self, readonly=True):

View File

@ -22,12 +22,12 @@ class Step_Spec_JEDECW(QPushButton, Cell):
super().__init__(u"\u238B modifica")
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
self.update_editor()
self.crud.modified.connect(self.update_editor)
self.crud().modified.connect(self.update_editor)
self.dialog.setWindowTitle(self.field_alias)
self.clicked.connect(self.dialog.show)
def update_editor(self):
self.editor_type = self.crud.db_tw.cellWidget(self.row_number, self.crud.select_index["type"])._parse()
self.editor_type = self.crud().db_tw.cellWidget(self.row_number, self.crud().select_index["type"])._parse()
self.editor = self.editors[self.editor_type]
if self.dialog.centralWidget is not self.editor:
self.dialog.setCentralWidget(self.editor)

View File

@ -252,26 +252,32 @@ class Test(Widget):
def set_leak(self, leak=None):
if "leak" not in self.data:
self.data["leak"] = []
self.data["leak"] = {}
leak["step"] = model_to_dict(self.step)
self.data["leak"].append(leak)
self.data["leak"][len(self.data["leak"])] = leak
self.data["overridden"] = self.data["overridden"] or leak.get("overridden", False)
self.data["ok"] = self.data["ok"] and leak.get("ok", False)
self.next()
def set_vision(self, vision=None):
if "vision" not in self.data:
self.data["vision"] = []
self.data["vision"] = {}
vision["step"] = model_to_dict(self.step)
self.data["vision"].append(vision)
self.data["vision"][len(self.data["vision"])] = vision
self.data["overridden"] = self.data["overridden"] or vision.get("overridden", False)
self.data["ok"] = self.data["ok"] and vision.get("ok", False)
self.next()
def done(self, ok=True):
self.log.info("cycle done")
self.data["vision"][0].pop("detections")
self.data["vision"][0].pop("results")
t = self.data.get("vision", {}).get(0, {}).get("time", None)
f = self.data.get("vision", {}).get(0, {}).get("frame", None)
if t is not None and f is not None:
file_path = self.components["vision_saver"].save(t, f)
self.log.info(f"cycle vision image saved locally: {file_path!r}")
for vision in self.data["vision"].values():
vision.pop("frame", None)
vision.pop("render", None)
archived = Archive.archive(self.recipe, self.data, ok and self.data["ok"], overridden=self.data["overridden"])
self.log.info(f"cycle archived locally: {archived!r}")
# COUNT OK
@ -281,29 +287,28 @@ class Test(Widget):
def print(self, archived=None):
self.log.info("cycle print")
# LABEL PRINT
datamatrix= archived.recipe.part_number+ archived.time.strftime("%m%y")+f"{archived.id:0>5}"
dt_label=archived.time.strftime("%d/%m/%Y %H:%M:%S")
pmax = self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("test_pressure", "-")
pmin=self.data.get("leak", [{}, {}])[0].get("results", {}).get("data", {}).get("Running test: pressure at the end of settling", "-")
leak=self.data.get("leak", [{}, {}])[0].get("results", {}).get("data", {}).get("Running test: measured leak", "-")
datamatrix = str(archived.recipe.part_number) + archived.time.strftime("%m%y") + f"{archived.id:0>5}"
pmax = self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure", "-")
pmin = self.data.get("leak", {}).get(0, {}).get("results", {}).get("data", {}).get("Running test: pressure at the end of settling", "-")
leak = self.data.get("leak", {}).get(0, {}).get("results", {}).get("data", {}).get("Running test: measured leak", "-")
context = {
"DATAMATRIX": datamatrix,
"DATAMATRIX_TEXT": datamatrix,
"PIECE_NUM": str(archived.id),
"DATETIME": dt_label,
"DATETIME": archived.time.strftime("%d/%m/%Y %H:%M:%S"),
"SHIFT": str(get_shift(archived.time)),
"STATION": str(self.machine_id),
"OPERATOR": str(Users.get_session().user.username),
"PMAX": f"{pmax:.3f}",
"PMIN": f"{pmin:.3f}",
"LEAK": f"{leak:.3f}",
"TFILL": str(self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("filling_time", "-")),
"TSTAB": str(self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("settling_time", "-")),
"TTEST": str(self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("test_time", "-")),
"MAXLEAK": str(self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("test_pressure_max_delta", "-")),
"PTESTMIN": str(self.data.get("leak", [{}, {}])[0].get("step", {}).get("spec", {}).get("test_pressure_min_delta", "-")),
"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(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("filling_time", "-")),
"TSTAB": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("settling_time", "-")),
"TTEST": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_time", "-")),
"MAXLEAK": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure_max_delta", "-")),
"PTESTMIN": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure_min_delta", "-")),
"RESULT_L1": "ESITO" + str(" FORZATO" if self.data.get("overridden", False) else ""),
"RESULT_L2": str("CONFORME" if self.data.get("leak", [{}, {}])[0].get("results", {}).get("ok", False) else "SCARTO"),
"RESULT_L2": str("CONFORME" if self.data.get("leak", {}).get(0, {}).get("results", {}).get("ok", False) else "SCARTO"),
}
self.components["label_printer"].print_label("EtichettaR5", context=context)
self.log.info(f"cycle printed: {context!r}")

View File

@ -1,18 +1,9 @@
import os
import sys
from datetime import datetime
import cv2
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from ui.test_test import Test_Test
TMP_DIR = "tmp"
ARCHIVE_DIR = "data/vision_saves"
INFERENCE_INPUT_W = 256
INFERENCE_INPUT_H = 256
class Test_Vision(Test_Test):
request_frame = pyqtSignal()
@ -36,7 +27,6 @@ class Test_Vision(Test_Test):
self.components["vision"].resume()
self.components["galaxy_camera"].resume()
self.request_frame.emit() # request first frame
self.save_b.clicked.connect(lambda: self.save_frame_all(position="tmp"))
def stop(self):
# disable camera-vision loop
@ -96,38 +86,12 @@ class Test_Vision(Test_Test):
def save_last(self):
if self.last is None:
return
self.components["vision_saver"].save(self.last["time"], self.last["frame"])
def emit_ok(self):
self.last.pop("frame", None)
self.last.pop("render", None)
super().emit_ok()
self.components["neo_pixels"].set_all_pixel_color("#000000")
def emit_ko(self):
self.last.pop("frame", None)
self.last.pop("render", None)
super().emit_ko()
self.components["neo_pixels"].set_all_pixel_color("#000000")
def save_frame_detection(self, position=None, date=None):
if date is None:
date = datetime.now()
if position == "archive":
save_dir = ARCHIVE_DIR
elif position == "tmp":
save_dir = TMP_DIR
elif position is None:
save_dir = self.config["image saver"]["location"]
else:
save_dir = position
save_dir += "/img_archive"
save_dir += f"/{date.strftime('%Y')}/{date.strftime('%m')}"
self.remove_older_images_if_needed()
if not os.path.exists(save_dir):
os.makedirs(save_dir, exist_ok=True)
filename = f"{save_dir}/{date.strftime('%Y-%m-%d_%H_%M_%S')}_{self.config['image saver']['suffix']}.png"
print(f"saving {filename}")
image_np_bgr = cv2.cvtColor(self.detection_image, cv2.COLOR_RGB2BGR)
cv2.imwrite(filename, image_np_bgr)
return filename

View File

@ -69,7 +69,7 @@ class Users_Management(Widget):
user = Users.generate(username=row["username"], password=row["password"], roles=row["roles"])
except AssertionError as e:
self.log.exception(traceback.format_exc())
crud.set_row_color(row_number, "red")
crud().set_row_color(row_number, "red")
QMessageBox.critical(None, "Errore Salvataggio DB", f"Errore alla riga {row_number}:\n{str(e)}")
return False, None, True
row.update(user)