wip
This commit is contained in:
parent
88e3520c3d
commit
0b15405d6e
12
simulate.sh
12
simulate.sh
|
|
@ -15,14 +15,10 @@ export QT_NO_WARNING_OUTPUT=0
|
|||
python -B -u "./src/main.py" \
|
||||
--auto-login-admin \
|
||||
--auto-select \
|
||||
--no-autotest \
|
||||
--no-edgetpu \
|
||||
--no-gpu \
|
||||
--panel \
|
||||
--sim-camera \
|
||||
--sim-modbus \
|
||||
--sim-os-label-printer \
|
||||
--sim-serial \
|
||||
--style windows \
|
||||
$* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # &
|
||||
# --about \
|
||||
|
|
@ -30,11 +26,19 @@ $* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # &
|
|||
# --auto-login-user \
|
||||
# --autotests-archive \
|
||||
# --camera-edits \
|
||||
# --full-screen \
|
||||
# --interact \
|
||||
# --maximized \
|
||||
# --no-autotest \
|
||||
# --no-gui \
|
||||
# --no-tflite \
|
||||
# --recipes-management \
|
||||
# --sim-archiver \
|
||||
# --sim-camera \
|
||||
# --sim-modbus \
|
||||
# --sim-serial \
|
||||
# --sim-vision \
|
||||
# --steps-management \
|
||||
# --users-management \
|
||||
# sudo renice -n -10 $!
|
||||
# fg
|
||||
|
|
|
|||
|
|
@ -69,38 +69,41 @@ class ModbusComponent(Component):
|
|||
# self.log.exception(traceback.format_exception(type(wrote), wrote, wrote.__traceback__))
|
||||
raise wrote
|
||||
|
||||
def _decode(self, read, data_type="16bit_uint", *args, **kwargs):
|
||||
def _decode(self, read, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
|
||||
decoder = BinaryPayloadDecoder.fromRegisters(read.registers, byteorder=self.byteorder, wordorder=self.wordorder)
|
||||
return getattr(decoder, f"decode_{data_type}")(*args, **kwargs)
|
||||
data = getattr(decoder, f"decode_{data_type}")(*args, **kwargs)
|
||||
data = (data - offset) / gain
|
||||
if data_type.endswith("uint"):
|
||||
data = int(abs(data))
|
||||
elif data_type.endswith("int"):
|
||||
data = int(data)
|
||||
else:
|
||||
raise NotImplementedError(f"data_type {data_type!r} is not supported")
|
||||
return data
|
||||
|
||||
def _encode(self, data, data_type="16bit_uint", *args, **kwargs):
|
||||
def _encode(self, data, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
|
||||
builder = BinaryPayloadBuilder(byteorder=self.byteorder, wordorder=self.wordorder)
|
||||
data = data * gain + offset
|
||||
if data_type.endswith("uint"):
|
||||
data = int(abs(data))
|
||||
elif data_type.endswith("int"):
|
||||
data = int(data)
|
||||
else:
|
||||
raise NotImplementedError(f"data_type {data_type!r} is not supported")
|
||||
getattr(builder, f"add_{data_type}")(data, *args, **kwargs)
|
||||
return builder.build()
|
||||
|
||||
def read(self, register, *args, **kwargs):
|
||||
if type(register) is str:
|
||||
register, s = self.registers[register]
|
||||
if not len(args):
|
||||
args = [s["dt"], *s.get("a", [])]
|
||||
if not len(kwargs):
|
||||
kwargs = s.get("k", {})
|
||||
if args[0].startswith("16bit_"):
|
||||
def read(self, register, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
|
||||
if data_type.startswith("16bit_"):
|
||||
count = 1
|
||||
elif args[0].startswith("32bit_"):
|
||||
elif data_type.startswith("32bit_"):
|
||||
count = 2
|
||||
else:
|
||||
raise NotImplementedError(f"data_type {args[0]!r} is not supported")
|
||||
return self._decode(self._read(register, count=count), *args, **kwargs)
|
||||
raise NotImplementedError(f"data_type {data_type!r} is not supported")
|
||||
return self._decode(self._read(register, count=count), *args, data_type=data_type, gain=gain, offset=offset, **kwargs)
|
||||
|
||||
def write(self, register, data, *args, **kwargs):
|
||||
if type(register) is str:
|
||||
register, s = self.registers[register]
|
||||
if not len(args):
|
||||
args = [s["dt"], *s.get("a", [])]
|
||||
if not len(kwargs):
|
||||
kwargs = s.get("k", {})
|
||||
self._write(register, self._encode(data, *args, **kwargs))
|
||||
def write(self, register, data, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
|
||||
self._write(register, self._encode(data, *args, data_type=data_type, gain=gain, offset=offset, **kwargs))
|
||||
|
||||
# def _get(self, data):
|
||||
# # print("MODBUS", str(int(QThread.currentThreadId())), flush=True)
|
||||
|
|
|
|||
|
|
@ -94,23 +94,78 @@ class TecnaMarpossProvasetT3P(ModbusComponent):
|
|||
data = encoding_map[data]
|
||||
return data
|
||||
|
||||
def read(self, register, *args, formatting=None, decoding_map=None, **kwargs):
|
||||
def read(self, register, *args, data_type=None, gain=None, offset=None, formatting=None, decoding_map=None, **kwargs):
|
||||
if type(register) is str:
|
||||
_, s = self.registers[register]
|
||||
register, s = self.registers[register]
|
||||
if data_type is None:
|
||||
data_type = s.get("dt", None)
|
||||
if gain is None:
|
||||
gain = s.get("g", None)
|
||||
if offset is None:
|
||||
offset = s.get("o", None)
|
||||
if formatting is None:
|
||||
formatting = s.get("f", None)
|
||||
if decoding_map is None:
|
||||
decoding_map = s.get("decoding", None)
|
||||
return self._convert_from_format(super().read(register, *args, **kwargs), formatting=formatting, decoding_map=decoding_map)
|
||||
if not len(args):
|
||||
args = s.get("a", [])
|
||||
if not len(kwargs):
|
||||
kwargs = s.get("k", {})
|
||||
if data_type is None:
|
||||
data_type = "16bit_uint"
|
||||
if gain is None:
|
||||
gain = 1
|
||||
if offset is None:
|
||||
offset = 0
|
||||
return self._convert_from_format(
|
||||
super().read(
|
||||
register,
|
||||
*args,
|
||||
data_type=data_type,
|
||||
gain=gain,
|
||||
offset=offset,
|
||||
**kwargs,
|
||||
),
|
||||
formatting=formatting,
|
||||
decoding_map=decoding_map,
|
||||
)
|
||||
|
||||
def write(self, register, data, *args, formatting=None, encoding_map=None, **kwargs):
|
||||
def write(self, register, data, *args, data_type=None, gain=None, offset=None, formatting=None, encoding_map=None, **kwargs):
|
||||
if type(register) is str:
|
||||
_, s = self.registers[register]
|
||||
register, s = self.registers[register]
|
||||
if data_type is None:
|
||||
data_type = s.get("dt", None)
|
||||
if gain is None:
|
||||
gain = s.get("g", None)
|
||||
if offset is None:
|
||||
offset = s.get("o", None)
|
||||
if formatting is None:
|
||||
formatting = s.get("f", None)
|
||||
if encoding_map is None:
|
||||
encoding_map = s.get("encoding", None)
|
||||
return super().write(register, self._convert_to_format(data, formatting=formatting, encoding_map=encoding_map), *args, **kwargs)
|
||||
if not len(args):
|
||||
args = s.get("a", [])
|
||||
if not len(kwargs):
|
||||
kwargs = s.get("k", {})
|
||||
if data_type is None:
|
||||
data_type = "16bit_uint"
|
||||
if gain is None:
|
||||
gain = 1
|
||||
if offset is None:
|
||||
offset = 0
|
||||
return super().write(
|
||||
register,
|
||||
self._convert_to_format(
|
||||
data,
|
||||
formatting=formatting,
|
||||
encoding_map=encoding_map,
|
||||
),
|
||||
*args,
|
||||
data_type=data_type,
|
||||
gain=gain,
|
||||
offset=offset,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def _get(self):
|
||||
# print("TECNA", str(int(QThread.currentThreadId())), flush=True)
|
||||
|
|
@ -125,10 +180,8 @@ class TecnaMarpossProvasetT3P(ModbusComponent):
|
|||
"Running test: test type",
|
||||
"Running test: sequence index",
|
||||
]}
|
||||
if info["Running test: active phase"] == "RESULT PRESENT":
|
||||
if info["Running test: active phase"] == "END TEST, WAITING THE START OF A NEW TEST":
|
||||
info.update(self.get_test_results())
|
||||
elif info["Running test: active phase"] == "WAITING START":
|
||||
pass
|
||||
self.log.debug(str(info))
|
||||
super()._get([info])
|
||||
|
||||
|
|
@ -155,30 +208,28 @@ class TecnaMarpossProvasetT3P(ModbusComponent):
|
|||
"Running test: result",
|
||||
]}
|
||||
|
||||
def write_recipe(self, recipe, table=100):
|
||||
# "pressure_ramp": self.pressure_ramp_sb,
|
||||
# "stabilization_cycles": self.stabilization_cycles_sb,
|
||||
recipe_name = recipe.spec["part_number"][:16].encode("ascii")
|
||||
def write_recipe(self, recipe, step, table=100):
|
||||
recipe_name = recipe.part_number[:16].encode("ascii")
|
||||
recipe_name += b"\x00" * (16 - len(recipe_name))
|
||||
recipe = {
|
||||
spec = {
|
||||
"Flag: Instrument settings": 0b0000000000000000,
|
||||
"Test program for read/write operation": table,
|
||||
**{719 - 1 + i: (recipe_name[i * 2 + 1] << 8) + recipe_name[i * 2] for i in range(8)},
|
||||
"Test type": "Leak Test",
|
||||
"Test flags": 0b0110000001011100,
|
||||
"T0 - Pre-filling time": recipe.spec["pre_filling_time"],
|
||||
"P0 - Pre-filling pressure": recipe.spec["pre_filling_pressure"],
|
||||
"T1 - Filling time": recipe.spec["filling_time"],
|
||||
"T2 - Settling time": recipe.spec["settling_time"],
|
||||
"PR- - Min pressure tolerance %": recipe.spec["settling_pressure_min_percent"],
|
||||
"PR+ - Max pressure tolerance % (P+)": recipe.spec["settling_pressure_max_percent"],
|
||||
"T3 - Measure time": recipe.spec["test_time"],
|
||||
"Q- Lower test leak limit": recipe.spec["test_pressure_min_delta"],
|
||||
"PREL - Nominal test pressure": recipe.spec["test_pressure"],
|
||||
"Q+ Upper test leak limit": recipe.spec["test_pressure_max_delta"],
|
||||
"FST - Discharge time": recipe.spec["flush_time"],
|
||||
"FSL - Discharge limit": recipe.spec["flush_pressure"],
|
||||
"T0 - Pre-filling time": step.spec["pre_filling_time"],
|
||||
"P0 - Pre-filling pressure": step.spec["pre_filling_pressure"],
|
||||
"T1 - Filling time": step.spec["filling_time"],
|
||||
"T2 - Settling time": step.spec["settling_time"],
|
||||
"PR- - Min pressure tolerance %": step.spec["settling_pressure_min_percent"],
|
||||
"PR+ - Max pressure tolerance % (P+)": step.spec["settling_pressure_max_percent"],
|
||||
"T3 - Measure time": step.spec["test_time"],
|
||||
"Q- Lower test leak limit": step.spec["test_pressure_min_delta"],
|
||||
"PREL - Nominal test pressure": step.spec["test_pressure"],
|
||||
"Q+ Upper test leak limit": step.spec["test_pressure_max_delta"],
|
||||
"FST - Discharge time": step.spec["flush_time"],
|
||||
"FSL - Discharge limit": step.spec["flush_pressure"],
|
||||
}
|
||||
self.log.debug(str(recipe))
|
||||
for register, value in recipe.items():
|
||||
self.log.debug(str(spec))
|
||||
for register, value in spec.items():
|
||||
self.write(register, value)
|
||||
|
|
|
|||
|
|
@ -174,20 +174,20 @@ registers = {
|
|||
# 0=litre 1=cm3
|
||||
"MEASURE UNITS: Flow rate": [617 - 1, {"dt": "16bit_uint", }],
|
||||
# 0=liters/min 1=liters/h 2=m3/h
|
||||
"Cage automation: closing time": [618 - 1, {"dt": "16bit_uint", }],
|
||||
"Cage automation: closing time": [618 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"Cage automation: opening time": [619 - 1, {"dt": "16bit_uint", }],
|
||||
"Cage automation: opening time": [619 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"Maximum pressure limit": [620 - 1, {"dt": "16bit_uint", }],
|
||||
"Plug automation: closing time": [621 - 1, {"dt": "16bit_uint", }],
|
||||
"Plug automation: closing time": [621 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"Plug automation: opening time": [622 - 1, {"dt": "16bit_uint", }],
|
||||
"Plug automation: opening time": [622 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"Marker: result based driving": [623 - 1, {"dt": "16bit_uint", }],
|
||||
# 0=Only passed
|
||||
# 1=Only failed
|
||||
# 2=All
|
||||
"Marker: driving time": [624 - 1, {"dt": "16bit_uint", }],
|
||||
"Marker: driving time": [624 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"PASSWORD: Administration": [631 - 1, {"dt": "32bit_uint"}],
|
||||
"PASSWORD: Modify program": [633 - 1, {"dt": "32bit_uint"}],
|
||||
|
|
@ -241,37 +241,37 @@ registers = {
|
|||
"T3 - Measure time": [708 - 1, {"dt": "16bit_uint", "f": 26, }],
|
||||
"PREL - Nominal test pressure": [709 - 1, {"dt": "16bit_uint", "f": 23, }],
|
||||
# To set a negative pressure (vacuum) this parameters must be written in absolute value and then set bit Pr- in register 702
|
||||
"PR- - Min pressure tolerance %": [710 - 1, {"dt": "16bit_uint", }],
|
||||
"PR- - Min pressure tolerance %": [710 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x %
|
||||
# NOTE: In blockage test minimum final pressure (format as indicated in register 23)
|
||||
"Q+ Upper test leak limit": [711 - 1, {"dt": "16bit_uint", "f": 22, }],
|
||||
"Q- Lower test leak limit": [712 - 1, {"dt": "16bit_uint", "f": 22, }],
|
||||
"FST - Discharge time": [713 - 1, {"dt": "16bit_uint", "f": 26, }],
|
||||
"VP - Test volume": [714 - 1, {"dt": "16bit_uint", "f": 25, }],
|
||||
"PSDEL: Start delay": [716 - 1, {"dt": "16bit_uint", "f": 25, }],
|
||||
"PSDEL: Start delay": [716 - 1, {"dt": "16bit_uint", "f": 25, "g": 100, }],
|
||||
# Format: x.x in 1/10 seconds
|
||||
"P% Pressure tol. (blockage test)": [717 - 1, {"dt": "16bit_uint", }],
|
||||
"P% Pressure tol. (blockage test)": [717 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x %
|
||||
"AW: Aperture weight time (AT)": [740 - 1, {"dt": "16bit_uint", }],
|
||||
"AN: Aperture number": [741 - 1, {"dt": "16bit_uint", }],
|
||||
# Format x
|
||||
"PV%": [742 - 1, {"dt": "16bit_uint", }],
|
||||
"PV%": [742 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Set of electronic regulator in blockage test (Format x.x %)
|
||||
"PB - Minimum burst pressure": [743 - 1, {"dt": "16bit_uint", "f": 23, }],
|
||||
"BD - Burst gap / PD Delta Aperture": [744 - 1, {"dt": "16bit_uint", "f": 23, }],
|
||||
"FSL - Discharge limit": [745 - 1, {"dt": "16bit_uint", "f": 23, }],
|
||||
"RP% - Pressure ratio": [746 - 1, {"dt": "16bit_uint", }],
|
||||
"RP% - Pressure ratio": [746 - 1, {"dt": "16bit_uint", "g": 100, }],
|
||||
# Format; x.xx %
|
||||
"PR+ - Max pressure tolerance % (P+)": [747 - 1, {"dt": "16bit_uint", }],
|
||||
"PR+ - Max pressure tolerance % (P+)": [747 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x %
|
||||
# NOTE: In blockage test maximum final pressure (format as indicated in register 23)
|
||||
"AV1: Advanced valve time": [748 - 1, {"dt": "16bit_uint", }],
|
||||
"AV1: Advanced valve time": [748 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"AV2: Advanced valve time": [749 - 1, {"dt": "16bit_uint", }],
|
||||
"AV2: Advanced valve time": [749 - 1, {"dt": "16bit_uint", "g": 10, }],
|
||||
# Format: x.x seconds
|
||||
"RVP%: volumetric ratio": [750 - 1, {"dt": "16bit_uint", }],
|
||||
"RVP%: volumetric ratio": [750 - 1, {"dt": "16bit_uint", "g": 100, }],
|
||||
# Format: x.xx (Range from 100.00 to 649.99)
|
||||
"RVP%: max tolerance": [751 - 1, {"dt": "16bit_uint", }],
|
||||
"RVP%: max tolerance": [751 - 1, {"dt": "16bit_uint", "g": 100, }],
|
||||
# Format: x.xx (Range from 0.10 to 50.00)
|
||||
"RAMPS: T0 configuration": [752 - 1, {"dt": "16bit_uint", }],
|
||||
# | 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0 |
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ class Vision(Component):
|
|||
self.classes_map = {c["name"]: k for k, c in self.category_index.items()}
|
||||
self.zone_detection_filter_mode = self.config[self.name].get("zone_detection_filter_mode", "box_touches")
|
||||
self.zone_detection_preference_mode = self.config[self.name].get("zone_detection_preference_mode", "distance")
|
||||
self.set_recipe("1.ini")
|
||||
|
||||
def get_center(self, rect):
|
||||
return [(rect[0] + rect[2]) / 2, (rect[1] + rect[3]) / 2]
|
||||
|
|
@ -333,7 +332,7 @@ class Vision(Component):
|
|||
# Run inference
|
||||
if lock:
|
||||
self.lock.lock()
|
||||
if self.simulate or tf_mode == "simulation":
|
||||
if self.simulate or self.tf_mode == "simulation":
|
||||
detections = {
|
||||
"detection_scores": [[1.0]],
|
||||
"detection_boxes": [[[0.2, 0.2, 0.8, 0.8]]],
|
||||
|
|
@ -425,7 +424,7 @@ class Vision(Component):
|
|||
|
||||
def process_detections(self, detections):
|
||||
if self.zones is None or not len(self.zones) or detections is None or not len(detections):
|
||||
return
|
||||
return {}
|
||||
# MATCH DETECTIONS WITH RECIPE
|
||||
results = dict.fromkeys(self.zones)
|
||||
for detection in detections:
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import logging
|
|||
|
||||
from playhouse.sqlite_ext import JSONField
|
||||
|
||||
from .models import Archive, Autotests, Log, Recipes, Session, Users, db
|
||||
from .models import Archive, Autotests, Log, Recipes, Session, Steps, Users, db
|
||||
|
||||
models_reference = {
|
||||
"archive": Archive,
|
||||
"autotests": Autotests,
|
||||
"log": Log,
|
||||
"recipes": Recipes,
|
||||
"steps": Steps,
|
||||
"users": Users,
|
||||
}
|
||||
|
||||
|
|
@ -58,32 +59,70 @@ if admin is None or not admin.is_admin:
|
|||
Users.register(username="ADMIN", password="123123", roles=["admin"])
|
||||
# register or reset user
|
||||
Users.register(username="USER", password="user")
|
||||
# register test steps
|
||||
Steps.replace(
|
||||
id=0,
|
||||
name="TEST_LEAK_TEST",
|
||||
type="leak",
|
||||
spec={
|
||||
"pre_filling_time": 5,
|
||||
"pre_filling_pressure": 1000,
|
||||
"filling_time": 5,
|
||||
"settling_time": 10,
|
||||
"settling_pressure_min_percent": 50,
|
||||
"settling_pressure_max_percent": 50,
|
||||
"test_time": 10,
|
||||
"test_pressure_min_delta": 500,
|
||||
"test_pressure": 1000,
|
||||
"test_pressure_max_delta": 500,
|
||||
"flush_time": 2,
|
||||
"flush_pressure": 5,
|
||||
},
|
||||
description="TEST_DESCRIPTION",
|
||||
archived=False,
|
||||
).execute()
|
||||
Steps.replace(
|
||||
id=1,
|
||||
name="TEST_LEAK_TEST",
|
||||
type="leak",
|
||||
spec={
|
||||
"pre_filling_time": 5,
|
||||
"pre_filling_pressure": 1000,
|
||||
"filling_time": 5,
|
||||
"settling_time": 10,
|
||||
"settling_pressure_min_percent": 50,
|
||||
"settling_pressure_max_percent": 50,
|
||||
"test_time": 10,
|
||||
"test_pressure_min_delta": 500,
|
||||
"test_pressure": 1000,
|
||||
"test_pressure_max_delta": 500,
|
||||
"flush_time": 2,
|
||||
"flush_pressure": 5,
|
||||
},
|
||||
description="TEST_DESCRIPTION",
|
||||
archived=False,
|
||||
).execute()
|
||||
Steps.replace(
|
||||
id=2,
|
||||
name="TEST_VISION_TEST",
|
||||
type="vision",
|
||||
spec={
|
||||
"recipe": "1.ini",
|
||||
},
|
||||
description="TEST_DESCRIPTION VISION_RECIPE: 1",
|
||||
archived=False,
|
||||
).execute()
|
||||
# register test recipe
|
||||
Recipes.replace(id=0, name="TEST", spec={
|
||||
# recipe
|
||||
"client": "TEST_CLIENT",
|
||||
"part_number": "TEST_PART_NUMBER",
|
||||
"station": "TEST_STATION",
|
||||
"description": "TEST_DESCRIPTION",
|
||||
# pre-filling
|
||||
"pre_filling_time": 5,
|
||||
"pre_filling_pressure": 3000,
|
||||
# filling
|
||||
"filling_time": 5,
|
||||
"settling_time": 10,
|
||||
"settling_pressure_min_percent": 10,
|
||||
"settling_pressure_max_percent": 10,
|
||||
# test
|
||||
"test_time": 10,
|
||||
"test_pressure_min_delta": 3.00,
|
||||
"test_pressure": 3000,
|
||||
"test_pressure_max_delta": 0.25,
|
||||
# flush
|
||||
"flush_time": 2,
|
||||
"flush_pressure": 5,
|
||||
# vision
|
||||
"vision_recipe": 0,
|
||||
}, archived=False).execute()
|
||||
Recipes.replace(
|
||||
id=0,
|
||||
name="TEST",
|
||||
client="TEST_CLIENT",
|
||||
part_number="TEST_PART_NUMBER",
|
||||
spec={"steps": [0, 1, 2, ]},
|
||||
description="TEST_DESCRIPTION",
|
||||
archived=False,
|
||||
).execute()
|
||||
|
||||
|
||||
if True:
|
||||
# crud_db must be imported after db and models_reference are available
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ from .autotests import Autotests
|
|||
from .base_model import db
|
||||
from .log import Log
|
||||
from .recipes import Recipes
|
||||
from .steps import Steps
|
||||
from .users import Session, Users
|
||||
|
|
|
|||
|
|
@ -2,14 +2,23 @@ from peewee import AutoField, BooleanField, TextField
|
|||
from playhouse.sqlite_ext import JSONField
|
||||
|
||||
from .base_model import BaseModel
|
||||
from .steps import Steps
|
||||
|
||||
|
||||
class Recipes(BaseModel):
|
||||
id = AutoField(primary_key=True, unique=True, null=False)
|
||||
name = TextField(null=False)
|
||||
client = TextField(null=False)
|
||||
part_number = TextField(null=False)
|
||||
spec = JSONField(null=False) # keys inside spec must not overlap withthe model
|
||||
description = TextField(null=False)
|
||||
archived = BooleanField(null=False, default=False)
|
||||
|
||||
def get_steps(self):
|
||||
s_ids = self.spec.get("steps", [])
|
||||
s = {s.id: s for s in Steps.select().where(Steps.id << s_ids)}
|
||||
return [s[s_id] for s_id in s_ids]
|
||||
|
||||
@classmethod
|
||||
def delete(cls, *args, **kwargs):
|
||||
# OVERRIDE DELETION
|
||||
|
|
|
|||
22
src/lib/db/models/steps.py
Normal file
22
src/lib/db/models/steps.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from peewee import AutoField, BooleanField, TextField
|
||||
from playhouse.sqlite_ext import JSONField
|
||||
|
||||
from .base_model import BaseModel
|
||||
|
||||
|
||||
class Steps(BaseModel):
|
||||
id = AutoField(primary_key=True, unique=True, null=False)
|
||||
name = TextField(null=False)
|
||||
type = TextField(null=False)
|
||||
spec = JSONField(null=False) # keys inside spec must not overlap withthe model
|
||||
description = TextField(null=False)
|
||||
archived = BooleanField(null=False, default=False)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, *args, **kwargs):
|
||||
# OVERRIDE DELETION
|
||||
# so that deleting a user will only archive it
|
||||
return cls.update(archived=True)
|
||||
|
||||
class Meta:
|
||||
table_name = "steps"
|
||||
17
src/main.py
17
src/main.py
|
|
@ -61,7 +61,8 @@ try:
|
|||
from PyQt5.QtCore import QObject, QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QApplication, QMessageBox
|
||||
from ui import (About, Archive, Autotests_Archive, Login, Main_Window,
|
||||
Test, Users_Management)
|
||||
Recipes_Management, Steps_Management, Test,
|
||||
Users_Management)
|
||||
|
||||
class Main(QObject):
|
||||
do = pyqtSignal(dict)
|
||||
|
|
@ -79,7 +80,7 @@ try:
|
|||
self.config = ConfigReader()
|
||||
# INIT COMPONENT
|
||||
self.components_specs = {
|
||||
"archive_synchronizer": {"c": ArchiveSynchronizer},
|
||||
# "archive_synchronizer": {"c": ArchiveSynchronizer},
|
||||
"galaxy_camera": {"c": GalaxyCamera, "k": {"paused": True}},
|
||||
"label_printer": {"c": Os_Label_Printer, "t": False},
|
||||
"neo_pixels": {"c": NeoPixels, "t": False},
|
||||
|
|
@ -119,9 +120,9 @@ try:
|
|||
self.main_window.archive_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Archive()))
|
||||
if "--archive" in sys.argv:
|
||||
self.main_window.archive_a.trigger()
|
||||
self.main_window.autotests_archive_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Autotests_Archive()))
|
||||
if "--autotests-archive" in sys.argv:
|
||||
self.main_window.autotests_archive_a.trigger()
|
||||
# self.main_window.autotests_archive_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Autotests_Archive()))
|
||||
# if "--autotests-archive" in sys.argv:
|
||||
# self.main_window.autotests_archive_a.trigger()
|
||||
self.main_window.about_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(About()))
|
||||
if "--about" in sys.argv:
|
||||
self.main_window.about_a.trigger()
|
||||
|
|
@ -130,6 +131,12 @@ try:
|
|||
self.main_window.users_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Users_Management()))
|
||||
if "--users-management" in sys.argv:
|
||||
self.main_window.users_management_a.trigger()
|
||||
self.main_window.recipes_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Recipes_Management()))
|
||||
if "--recipes-management" in sys.argv:
|
||||
self.main_window.recipes_management_a.trigger()
|
||||
self.main_window.steps_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Steps_Management()))
|
||||
if "--steps-management" in sys.argv:
|
||||
self.main_window.steps_management_a.trigger()
|
||||
# OPEN LOGIN TAB
|
||||
self.open_login()
|
||||
# SHOW MAIN WINDOW
|
||||
|
|
|
|||
|
|
@ -1,22 +1,34 @@
|
|||
from .about import About
|
||||
from .archive import Archive
|
||||
from .autotests_archive import Autotests_Archive
|
||||
from .crud import (Cell, Combo_Box_Cell_Widget, CopyPastableCrudQTableWidget,
|
||||
Crud, External_Dialog_Cell_Widget,
|
||||
Json_External_Dialog_Cell_Widget,
|
||||
Json_External_Dialog_Editor_Cell_Widget,
|
||||
Line_Edit_Cell_Widget)
|
||||
from .dialog import Dialog
|
||||
from .editor import Editor
|
||||
from .helpers import calc_foreground_color, replace_widget
|
||||
from .leak_step_editor import Leak_Step_Editor
|
||||
from .login import Login
|
||||
from .main_window import Main_Window
|
||||
from .qml_circular_gauge import Qml_Circular_Gauge
|
||||
from .qml_led import Qml_Led
|
||||
from .qml_switch import Qml_Switch
|
||||
from .qml_widget import Qml_Widget
|
||||
from .recipe_editor import Recipe_Editor
|
||||
from .recipe_selection import Recipe_Selection
|
||||
from .recipe_spec_editor import Recipe_Spec_Editor
|
||||
from .recipes_management import Recipes_Management
|
||||
from .steps_management import Steps_Management
|
||||
from .test import Test
|
||||
from .test_admin_permission import Test_Admin_Permission
|
||||
from .test_assembly import Test_Assembly
|
||||
from .test_autotest import Test_Autotest
|
||||
from .test_home import Test_Home
|
||||
from .test_leak import Test_Leak
|
||||
from .test_test import Test_Test
|
||||
from .test_vision import Test_Vision
|
||||
from .users_management import Users_Management
|
||||
from .vision_step_editor import Vision_Step_Editor
|
||||
from .widget import Widget
|
||||
from .window import Window
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
from .CopyPastableCrudQTableWidget import CopyPastableCrudQTableWidget
|
||||
from .crud import (Cell, Combo_Box_Cell_Widget, Crud,
|
||||
External_Dialog_Cell_Widget,
|
||||
Json_External_Dialog_Cell_Widget, Line_Edit_Cell_Widget)
|
||||
Json_External_Dialog_Cell_Widget,
|
||||
Json_External_Dialog_Editor_Cell_Widget,
|
||||
Line_Edit_Cell_Widget)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ from datetime import datetime
|
|||
|
||||
from lib.db import Crud_DB
|
||||
from peewee import TextField
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import (QAbstractItemView, QComboBox, QDialog,
|
||||
QGridLayout, QHeaderView, QLineEdit, QMessageBox,
|
||||
QPlainTextEdit, QPushButton)
|
||||
from ui.dialog import Dialog
|
||||
from ui.editor import Editor
|
||||
from ui.widget import Widget
|
||||
|
||||
|
||||
|
|
@ -37,12 +39,14 @@ def from_str(data, field=None):
|
|||
class Cell:
|
||||
modified = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
self.readonly = readonly
|
||||
self.autocomplete = autocomplete
|
||||
self.field_name = field_name
|
||||
self.field_alias = field_alias
|
||||
self.field = field
|
||||
self.row_number = row_number
|
||||
self.crud = crud
|
||||
self.set_readonly(self.readonly)
|
||||
self.value = None
|
||||
self.is_modified = False
|
||||
|
|
@ -96,9 +100,9 @@ class Cell:
|
|||
|
||||
|
||||
class Line_Edit_Cell_Widget(QLineEdit, Cell):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
super().__init__()
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field)
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
self.setReadOnly(readonly)
|
||||
|
|
@ -115,9 +119,9 @@ class Line_Edit_Cell_Widget(QLineEdit, Cell):
|
|||
|
||||
|
||||
class Combo_Box_Cell_Widget(QComboBox, Cell):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
super().__init__()
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field)
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
self.setEditable(not readonly)
|
||||
|
|
@ -137,15 +141,15 @@ class Combo_Box_Cell_Widget(QComboBox, Cell):
|
|||
|
||||
|
||||
class External_Dialog_Cell_Widget(QPushButton, Cell):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
self.dialog = QDialog()
|
||||
self.editor = QPlainTextEdit()
|
||||
self.dialog.setLayout(QGridLayout())
|
||||
self.dialog.layout().setSpacing(0)
|
||||
self.dialog.layout().setContentsMargins(0, 0, 0, 0)
|
||||
self.dialog.layout().addWidget(self.editor, 0, 0, -1, -1)
|
||||
super().__init__(u"\u238B apri")
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field)
|
||||
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.setWindowTitle(self.field_alias)
|
||||
self.clicked.connect(self.dialog.show)
|
||||
|
||||
|
|
@ -170,6 +174,35 @@ class Json_External_Dialog_Cell_Widget(External_Dialog_Cell_Widget):
|
|||
return json.loads(self.editor.toPlainText())
|
||||
|
||||
|
||||
class Json_External_Dialog_Editor_Cell_Widget(QPushButton, Cell):
|
||||
def __init__(self, editor_widget_instance, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
if not isinstance(editor_widget_instance, Editor):
|
||||
raise AssertionError(f"editor_widget_instance {editor_widget_instance!r} must be a subclass of {Editor!r}")
|
||||
self.editor = editor_widget_instance
|
||||
self.dialog = Dialog()
|
||||
self.dialog.setAttribute(Qt.WA_DeleteOnClose, on=False)
|
||||
self.dialog.setCentralWidget(self.editor)
|
||||
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.setWindowTitle(self.field_alias)
|
||||
self.clicked.connect(self.dialog.show)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
self.editor.set_readonly(readonly)
|
||||
|
||||
def do_autocomplete(self, autocomplete):
|
||||
self.editor.do_autocomplete(autocomplete)
|
||||
|
||||
def connect_modified(self):
|
||||
self.editor.connect_modified(self.check_modified)
|
||||
|
||||
def render(self, data, field_name=None, row_number=None, crud=None):
|
||||
self.editor.render(data, field_name=field_name, row_number=row_number, crud=crud)
|
||||
|
||||
def parse(self, row_number=None, crud=None):
|
||||
return self.editor.parse(row_number=row_number, crud=crud)
|
||||
|
||||
|
||||
class Crud(Widget):
|
||||
modified = pyqtSignal(bool)
|
||||
selected = pyqtSignal(list)
|
||||
|
|
@ -378,7 +411,7 @@ 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))
|
||||
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.modified.connect(self.set_modified)
|
||||
if fn in r:
|
||||
w._render(data=r[fn], row_number=rn, crud=self)
|
||||
|
|
@ -400,7 +433,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))
|
||||
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.modified.connect(self.set_modified)
|
||||
self.db_tw.setCellWidget(rn, cn, w)
|
||||
self.db_tw.scrollToBottom()
|
||||
|
|
|
|||
1
src/ui/editor/__init__.py
Normal file
1
src/ui/editor/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .editor import Editor
|
||||
|
|
@ -1,43 +1,22 @@
|
|||
from PyQt5.QtCore import QObject
|
||||
from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit,
|
||||
QPlainTextEdit, QRadioButton, QSpinBox)
|
||||
QListWidget, QPlainTextEdit, QRadioButton,
|
||||
QSpinBox)
|
||||
from ui.widget import Widget
|
||||
|
||||
|
||||
class Recipe_Editor(Widget):
|
||||
class Editor(Widget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.spec = {
|
||||
# recipe
|
||||
"client": self.client_le,
|
||||
"part_number": self.part_number_le,
|
||||
"station": self.station_le,
|
||||
"description": self.description_pte,
|
||||
# pre-filling
|
||||
"pre_filling_time": self.pre_filling_time_sb,
|
||||
"pre_filling_pressure": self.pre_filling_pressure_sb,
|
||||
# filling
|
||||
"filling_time": self.filling_time_sb,
|
||||
"settling_time": self.settling_time_sb,
|
||||
"settling_pressure_min_percent": self.settling_pressure_min_percent_sb,
|
||||
"settling_pressure_max_percent": self.settling_pressure_max_percent_sb,
|
||||
# test
|
||||
"test_time": self.test_time_sb,
|
||||
"test_pressure_min_delta": self.test_pressure_min_delta_sb,
|
||||
"test_pressure": self.test_pressure_sb,
|
||||
"test_pressure_max_delta": self.test_pressure_max_delta_sb,
|
||||
"cycles": self.cycles_sb,
|
||||
# flush
|
||||
"flush_time": self.flush_time_sb,
|
||||
"flush_pressure": self.flush_pressure_sb,
|
||||
# vision
|
||||
"vision_recipe": self.vision_recipe_cb,
|
||||
}
|
||||
self.spec = {}
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
for w in self.spec.values():
|
||||
if isinstance(w, QComboBox):
|
||||
w.setDisabled(readonly)
|
||||
else:
|
||||
elif isinstance(w, QListWidget):
|
||||
w.setDisabled(readonly)
|
||||
elif isinstance(w, QObject):
|
||||
w.setReadOnly(readonly)
|
||||
|
||||
def do_autocomplete(self, autocomplete):
|
||||
|
|
@ -48,19 +27,30 @@ class Recipe_Editor(Widget):
|
|||
if isinstance(w, QCheckBox):
|
||||
w.setChecked(bool(v))
|
||||
elif isinstance(w, QComboBox):
|
||||
# while w.count() > 0:
|
||||
# w.removeItem(0)
|
||||
# w.clear()
|
||||
w.addItems(list(map(str, v)))
|
||||
elif isinstance(w, QDoubleSpinBox):
|
||||
w.setValue(float(v))
|
||||
elif isinstance(w, QLineEdit):
|
||||
w.setText(str(v))
|
||||
elif isinstance(w, QListWidget):
|
||||
# while w.count() > 0:
|
||||
# w.takeItem(0)
|
||||
# w.clear()
|
||||
w.addItems(list(map(str, v)))
|
||||
elif isinstance(w, QRadioButton):
|
||||
w.setChecked(bool(v))
|
||||
elif isinstance(w, QSpinBox):
|
||||
w.setValue(int(v))
|
||||
elif isinstance(w, QPlainTextEdit):
|
||||
w.setPlainText(str(v))
|
||||
else:
|
||||
elif isinstance(w, QObject):
|
||||
raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
|
||||
else:
|
||||
# ignore default values
|
||||
pass
|
||||
|
||||
def connect_modified(self, check_modified):
|
||||
for k, w in self.spec.items():
|
||||
|
|
@ -72,14 +62,19 @@ class Recipe_Editor(Widget):
|
|||
w.valueChanged.connect(check_modified)
|
||||
elif isinstance(w, QLineEdit):
|
||||
w.textChanged.connect(check_modified)
|
||||
elif isinstance(w, QListWidget):
|
||||
w.currentItemChanged.connect(check_modified)
|
||||
elif isinstance(w, QRadioButton):
|
||||
w.toggled.connect(check_modified)
|
||||
elif isinstance(w, QSpinBox):
|
||||
w.valueChanged.connect(check_modified)
|
||||
elif isinstance(w, QPlainTextEdit):
|
||||
w.textChanged.connect(check_modified)
|
||||
else:
|
||||
elif isinstance(w, QObject):
|
||||
raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
|
||||
else:
|
||||
# ignore default values
|
||||
pass
|
||||
|
||||
def render(self, data, field_name=None, row_number=None, crud=None):
|
||||
for k, v in data.items():
|
||||
|
|
@ -94,14 +89,20 @@ class Recipe_Editor(Widget):
|
|||
w.setValue(float(v))
|
||||
elif isinstance(w, QLineEdit):
|
||||
w.setText(str(v))
|
||||
elif isinstance(w, QListWidget):
|
||||
w.clear()
|
||||
w.addItems(list(map(str, v)))
|
||||
elif isinstance(w, QRadioButton):
|
||||
w.setChecked(bool(v))
|
||||
elif isinstance(w, QSpinBox):
|
||||
w.setValue(int(v))
|
||||
elif isinstance(w, QPlainTextEdit):
|
||||
w.setPlainText(str(v))
|
||||
else:
|
||||
elif isinstance(w, QObject):
|
||||
raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
|
||||
else:
|
||||
# ignore default values
|
||||
pass
|
||||
|
||||
def parse(self, row_number=None, crud=None):
|
||||
ret = {}
|
||||
|
|
@ -114,12 +115,17 @@ class Recipe_Editor(Widget):
|
|||
ret[k] = w.value()
|
||||
elif isinstance(w, QLineEdit):
|
||||
ret[k] = w.text()
|
||||
elif isinstance(w, QListWidget):
|
||||
ret[k] = [w.item(i).data(0) for i in range(w.count())]
|
||||
elif isinstance(w, QRadioButton):
|
||||
ret[k] = w.isChecked()
|
||||
elif isinstance(w, QSpinBox):
|
||||
ret[k] = w.value()
|
||||
elif isinstance(w, QPlainTextEdit):
|
||||
ret[k] = w.toPlainText()
|
||||
else:
|
||||
elif isinstance(w, QObject):
|
||||
raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
|
||||
else:
|
||||
# pass through default values
|
||||
ret[k] = w
|
||||
return ret
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Recipe_Editor</class>
|
||||
<widget class="QWidget" name="Recipe_Editor">
|
||||
<class>Editor</class>
|
||||
<widget class="QWidget" name="Editor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
|
|
@ -11,58 +11,58 @@
|
|||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<item row="2" column="3">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Pre-Riempimento</string>
|
||||
<string>Scarico</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="flush_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="flush_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_31">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_7">
|
||||
<property name="title">
|
||||
<string>Riempimento</string>
|
||||
|
|
@ -155,168 +155,7 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Cicli</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_min_delta_sb">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_max_delta_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="test_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Delta min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Delta max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QSpinBox" name="cycles_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Scarico</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="flush_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="flush_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_31">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="4">
|
||||
<item row="3" column="0" colspan="4">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Visione</string>
|
||||
|
|
@ -335,26 +174,159 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="4">
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Pre-Riempimento</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Delta min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_max_delta_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="test_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Delta max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_min_delta_sb">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Ricetta</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Cliente</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Stazione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
|
@ -362,16 +334,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="station_le"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="part_number_le"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="client_le"/>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Descrizione</string>
|
||||
|
|
@ -383,6 +346,19 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Cliente</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="client_le"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="part_number_le"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
import logging
|
||||
import traceback
|
||||
|
||||
logger = logging.getLogger("replace_widget")
|
||||
|
||||
|
||||
def replace_widget(parent, name, new, delete=False):
|
||||
old = getattr(parent, name)
|
||||
replaced = old.parentWidget().layout().replaceWidget(old, new)
|
||||
if replaced is None:
|
||||
if old is new:
|
||||
logger.warning(f"\n{''.join(traceback.format_stack())}\nyou are trying to replace {old!r} with itself.")
|
||||
return
|
||||
if old.parentWidget().layout().replaceWidget(old, new) is None:
|
||||
raise AssertionError(f"{name} not found, cannot replace it.")
|
||||
old.hide()
|
||||
setattr(parent, name, new)
|
||||
|
|
|
|||
1
src/ui/leak_step_editor/__init__.py
Normal file
1
src/ui/leak_step_editor/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .leak_step_editor import Leak_Step_Editor
|
||||
24
src/ui/leak_step_editor/leak_step_editor.py
Normal file
24
src/ui/leak_step_editor/leak_step_editor.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
from ui.editor import Editor
|
||||
|
||||
|
||||
class Leak_Step_Editor(Editor):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.spec.update({
|
||||
# pre-filling
|
||||
"pre_filling_time": self.pre_filling_time_sb,
|
||||
"pre_filling_pressure": self.pre_filling_pressure_sb,
|
||||
# filling
|
||||
"filling_time": self.filling_time_sb,
|
||||
"settling_time": self.settling_time_sb,
|
||||
"settling_pressure_min_percent": self.settling_pressure_min_percent_sb,
|
||||
"settling_pressure_max_percent": self.settling_pressure_max_percent_sb,
|
||||
# test
|
||||
"test_time": self.test_time_sb,
|
||||
"test_pressure_min_delta": self.test_pressure_min_delta_sb,
|
||||
"test_pressure": self.test_pressure_sb,
|
||||
"test_pressure_max_delta": self.test_pressure_max_delta_sb,
|
||||
# flush
|
||||
"flush_time": self.flush_time_sb,
|
||||
"flush_pressure": self.flush_pressure_sb,
|
||||
})
|
||||
309
src/ui/leak_step_editor/leak_step_editor.ui
Normal file
309
src/ui/leak_step_editor/leak_step_editor.ui
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Leak Step Editor</class>
|
||||
<widget class="QWidget" name="Leak Step Editor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>845</width>
|
||||
<height>194</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Pre-Riempimento</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="pre_filling_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Delta min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_max_delta_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="test_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Delta max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="test_pressure_min_delta_sb">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_7">
|
||||
<property name="title">
|
||||
<string>Riempimento</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Soglia min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="settling_pressure_min_percent_sb">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="filling_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Soglia max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="settling_pressure_max_percent_sb">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_27">
|
||||
<property name="text">
|
||||
<string>%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Assestamento</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="settling_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Scarico</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>Pressione</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="flush_pressure_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="flush_time_sb">
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_31">
|
||||
<property name="text">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -31,6 +31,8 @@
|
|||
<string>Amministrazione</string>
|
||||
</property>
|
||||
<addaction name="users_management_a"/>
|
||||
<addaction name="recipes_management_a"/>
|
||||
<addaction name="steps_management_a"/>
|
||||
<addaction name="quit_a"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuStrumenti">
|
||||
|
|
@ -38,7 +40,6 @@
|
|||
<string>Strumenti</string>
|
||||
</property>
|
||||
<addaction name="archive_a"/>
|
||||
<addaction name="autotests_archive_a"/>
|
||||
</widget>
|
||||
<addaction name="menuStrumenti"/>
|
||||
<addaction name="admin_m"/>
|
||||
|
|
@ -69,6 +70,16 @@
|
|||
<string>Esci</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="recipes_management_a">
|
||||
<property name="text">
|
||||
<string>Gestione ricette</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="steps_management_a">
|
||||
<property name="text">
|
||||
<string>Gestione fasi di test</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
from .recipe_editor import Recipe_Editor
|
||||
|
|
@ -1,2 +1 @@
|
|||
from .recipe_selection import (Json_Spec_External_Dialog_Cell_Widget,
|
||||
Recipe_Selection)
|
||||
from .recipe_selection import Recipe_Selection
|
||||
|
|
|
|||
|
|
@ -1,58 +1,15 @@
|
|||
import sys
|
||||
from glob import iglob
|
||||
|
||||
from lib.db import Recipes, Users
|
||||
from PyQt5.QtCore import Qt, QTimer, pyqtSignal
|
||||
from PyQt5.QtCore import QTimer, pyqtSignal
|
||||
from PyQt5.QtGui import QKeySequence
|
||||
from PyQt5.QtWidgets import QPushButton, QShortcut
|
||||
from ui.crud import Cell, Crud
|
||||
from ui.dialog import Dialog
|
||||
from PyQt5.QtWidgets import QShortcut
|
||||
from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget
|
||||
from ui.helpers import replace_widget
|
||||
from ui.recipe_editor import Recipe_Editor
|
||||
from ui.recipe_spec_editor import Recipe_Spec_Editor
|
||||
from ui.widget import Widget
|
||||
|
||||
|
||||
class Json_Spec_External_Dialog_Cell_Widget(QPushButton, Cell):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None):
|
||||
self.dialog = Dialog()
|
||||
self.dialog.setAttribute(Qt.WA_DeleteOnClose, on=False)
|
||||
self.editor = Recipe_Editor()
|
||||
self.dialog.setCentralWidget(self.editor)
|
||||
super().__init__(u"\u238B apri")
|
||||
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field)
|
||||
self.dialog.setWindowTitle(self.field_alias)
|
||||
self.clicked.connect(self.dialog.show)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
self.editor.set_readonly(readonly)
|
||||
|
||||
def do_autocomplete(self, autocomplete):
|
||||
self.editor.do_autocomplete(autocomplete)
|
||||
|
||||
def connect_modified(self):
|
||||
self.editor.connect_modified(self.check_modified)
|
||||
|
||||
def render(self, data, field_name=None, row_number=None, crud=None):
|
||||
self.editor.render(data, field_name=field_name, row_number=row_number, crud=crud)
|
||||
|
||||
def parse(self, row_number=None, crud=None):
|
||||
return self.editor.parse(row_number=row_number, crud=crud)
|
||||
|
||||
|
||||
def recipes_row_upgrader(row, row_number, crud):
|
||||
if len(row.keys() & row["spec"].keys()):
|
||||
raise AssertionError("field keys in Recipes model MUST NOT be present inside Recipes.spec")
|
||||
row.update(row["spec"])
|
||||
return row
|
||||
|
||||
|
||||
def recipes_row_filter(row, row_number, crud):
|
||||
for k in list(row):
|
||||
if k in row["spec"]:
|
||||
row["spec"][k] = row.pop(k)
|
||||
return True, row, False
|
||||
|
||||
|
||||
class Recipe_Selection(Widget):
|
||||
ok = pyqtSignal(Recipes)
|
||||
|
||||
|
|
@ -63,24 +20,10 @@ class Recipe_Selection(Widget):
|
|||
readonly = False
|
||||
crud_aliases = {
|
||||
"name": "Ricetta",
|
||||
"client": "Cliente",
|
||||
"part_number": "N° disegno",
|
||||
"spec": "Specifica",
|
||||
# "client": "Cliente",
|
||||
# "part_number": "N° disegno",
|
||||
# "station": "Stazione",
|
||||
# "cleaning_time": "Tempo di pulizia",
|
||||
# "pressure_ramp": "Rampa di salita",
|
||||
# "tolerance": "Tolleranza",
|
||||
# "test_duration": "Tempo di prova",
|
||||
# "flush_duration": "Tempo di scarico",
|
||||
# "pressure_min": "Pressione min",
|
||||
# "pressure_test": "Pressione test",
|
||||
# "pressure_max": "Pressione max",
|
||||
# "stabilization_time": "Tempo di stabilizzazione",
|
||||
# "stabilization_level_min": "Soglia di stabilizzazione min",
|
||||
# "stabilization_level_max": "Soglia di stabilizzazione max",
|
||||
# "stabilization_settling_time": "Tempo di assestamento",
|
||||
# "stabilization_cycles": "Numero di cicli",
|
||||
# "description": "Desccrizione",
|
||||
"description": "Desccrizione",
|
||||
"archived": "Archiviata",
|
||||
}
|
||||
filters = None
|
||||
|
|
@ -90,8 +33,9 @@ class Recipe_Selection(Widget):
|
|||
"name": "Ricetta",
|
||||
"client": "Cliente",
|
||||
"part_number": "N° disegno",
|
||||
"description": "Desccrizione",
|
||||
"spec": "Specifica",
|
||||
"description": "Desccrizione",
|
||||
# "archived": "Archiviata",
|
||||
}
|
||||
filters = {"archived": False}
|
||||
self.crud = Crud(
|
||||
|
|
@ -103,14 +47,8 @@ class Recipe_Selection(Widget):
|
|||
fields_aliases=crud_aliases,
|
||||
autocomplete={
|
||||
"archived": False,
|
||||
"spec": {
|
||||
# "vision_recipe": iglob("*.ini", root_dir="./config/vision/recipes/"), # only in python3.10
|
||||
"vision_recipe": list(iglob("./config/vision/recipes/*.ini")),
|
||||
},
|
||||
},
|
||||
row_upgrader=recipes_row_upgrader,
|
||||
widget_classes={"spec": Json_Spec_External_Dialog_Cell_Widget, },
|
||||
row_filter=recipes_row_filter,
|
||||
widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_Editor(), *args, **kwargs), },
|
||||
)
|
||||
replace_widget(self, "crud_w", self.crud)
|
||||
self.crud_modified = None
|
||||
|
|
|
|||
1
src/ui/recipe_spec_editor/__init__.py
Normal file
1
src/ui/recipe_spec_editor/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .recipe_spec_editor import Recipe_Spec_Editor
|
||||
18
src/ui/recipe_spec_editor/recipe_spec_editor.py
Normal file
18
src/ui/recipe_spec_editor/recipe_spec_editor.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from PyQt5.QtWidgets import QAbstractItemView
|
||||
from ui.editor import Editor
|
||||
|
||||
|
||||
class Recipe_Spec_Editor(Editor):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.spec.update({
|
||||
"steps": self.steps_lw,
|
||||
})
|
||||
self.steps_lw.setDragDropMode(QAbstractItemView.InternalMove)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
super().set_readonly(readonly)
|
||||
self.steps_lw.setDisabled(readonly)
|
||||
self.remove_step_b.setDisabled(readonly)
|
||||
self.steps_available_lw.setDisabled(readonly)
|
||||
self.add_step_b.setDisabled(readonly)
|
||||
68
src/ui/recipe_spec_editor/recipe_spec_editor.ui
Normal file
68
src/ui/recipe_spec_editor/recipe_spec_editor.ui
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Recipe Spec Editor</class>
|
||||
<widget class="QWidget" name="Recipe Spec Editor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>536</width>
|
||||
<height>293</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Disponibili</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QListWidget" name="steps_lw"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="add_step_b">
|
||||
<property name="text">
|
||||
<string>Aggiungi passo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="remove_step_b">
|
||||
<property name="text">
|
||||
<string>Rimuovi passo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Passi</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Abilitati</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QListWidget" name="steps_available_lw"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
1
src/ui/recipes_management/__init__.py
Normal file
1
src/ui/recipes_management/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .recipes_management import Recipes_Management
|
||||
29
src/ui/recipes_management/recipes_management.py
Normal file
29
src/ui/recipes_management/recipes_management.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget
|
||||
from ui.recipe_spec_editor import Recipe_Spec_Editor
|
||||
from ui.widget import Widget
|
||||
|
||||
|
||||
class Recipes_Management(Widget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
crud_aliases = {
|
||||
"id": "Id",
|
||||
"name": "Ricetta",
|
||||
"client": "Cliente",
|
||||
"part_number": "N° disegno",
|
||||
"spec": "Specifica",
|
||||
"description": "Desccrizione",
|
||||
"archived": "Archiviata",
|
||||
}
|
||||
self.crud = Crud(
|
||||
"recipes",
|
||||
display_name="GESTIONE RICETTE",
|
||||
readonly=["id"],
|
||||
select=list(crud_aliases.keys()),
|
||||
fields_aliases=crud_aliases,
|
||||
autocomplete={
|
||||
"archived": False,
|
||||
},
|
||||
widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_Editor(), *args, **kwargs), },
|
||||
)
|
||||
self.layout().addWidget(self.crud, 0, 0, -1, -1)
|
||||
17
src/ui/recipes_management/recipes_management.ui
Normal file
17
src/ui/recipes_management/recipes_management.ui
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Recipes management</class>
|
||||
<widget class="QWidget" name="Recipes management">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>94</width>
|
||||
<height>18</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
1
src/ui/steps_management/__init__.py
Normal file
1
src/ui/steps_management/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .steps_management import Steps_Management
|
||||
100
src/ui/steps_management/steps_management.py
Normal file
100
src/ui/steps_management/steps_management.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
from glob import iglob
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit,
|
||||
QPlainTextEdit, QPushButton, QRadioButton,
|
||||
QSpinBox)
|
||||
from ui.crud import (Cell, Combo_Box_Cell_Widget, Crud,
|
||||
Json_External_Dialog_Editor_Cell_Widget)
|
||||
from ui.dialog import Dialog
|
||||
from ui.leak_step_editor import Leak_Step_Editor
|
||||
from ui.vision_step_editor import Vision_Step_Editor
|
||||
from ui.widget import Widget
|
||||
|
||||
|
||||
class Step_Spec_JEDECW(QPushButton, Cell):
|
||||
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
|
||||
self.editors = {
|
||||
"vision": Vision_Step_Editor(),
|
||||
"leak": Leak_Step_Editor(),
|
||||
}
|
||||
self.editor = None
|
||||
self.editor_type = None
|
||||
self.dialog = Dialog()
|
||||
self.dialog.setAttribute(Qt.WA_DeleteOnClose, on=False)
|
||||
super().__init__(u"\u238B modifica")
|
||||
print(readonly, autocomplete, field_name, field_alias, field, row_number, crud)
|
||||
super(QPushButton).__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
|
||||
print(self.readonly, self.autocomplete, self.field_name, self.field_alias, self.field, self.row_number, self.crud)
|
||||
print("readonly, autocomplete, field_name, field_alias, field, row_number, crud")
|
||||
raise Exception()
|
||||
self.crud.modified.connect(self.update_editor)
|
||||
self.dialog.setWindowTitle(self.field_alias)
|
||||
self.clicked.connect(self.dialog.show)
|
||||
|
||||
def update_editor(self):
|
||||
print(self.editor, self.row_number, self.crud)
|
||||
self.editor_type = self.crud.db_tw.cellWidget(self.row_number, self.crud.select_index["type"])._parse()
|
||||
print(self.editor_type)
|
||||
self.editor = self.editors[self.editor_type]
|
||||
self.dialog.setCentralWidget(self.editor)
|
||||
|
||||
def set_readonly(self, readonly):
|
||||
for editor in self.editors.values():
|
||||
editor.set_readonly(readonly)
|
||||
|
||||
def do_autocomplete(self, autocomplete):
|
||||
self.update_editor()
|
||||
for editor_type, editor in self.editors.items():
|
||||
if autocomplete is None:
|
||||
editor.do_autocomplete(None)
|
||||
elif editor_type in autocomplete:
|
||||
editor.do_autocomplete(autocomplete[editor_type])
|
||||
|
||||
def connect_modified(self):
|
||||
for editor in self.editors.values():
|
||||
editor.connect_modified(self.check_modified)
|
||||
|
||||
def render(self, data, field_name=None, row_number=None, crud=None):
|
||||
self.editor.render(data, field_name=field_name, row_number=row_number, crud=crud)
|
||||
|
||||
def parse(self, row_number=None, crud=None):
|
||||
return self.editor.parse(row_number=row_number, crud=crud)
|
||||
|
||||
|
||||
class Steps_Management(Widget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
crud_aliases = {
|
||||
"id": "Id",
|
||||
"name": "Fase di test",
|
||||
"type": "Tipo",
|
||||
"spec": "Specifica",
|
||||
"description": "Desccrizione",
|
||||
"archived": "Archiviata",
|
||||
}
|
||||
self.crud = Crud(
|
||||
"steps",
|
||||
display_name="GESTIONE FASI DI TEST",
|
||||
readonly=["id"],
|
||||
select=list(crud_aliases.keys()),
|
||||
fields_aliases=crud_aliases,
|
||||
autocomplete={
|
||||
"type": [
|
||||
"leak",
|
||||
"vision",
|
||||
],
|
||||
"spec": {
|
||||
"vision": {
|
||||
# "recipe": iglob("*.ini", root_dir="./config/vision/recipes/"), # only in python3.10
|
||||
"recipe": list(iglob("./config/vision/recipes/*.ini")),
|
||||
},
|
||||
},
|
||||
"archived": False,
|
||||
},
|
||||
widget_classes={
|
||||
"type": Combo_Box_Cell_Widget,
|
||||
"spec": Step_Spec_JEDECW,
|
||||
},
|
||||
)
|
||||
self.layout().addWidget(self.crud, 0, 0, -1, -1)
|
||||
17
src/ui/steps_management/steps_management.ui
Normal file
17
src/ui/steps_management/steps_management.ui
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Steps Management</class>
|
||||
<widget class="QWidget" name="Steps Management">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>94</width>
|
||||
<height>18</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -3,7 +3,7 @@ import os
|
|||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from lib.db import Archive, Users
|
||||
from lib.db import Archive, Steps, Users
|
||||
from PyQt5.QtCore import QTimer
|
||||
from ui.helpers import replace_widget
|
||||
from ui.recipe_selection import Recipe_Selection
|
||||
|
|
@ -32,28 +32,29 @@ class Test(Widget):
|
|||
self.refresh_time(init=True)
|
||||
# INIT RECIPE
|
||||
self.recipe = None
|
||||
self.step = None
|
||||
# INIT CYCLE STATES
|
||||
self.cycle_state = None
|
||||
self.cycle_states = {
|
||||
self.cycle_available_steps = {
|
||||
# "assembly_1": Test_Assembly(self.select_step_img("assembly_1"), u"INSERIRE SENSORE"),
|
||||
"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\""),
|
||||
"fail": Test_Assembly(self.select_step_img("fail"), u"CICLO INTERROTTO - RIMUOVERE IL SENSORE"),
|
||||
"run_test": Test_Assembly(self.select_step_img("wait"), u"ESECUZIONE TEST IN CORSO - ATTENDERE", Test_Leak(components=self.components, recipe=self.recipe)),
|
||||
"leak": Test_Assembly(None, u"ESECUZIONE TEST IN CORSO - ATTENDERE", Test_Leak(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"select_recipe": Test_Assembly(None, u"SELEZIONARE IL CODICE DA COLLAUDARE", Recipe_Selection()),
|
||||
"vision": Test_Assembly(None, u"ESEGUIRE PROCEDURA DI AUTOTEST", Test_Vision(components=self.components, recipe=self.recipe)),
|
||||
"vision": Test_Assembly(None, u"ESEGUIRE PROCEDURA DI AUTOTEST", Test_Vision(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"wait": Test_Assembly(self.select_step_img("wait"), u"ATTENDERE - PAUSA INTER CICLO"),
|
||||
None: Test_Assembly(self.select_step_img("warning"), u"ATTENZIONE - LA RICETTA SELEZIONATA NON CONTIENE FASI DI TEST"),
|
||||
}
|
||||
self.cycle_loop = ["run_test", "vision", "done", "wait"]
|
||||
self.cycle_steps = None
|
||||
self.cycle_index = -1
|
||||
# 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
|
||||
# if "--no-autotest" not in sys.argv:
|
||||
# self.autotest_period = 12 * 60 * 60 * 1000
|
||||
# self.request_autotest("init")
|
||||
# else:
|
||||
self.autotest_period = None
|
||||
# INIT TEST DATA
|
||||
self.data = {}
|
||||
# INIT PIECES COUNTER ([pieces_ok, pieces_failed])
|
||||
|
|
@ -61,7 +62,7 @@ class Test(Widget):
|
|||
# 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():
|
||||
for w in self.cycle_available_steps.values():
|
||||
if hasattr(w, "ok"):
|
||||
# custom ok handlers should call next again
|
||||
if type(w.widget) is Recipe_Selection:
|
||||
|
|
@ -128,79 +129,87 @@ class Test(Widget):
|
|||
self.time_timer.start(self.autotest_period)
|
||||
reason = "boot"
|
||||
self.autotest_request = reason
|
||||
self.cycle_states["autotest"].widget.set_reason(reason)
|
||||
self.cycle_available_steps["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}")
|
||||
current_w = self.cycle_states.get(self.cycle_state, None)
|
||||
if current_w is not None and hasattr(current_w, "stop"):
|
||||
current_w.stop()
|
||||
self.log.debug(f"cycle next: cycle step: {self.step!r} action: {action!r}")
|
||||
if self.step is not None:
|
||||
current_w = self.cycle_available_steps[self.step.type]
|
||||
if hasattr(current_w, "stop"):
|
||||
current_w.stop()
|
||||
if action == "change_recipe":
|
||||
self.log.info(f"cycle next: action: {action!r}")
|
||||
self.set_recipe(recipe=None)
|
||||
self.cycle_state = "select_recipe"
|
||||
self.step = Steps(type="select_recipe")
|
||||
self.cycle_index = -1
|
||||
# RESET TEST DATA
|
||||
self.data.clear()
|
||||
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"
|
||||
self.step = Steps(type="fail")
|
||||
self.cycle_index = -1
|
||||
# RESET TEST DATA
|
||||
self.data.clear()
|
||||
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
|
||||
if self.recipe is None:
|
||||
# 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:
|
||||
# if recipe not set: select_recipe
|
||||
self.cycle_state = "select_recipe"
|
||||
else:
|
||||
self.step = Steps(type="select_recipe")
|
||||
elif action is None:
|
||||
if self.cycle_index == -1 and self.autotest_request is not False:
|
||||
# if cycle_loop is not started or has ended
|
||||
# if cycle_steps is not started or has ended
|
||||
# and autotest was requested
|
||||
self.autotest_request = False
|
||||
self.cycle_state = "autotest"
|
||||
self.step = Steps(type="autotest")
|
||||
if self.autotest_period is not None: # reset periodic autotest timer
|
||||
self.time_timer.start(self.autotest_period)
|
||||
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]
|
||||
else:
|
||||
# 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]
|
||||
self.cycle_index = -1
|
||||
self.step = Steps(type=None)
|
||||
# enable/disable cycle controls
|
||||
self.change_recipe_b.setEnabled(self.recipe is not None)
|
||||
self.cancel_b.setEnabled(self.cycle_state not in {
|
||||
self.cancel_b.setEnabled(self.step.type is not None and self.step.type not in {
|
||||
"emergency",
|
||||
"fail",
|
||||
"select_recipe",
|
||||
"wait",
|
||||
})
|
||||
self.log.info(f"cycle next: next cycle_state: {self.cycle_state!r}")
|
||||
self.log.info(f"cycle next: next cycle step: {self.step!r}")
|
||||
# INIT TEST DATA IF STARTING CYCLE LOOP
|
||||
if self.cycle_index == 0:
|
||||
self.data.clear()
|
||||
w = self.cycle_states[self.cycle_state]
|
||||
w = self.cycle_available_steps[self.step.type]
|
||||
if hasattr(w, "start"):
|
||||
w.start(recipe=self.recipe)
|
||||
w.start(recipe=self.recipe, step=self.cycle_steps[self.cycle_index])
|
||||
self.setCentralWidget(w)
|
||||
if self.cycle_state == "done":
|
||||
if self.step.type == "done":
|
||||
self.done()
|
||||
self.next_timer.start(2000)
|
||||
elif self.cycle_state == "wait":
|
||||
elif self.step.type == "fail":
|
||||
self.next_timer.start(2000)
|
||||
elif self.step.type == "wait":
|
||||
self.next_timer.start(6000)
|
||||
# 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
|
||||
if self.recipe is None:
|
||||
self.cycle_steps = None
|
||||
else:
|
||||
self.cycle_steps = self.recipe.get_steps() + [Steps(type="done"), Steps(type="wait")]
|
||||
# UPDATE RECIPE DISPLAY
|
||||
if self.recipe is not None:
|
||||
self.recipe_l.setText(self.recipe.name)
|
||||
|
|
@ -222,7 +231,7 @@ class Test(Widget):
|
|||
self.data["ok"] = self.data.get("ok", True) and self.data["leak"].get("ok", False)
|
||||
self.next()
|
||||
|
||||
def done(self, ok=False, next=False):
|
||||
def done(self, ok=True):
|
||||
self.log.info("cycle done")
|
||||
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}")
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ from ui.test_test import Test_Test
|
|||
|
||||
|
||||
class Test_Leak(Test_Test):
|
||||
def __init__(self, components=None, recipe=None):
|
||||
super().__init__(components, recipe)
|
||||
def __init__(self, components=None, recipe=None, step=None):
|
||||
super().__init__(components=components, recipe=recipe, step=step)
|
||||
self.start_b.clicked.connect(lambda checked, self=weakref.ref(self): self().components["tecna_t3"].start_test())
|
||||
self.stop_b.clicked.connect(lambda checked, self=weakref.ref(self): self().components["tecna_t3"].stop_test())
|
||||
|
||||
def start(self, recipe=None):
|
||||
super().start(recipe=recipe)
|
||||
def start(self, recipe=None, step=None):
|
||||
super().start(recipe=recipe, step=step)
|
||||
# setup test loop
|
||||
self.components["tecna_t3"].write_recipe(self.recipe)
|
||||
self.components["tecna_t3"].write_recipe(self.recipe, self.step)
|
||||
self.get_connection = self.components["tecna_t3"].out.connect(self.get)
|
||||
self.components["tecna_t3"].resume()
|
||||
self.components["tecna_t3"].start_test()
|
||||
|
|
@ -37,7 +37,7 @@ class Test_Leak(Test_Test):
|
|||
ok = type(result) is str and "passed" in result.lower()
|
||||
else:
|
||||
result = None
|
||||
ok = False
|
||||
ok = None
|
||||
super().get([{
|
||||
"time": data.get("time", None),
|
||||
"results": {
|
||||
|
|
@ -45,7 +45,7 @@ class Test_Leak(Test_Test):
|
|||
"result": result,
|
||||
"data": data["tecna_t3"],
|
||||
},
|
||||
}], override=override)
|
||||
}], override=override, fail=ok is False)
|
||||
|
||||
def visualize(self, data=None):
|
||||
if data is None:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -12,10 +12,11 @@ class Test_Test(Widget):
|
|||
ok = pyqtSignal(dict)
|
||||
ko = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, components=None, recipe=None):
|
||||
def __init__(self, components=None, recipe=None, step=None):
|
||||
super().__init__()
|
||||
self.components = components
|
||||
self.recipe = recipe
|
||||
self.step = step
|
||||
# setup variables
|
||||
self.ok_counter = 0
|
||||
self.ok_counter_limit = 1
|
||||
|
|
@ -24,6 +25,10 @@ class Test_Test(Widget):
|
|||
self.ok_timer.setSingleShot(True)
|
||||
self.ok_timer.setInterval(2000)
|
||||
self.ok_timer.timeout.connect(self.emit_ok)
|
||||
self.ko_timer = QTimer()
|
||||
self.ko_timer.setSingleShot(True)
|
||||
self.ko_timer.setInterval(2000)
|
||||
self.ko_timer.timeout.connect(self.emit_ko)
|
||||
# setup save frame button
|
||||
self.last = None
|
||||
self.save_b.setEnabled(False)
|
||||
|
|
@ -54,8 +59,9 @@ class Test_Test(Widget):
|
|||
self.status_palettes[""].setColor(QPalette.Base, QColor(255, 255, 0))
|
||||
self.visualize()
|
||||
|
||||
def start(self, recipe=None):
|
||||
def start(self, recipe=None, step=None):
|
||||
self.recipe = recipe
|
||||
self.step = step
|
||||
self.visualize()
|
||||
# start test
|
||||
self.start_time = timing()
|
||||
|
|
@ -68,19 +74,20 @@ class Test_Test(Widget):
|
|||
def stop(self):
|
||||
pass
|
||||
|
||||
def get(self, data=None, override=False):
|
||||
if self.ok_timer.isActive():
|
||||
def get(self, data=None, override=False, fail=False):
|
||||
if self.ok_timer.isActive() or self.ko_timer.isActive():
|
||||
# avoid proccessing if test was completed
|
||||
return
|
||||
if data is None:
|
||||
if self.last is not None:
|
||||
data = self.last
|
||||
else:
|
||||
data = {}
|
||||
data = self.last if self.last is not None else {}
|
||||
else:
|
||||
data = data[-1]
|
||||
data_usable = [d is not None for d in reversed(data)]
|
||||
if not any(data_usable):
|
||||
data = self.last if self.last is not None else {}
|
||||
else:
|
||||
data = data[-data_usable.index(True) - 1]
|
||||
if not override:
|
||||
result_ok = data.get("results", {}).get("ok", False)
|
||||
result_ok = data.get("results", {}).get("ok", None)
|
||||
else:
|
||||
result_ok = True
|
||||
self.last = {
|
||||
|
|
@ -89,15 +96,20 @@ class Test_Test(Widget):
|
|||
"duration": timing() - self.start_time,
|
||||
"ok": result_ok,
|
||||
}
|
||||
if not override:
|
||||
if fail:
|
||||
self.ok_counter = 0
|
||||
elif override:
|
||||
self.ok_counter = self.ok_counter_limit
|
||||
else:
|
||||
if result_ok is True:
|
||||
self.ok_counter += 1
|
||||
else:
|
||||
self.ok_counter = 0
|
||||
else:
|
||||
self.ok_counter = self.ok_counter_limit
|
||||
# check if completed
|
||||
if self.ok_counter >= self.ok_counter_limit:
|
||||
if fail:
|
||||
self.stop()
|
||||
self.ko_timer.start()
|
||||
elif self.ok_counter >= self.ok_counter_limit:
|
||||
self.stop()
|
||||
self.ok_timer.start()
|
||||
self.visualize(self.last)
|
||||
|
|
@ -118,7 +130,7 @@ class Test_Test(Widget):
|
|||
self.state_l.setPixmap(self.status_imgs_small["warning"])
|
||||
elif results is None:
|
||||
self.state_l.setPixmap(self.status_imgs_small[None])
|
||||
elif results.get("ok", False) is True:
|
||||
elif results.get("ok", None) is True:
|
||||
self.state_l.setPixmap(self.status_imgs_small[True])
|
||||
else:
|
||||
self.state_l.setPixmap(self.status_imgs_small[False])
|
||||
|
|
@ -131,6 +143,10 @@ class Test_Test(Widget):
|
|||
if img is None:
|
||||
if overridden:
|
||||
self.img = self.status_imgs_full["warning"]
|
||||
elif results is None or results.get("ok", None) is None:
|
||||
self.img = self.status_imgs_full[None]
|
||||
elif results.get("ok", None) is False:
|
||||
self.img = self.status_imgs_full[False]
|
||||
else:
|
||||
self.img = self.status_imgs_full[None]
|
||||
else:
|
||||
|
|
@ -165,3 +181,6 @@ class Test_Test(Widget):
|
|||
|
||||
def emit_ok(self):
|
||||
self.ok.emit(self.last)
|
||||
|
||||
def emit_ko(self):
|
||||
self.ko.emit(self.last)
|
||||
|
|
|
|||
|
|
@ -8,20 +8,21 @@ from ui.test_test import Test_Test
|
|||
class Test_Vision(Test_Test):
|
||||
request_frame = pyqtSignal()
|
||||
|
||||
def __init__(self, components=None, recipe=None):
|
||||
def __init__(self, components=None, recipe=None, step=None):
|
||||
if "--sim-camera" not in sys.argv:
|
||||
self.ok_counter_limit = 2
|
||||
else:
|
||||
self.ok_counter_limit = 1
|
||||
super().__init__(components, recipe)
|
||||
super().__init__(components=components, recipe=recipe, step=step)
|
||||
|
||||
def start(self, recipe=None):
|
||||
super().start(recipe=recipe)
|
||||
def start(self, recipe=None, step=None):
|
||||
super().start(recipe=recipe, step=step)
|
||||
# setup camera-vision loop
|
||||
self.components["galaxy_camera"].set_period(period=None) # only get frame on request
|
||||
self.components["galaxy_camera"].add_sources({"test_vision": self.request_frame})
|
||||
self.request_frame_connection = self.components["vision"].out.connect(self.request_frame) # request new frame as soon as vision finishes
|
||||
self.get_connection = self.components["vision"].out.connect(self.get)
|
||||
self.components["vision"].set_recipe(self.step.spec.get("recipe", "1.ini"))
|
||||
self.components["vision"].resume()
|
||||
self.components["galaxy_camera"].resume()
|
||||
self.request_frame.emit() # request first frame
|
||||
|
|
|
|||
1
src/ui/vision_step_editor/__init__.py
Normal file
1
src/ui/vision_step_editor/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .vision_step_editor import Vision_Step_Editor
|
||||
9
src/ui/vision_step_editor/vision_step_editor.py
Normal file
9
src/ui/vision_step_editor/vision_step_editor.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from ui.editor import Editor
|
||||
|
||||
|
||||
class Vision_Step_Editor(Editor):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.spec.update({
|
||||
"recipe": self.vision_recipe_cb,
|
||||
})
|
||||
37
src/ui/vision_step_editor/vision_step_editor.ui
Normal file
37
src/ui/vision_step_editor/vision_step_editor.ui
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Vision Step Editor</class>
|
||||
<widget class="QWidget" name="Vision Step Editor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>174</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Visione</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_29">
|
||||
<property name="text">
|
||||
<string>Ricetta</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="vision_recipe_cb"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
Reference in New Issue
Block a user