From b5d4a07ab2ba8aa2efc7938f1f47f3cdb5c45640 Mon Sep 17 00:00:00 2001 From: neo Date: Tue, 17 Sep 2024 15:19:36 +0200 Subject: [PATCH 01/88] remove steps table wip --- src/lib/db/__init__.py | 2 +- src/lib/db/models/recipes.py | 24 ++-------- src/lib/db/models/steps.py | 23 --------- src/ui/crud/crud.py | 5 -- src/ui/recipe_selection/recipe_selection.py | 10 +--- .../recipe_spec_and_step_editor.py | 47 +++++-------------- 6 files changed, 17 insertions(+), 94 deletions(-) delete mode 100644 src/lib/db/models/steps.py diff --git a/src/lib/db/__init__.py b/src/lib/db/__init__.py index fb0510d..d96896e 100644 --- a/src/lib/db/__init__.py +++ b/src/lib/db/__init__.py @@ -6,7 +6,7 @@ import re from playhouse.sqlite_ext import JSONField -from .models import Archive, Log, Recipes, Session, Steps, Users, db +from .models import Archive, Log, Recipes, Session, Users, db models_reference = { "archive": Archive, diff --git a/src/lib/db/models/recipes.py b/src/lib/db/models/recipes.py index 14c7ccc..5279d4e 100644 --- a/src/lib/db/models/recipes.py +++ b/src/lib/db/models/recipes.py @@ -4,46 +4,28 @@ from peewee import BooleanField, TextField from playhouse.sqlite_ext import JSONField from .base_model import BaseModel -from .steps import Steps class Recipes(BaseModel): name = TextField(primary_key=True, unique=True, null=False, default=lambda: uuid().hex) client = TextField(null=True) part_number = TextField(null=False) - spec = JSONField(null=False) # keys inside spec must not overlap withthe model + spec = JSONField(null=False) description = TextField(null=True) archived = BooleanField(null=False, default=False) def get_steps(self): - steps = [] - for step_pk in self.spec.get("steps", []): - steps.append(Steps.get_by_id(step_pk)) - return steps - - def delete_associated_steps(self): - return Steps.delete().where(Steps._meta.primary_key << list(self.spec.get("available_steps", {}).values())).execute() + return self.spec def get_steps_map(self): - steps = {} - for step_name, step_pk in self.spec.get("available_steps", {}).items(): - steps[step_name] = Steps.get_by_id(step_pk) - return steps + return self.spec @classmethod def crud_delete(cls, deleted_rows): - # return cls.delete().where(self._meta.primary_key << deleted_rows).execute() recipes = list(cls.select().where(cls._meta.primary_key << deleted_rows).execute()) for recipe in recipes: - recipe.delete_associated_steps() recipe.delete_instance() return len(recipes) - # @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 = "recipes" diff --git a/src/lib/db/models/steps.py b/src/lib/db/models/steps.py deleted file mode 100644 index 4baa839..0000000 --- a/src/lib/db/models/steps.py +++ /dev/null @@ -1,23 +0,0 @@ -from uuid import uuid4 as uuid - -from peewee import BooleanField, TextField -from playhouse.sqlite_ext import JSONField - -from .base_model import BaseModel - - -class Steps(BaseModel): - name = TextField(primary_key=True, unique=True, null=False, default=lambda: uuid().hex) - type = TextField(null=False) - spec = JSONField(null=False) # keys inside spec must not overlap withthe model - description = TextField(null=True) - 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" diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 6eb3e3d..7f0d111 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -221,11 +221,6 @@ class Json_External_Dialog_Editor_Cell_Widget(QPushButton, Cell): 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, action=None, row_number=None, crud=None): - # if action != "commit" and self.connected_modified and not self.is_modified: - # return self.value - # return self.editor.parse(action=action, row_number=row_number, crud=crud) - def parse(self, action=None, row_number=None, crud=None): return self.editor.parse(row_number=row_number, crud=crud) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 9c7b2e1..766eaf8 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -5,7 +5,7 @@ import sys import weakref from glob import glob -from lib.db import Recipes, Steps, Users, db +from lib.db import Recipes, Users, db from PyQt5.QtCore import QTimer, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QFileDialog, QMessageBox, QShortcut @@ -306,18 +306,13 @@ class Recipe_Selection(Widget): recipe = Recipes(name=recipe_name, part_number="TEMPORARY") steps = {} for step_type, step_spec in steps_specs.items(): - step = Steps() + step = {} steps[step_type] = step recipe_is_new = True for step_name, step_spec in steps_specs.items(): step = steps[step_name] - # step.type = re.sub(r"^(.*)_[0-9]+$", r"\1", step_name) step.type = step_name step.spec = step_spec - if recipe_is_new: - step.save(force_insert=True) - else: - step.save() recipe.client = row.get("cliente", defaults["cliente"]) recipe.part_number = row.get(part_number_field, defaults["part_number"]) recipe.description = row.get(description_field, defaults["descrizione"]) @@ -498,5 +493,4 @@ class Recipe_Selection(Widget): ) if ret == QMessageBox.Ok: Recipes.delete().execute() - Steps.delete().execute() self.crud.refresh() diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index c34536c..e49bd66 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -1,4 +1,3 @@ -from lib.db import Steps from peewee import IntegrityError from ui.barcodes_step_editor import Barcodes_Step_Editor from ui.connector_step_editor import Connector_Step_Editor @@ -16,7 +15,7 @@ from ui.instruction_step_editor import Instruction_Step_Editor class Recipe_Spec_And_Step_Editor(Editor): def __init__(self, action=None, cell_widget=None, unsupported_steps=None): super().__init__(action=action, cell_widget=cell_widget) - self.map = { + self.steps_map = { "count": { "type": "count", "enable": self.count_enabled_cb, @@ -90,9 +89,9 @@ class Recipe_Spec_And_Step_Editor(Editor): }, } for step_name in unsupported_steps: - self.map.get(step_name, {})["hidden"] = True - self.spec.update({step_name: map["enable"] for step_name, map in self.map.items()}) - for map in self.map.values(): + self.steps_map.get(step_name, {})["hidden"] = True + self.spec.update({step_name: map["enable"] for step_name, map in self.steps_map.items()}) + for map in self.steps_map.values(): editor = map.get("editor", None) if editor is not None: replace_widget(self, map["widget"], editor) @@ -100,10 +99,11 @@ class Recipe_Spec_And_Step_Editor(Editor): self.save_steps_b.clicked.connect(self.save_steps) self.reset_steps_b.clicked.connect(self.reset_steps) self.available_steps = {} + self.recipe = None def set_readonly(self, readonly=True): super().set_readonly(readonly=readonly) - for map in self.map.values(): + for map in self.steps_map.values(): editor = map.get("editor", None) if editor is not None: editor.set_readonly(readonly=readonly) @@ -116,64 +116,40 @@ class Recipe_Spec_And_Step_Editor(Editor): step_editors_autocomplete = autocomplete.get("step_editors", None) super().do_autocomplete(autocomplete) if step_editors_autocomplete is not None: - for step_name, map in self.map.items(): + for step_name, map in self.steps_map.items(): editor = map.get("editor", None) if editor is not None: editor.do_autocomplete(step_editors_autocomplete.get(step_name, None)) def init(self, action=None): - self.get_steps() if action == "add": self.save_steps() def showing_dialog(self): self.reset_steps() - # def connect_modified(self, check_modified): - # super().connect_modified(check_modified) - # for map in self.map.values(): - # editor = map.get("editor", None) - # if editor is not None: - # editor.connect_modified(check_modified) - def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) self.available_steps = data.get("available_steps", None) - self.get_steps() steps = set(data.get("steps", set())) - for map in self.map.values(): + for map in self.steps_map.values(): step = map.get("step", None) if step is not None: map["enable"].setChecked(step.name in steps and not map.get("hidden", False)) self.render_steps() def parse(self, action=None, row_number=None, crud=None): - # if action == "commit": - # self.save_steps() ret = super().parse(row_number=row_number, crud=crud) ret["steps"] = [] ret["available_steps"] = {} - for step_name, map in self.map.items(): + for step_name, map in self.steps_map.items(): ret["available_steps"][step_name] = map["step"].name if map["enable"].isChecked() and not map.get("hidden", False): ret["steps"].append(map["step"].name) return ret - def get_steps(self): - for step_name, map in self.map.items(): - if step_name in self.available_steps: - try: - map["step"] = Steps.get_by_id(self.available_steps[step_name]) - map["step_is_new"] = False - except Steps.DoesNotExist: - map["step"] = Steps(name=self.available_steps[step_name], type=map["type"], spec={}) - map["step_is_new"] = True - elif map.get("step", None) is None: - map["step"] = Steps(type=map["type"], spec={}) - map["step_is_new"] = True - def render_steps(self): - for step_name, map in self.map.items(): + for step_name, map in self.steps_map.items(): step = map.get("step", None) if step is not None: editor = map.get("editor", None) @@ -181,11 +157,10 @@ class Recipe_Spec_And_Step_Editor(Editor): editor.render(step.spec) def reset_steps(self): - self.get_steps() self.render_steps() def save_steps(self): - for map in self.map.values(): + for map in self.steps_map.values(): step = map.get("step", None) if step is not None: editor = map.get("editor", None) From d65e2a03ea9e16b65521be6c6677607befcd9bf0 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 18 Sep 2024 14:18:07 +0200 Subject: [PATCH 02/88] remove steps table wip, import ok --- src/components/tecna_marposs_provaset_t3.py | 4 +- src/lib/db/__init__.py | 52 ------------ src/lib/db/models/__init__.py | 1 - src/lib/helpers/step.py | 8 ++ src/main.py | 2 +- src/ui/crud/crud.py | 18 ++-- src/ui/recipe_selection/recipe_selection.py | 32 ++----- .../recipe_spec_and_step_editor.py | 4 - src/ui/test/test.py | 84 +++++++++---------- 9 files changed, 71 insertions(+), 134 deletions(-) create mode 100644 src/lib/helpers/step.py diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 201e681..cfba77b 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -1,4 +1,4 @@ -from lib.db import Recipes, Steps, db +from lib.db import Recipes, db from PyQt5.QtCore import QSemaphore, pyqtSignal from PyQt5.QtWidgets import QMessageBox @@ -333,7 +333,7 @@ class TecnaMarpossProvasetT3(ModbusComponent): recipes = [] for recipe in list(Recipes.select().order_by(Recipes.name.asc())): # if recipe.spec["leak_1"]: - recipes.append([recipe, Steps.get_by_id(recipe.spec["available_steps"]["leak_1"])]) + recipes.append([recipe, recipe.spec["steps"]["leak_1"]]) # reverve last for our recipe control if len(recipes) > max(self.max_program_number - 1, 0): self.log.warning(f"too many recipes ({len(recipes)}), saving only first {max(self.max_program_number - 1, 0)}") diff --git a/src/lib/db/__init__.py b/src/lib/db/__init__.py index d96896e..bad5971 100644 --- a/src/lib/db/__init__.py +++ b/src/lib/db/__init__.py @@ -12,7 +12,6 @@ models_reference = { "archive": Archive, "log": Log, "recipes": Recipes, - "steps": Steps, "users": Users, } @@ -49,57 +48,6 @@ def init_db(): except FileNotFoundError: pass - # try: - # with open("src/lib/db/imports/connectors.csv", "r") as f: - # log.info("importing connectors") - # reader = csv.DictReader(f) - # count = 0 - # for row in reader: - # steps = {} - # for step_type, step_spec in { - # "connector": {"connector": row["connector"]}, - # "barcodes": {"serial": ""}, - # "resistance": {"scale": 500, "expected": float(row["resistance_expected"]), "tolerance": float(row["resistance_tolerance"])}, - # "leak_1": {"pre_filling_time": 1, "pre_filling_pressure": 1000, "filling_time": 1, "settling_time": 1, "settling_pressure_min_percent": 5, "settling_pressure_max_percent": 5, "test_time": 5, "test_pressure_qneg": 100, "test_pressure": 1000, "test_pressure_qpos": 100, "flush_time": 1, "flush_pressure": 100}, - # "leak_2": {"pre_filling_time": 1, "pre_filling_pressure": 1000, "filling_time": 1, "settling_time": 1, "settling_pressure_min_percent": 5, "settling_pressure_max_percent": 5, "test_time": 5, "test_pressure_qneg": 100, "test_pressure": 1000, "test_pressure_qpos": 100, "flush_time": 1, "flush_pressure": 100}, - # "vision": {"recipe": "termorestringente_923578.ini"}, - # "print": {"template": "EtichettaR5.prn", }, - # }.items(): - # steps[step_type] = Steps( - # type=re.sub(r"^(.*)_[0-9]+$", r"\1", step_type), - # spec=step_spec, - # ) - # steps[step_type].save(force_insert=True) - # recipe = Recipes( - # name=row["name"], - # client=row["client"], - # part_number=row["part_number"], - # spec={ - # "connector": True, - # "barcodes": True, - # "resistance": True, - # "leak_1": False, - # "leak_2": False, - # "vision": False, - # "print": True, - # "steps": [steps["connector"].name, steps["resistance"].name, steps["print"].name, ], # pks of the enabled steps - # "available_steps": { - # "connector": steps["connector"].name, - # "barcodes": steps["barcodes"].name, - # "resistance": steps["resistance"].name, - # "leak_1": steps["leak_1"].name, - # "leak_2": steps["leak_2"].name, - # "vision": steps["vision"].name, - # "print": steps["print"].name, - # }, - # }, - # ) - # recipe.save(force_insert=True) - # count += 1 - # log.info(f"connectors: imported {count} rows.") - # except FileNotFoundError: - # pass - init_db() diff --git a/src/lib/db/models/__init__.py b/src/lib/db/models/__init__.py index ee3118a..d26cab3 100644 --- a/src/lib/db/models/__init__.py +++ b/src/lib/db/models/__init__.py @@ -2,5 +2,4 @@ from .archive import Archive from .base_model import db from .log import Log from .recipes import Recipes -from .steps import Steps from .users import Session, Users diff --git a/src/lib/helpers/step.py b/src/lib/helpers/step.py new file mode 100644 index 0000000..9429943 --- /dev/null +++ b/src/lib/helpers/step.py @@ -0,0 +1,8 @@ + + +class Step(object): + step_type = None + spec = {} + def __init__(self,step_type=None,spec=dict): + self.step_type = step_type + self.spec = spec diff --git a/src/main.py b/src/main.py index 45583be..78efe28 100644 --- a/src/main.py +++ b/src/main.py @@ -277,7 +277,7 @@ try: app = QApplication(sys.argv) with SingleProcess() as single_process_lock: - if not single_process_lock: + if not single_process_lock and "--no-lock" not in sys.argv: logging.error(f"Program already opened, exiting...") QMessageBox.critical(None, "ERRORE", "IL PROGRAMMA E' GIA' IN ESECUZIONE") exit(0) diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 7f0d111..57b633c 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -270,7 +270,7 @@ class Crud(Widget): self.filter_delay = QTimer() self.filter_delay.setSingleShot(True) self.filter_delay.setInterval(500) - self.filter_delay.timeout.connect(lambda self=weakref.ref(self): self().do_filter(self().filter_cn)) + self.filter_delay.timeout.connect(lambda selfi=weakref.ref(self): selfi().do_filter(selfi().filter_cn)) self.db_tw.crud = self self.refresh("init") self.db_tw.horizontalHeader().sectionClicked.connect(self.toggle_sort) @@ -283,13 +283,13 @@ class Crud(Widget): else: self.db_tw.setSelectionMode(QAbstractItemView.ExtendedSelection) self.db_tw.itemSelectionChanged.connect(self.show_selection) - self.revert_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("revert")) + self.revert_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("revert")) if self.pagination is not False: - self.start_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=0)) - self.previous_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=max(self().page - 1, 0))) - self.page_n_sb.valueChanged.connect(lambda page, self=weakref.ref(self): self().refresh("pagination", page=page - 1)) - self.next_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=self().page + 1)) - self.end_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=-1)) + self.start_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=0)) + self.previous_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=max(selfi().page - 1, 0))) + self.page_n_sb.valueChanged.connect(lambda page, selfi=weakref.ref(self): selfi().refresh("pagination", page=page - 1)) + self.next_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=selfi().page + 1)) + self.end_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=-1)) else: self.next_b.setHidden(True) self.previous_b.setHidden(True) @@ -468,8 +468,8 @@ class Crud(Widget): if fn in self.db.table_fields: w.setPlaceholderText("Filtro") w.setText(self.filters.get(fn, None)) - w.editingFinished.connect(lambda cn=cn, self=weakref.ref(self): self().do_filter(cn)) - w.textChanged.connect(lambda text, cn=cn, self=weakref.ref(self): self().filter_edited(cn)) + w.editingFinished.connect(lambda cni=cn, selfi=weakref.ref(self): selfi().do_filter(cni)) + w.textChanged.connect(lambda text, cni=cn, selfi=weakref.ref(self): selfi().filter_edited(cni)) else: w.setPlaceholderText("Non filtrabile") w.setEnabled(False) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 766eaf8..98d6675 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -9,6 +9,8 @@ from lib.db import Recipes, Users, db from PyQt5.QtCore import QTimer, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QFileDialog, QMessageBox, QShortcut + +from lib.helpers.step import Step from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget from ui.helpers import replace_widget from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor @@ -298,6 +300,8 @@ class Recipe_Selection(Widget): row = dict((k.lower(), v) for k, v in ucrow.items()) recipe_name = row.get(recipe_name_field, defaults["codice_ricetta"]) steps_specs = self.read_steps(row, defaults=defaults) + + # create recipe or update existing one in DB try: recipe = Recipes.get_by_id(recipe_name) steps = recipe.get_steps_map() @@ -305,14 +309,11 @@ class Recipe_Selection(Widget): except Recipes.DoesNotExist: recipe = Recipes(name=recipe_name, part_number="TEMPORARY") steps = {} - for step_type, step_spec in steps_specs.items(): - step = {} - steps[step_type] = step + for step_name, step_spec in steps_specs.items(): + if step_name not in self.unsupported_steps: + steps[step_name] = step_spec recipe_is_new = True - for step_name, step_spec in steps_specs.items(): - step = steps[step_name] - step.type = step_name - step.spec = step_spec + recipe.client = row.get("cliente", defaults["cliente"]) recipe.part_number = row.get(part_number_field, defaults["part_number"]) recipe.description = row.get(description_field, defaults["descrizione"]) @@ -329,23 +330,8 @@ class Recipe_Selection(Widget): "leak_2": len(row.get("prova_tenuta_abilitata_2", defaults["prova_tenuta_abilitata_2"])) and "leak_2" not in self.unsupported_steps, "vision": len(row.get("test_visione_abilitato", defaults["test_visione_abilitato"])) and "vision" not in self.unsupported_steps, "print": len(row.get("stampa_etichetta_abilitata", defaults["stampa_etichetta_abilitata"])) and "print" not in self.unsupported_steps, - "steps": [], # should be pks of the enabled steps - "available_steps": { - "count": steps["count"].get_id(), - "connector": steps["connector"].get_id(), - "barcodes": steps["barcodes"].get_id(), - "resistance": steps["resistance"].get_id(), - "screws": steps["screws"].get_id(), - "instruction": steps["instruction"].get_id(), - "leak_1": steps["leak_1"].get_id(), - "leak_2": steps["leak_2"].get_id(), - "vision": steps["vision"].get_id(), - "print": steps["print"].get_id(), - }, + "steps": steps, } - for step_name, step in recipe.spec["available_steps"].items(): - if recipe.spec[step_name]: - recipe.spec["steps"].append(step) if recipe_is_new: recipe.save(force_insert=True) else: diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index e49bd66..40ee0e9 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -98,7 +98,6 @@ class Recipe_Spec_And_Step_Editor(Editor): self.steps_tw.setTabVisible(self.steps_tw.indexOf(map["tab"]), not map.get("hidden", False)) self.save_steps_b.clicked.connect(self.save_steps) self.reset_steps_b.clicked.connect(self.reset_steps) - self.available_steps = {} self.recipe = None def set_readonly(self, readonly=True): @@ -130,7 +129,6 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) - self.available_steps = data.get("available_steps", None) steps = set(data.get("steps", set())) for map in self.steps_map.values(): step = map.get("step", None) @@ -141,9 +139,7 @@ class Recipe_Spec_And_Step_Editor(Editor): def parse(self, action=None, row_number=None, crud=None): ret = super().parse(row_number=row_number, crud=crud) ret["steps"] = [] - ret["available_steps"] = {} for step_name, map in self.steps_map.items(): - ret["available_steps"][step_name] = map["step"].name if map["enable"].isChecked() and not map.get("hidden", False): ret["steps"].append(map["step"].name) return ret diff --git a/src/ui/test/test.py b/src/ui/test/test.py index b4a379c..616eeb6 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -7,8 +7,9 @@ from datetime import datetime, timedelta from components import ArchiveSynchronizer from PyQt5.QtCore import QTimer, pyqtSlot from PyQt5.QtWidgets import QMessageBox -from lib.db import Archive, Steps, Users +from lib.db import Archive, Recipes, Users from lib.helpers import get_shift +from lib.helpers.step import Step from playhouse.shortcuts import model_to_dict from ui.barcode_recipe_selection import Barcode_Recipe_Selection from ui.helpers import replace_widget @@ -259,7 +260,7 @@ class Test(Widget): if self.config["hardware_config"]["tecna_t3"] == "present" or self.config["hardware_config"]["furness_controls"] == "present": self.cycle_available_steps["leak_1"].widget.recipe_written = False self.cycle_available_steps["leak_2"].widget.recipe_written = False - self.step = Steps(type="select_recipe") + self.step = Step(step_type="select_recipe") self.cycle_index = -1 self.recipe = None self.cycle_steps = None @@ -269,7 +270,7 @@ class Test(Widget): elif action in ("fail", "abort"): self.log.info(f"cycle next: action: {action!r}") # FAIL AND RESTART TEST - self.step = Steps(type="fail") + self.step = Step(step_type="fail") self.cycle_index = -1 # COUNT FAIL if action == "fail": @@ -282,10 +283,10 @@ class Test(Widget): # if recipe not set: select_recipe if self.recipe_selection_mode == "barcode": self.log.info(f"returning to barcode recipe selection") - self.step = Steps(type="barcode_recipe_selection") + self.step = {"type":"barcode_recipe_selection","spec":{}} else: self.log.info(f"returning to recipe selection table") - self.step = Steps(type="select_recipe") + self.step = Step(step_type="select_recipe") elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested @@ -324,25 +325,25 @@ class Test(Widget): else: self.cycle_index = -1 - self.step = Steps(type=None) + self.step = Step(step_type=None) # enable/disable cycle controls self.change_recipe_b.setEnabled(self.recipe is not None) - self.cancel_b.setEnabled(self.step.type is not None and self.step.type not in { + self.cancel_b.setEnabled(self.step.step_type is not None and self.step.step_type not in { "emergency", "fail", "select_recipe", "wait", }) - self.log.info(f"next cycle step: {model_to_dict(self.step)!r}") + self.log.info(f"next cycle step: {self.step.step_type!r}") # INIT TEST DATA IF STARTING CYCLE LOOP OR IF RESET IS NEEDED if self.cycle_index == 0: self.data = {"ok": True, "overridden": False} self.archived = None if self.recipe is not None and "recipe" not in self.data: self.data["recipe"] = model_to_dict(self.recipe) - w = self.cycle_available_steps[self.step.type] + w = self.cycle_available_steps[self.step.step_type] show = None - if self.step.type == "leak_2": + if self.step.step_type == "leak_2": self.setCentralWidget(w) # NEED TO PRESHOW UI if hasattr(w, "start"): show = w.start(recipe=self.recipe, step=self.step, pieces=self.pieces) @@ -350,16 +351,16 @@ class Test(Widget): self.setCentralWidget(w) elif show is False: self.next_timer.start(0) - if self.step.type == "done": + if self.step.step_type == "done": self.archived = self.done() self.last_label = copy.deepcopy(self.archived) self.next_timer.start(500) - elif self.step.type == "print": + elif self.step.step_type == "print": compiled_label = self.print(self.archived, self.step.spec.get("template", "EtichettaR5")) self.archived.label = compiled_label self.archived.save() self.next_timer.start(500) - elif self.step.type == "wait": + elif self.step.step_type == "wait": self.next_timer.start(500) # UPDATE COUNT DISPLAY self.update_count_display() @@ -387,7 +388,7 @@ class Test(Widget): # create step sequence list barcode_names = ['serial', 'barcode_input_2', 'barcode_input_3', 'barcode_input_4', 'barcode_input_5'] for i, step in enumerate(steps): - if step.type == "barcodes": + if step.step_type == "barcodes": n_pieces = int(step.spec.get("n_pieces", 1)) n_pieces_adapted = n_pieces if n_pieces_adapted == 1: @@ -401,47 +402,47 @@ class Test(Widget): steps.insert(i + 1, new_barcode_step) if i in skip: continue - if step.type == "vision": + if step.step_type == "vision": self.components["vision"].config_changed(vision_recipe=self.recipe.name) - if step.type == "count": + if step.step_type == "count": count_found = True if "warning_img" in step.spec: if step.spec["warning_img"]: - steps.insert(i, Steps(type="warning_img", spec={"warning_img": step.spec["warning_img"]})) + steps.insert(i, Step(step_type="warning_img", spec={"warning_img": step.spec["warning_img"]})) skip.add(i + 1) if "assembly" in step.spec: if step.spec["assembly"]: - steps.insert(i, Steps(type="instructions", spec={})) + steps.insert(i, Step(step_type="instructions", spec={})) skip.add(i + 1) if "require_discard_piece" in step.spec: if step.spec["require_discard_piece"]: self.require_discard_piece = True - if step.type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR - steps.insert(i + 1, Steps(type="resistance", spec={ + if step.step_type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR + steps.insert(i + 1, Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, "tolerance_neg": 0, })) skip.add(i + 1) - if step.type == "print": + if step.step_type == "print": if print_found: continue - steps.insert(i, Steps(type="done")) + steps.insert(i, Step(step_type="done")) print_found = True self.print_step = step if self.config["hardware_config"].get("enforce_piece_removal", "no") == "yes": - steps.append(Steps(type="piece_removal")) + steps.append(Step(step_type="piece_removal")) if count_found: - steps.append(Steps(type="count_end")) - if step.type in ("leak_1", "leak_2"): + steps.append(Step(step_type="count_end")) + if step.step_type in ("leak_1", "leak_2"): self.leak_step = step if not print_found: - steps.append(Steps(type="done")) + steps.append(Step(step_type="done")) if count_found: - steps.append(Steps(type="count_end")) - steps.append(Steps(type="wait")) + steps.append(Step(step_type="count_end")) + steps.append(Step(step_type="wait")) self.cycle_steps = steps self.check_steps_dependencies(self.cycle_steps) leak_autotest_steps = [] @@ -457,32 +458,32 @@ class Test(Widget): l_at_2["test_pressure_qneg"] = l_at_2["test_pressure_tt_qneg"] l_at_2["test_pressure_qpos"] = l_at_2["test_pressure_tt_qpos"] l_at_2["autotest"] = "ok_check" - leak_autotest_steps = [Steps(type="leak_1", spec=l_at_1), Steps(type="leak_1", spec=l_at_2)] + leak_autotest_steps = [Step(step_type="leak_1", spec=l_at_1), Step(step_type="leak_1", spec=l_at_2)] self.autotest_cycle_steps = [ *([ - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": 1, "tolerance_pos": 5, "tolerance_neg": 5, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, "tolerance_neg": 0, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": 10, "tolerance_pos": 1, "tolerance_neg": 1, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, @@ -491,8 +492,8 @@ class Test(Widget): }), ] if "resistance" not in self.unsupported_steps else []), *(leak_autotest_steps), - Steps(type="done"), - Steps(type="wait"), + Step(step_type="done"), + Step(step_type="wait"), ] for w in self.cycle_available_steps.values(): if hasattr(w, "reset"): @@ -513,13 +514,13 @@ class Test(Widget): unsupported_steps = set() missing_components = set() for step in steps: - if step.type in self.unsupported_steps or step.type not in self.cycle_available_steps: - unsupported_steps.add(step.type) + if step.step_type in self.unsupported_steps or step.step_type not in self.cycle_available_steps: + unsupported_steps.add(step.step_type) else: - for dependency in self.steps_dependencies.get(step.type, []): + for dependency in self.steps_dependencies.get(step.step_type, []): if isinstance(dependency, tuple): if all([d not in self.components for d in dependency]): - unsupported_steps.add(step.type) + unsupported_steps.add(step.step_type) else: unready = set() for d in dependency: @@ -534,7 +535,7 @@ class Test(Widget): missing_components.add(" or ".join(dependency)) else: if dependency not in self.components: - unsupported_steps.add(step.type) + unsupported_steps.add(step.step_type) else: if not self.components[dependency].ready: self.components[dependency].reconfigure() @@ -571,7 +572,6 @@ class Test(Widget): # remove useless info self.data.get("recipe", {}).get("spec", {}).pop("steps", None) - self.data.get("recipe", {}).get("spec", {}).pop("available_steps", None) for leak in ["leak_1", "leak_2"]: if leak in self.data.keys(): results = {k: self.data[leak]["results"][self.tester_component][k] for k in ["Running test: result"]} @@ -757,7 +757,7 @@ class Test(Widget): def load_recipe_from_rfid(self, data): if data not in(None,''): self.tag_loaded_recipe = data - if self.step.type == "barcode_recipe_selection": + if self.step.step_type == "barcode_recipe_selection": if data is not None: self.cycle_available_steps["barcode_recipe_selection"].widget.get(data) else: From e7fc30d5f62b19adeece3273a7d773c9b877c541 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 18 Sep 2024 18:03:13 +0200 Subject: [PATCH 03/88] remove steps table wip --- config/machine_settings/st-ten-10.ini | 15 --------------- src/lib/db/models/recipes.py | 13 +++++++++++-- .../recipe_spec_and_step_editor.py | 8 +++----- src/ui/test/test.py | 15 +++++++++++---- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/config/machine_settings/st-ten-10.ini b/config/machine_settings/st-ten-10.ini index da5870c..f33dd28 100644 --- a/config/machine_settings/st-ten-10.ini +++ b/config/machine_settings/st-ten-10.ini @@ -83,18 +83,3 @@ tester_discharge_enable: yes [autotest_leak] enabled: false -pre_filling_time: 0 -pre_filling_pressure: 0 -filling_time: 10 -settling_time: 10 -settling_pressure_min_percent: 5 -settling_pressure_max_percent: 5 -test_pressure: 5000 -test_time: 10 -test_pressure_qpos: 10 #Q+ Upper test leak limit -test_pressure_qneg: 30 #Q- Lower test leak limit -test_pressure_tt_qpos: 1 # Q+ Upper test leak limit (tube-tube) -test_pressure_tt_qneg: 5 # Q- Lower test leak limit (tube-tube) -flush_time: 1 -flush_pressure: 100 -relay_config: 1 diff --git a/src/lib/db/models/recipes.py b/src/lib/db/models/recipes.py index 5279d4e..0cd5a90 100644 --- a/src/lib/db/models/recipes.py +++ b/src/lib/db/models/recipes.py @@ -1,9 +1,11 @@ +import json from uuid import uuid4 as uuid from peewee import BooleanField, TextField from playhouse.sqlite_ext import JSONField from .base_model import BaseModel +from ...helpers.step import Step class Recipes(BaseModel): @@ -15,10 +17,17 @@ class Recipes(BaseModel): archived = BooleanField(null=False, default=False) def get_steps(self): - return self.spec + steps = [] + for step_name, enabled in self.spec.items(): + if enabled in (True, 1): + steps.append(Step(step_type=step_name,spec=self.spec["steps"][step_name])) + return steps def get_steps_map(self): - return self.spec + steps = {} + for step_name, step_pk in self.spec.get("available_steps", {}).items(): + steps[step_name] = Step(step_type=step_name,spec=self.spec["steps"][step_name]) + return steps @classmethod def crud_delete(cls, deleted_rows): diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index 40ee0e9..bb124df 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -129,11 +129,9 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) - steps = set(data.get("steps", set())) - for map in self.steps_map.values(): - step = map.get("step", None) - if step is not None: - map["enable"].setChecked(step.name in steps and not map.get("hidden", False)) + for step_name,step_def in self.steps_map.items(): + if not step_def.get("hidden", False): + step_def["enable"].setChecked(data.get(step_name,{}) in (True,1,"x") ) self.render_steps() def parse(self, action=None, row_number=None, crud=None): diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 616eeb6..512d413 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -235,7 +235,13 @@ class Test(Widget): if self.autotest_period is not None: self.autotest_timer.start(self.autotest_period) reason = "boot" - self.autotest_request = reason + + if self.config["autotest_leak"]["enabled"] == "true": + self.autotest_request = reason + else: + self.autotest_request = False + else: + self.log.info(f"Autotest request ignored (reason: {reason!r}) --no-autotest flag detected") if reason == "logout": self.next(action="abort") @@ -244,7 +250,7 @@ class Test(Widget): def next(self, action=None): if self.step is not None: - self.log.info(f"cycle step: {model_to_dict(self.step)!r} action: {action!r} current index:{self.cycle_index}") + self.log.info(f"cycle step: {self.step.step_type!r} action: {action!r} current index:{self.cycle_index}") else: self.log.info(f"cycle step: {self.step!r} action: {action!r} current index:{self.cycle_index}") @@ -294,6 +300,7 @@ class Test(Widget): self.autotesting = True self.autotesting_reason = self.autotest_request self.autotest_request = False + self.log.info(f"Autotest requested (reason: {self.autotesting_reason})") if self.autotest_period is not None: # reset periodic autotest timer self.time_timer.start(self.autotest_period) self.require_discard_piece = False @@ -500,7 +507,7 @@ class Test(Widget): w.reset() # UPDATE RECIPE DISPLAY if self.recipe is not None: - self.log.info(f"set recipe: {model_to_dict(self.recipe)!r} cycle steps: {[model_to_dict(s) for s in self.cycle_steps]}") + self.log.info(f"set recipe: {model_to_dict(self.recipe)!r} cycle steps: {[s.step_type for s in self.cycle_steps]}") self.recipe_l.setText(self.recipe.name) self.recipe_l.setStyleSheet("") self.cycle_index = -1 @@ -554,7 +561,7 @@ class Test(Widget): if step_name not in self.data: self.data[step_name] = {} if data is not None: - data["step"] = model_to_dict(self.step) + data["step"] = self.step.spec data["step"].pop("name", None) # MAKE ARRAY ONLY IF MORE THAN ONE TEST OF SAME TYPE From 938e4208000641bf7c7b755e313827cc41fad5d7 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 18 Sep 2024 18:15:01 +0200 Subject: [PATCH 04/88] wtf --- src/components/archive_synchronizer.py | 22 +++++++--------------- src/ui/test/test.py | 4 ---- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index b9ab049..f6ee93f 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -19,11 +19,10 @@ from .component import Component # Suppress insecure request warning requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) class ArchiveSynchronizer(Component): - machine_status = "offline" def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv - self.status= ArchiveSynchronizer.machine_status + self.machine_status = "offline" def config_changed(self): self.machine_id = self.config.machine_id @@ -31,8 +30,6 @@ class ArchiveSynchronizer(Component): self.archive_endpoint =f"https://dev.r5portal.it/api/st-ten-save/" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] - #self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id_endpoint}&status={self.status}" - # self.images_path = self.config[self.name]["images_path"] self._do_set_period({"period": float(self.config[self.name]["poll_time"])}) self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000) self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"]) @@ -60,14 +57,9 @@ class ArchiveSynchronizer(Component): super()._get() def update_machine_status(self): - self.status = ArchiveSynchronizer.machine_status - #print(f"machine_status_global: {ArchiveSynchronizer.machine_status}") # TESTING - self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.status}" + self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" - if self.status not in ["working", "logged-in", "logged-out"]: - status_dict = {"last_status": "offline"} - else: - status_dict = {"last_status": self.status} + status_dict = {"last_status": self.machine_status} response = None try: @@ -79,21 +71,21 @@ class ArchiveSynchronizer(Component): raise AssertionError("bad status response") except AssertionError as e: self.log.warning( - f"Status: {self.status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}" + f"Status: {self.machine_status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}" ) return False except (requests.ConnectionError, requests.Timeout) as e: self.log.warning( - f"Status: {self.status}: failed to update machine status, archive_endpoint might be unreachable: {str(e)}" + f"Status: {self.machine_status}: failed to update machine status, archive_endpoint might be unreachable: {str(e)}" ) return False except Exception: self.log.error( - f"Status: {self.status}: failed to update machine status:\n{traceback.format_exc()}:\n{response.status_code if response else 'no response'}: {response.content if response else 'no response'}" + f"Status: {self.machine_status}: failed to update machine status:\n{traceback.format_exc()}:\n{response.status_code if response else 'no response'}: {response.content if response else 'no response'}" ) return False - self.log.info(f"Status: {self.status}: Machine Status Updated Successfully") + self.log.info(f"Status: {self.machine_status}: Machine Status Updated Successfully") return True def remote_archive(self, record): r = None diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 512d413..fe38ed5 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -4,7 +4,6 @@ import os import sys import weakref from datetime import datetime, timedelta -from components import ArchiveSynchronizer from PyQt5.QtCore import QTimer, pyqtSlot from PyQt5.QtWidgets import QMessageBox from lib.db import Archive, Recipes, Users @@ -254,9 +253,6 @@ class Test(Widget): else: self.log.info(f"cycle step: {self.step!r} action: {action!r} current index:{self.cycle_index}") - ArchiveSynchronizer.machine_status = "working" - # print(f"{ArchiveSynchronizer.machine_status}")#testing - current_w = self.centralWidget if hasattr(current_w, "stop"): current_w.stop() From e3db54583dc3e3ac6f1dc227931fe7986d90ca41 Mon Sep 17 00:00:00 2001 From: neo Date: Fri, 27 Sep 2024 19:11:49 +0200 Subject: [PATCH 05/88] Tecna recipe reader tool WIP --- src/components/tecna_marposs_provaset_t3.py | 35 +++++ src/scripts/save_tecna_recipes_to_csv.py | 137 ++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/scripts/save_tecna_recipes_to_csv.py diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index cfba77b..e138835 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -360,3 +360,38 @@ class TecnaMarpossProvasetT3(ModbusComponent): self.write_recipe(recipe, step, table=i) self.log.info(f"saved {min(len(recipes), max(self.max_program_number - 1, 0))} recipes") self._store_recipes_lock.release(1) + + def read_recipe(self, recipe_number, step): + spec = { + "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_qneg"], + "Q+ Upper test leak limit": step.spec["test_pressure_qpos"], + "FST - Discharge time": step.spec["flush_time"], + "FSL - Discharge limit": step.spec["flush_pressure"], + } + if self.model == "t3p": + spec.update({ + "PREL - Nominal test pressure": step.spec["test_pressure"], + }) + elif self.model == "t3l": + spec.update({ + "Nominal peak pressure": step.spec["test_pressure"], + }) + else: + raise NotImplementedError(f"tecna t3 model {self.model!r} not implemented.") + + # SET RECIPE NUMBER + self.write("Active test program number", recipe_number) + + read_recipe={} + # READ ALL PARAMETERS + for register_name, field_name in spec.items(): + read_recipe[field_name] = self.read(register_name) + + return read_recipe diff --git a/src/scripts/save_tecna_recipes_to_csv.py b/src/scripts/save_tecna_recipes_to_csv.py new file mode 100644 index 0000000..4f46a48 --- /dev/null +++ b/src/scripts/save_tecna_recipes_to_csv.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +import argparse +import faulthandler +import logging +import os +import platform +import signal +import sys +import traceback +import weakref +from datetime import datetime +from pathlib import Path +from ui.diagnostics import Diagnostics +from lib.helpers.single_process import SingleProcess + +if platform.system().lower() == "windows": + sys.path.append(f"{os.getcwd()}\src\components") +else: + sys.path.append(f"{os.getcwd()}/src/components") + +app = None + +parser = argparse.ArgumentParser(prog='ST-TEN', description='Leak test system') +parser.add_argument('-s', '--system-id') +args, unspec = parser.parse_known_args() + + +def quit_app(signalnum=None, handler=None): + logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}") + global app + if app is not None: + app.quit() + quit() + + +# SETUP QUITTING ON CTRL+C +signal.signal(signal.SIGINT, quit_app) + +# SETUP FAULTHANDLER +faulthandler.enable(file=sys.stderr, all_threads=True) + +# SETUP LOGS +logs_dir = Path(".") / "data" / "logs" +os.makedirs(logs_dir, exist_ok=True) +logging.basicConfig( + format="{asctime}:{name}:{levelname}:{message}", + datefmt="%Y-%m-%d_%H-%M-%S", + style="{", + level="DEBUG" if "--debug" in sys.argv else "INFO", + handlers=[ + logging.StreamHandler(stream=sys.stderr), + logging.FileHandler( + logs_dir / f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log", + mode="a", + encoding="utf-8", + delay=False, + **({"errors": "surrogateescape"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}), + ), + ], + force=True, + **({"encoding": "utf-8"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}), + **({"errors": "surrogateescape"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}), +) + +try: + # IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGING + from components import TecnaMarpossProvasetT3 + from lib.db import Users + from lib.helpers import ConfigReader + from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot + from PyQt5.QtWidgets import QApplication, QMessageBox + from ui import About, Archive, Login, Main_Window, Test, Users_Management, Recipe_Selection, \ + Barcode_Recipe_Selection + + + + class Main(QObject): + + def __init__(self, parent=None): + # print(f"MAIN {int(QThread.currentThreadId())}", flush=True) + super().__init__() + try: + # READ CONFIG + + system_id = args.system_id if "system_id" in args else None + + self.config = ConfigReader(system_id=system_id) + logging.info(f"STARTING SESSION ON MACHINE {self.config['machine']['description']}") + # INIT COMPONENT + self.components_specs = { + "tecna_t3": {"c": TecnaMarpossProvasetT3, "k": {"paused": True}}, + } + + self.components = {} + self.threads = {} + for component_name, spec in self.components_specs.items(): + self.components[component_name] = spec["c"](*spec.get("a", []), config=self.config, + name=component_name, **spec.get("k", {})) + if spec.get("t", True): + self.threads[component_name] = QThread() + self.threads[component_name].setTerminationEnabled(True) + self.components[component_name].moveToThread(self.threads[component_name]) + + for component_name, thread in self.threads.items(): + component = self.components[component_name] + thread.started.connect(component.start) + thread.start() + # DEBUGGER WORKAROUND + QApplication.processEvents() + QThread.msleep(1000) + QApplication.processEvents() + component.wait_completion() + + except Exception as e: + logging.exception(traceback.format_exc()) + QMessageBox.critical(None, "Errore", f"Errore di avvio del programma di collaudo:\n\n{e}") + quit() + + def save_recipes(self): + self.components["tecna_t3"].read_recipes + + + if __name__ == "__main__": + app = QApplication(sys.argv) + + with SingleProcess() as single_process_lock: + if not single_process_lock and "--no-lock" not in sys.argv: + logging.error(f"Program already opened, exiting...") + QMessageBox.critical(None, "ERRORE", "IL PROGRAMMA E' GIA' IN ESECUZIONE") + exit(0) + + main = Main() + if "--no-gui" not in sys.argv: + app.exec() + +except Exception: + logging.exception(traceback.format_exc()) From ded52c83d82e7a482a9d9b3187e0b47b9a981a4e Mon Sep 17 00:00:00 2001 From: neonb Date: Mon, 30 Sep 2024 14:25:38 +0200 Subject: [PATCH 06/88] new recipes st-ten-11 --- .../st-ten-11/07N131597.svg | 113 ++++++++++++++++++ .../st-ten-11/07N131628.svg | 68 +++++++++++ 2 files changed, 181 insertions(+) create mode 100644 config/instruction_images/st-ten-11/07N131597.svg create mode 100644 config/instruction_images/st-ten-11/07N131628.svg diff --git a/config/instruction_images/st-ten-11/07N131597.svg b/config/instruction_images/st-ten-11/07N131597.svg new file mode 100644 index 0000000..1d15486 --- /dev/null +++ b/config/instruction_images/st-ten-11/07N131597.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/07N131628.svg b/config/instruction_images/st-ten-11/07N131628.svg new file mode 100644 index 0000000..332702c --- /dev/null +++ b/config/instruction_images/st-ten-11/07N131628.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + From 63f95b4e61242fe6567c9205d63ef03baaf68b89 Mon Sep 17 00:00:00 2001 From: neo Date: Tue, 1 Oct 2024 13:03:51 +0200 Subject: [PATCH 07/88] ferrari label on st ten 1 --- .../label_templates/st-ten-1/ferrari_c01.prn | 53 +++++++++++++++++ .../st-ten-1/ferrari_stten8.prn | 58 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 config/label_templates/st-ten-1/ferrari_c01.prn create mode 100644 config/label_templates/st-ten-1/ferrari_stten8.prn diff --git a/config/label_templates/st-ten-1/ferrari_c01.prn b/config/label_templates/st-ten-1/ferrari_c01.prn new file mode 100644 index 0000000..15efb50 --- /dev/null +++ b/config/label_templates/st-ten-1/ferrari_c01.prn @@ -0,0 +1,53 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD20 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW472 +^LL1654 +^LS0 +^FT40,729^A0N,38,33^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT259,729^A0N,38,33^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 +^FT27,1497^A0N,46,46^FH\^CI28^FDESITO:^FS^CI27 +^FT213,1497^A0N,46,46^FH\^CI28^FDCONFORME^FS^CI27 +^FT43,130^A0N,38,38^FH\^CI28^FDNumero Disegno^FS^CI27 +^FT40,683^A0N,38,38^FH\^CI28^FDData/Ora Prova^FS^CI27 +^FT40,784^A0N,38,38^FH\^CI28^FDStazione: {STATION}^FS^CI27 +^FT40,615^A0N,38,38^FH\^CI28^FDN. Pezzo:^FS^CI27 +^FT200,617^A0N,38,38^FH\^CI28^FD{SN5}^FS^CI27 +^FT40,831^A0N,38,38^FH\^CI28^FDOPERATORE: {OPERATOR}^FS^CI27 +^FO77,960^GB318,0,12^FS +^FT28,1043^A0N,38,38^FH\^CI28^FDP. prova:^FS^CI27 +^FT28,1090^A0N,38,38^FH\^CI28^FDP. rilevata:^FS^CI27 +^FT214,1090^A0N,38,38^FH\^CI28^FD{RESPSET}mbar^FS^CI27 +^FT28,1130^A0N,38,38^FH\^CI28^FDCaduta ammessa:^FS^CI27 +^FT305,1130^A0N,38,38^FH\^CI28^FD{PMIN} mbar^FS^CI27 +^FT28,1179^A0N,38,38^FH\^CI28^FDCaduta rilevata:^FS^CI27 +^FT264,1179^A0N,38,38^FH\^CI28^FD{RESLEAK} mbar^FS^CI27 +^FT28,1342^A0N,38,38^FH\^CI28^FDT.Prova^FS^CI27 +^FT306,1348^A0N,38,38^FH\^CI28^FD{TTEST} s^FS^CI27 +^FT27,1278^A0N,38,38^FH\^CI28^FDT.Riempim.^FS^CI27 +^FT306,1278^A0N,38,38^FH\^CI28^FD{TFILL} s^FS^CI27 +^FT28,1310^A0N,38,38^FH\^CI28^FDT.Stabilizzazione^FS^CI27 +^FT306,1313^A0N,38,38^FH\^CI28^FD{TSET} s^FS^CI27 +^FT214,1043^A0N,38,38^FH\^CI28^FD{PTEST} mbar^FS^CI27 +^FT46,352^BXN,9,200,0,0,1,_,1 +^FH\^FD{PART}{MO}{YY}{SN5}^FS +^FT43,425^A0N,38,38^FH\^CI28^FD{PART}{MO}{YY}{SN5}^FS^CI27 +^PQ1,0,1,Y +^XZ diff --git a/config/label_templates/st-ten-1/ferrari_stten8.prn b/config/label_templates/st-ten-1/ferrari_stten8.prn new file mode 100644 index 0000000..ab9abe9 --- /dev/null +++ b/config/label_templates/st-ten-1/ferrari_stten8.prn @@ -0,0 +1,58 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD20 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW336 +^LL1055 +^LS0 +^FT65,66^A0N,39,38^FH\^CI28^FDERRECINQUE^FS^CI27 +^FT52,403^BQN,2,7 +^FH\^FDLA,{PART}^FS +^FT23,436^A0N,31,30^FH\^CI28^FDPart number:^FS^CI27 +^FT23,527^A0N,31,30^FH\^CI28^FD{PART}^FS^CI27 +^FT25,101^A0N,17,18^FH\^CI28^FDVia Meucci 31/A - 10079 Mappano(TO)^FS^CI27 +^FT61,173^A0N,39,38^FH\^CI28^FD{CLIENT}^FS^CI27 +^FT61,211^A0N,39,38^FH\^CI28^FDLEAK TEST^FS^CI27 +^FT23,921^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT169,921^A0N,23,23^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 +^FT25,1006^A0N,31,30^FH\^CI28^FDCHECK:^FS^CI27 +^FT151,1006^A0N,31,30^FH\^CI28^FDPASSED^FS^CI27 +^FT23,964^A0N,25,25^FH\^CI28^FDOperator:^FS^CI27 +^FT151,964^A0N,25,25^FH\^CI28^FD{OPERATOR}^FS^CI27 +^FT23,489^A0N,31,30^FH\^CI28^FD{DESCRIPTION}^FS^CI27 +^FT23,567^A0N,31,30^FH\^CI28^FDSequential number:^FS^CI27 +^FT23,602^A0N,31,30^FH\^CI28^FD{SN5}^FS^CI27 +^FT27,658^A0N,28,28^FH\^CI28^FDTest 1:^FS^CI27 +^FT27,685^A0N,23,23^FH\^CI28^FDMeasured press.:^FS^CI27 +^FT199,687^A0N,20,20^FH\^CI28^FD{RESPSET} mbar^FS^CI27 +^FT27,707^A0N,23,23^FH\^CI28^FDAllowed leak:^FS^CI27 +^FT199,709^A0N,20,20^FH\^CI28^FD{PMIN} mbar^FS^CI27 +^FT27,730^A0N,23,23^FH\^CI28^FDMeasured leak:^FS^CI27 +^FT187,731^A0N,20,20^FH\^CI28^FD{RESLEAK} mbar^FS^CI27 +^FT27,817^A0N,23,23^FH\^CI28^FDMeasure time:^FS^CI27 +^FT215,818^A0N,20,20^FH\^CI28^FD{TTEST} s^FS^CI27 +^FT26,773^A0N,23,23^FH\^CI28^FDFill time:^FS^CI27 +^FT215,770^A0N,20,20^FH\^CI28^FD{TFILL} s^FS^CI27 +^FT27,795^A0N,23,23^FH\^CI28^FDSettling time:^FS^CI27 +^FT215,794^A0N,20,20^FH\^CI28^FD{TSET} s^FS^CI27 +^FT136,658^A0N,28,28^FH\^CI28^FD{PTEST} mbar^FS^CI27 +^FT151,124^A0N,17,18^FH\^CI28^FDItaly^FS^CI27 +^FT27,893^A0N,23,23^FH\^CI28^FDTest date/time:^FS^CI27 +^PQ1,0,1,Y +^XZ From dd88b1eafaaa5e9fce00577b72a1627b0ee333fa Mon Sep 17 00:00:00 2001 From: neo Date: Fri, 4 Oct 2024 11:39:16 +0200 Subject: [PATCH 08/88] save recipes wip --- config/machine_settings/st-ten-1-linux.ini | 97 +++++++++---- config/machine_settings/test-linux.ini | 107 ++++++++++++++ src/components/tecna_marposs_provaset_t3.py | 36 ++--- src/scripts/save_tecna_recipes_to_csv.py | 146 ++++++++++++++++++-- src/ui/crud/crud.py | 2 + src/ui/recipe_selection/recipe_selection.py | 3 + src/ui/test_leak/test_leak.py | 8 +- 7 files changed, 342 insertions(+), 57 deletions(-) create mode 100644 config/machine_settings/test-linux.ini diff --git a/config/machine_settings/st-ten-1-linux.ini b/config/machine_settings/st-ten-1-linux.ini index 7561095..b88254e 100644 --- a/config/machine_settings/st-ten-1-linux.ini +++ b/config/machine_settings/st-ten-1-linux.ini @@ -1,66 +1,107 @@ [machine] -description = ST-TEN-2 - COLLAUDO TUBI RISCALDATI VOLPIANO -instruction_folder = st-ten-2 -image_for_warning= st-ten-2 +description = ST-TEN-1 +instruction_folder = st-ten-1 +image_for_warning= st-ten-1 [hardware_config] archive_synchronizer: present +galaxy_camera: absent +uvc_camera: absent label_printer: present +neo_pixels: absent remote_api: absent tecna_t3: present - -[digital_io] -# OUTPUT MAP FOR EXTERNAL FLUSH/BLOW UNIT -id_flush_blow: USB-5860,BID#0 -blow_on: 0 # INPUT VALVE TO SERVICE AIR -flush_on: 1 # OUTPUT VALVE TO DIRT COLLECTOR -blow_led:2 # CLEAN INDICATOR -test_on_led:3 # LEAK TEST ACTIVE INDICATOR -flush_led:4 # FLUSH INDICATOR +vision_saver: absent +vision: absent +screwdriver: absent +fixture_id: absent +digital_io: present +external_flush_blow: absent [tecna_t3] port: /dev/ttyUSB0 +model: t3l + +[fixture_rfid] +port: COM5 + +[digital_io] +# OUTPUT MAP FOR FIXTURE CONNECTOR +id_fixture: USB-5862,BID#0 +discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING [recipe] -recipe_name_field: cod finito cliente -part_number_field: cod finito r5 -barcode_enable_field: verifica_codice_a_barre_abilitata -barcode_serial_field: codice_a_barre -label_template_field: etichetta -description_field: cod semilavorato costampato +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[label_printer] +platform: windows +printer: zd420 [recipes_defaults] -prova_tenuta_abilitata: x +tester_discharge_enable: yes +codice_ricetta: specificare ricetta +cliente: IVECO +part_number: specificare part number +canale_di_prova: 0 warning_img: + +dimensione_lotto_abilitata: n_componenti:1 +istruzione_abilitata: x +numero nastri (n):0 +numero sensori anello (sa):0 +numero sensori presenza (sp):0 + +prova_tenuta_abilitata: x tempo_pre_riempimento: 0 -pressione_pre_riempimento: 1000 -tempo_riempimento: 10 +pressione_pre_riempimento: 5000 +tempo_riempimento: 5 tempo_assestamento: 10 percentuale_minima_pressione_assestamento: 5 percentuale_massima_pressione_assestamento: 5 tempo_di_test: 10 pressione_di_test_delta_minimo: 30 -pressione_di_test: 15000 +pressione_di_test: 5000 pressione_di_test_delta_massimo: 30 tempo_svuotamento: 1 pressione_svuotamento: 100 -canale_di_prova: 0 -tester_discharge_enable: yes + +prova_tenuta_abilitata_2: +tempo_pre_riempimento_2: 0 +pressione_pre_riempimento_2: 1000 +tempo_riempimento_2: 5 +tempo_assestamento_2: 5 +percentuale_minima_pressione_assestamento_2: 5 +percentuale_massima_pressione_assestamento_2: 5 +tempo_di_test_2: 5 +pressione_di_test_delta_minimo_2: 200 +pressione_di_test_2: 1000 +pressione_di_test_delta_massimo_2: 200 +tempo_svuotamento_2: 1 +pressione_svuotamento_2: 100 + +stampa_etichetta_abilitata: x +modello_etichetta: ETA30x16_203dpi.prn +descrizione: inserire descrizione ricetta [autotest_leak] enabled: true pre_filling_time: 0 pre_filling_pressure: 1000 -filling_time: 5 +filling_time: 10 settling_time: 10 settling_pressure_min_percent: 5 settling_pressure_max_percent: 5 +test_pressure: 7000 test_time: 10 -test_pressure_qneg: 5 -test_pressure: 9000 -test_pressure_qpos: 5 +test_pressure_qpos: 10 #Q+ Upper test leak limit +test_pressure_qneg: 30 #Q- Lower test leak limit +test_pressure_tt_qpos: 1 # Q+ Upper test leak limit (tube-tube) +test_pressure_tt_qneg: 5 # Q- Lower test leak limit (tube-tube) flush_time: 1 flush_pressure: 100 relay_config: 1 \ No newline at end of file diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini new file mode 100644 index 0000000..490c522 --- /dev/null +++ b/config/machine_settings/test-linux.ini @@ -0,0 +1,107 @@ +[machine] +description = TEST-LINUX +instruction_folder = st-ten-1 +image_for_warning= st-ten-1 + + +[hardware_config] +archive_synchronizer: absent +galaxy_camera: absent +uvc_camera: absent +label_printer: present +neo_pixels: absent +remote_api: absent +tecna_t3: present +vision_saver: absent +vision: absent +screwdriver: absent +fixture_id: absent +digital_io: absent +external_flush_blow: absent + +[tecna_t3] +port: /dev/ttyUSB0 +model: t3p + +[fixture_rfid] +port: COM5 + +[digital_io] +# OUTPUT MAP FOR FIXTURE CONNECTOR +id_fixture: USB-5862,BID#0 +discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING + +[recipe] +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[label_printer] +platform: windows +printer: zd420 + +[recipes_defaults] +tester_discharge_enable: yes +codice_ricetta: specificare ricetta +cliente: IVECO +part_number: specificare part number +canale_di_prova: 0 +warning_img: + +dimensione_lotto_abilitata: +n_componenti:1 +istruzione_abilitata: x +numero nastri (n):0 +numero sensori anello (sa):0 +numero sensori presenza (sp):0 + +prova_tenuta_abilitata: x +tempo_pre_riempimento: 0 +pressione_pre_riempimento: 5000 +tempo_riempimento: 5 +tempo_assestamento: 10 +percentuale_minima_pressione_assestamento: 5 +percentuale_massima_pressione_assestamento: 5 +tempo_di_test: 10 +pressione_di_test_delta_minimo: 30 +pressione_di_test: 5000 +pressione_di_test_delta_massimo: 30 +tempo_svuotamento: 1 +pressione_svuotamento: 100 + +prova_tenuta_abilitata_2: +tempo_pre_riempimento_2: 0 +pressione_pre_riempimento_2: 1000 +tempo_riempimento_2: 5 +tempo_assestamento_2: 5 +percentuale_minima_pressione_assestamento_2: 5 +percentuale_massima_pressione_assestamento_2: 5 +tempo_di_test_2: 5 +pressione_di_test_delta_minimo_2: 200 +pressione_di_test_2: 1000 +pressione_di_test_delta_massimo_2: 200 +tempo_svuotamento_2: 1 +pressione_svuotamento_2: 100 + +stampa_etichetta_abilitata: x +modello_etichetta: ETA30x16_203dpi.prn +descrizione: inserire descrizione ricetta + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 10 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_pressure: 7000 +test_time: 10 +test_pressure_qpos: 10 #Q+ Upper test leak limit +test_pressure_qneg: 30 #Q- Lower test leak limit +test_pressure_tt_qpos: 1 # Q+ Upper test leak limit (tube-tube) +test_pressure_tt_qneg: 5 # Q- Lower test leak limit (tube-tube) +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index e138835..65fea7c 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -361,27 +361,29 @@ class TecnaMarpossProvasetT3(ModbusComponent): self.log.info(f"saved {min(len(recipes), max(self.max_program_number - 1, 0))} recipes") self._store_recipes_lock.release(1) - def read_recipe(self, recipe_number, step): + # SELECT & READ RECIPE FROM TECNA MEMORY + + def read_recipe(self, recipe_number): spec = { - "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_qneg"], - "Q+ Upper test leak limit": step.spec["test_pressure_qpos"], - "FST - Discharge time": step.spec["flush_time"], - "FSL - Discharge limit": step.spec["flush_pressure"], + "T0 - Pre-filling time": "pre_filling_time", + "P0 - Pre-filling pressure": "pre_filling_pressure", + "T1 - Filling time": "filling_time", + "T2 - Settling time": "settling_time", + "PR- - Min pressure tolerance %": "settling_pressure_min_percent", + "PR+ - Max pressure tolerance % (P+)": "settling_pressure_max_percent", + "T3 - Measure time": "test_time", + "Q- Lower test leak limit": "test_pressure_qneg", + "Q+ Upper test leak limit": "test_pressure_qpos", + "FST - Discharge time": "flush_time", + "FSL - Discharge limit": "flush_pressure", } if self.model == "t3p": spec.update({ - "PREL - Nominal test pressure": step.spec["test_pressure"], + "PREL - Nominal test pressure": "test_pressure", }) elif self.model == "t3l": spec.update({ - "Nominal peak pressure": step.spec["test_pressure"], + "Nominal peak pressure": "test_pressure", }) else: raise NotImplementedError(f"tecna t3 model {self.model!r} not implemented.") @@ -389,9 +391,9 @@ class TecnaMarpossProvasetT3(ModbusComponent): # SET RECIPE NUMBER self.write("Active test program number", recipe_number) - read_recipe={} + recipe_data={} # READ ALL PARAMETERS for register_name, field_name in spec.items(): - read_recipe[field_name] = self.read(register_name) + recipe_data[field_name] = self.read(register_name) - return read_recipe + return recipe_data diff --git a/src/scripts/save_tecna_recipes_to_csv.py b/src/scripts/save_tecna_recipes_to_csv.py index 4f46a48..3e6dfb6 100644 --- a/src/scripts/save_tecna_recipes_to_csv.py +++ b/src/scripts/save_tecna_recipes_to_csv.py @@ -1,11 +1,16 @@ #!/usr/bin/env python3 import argparse +import csv import faulthandler import logging import os import platform import signal import sys +sys.argv.append("--debug") +sys.argv.append("--sim-io") +sys.argv.append("--system-id=test-linux") + import traceback import weakref from datetime import datetime @@ -24,7 +29,6 @@ parser = argparse.ArgumentParser(prog='ST-TEN', description='Leak test system') parser.add_argument('-s', '--system-id') args, unspec = parser.parse_known_args() - def quit_app(signalnum=None, handler=None): logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}") global app @@ -68,7 +72,7 @@ try: from lib.db import Users from lib.helpers import ConfigReader from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot - from PyQt5.QtWidgets import QApplication, QMessageBox + from PyQt5.QtWidgets import QApplication, QMessageBox, QFileDialog from ui import About, Archive, Login, Main_Window, Test, Users_Management, Recipe_Selection, \ Barcode_Recipe_Selection @@ -79,6 +83,7 @@ try: def __init__(self, parent=None): # print(f"MAIN {int(QThread.currentThreadId())}", flush=True) super().__init__() + self.recipes = None try: # READ CONFIG @@ -116,20 +121,145 @@ try: QMessageBox.critical(None, "Errore", f"Errore di avvio del programma di collaudo:\n\n{e}") quit() - def save_recipes(self): - self.components["tecna_t3"].read_recipes + def read_recipes(self): + self.recipes = {} + for recipe_num in range(1,100): + self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num) + + def export_recipes(self, csv_path=None): + if csv_path is None: + csv_path, _ = QFileDialog.getSaveFileName( + None, + "Esportazione ricette", + "ricette.csv", + "CSV data (*.csv);;All Files (*)", + ) + csv_path = str(csv_path) + if not len(csv_path): + return + if not csv_path.lower().endswith(".csv"): + csv_path += ".csv" + csv_dir = os.path.dirname(csv_path) + if len(csv_dir): + os.makedirs(csv_dir, exist_ok=True) + data = [] + fieldnames = [ + "ricetta", + "cliente", + "part_number", + "dimensione_lotto_abilitata", + "dimensione_lotto", + "verifica_connettore_abilitata", + "connettore", + "verifica_resistenza_connettore_abilitata", + "scala_resistenza", + "r nominale", + "tolleranza_resistenza_pos", + "tolleranza_resistenza_neg", + "avvitatura_abilitata", + "viti", + "prova_tenuta_abilitata", + "tempo_pre_riempimento", + "pressione_pre_riempimento", + "tempo_riempimento", + "tempo_assestamento", + "percentuale_minima_pressione_assestamento", + "percentuale_massima_pressione_assestamento", + "tempo_di_test", + "pressione_di_test_delta_minimo", + "pressione_di_test", + "pressione_di_test_delta_massimo", + "tempo_svuotamento", + "pressione_svuotamento", + "prova_tenuta_abilitata_2", + "tempo_pre_riempimento_2", + "pressione_pre_riempimento_2", + "tempo_riempimento_2", + "tempo_assestamento_2", + "percentuale_minima_pressione_assestamento_2", + "percentuale_massima_pressione_assestamento_2", + "tempo_di_test_2", + "pressione_di_test_delta_minimo_2", + "pressione_di_test_2", + "pressione_di_test_delta_massimo_2", + "tempo_svuotamento_2", + "pressione_svuotamento_2", + "test_visione_abilitato", + "ricetta_visione", + "stampa_etichetta_abilitata", + print_template_field, + ] + for num,recipe in self.recipes.items(): + steps = recipe.get_steps_map() + exportable = { + recipe_name_field: recipe.name, + "cliente": recipe.client, + "part_number": recipe.part_number, + # "dimensione_lotto_abilitata": "x" if recipe.spec["count"] else "", + # "dimensione_lotto": steps["count"].spec["amount"], + "verifica_connettore_abilitata": "x" if recipe.spec["connector"] else "", + "connettore": steps["connector"].spec["connector"], + barcode_enable_field: "x" if recipe.spec["barcodes"] else "", + barcode_serial_field: steps["barcodes"].spec["serial"], + "verifica_resistenza_connettore_abilitata": "x" if recipe.spec["resistance"] else "", + "scala_resistenza": steps["resistance"].spec["scale"], + "r nominale": steps["resistance"].spec["expected"], + "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], + "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"], + # "avvitatura_abilitata": "x" if recipe.spec["screws"] else "", + # "viti": steps["screws"].spec["quantity"], + "prova_tenuta_abilitata": "x" if recipe.spec["leak_1"] else "", + "tempo_pre_riempimento": steps["leak_1"].spec["pre_filling_time"], + "pressione_pre_riempimento": steps["leak_1"].spec["pre_filling_pressure"], + "tempo_riempimento": steps["leak_1"].spec["filling_time"], + "tempo_assestamento": steps["leak_1"].spec["settling_time"], + "percentuale_minima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_min_percent"], + "percentuale_massima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_max_percent"], + "tempo_di_test": steps["leak_1"].spec["test_time"], + "pressione_di_test_delta_minimo": steps["leak_1"].spec["test_pressure_qneg"], + "pressione_di_test": steps["leak_1"].spec["test_pressure"], + "pressione_di_test_delta_massimo": steps["leak_1"].spec["test_pressure_qpos"], + "tempo_svuotamento": steps["leak_1"].spec["flush_time"], + "pressione_svuotamento": steps["leak_1"].spec["flush_pressure"], + "prova_tenuta_abilitata_2": "x" if recipe.spec["leak_2"] else "", + "tempo_pre_riempimento_2": steps["leak_2"].spec["pre_filling_time"], + "pressione_pre_riempimento_2": steps["leak_2"].spec["pre_filling_pressure"], + "tempo_riempimento_2": steps["leak_2"].spec["filling_time"], + "tempo_assestamento_2": steps["leak_2"].spec["settling_time"], + "percentuale_minima_pressione_assestamento_2": steps["leak_2"].spec[ + "settling_pressure_min_percent"], + "percentuale_massima_pressione_assestamento_2": steps["leak_2"].spec[ + "settling_pressure_max_percent"], + "tempo_di_test_2": steps["leak_2"].spec["test_time"], + "pressione_di_test_delta_minimo_2": steps["leak_2"].spec["test_pressure_qneg"], + "pressione_di_test_2": steps["leak_2"].spec["test_pressure"], + "pressione_di_test_delta_massimo_2": steps["leak_2"].spec["test_pressure_qpos"], + "tempo_svuotamento_2": steps["leak_2"].spec["flush_time"], + "pressione_svuotamento_2": steps["leak_2"].spec["flush_pressure"], + "test_visione_abilitato": recipe.spec["vision"], + "ricetta_visione": steps["vision"].spec["recipe"], + "stampa_etichetta_abilitata": "x" if recipe.spec["print"] else "", + "modello_etichetta": steps["print"].spec["template"], + } + data.append(exportable) + if len(data): + self.log.info(f"recipes: exporting recipes to {csv_path}") + with open(csv_path, "w", newline="") as f: + w = csv.DictWriter(f, fieldnames, extrasaction="ignore") + w.writeheader() + w.writerows(data) + self.log.info(f"recipes: exported {len(data)} rows.") if __name__ == "__main__": app = QApplication(sys.argv) with SingleProcess() as single_process_lock: - if not single_process_lock and "--no-lock" not in sys.argv: - logging.error(f"Program already opened, exiting...") - QMessageBox.critical(None, "ERRORE", "IL PROGRAMMA E' GIA' IN ESECUZIONE") - exit(0) main = Main() + main.read_recipes() + main.export_recipes() + if "--no-gui" not in sys.argv: app.exec() diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 57b633c..2b4181c 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -1,5 +1,6 @@ import ast import json +import logging import traceback import weakref from datetime import datetime @@ -40,6 +41,7 @@ class Cell: modified = pyqtSignal(bool) def __init__(self, action=None, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None): + self.log = logging.getLogger(f"{self.__class__.__name__} ({id(self)})") self.readonly = readonly self.autocomplete = autocomplete self.field_name = field_name diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 98d6675..614400d 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -182,6 +182,7 @@ class Recipe_Selection(Widget): val = dict.get(key, self.defaults[key]) return val if val != "" else self.defaults[key] + # READ RECIPE STEPS FROM CSV ROW def read_steps(self, row, defaults=None): if defaults is None: global noner @@ -273,6 +274,7 @@ class Recipe_Selection(Widget): }, } + # IMPORT RECIPES FROM CSV FILE TO DATABASE def import_recipes(self, csv_path=None, defaults=None): if defaults is None: global noner @@ -341,6 +343,7 @@ class Recipe_Selection(Widget): self.log.info(f"recipes: imported {count} rows.") self.crud.refresh() + # EXPORT RECIPES TABLE TO CSV FILE def export_recipes(self, csv_path=None): if csv_path is None: csv_path, _ = QFileDialog.getSaveFileName( diff --git a/src/ui/test_leak/test_leak.py b/src/ui/test_leak/test_leak.py index 24b77b1..0728174 100644 --- a/src/ui/test_leak/test_leak.py +++ b/src/ui/test_leak/test_leak.py @@ -43,7 +43,7 @@ class Test_Leak(Test_Test): def start_test(self): # print extra labels - if self.step.type == "leak_1": + if self.step.step_type == "leak_1": self.parent.print_extra_labels() # SELECT TEST CHANNEL @@ -93,8 +93,8 @@ class Test_Leak(Test_Test): if show is False: return show - if "leak_2" in [s.type for s in self.parent.cycle_steps]: - if self.step.type=="leak_1": + if "leak_2" in [s.step_type for s in self.parent.cycle_steps]: + if self.step.step_type=="leak_1": self.test_num_l.setText("1/2") else: self.test_num_l.setText("2/2") @@ -143,7 +143,7 @@ class Test_Leak(Test_Test): time.sleep(2) # AUTO START SECOND TEST - if step.type == "leak_2": + if step.step_type == "leak_2": self.recipe_written = False time.sleep(1) self.start_b.setEnabled(True) From 700849ef9bbe93bef4343a993121af943909c0dd Mon Sep 17 00:00:00 2001 From: gg Date: Fri, 4 Oct 2024 15:52:54 +0200 Subject: [PATCH 09/88] save recipes OK --- config/machine_settings/test-windows.ini | 107 +++++++++++++++++ src/components/tecna_marposs_provaset_t3.py | 47 +++++++- src/scripts/save_tecna_recipes_to_csv.py | 123 +++++--------------- 3 files changed, 183 insertions(+), 94 deletions(-) create mode 100644 config/machine_settings/test-windows.ini diff --git a/config/machine_settings/test-windows.ini b/config/machine_settings/test-windows.ini new file mode 100644 index 0000000..7d88955 --- /dev/null +++ b/config/machine_settings/test-windows.ini @@ -0,0 +1,107 @@ +[machine] +description = TEST-WINDOWS +instruction_folder = st-ten-1 +image_for_warning= st-ten-1 + + +[hardware_config] +archive_synchronizer: absent +galaxy_camera: absent +uvc_camera: absent +label_printer: present +neo_pixels: absent +remote_api: absent +tecna_t3: present +vision_saver: absent +vision: absent +screwdriver: absent +fixture_id: absent +digital_io: absent +external_flush_blow: absent + +[tecna_t3] +port: COM4 +model: t3p + +[fixture_rfid] +port: COM5 + +[digital_io] +# OUTPUT MAP FOR FIXTURE CONNECTOR +id_fixture: USB-5862,BID#0 +discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING + +[recipe] +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[label_printer] +platform: windows +printer: zd420 + +[recipes_defaults] +tester_discharge_enable: yes +codice_ricetta: specificare ricetta +cliente: IVECO +part_number: specificare part number +canale_di_prova: 0 +warning_img: + +dimensione_lotto_abilitata: +n_componenti:1 +istruzione_abilitata: x +numero nastri (n):0 +numero sensori anello (sa):0 +numero sensori presenza (sp):0 + +prova_tenuta_abilitata: x +tempo_pre_riempimento: 0 +pressione_pre_riempimento: 5000 +tempo_riempimento: 5 +tempo_assestamento: 10 +percentuale_minima_pressione_assestamento: 5 +percentuale_massima_pressione_assestamento: 5 +tempo_di_test: 10 +pressione_di_test_delta_minimo: 30 +pressione_di_test: 5000 +pressione_di_test_delta_massimo: 30 +tempo_svuotamento: 1 +pressione_svuotamento: 100 + +prova_tenuta_abilitata_2: +tempo_pre_riempimento_2: 0 +pressione_pre_riempimento_2: 1000 +tempo_riempimento_2: 5 +tempo_assestamento_2: 5 +percentuale_minima_pressione_assestamento_2: 5 +percentuale_massima_pressione_assestamento_2: 5 +tempo_di_test_2: 5 +pressione_di_test_delta_minimo_2: 200 +pressione_di_test_2: 1000 +pressione_di_test_delta_massimo_2: 200 +tempo_svuotamento_2: 1 +pressione_svuotamento_2: 100 + +stampa_etichetta_abilitata: x +modello_etichetta: ETA30x16_203dpi.prn +descrizione: inserire descrizione ricetta + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 10 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_pressure: 7000 +test_time: 10 +test_pressure_qpos: 10 #Q+ Upper test leak limit +test_pressure_qneg: 30 #Q- Lower test leak limit +test_pressure_tt_qpos: 1 # Q+ Upper test leak limit (tube-tube) +test_pressure_tt_qneg: 5 # Q- Lower test leak limit (tube-tube) +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 65fea7c..e89e60e 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -365,6 +365,10 @@ class TecnaMarpossProvasetT3(ModbusComponent): def read_recipe(self, recipe_number): spec = { + **{(719 - 1 + i) : f"R{i}" for i in range(8)}, + **{(727 - 1 + i) : f"C{i}" for i in range(12)}, + **{(761 - 1 + i) : f"F1_{i}" for i in range(8)}, + **{(769 - 1 + i) : f"F2_{i}" for i in range(8)}, "T0 - Pre-filling time": "pre_filling_time", "P0 - Pre-filling pressure": "pre_filling_pressure", "T1 - Filling time": "filling_time", @@ -376,6 +380,7 @@ class TecnaMarpossProvasetT3(ModbusComponent): "Q+ Upper test leak limit": "test_pressure_qpos", "FST - Discharge time": "flush_time", "FSL - Discharge limit": "flush_pressure", + "Print options": "print_options" } if self.model == "t3p": spec.update({ @@ -389,11 +394,47 @@ class TecnaMarpossProvasetT3(ModbusComponent): raise NotImplementedError(f"tecna t3 model {self.model!r} not implemented.") # SET RECIPE NUMBER - self.write("Active test program number", recipe_number) + #self.write("Source of test program number selection", "FROM PARAMETER (SET BY LCD OR SERIAL LINE)") + #self.write("Selected program", recipe_number) + self.write("Test program for read/write operation", recipe_number) - recipe_data={} + recipe_data = {} # READ ALL PARAMETERS for register_name, field_name in spec.items(): recipe_data[field_name] = self.read(register_name) - + recipe_name=self.int_array_to_str([recipe_data[f"R{wn}"] for wn in range(8)]) + recipe_code=self.int_array_to_str([recipe_data[f"C{wn}"] for wn in range(12)]) + recipe_f1=self.int_array_to_str([recipe_data[f"F1_{wn}"] for wn in range(8)]) + recipe_f2=self.int_array_to_str([recipe_data[f"F2_{wn}"] for wn in range(8)]) + recipe_data["recipe_name"]=recipe_name + recipe_data["recipe_code"]=recipe_code + recipe_data["recipe_f1"]=recipe_f1 + recipe_data["recipe_f2"]=recipe_f2 + recipe_data["print_template"] = chr(recipe_data["print_options"] & 0xFF) return recipe_data + + @staticmethod + def int_array_to_str(arr): + """ + Translates an array of 16-bit integers, where each integer contains 2 ASCII characters, + into a string. + + Args: + arr: The array of 16-bit integers. + + Returns: + The translated string. + """ + result = "" + for value in arr: + char1 = chr(value & 0xFF) + char2 = chr(value >> 8) + + # Stop if we encounter a null byte + if char1 == '\0': + break + result+=char1 + if char2 == '\0': + break + result+=char2 + return result diff --git a/src/scripts/save_tecna_recipes_to_csv.py b/src/scripts/save_tecna_recipes_to_csv.py index 3e6dfb6..f312bdc 100644 --- a/src/scripts/save_tecna_recipes_to_csv.py +++ b/src/scripts/save_tecna_recipes_to_csv.py @@ -7,9 +7,14 @@ import os import platform import signal import sys -sys.argv.append("--debug") sys.argv.append("--sim-io") -sys.argv.append("--system-id=test-linux") +sys.argv.append("--system-id=test-windows") + +if platform.system().lower() == "windows": + sys.path.append(f"{os.getcwd()}\src\components") + sys.path.append(f"{os.getcwd()}\src") +else: + sys.path.append(f"{os.getcwd()}/src/components") import traceback import weakref @@ -18,10 +23,6 @@ from pathlib import Path from ui.diagnostics import Diagnostics from lib.helpers.single_process import SingleProcess -if platform.system().lower() == "windows": - sys.path.append(f"{os.getcwd()}\src\components") -else: - sys.path.append(f"{os.getcwd()}/src/components") app = None @@ -123,7 +124,8 @@ try: def read_recipes(self): self.recipes = {} - for recipe_num in range(1,100): + for recipe_num in range(1, self.components["tecna_t3"].max_program_number+1): + logging.info(f"READING RECIPE #{recipe_num}") self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num) def export_recipes(self, csv_path=None): @@ -144,21 +146,8 @@ try: os.makedirs(csv_dir, exist_ok=True) data = [] fieldnames = [ - "ricetta", - "cliente", + "codice_ricetta", "part_number", - "dimensione_lotto_abilitata", - "dimensione_lotto", - "verifica_connettore_abilitata", - "connettore", - "verifica_resistenza_connettore_abilitata", - "scala_resistenza", - "r nominale", - "tolleranza_resistenza_pos", - "tolleranza_resistenza_neg", - "avvitatura_abilitata", - "viti", - "prova_tenuta_abilitata", "tempo_pre_riempimento", "pressione_pre_riempimento", "tempo_riempimento", @@ -171,84 +160,38 @@ try: "pressione_di_test_delta_massimo", "tempo_svuotamento", "pressione_svuotamento", - "prova_tenuta_abilitata_2", - "tempo_pre_riempimento_2", - "pressione_pre_riempimento_2", - "tempo_riempimento_2", - "tempo_assestamento_2", - "percentuale_minima_pressione_assestamento_2", - "percentuale_massima_pressione_assestamento_2", - "tempo_di_test_2", - "pressione_di_test_delta_minimo_2", - "pressione_di_test_2", - "pressione_di_test_delta_massimo_2", - "tempo_svuotamento_2", - "pressione_svuotamento_2", - "test_visione_abilitato", - "ricetta_visione", - "stampa_etichetta_abilitata", - print_template_field, + "template_di_stampa", + "campo1", + "campo2" ] for num,recipe in self.recipes.items(): - steps = recipe.get_steps_map() exportable = { - recipe_name_field: recipe.name, - "cliente": recipe.client, - "part_number": recipe.part_number, - # "dimensione_lotto_abilitata": "x" if recipe.spec["count"] else "", - # "dimensione_lotto": steps["count"].spec["amount"], - "verifica_connettore_abilitata": "x" if recipe.spec["connector"] else "", - "connettore": steps["connector"].spec["connector"], - barcode_enable_field: "x" if recipe.spec["barcodes"] else "", - barcode_serial_field: steps["barcodes"].spec["serial"], - "verifica_resistenza_connettore_abilitata": "x" if recipe.spec["resistance"] else "", - "scala_resistenza": steps["resistance"].spec["scale"], - "r nominale": steps["resistance"].spec["expected"], - "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], - "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"], - # "avvitatura_abilitata": "x" if recipe.spec["screws"] else "", - # "viti": steps["screws"].spec["quantity"], - "prova_tenuta_abilitata": "x" if recipe.spec["leak_1"] else "", - "tempo_pre_riempimento": steps["leak_1"].spec["pre_filling_time"], - "pressione_pre_riempimento": steps["leak_1"].spec["pre_filling_pressure"], - "tempo_riempimento": steps["leak_1"].spec["filling_time"], - "tempo_assestamento": steps["leak_1"].spec["settling_time"], - "percentuale_minima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_min_percent"], - "percentuale_massima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_max_percent"], - "tempo_di_test": steps["leak_1"].spec["test_time"], - "pressione_di_test_delta_minimo": steps["leak_1"].spec["test_pressure_qneg"], - "pressione_di_test": steps["leak_1"].spec["test_pressure"], - "pressione_di_test_delta_massimo": steps["leak_1"].spec["test_pressure_qpos"], - "tempo_svuotamento": steps["leak_1"].spec["flush_time"], - "pressione_svuotamento": steps["leak_1"].spec["flush_pressure"], - "prova_tenuta_abilitata_2": "x" if recipe.spec["leak_2"] else "", - "tempo_pre_riempimento_2": steps["leak_2"].spec["pre_filling_time"], - "pressione_pre_riempimento_2": steps["leak_2"].spec["pre_filling_pressure"], - "tempo_riempimento_2": steps["leak_2"].spec["filling_time"], - "tempo_assestamento_2": steps["leak_2"].spec["settling_time"], - "percentuale_minima_pressione_assestamento_2": steps["leak_2"].spec[ - "settling_pressure_min_percent"], - "percentuale_massima_pressione_assestamento_2": steps["leak_2"].spec[ - "settling_pressure_max_percent"], - "tempo_di_test_2": steps["leak_2"].spec["test_time"], - "pressione_di_test_delta_minimo_2": steps["leak_2"].spec["test_pressure_qneg"], - "pressione_di_test_2": steps["leak_2"].spec["test_pressure"], - "pressione_di_test_delta_massimo_2": steps["leak_2"].spec["test_pressure_qpos"], - "tempo_svuotamento_2": steps["leak_2"].spec["flush_time"], - "pressione_svuotamento_2": steps["leak_2"].spec["flush_pressure"], - "test_visione_abilitato": recipe.spec["vision"], - "ricetta_visione": steps["vision"].spec["recipe"], - "stampa_etichetta_abilitata": "x" if recipe.spec["print"] else "", - "modello_etichetta": steps["print"].spec["template"], + "codice_ricetta": recipe["recipe_name"], + "part_number": recipe["recipe_code"], + "campo1": recipe["recipe_f1"], + "campo2": recipe["recipe_f2"], + "tempo_pre_riempimento": recipe["pre_filling_time"], + "pressione_pre_riempimento": recipe["pre_filling_pressure"], + "tempo_riempimento": recipe["filling_time"], + "tempo_assestamento": recipe["settling_time"], + "percentuale_minima_pressione_assestamento": recipe["settling_pressure_min_percent"], + "percentuale_massima_pressione_assestamento": recipe["settling_pressure_max_percent"], + "tempo_di_test": recipe["test_time"], + "pressione_di_test_delta_minimo": recipe["test_pressure_qneg"], + "pressione_di_test": recipe["test_pressure"], + "pressione_di_test_delta_massimo": recipe["test_pressure_qpos"], + "tempo_svuotamento": recipe["flush_time"], + "pressione_svuotamento": recipe["flush_pressure"], + "template_di_stampa": recipe["print_template"], } data.append(exportable) if len(data): - self.log.info(f"recipes: exporting recipes to {csv_path}") + logging.info(f"recipes: exporting recipes to {csv_path}") with open(csv_path, "w", newline="") as f: w = csv.DictWriter(f, fieldnames, extrasaction="ignore") w.writeheader() w.writerows(data) - self.log.info(f"recipes: exported {len(data)} rows.") + logging.info(f"recipes: exported {len(data)} rows.") if __name__ == "__main__": @@ -260,8 +203,6 @@ try: main.read_recipes() main.export_recipes() - if "--no-gui" not in sys.argv: - app.exec() except Exception: logging.exception(traceback.format_exc()) From fd632bee8e194c0c837ffd0df2ed8185b56d06d6 Mon Sep 17 00:00:00 2001 From: neo Date: Fri, 4 Oct 2024 19:06:04 +0200 Subject: [PATCH 10/88] remove steps table wip add recipe & first save ok --- .../barcodes_step_editor.ui | 108 +++++++++--------- .../recipe_spec_and_step_editor.py | 35 +++--- 2 files changed, 69 insertions(+), 74 deletions(-) diff --git a/src/ui/barcodes_step_editor/barcodes_step_editor.ui b/src/ui/barcodes_step_editor/barcodes_step_editor.ui index c65c4b8..8a09e06 100644 --- a/src/ui/barcodes_step_editor/barcodes_step_editor.ui +++ b/src/ui/barcodes_step_editor/barcodes_step_editor.ui @@ -6,8 +6,8 @@ 0 0 - 538 - 234 + 1004 + 300 @@ -29,102 +29,102 @@ - 10 - 33 - 52 - 16 + 20 + 50 + 81 + 20 - Seriale-1 + Barcode 1 - 68 - 33 - 133 - 22 + 100 + 40 + 321 + 36 - 68 - 68 - 133 - 22 + 100 + 80 + 321 + 36 - 10 - 68 - 52 - 16 + 20 + 90 + 81 + 20 - Seriale-2 + Barcode 2 - 68 - 103 - 133 - 22 + 100 + 120 + 321 + 36 - 10 - 103 - 52 - 16 + 20 + 130 + 81 + 20 - Seriale-3 + Barcode 3 - 68 - 138 - 133 - 22 + 100 + 160 + 321 + 36 - 10 - 138 - 52 - 16 + 20 + 170 + 81 + 20 - Seriale-4 + Barcode 4 - 297 - 33 - 133 - 22 + 610 + 40 + 321 + 36 @@ -134,9 +134,9 @@ - 207 - 33 - 84 + 480 + 50 + 131 16 @@ -147,10 +147,10 @@ - 68 - 173 - 133 - 22 + 100 + 200 + 321 + 36 @@ -160,14 +160,14 @@ - 10 - 173 - 52 - 16 + 20 + 210 + 81 + 20 - Seriale-4 + Barcode 5 diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index bb124df..7d5b217 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -120,10 +120,6 @@ class Recipe_Spec_And_Step_Editor(Editor): if editor is not None: editor.do_autocomplete(step_editors_autocomplete.get(step_name, None)) - def init(self, action=None): - if action == "add": - self.save_steps() - def showing_dialog(self): self.reset_steps() @@ -136,17 +132,18 @@ class Recipe_Spec_And_Step_Editor(Editor): def parse(self, action=None, row_number=None, crud=None): ret = super().parse(row_number=row_number, crud=crud) - ret["steps"] = [] - for step_name, map in self.steps_map.items(): - if map["enable"].isChecked() and not map.get("hidden", False): - ret["steps"].append(map["step"].name) + ret["steps"] = {} + self.save_steps() + for step_name, step_map in self.steps_map.items(): + if not step_map.get("hidden", False): + ret["steps"][step_name]=self.steps_map[step_name]["spec"] return ret def render_steps(self): - for step_name, map in self.steps_map.items(): - step = map.get("step", None) + for step_name, step_map in self.steps_map.items(): + step = step_map.get("step", None) if step is not None: - editor = map.get("editor", None) + editor = step_map.get("editor", None) if editor is not None: editor.render(step.spec) @@ -154,15 +151,13 @@ class Recipe_Spec_And_Step_Editor(Editor): self.render_steps() def save_steps(self): - for map in self.steps_map.values(): - step = map.get("step", None) - if step is not None: - editor = map.get("editor", None) + for step_name,step_map in self.steps_map.items(): + step = step_map.get("step", None) + if step is None: + editor = step_map.get("editor", None) if editor is not None: - step.spec = editor.parse() - if map["step_is_new"]: - step.save(force_insert=True) + step_dict = editor.parse() + self.steps_map[step_name]["spec"]=step_dict else: - step.save() - map["step_is_new"] = False + self.steps_map[step_name]["spec"] = {} self.reset_steps() From 9bf55ee87fe56136e41daf73d3f6639cff2a63d1 Mon Sep 17 00:00:00 2001 From: neo Date: Sat, 5 Oct 2024 17:16:57 +0200 Subject: [PATCH 11/88] remove steps table wip editor modify ok --- src/ui/crud/crud.py | 2 +- .../recipe_spec_and_step_editor.py | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 2b4181c..583bf4b 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -75,7 +75,7 @@ class Cell: self.render(data, *args, **kwargs) if not self.connected_modified: # only connect after first render - # to avoid false modified signals trigghered by autocomplete + # to avoid false modified signals triggered by autocomplete self.connect_modified() self.connected_modified = True diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index 7d5b217..1344e2b 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -15,6 +15,7 @@ from ui.instruction_step_editor import Instruction_Step_Editor class Recipe_Spec_And_Step_Editor(Editor): def __init__(self, action=None, cell_widget=None, unsupported_steps=None): super().__init__(action=action, cell_widget=cell_widget) + self.crud = None self.steps_map = { "count": { "type": "count", @@ -125,15 +126,17 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) + self.crud=crud for step_name,step_def in self.steps_map.items(): if not step_def.get("hidden", False): step_def["enable"].setChecked(data.get(step_name,{}) in (True,1,"x") ) + self.steps_map[step_name]["spec"]=data["steps"].get(step_name,{}) self.render_steps() def parse(self, action=None, row_number=None, crud=None): ret = super().parse(row_number=row_number, crud=crud) ret["steps"] = {} - self.save_steps() + #self.save_steps() for step_name, step_map in self.steps_map.items(): if not step_map.get("hidden", False): ret["steps"][step_name]=self.steps_map[step_name]["spec"] @@ -141,23 +144,25 @@ class Recipe_Spec_And_Step_Editor(Editor): def render_steps(self): for step_name, step_map in self.steps_map.items(): - step = step_map.get("step", None) - if step is not None: + spec = step_map.get("spec", None) + if spec is not None: editor = step_map.get("editor", None) if editor is not None: - editor.render(step.spec) + editor.render(spec) def reset_steps(self): self.render_steps() def save_steps(self): for step_name,step_map in self.steps_map.items(): - step = step_map.get("step", None) - if step is None: + if not step_map.get("hidden", False): editor = step_map.get("editor", None) if editor is not None: step_dict = editor.parse() self.steps_map[step_name]["spec"]=step_dict else: self.steps_map[step_name]["spec"] = {} + self.crud().set_modified() + parsed_value=self.parse() + self.cell_widget().value = parsed_value self.reset_steps() From 486e09b479195c143eea6119d5c15f47b7a20293 Mon Sep 17 00:00:00 2001 From: gg Date: Mon, 7 Oct 2024 09:33:11 +0200 Subject: [PATCH 12/88] new recipe and import svg rows names --- .../st-ten-11/07N131597.svg | 89 +++++++++++++------ src/ui/recipe_selection/recipe_selection.py | 10 ++- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/config/instruction_images/st-ten-11/07N131597.svg b/config/instruction_images/st-ten-11/07N131597.svg index 1d15486..be47551 100644 --- a/config/instruction_images/st-ten-11/07N131597.svg +++ b/config/instruction_images/st-ten-11/07N131597.svg @@ -27,9 +27,9 @@ inkscape:deskcolor="#d1d1d1" showgrid="false" inkscape:zoom="1.8882664" - inkscape:cx="339.46481" - inkscape:cy="210.24575" - inkscape:window-width="1850" + inkscape:cx="339.72961" + inkscape:cy="210.24576" + inkscape:window-width="2490" inkscape:window-height="1016" inkscape:window-x="70" inkscape:window-y="27" @@ -45,38 +45,73 @@ preserveAspectRatio="none" xlink:href="data:image/png;base64,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 " id="image1" /> - + + + + diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 9c7b2e1..314b155 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -319,7 +319,7 @@ class Recipe_Selection(Widget): else: step.save() recipe.client = row.get("cliente", defaults["cliente"]) - recipe.part_number = row.get(part_number_field, defaults["part_number"]) + recipe.part_number = row.get(part_number_field, defaults["codice_prodotto"]) recipe.description = row.get(description_field, defaults["descrizione"]) recipe.spec = { "count": len(row.get("dimensione_lotto_abilitata", defaults["dimensione_lotto_abilitata"])) and "count" not in self.unsupported_steps, @@ -377,6 +377,8 @@ class Recipe_Selection(Widget): if len(csv_dir): os.makedirs(csv_dir, exist_ok=True) recipe_name_field = self.config.get("recipe", {}).get("recipe_name_field", "codice_ricetta").strip() + part_number_field = self.config.get("recipe", {}).get("part_number_field", "codice_prodotto").strip() + description_field = self.config.get("recipe", {}).get("description_field", "descrizione").strip() barcode_enable_field = self.config.get("recipe", {}).get("barcode_enable_field", "verifica_codice_a_barre_abilitata").strip() barcode_serial_field = self.config.get("recipe", {}).get("barcode_serial_field", "codice_a_barre").strip() print_template_field = self.config.get("recipe", {}).get("label_template_field", "modello_etichetta").strip() @@ -384,7 +386,8 @@ class Recipe_Selection(Widget): fieldnames = [ recipe_name_field, "cliente", - "part_number", + part_number_field, + description_field, "dimensione_lotto_abilitata", "dimensione_lotto", "verifica_connettore_abilitata", @@ -434,7 +437,8 @@ class Recipe_Selection(Widget): exportable = { recipe_name_field: recipe.name, "cliente": recipe.client, - "part_number": recipe.part_number, + part_number_field: recipe.part_number, + description_field: recipe.description, # "dimensione_lotto_abilitata": "x" if recipe.spec["count"] else "", # "dimensione_lotto": steps["count"].spec["amount"], "verifica_connettore_abilitata": "x" if recipe.spec["connector"] else "", From e1c496ea3026d14beb2ae5b54327ef55591b928f Mon Sep 17 00:00:00 2001 From: gg Date: Mon, 7 Oct 2024 11:19:21 +0200 Subject: [PATCH 13/88] st-ten-11.csv --- config/csv_import/st-ten-11.csv | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 config/csv_import/st-ten-11.csv diff --git a/config/csv_import/st-ten-11.csv b/config/csv_import/st-ten-11.csv new file mode 100644 index 0000000..1b4c3dc --- /dev/null +++ b/config/csv_import/st-ten-11.csv @@ -0,0 +1,3 @@ +codice_ricetta,cliente,codice_prodotto,descrizione,dimensione_lotto_abilitata,dimensione_lotto,verifica_connettore_abilitata,connettore,verifica_codice_a_barre_abilitata,codice_a_barre,verifica_resistenza_connettore_abilitata,scala_resistenza,r nominale,tolleranza_resistenza_pos,tolleranza_resistenza_neg,avvitatura_abilitata,viti,prova_tenuta_abilitata,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,prova_tenuta_abilitata_2,tempo_pre_riempimento_2,pressione_pre_riempimento_2,tempo_riempimento_2,tempo_assestamento_2,percentuale_minima_pressione_assestamento_2,percentuale_massima_pressione_assestamento_2,tempo_di_test_2,pressione_di_test_delta_minimo_2,pressione_di_test_2,pressione_di_test_delta_massimo_2,tempo_svuotamento_2,pressione_svuotamento_2,test_visione_abilitato,ricetta_visione,stampa_etichetta_abilitata,modello_etichetta +07N131597,Lamborghini,07N131597,nuova dima grande,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn +07N131628,Lamborghini,07N131628,nuova dima piccola,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn From fc105eadf09c24bae02dc5c34c65a011c477272a Mon Sep 17 00:00:00 2001 From: edo-neo Date: Mon, 7 Oct 2024 11:49:38 +0200 Subject: [PATCH 14/88] second test instruction step for st-ten-11 tbt sim ok --- .../{5803034806.svg => 5802820548.svg} | 0 config/machine_settings/defaults.ini | 1 + config/machine_settings/st-ten-11.ini | 4 +- src/ui/recipe_selection/recipe_selection.py | 1 + .../recipe_spec_and_step_editor.py | 7 +++ .../recipe_spec_and_step_editor.ui | 63 ++++++++++++++++--- src/ui/test/test.py | 14 ++++- src/ui/test_leak/test_leak.py | 16 +++-- 8 files changed, 88 insertions(+), 18 deletions(-) rename config/instruction_images/st-ten-11/{5803034806.svg => 5802820548.svg} (100%) diff --git a/config/instruction_images/st-ten-11/5803034806.svg b/config/instruction_images/st-ten-11/5802820548.svg similarity index 100% rename from config/instruction_images/st-ten-11/5803034806.svg rename to config/instruction_images/st-ten-11/5802820548.svg diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index 73f8223..1182755 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -118,6 +118,7 @@ r nominale: 1000000000 tolleranza_resistenza_pos: 10 tolleranza_resistenza_neg: 5 prova_tenuta_abilitata: x +istruzione_abilitata_extra: warning_img: #TECNA RECIPE PARAMETERS diff --git a/config/machine_settings/st-ten-11.ini b/config/machine_settings/st-ten-11.ini index cd164e2..bf60f4c 100644 --- a/config/machine_settings/st-ten-11.ini +++ b/config/machine_settings/st-ten-11.ini @@ -17,7 +17,9 @@ digital_io: present barcode_recipe_selection: present fixture_id: present discard_box: absent -enforce_piece_removal: yes +second_leak_test: present +dual_channel: absent +#enforce_piece_removal: yes [tecna_t3] port: COM4 diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 9c7b2e1..e888353 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -94,6 +94,7 @@ class Recipe_Selection(Widget): self.config.get("recipes_defaults", noner)["verifica_resistenza_connettore_abilitata"]) and "resistance" not in self.unsupported_steps, "screws": len(self.config.get("recipes_defaults", noner)["avvitatura_abilitata"]) and "screws" not in self.unsupported_steps, "instruction": len(self.config.get("recipes_defaults", noner)["istruzione_abilitata"]) and "instruction" not in self.unsupported_steps, + "instruction_extra": len(self.config.get("recipes_defaults", noner)["istruzione_abilitata_extra"]) and "instruction" not in self.unsupported_steps, "leak_1": len(self.config.get("recipes_defaults", noner)["prova_tenuta_abilitata"]) and "leak_1" not in self.unsupported_steps, "leak_2": len(self.config.get("recipes_defaults", noner)["prova_tenuta_abilitata_2"]) and "leak_2" not in self.unsupported_steps, "vision": len(self.config.get("recipes_defaults", noner)["test_visione_abilitato"]) and "vision" not in self.unsupported_steps, diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index c34536c..1f272da 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -59,6 +59,13 @@ class Recipe_Spec_And_Step_Editor(Editor): "editor": Instruction_Step_Editor(), "tab": self.instruction_t, }, + "instruction_extra": { + "type": "instruction_extra", + "enable": self.instruction_extra_enabled_cb, + "widget": "instruction_editor_w", + "editor": Instruction_Step_Editor(), + "tab": self.instruction_extra_t, + }, "leak_1": { "type": "leak_1", "enable": self.leak_enabled_1_cb, diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui index 506f39e..6852f91 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui @@ -38,7 +38,7 @@ Fasi di Test - 0 + 6 @@ -260,7 +260,7 @@ Fasi di Test Montaggio - + Qt::Horizontal @@ -273,14 +273,10 @@ Fasi di Test - - - - Fase Abilitata - - + + - + Qt::Horizontal @@ -293,8 +289,55 @@ Fasi di Test + + + + Fase Abilitata + + + + + + + + Montaggio extra + + + + + + Qt::Horizontal + + + + 572 + 20 + + + + + + + + Fase Abilitata + + + + + + + Qt::Horizontal + + + + 571 + 20 + + + + - + diff --git a/src/ui/test/test.py b/src/ui/test/test.py index b4a379c..e615456 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -106,13 +106,15 @@ class Test(Widget): text=u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\"", widget=None), "fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO, PREMERE CONTINUA PER COMINCIARE UN NUOVO CICLO", widget=Test_Fail(parent=self)), "blow": Test_Assembly(img_path=None, text=u"SOFFIAGGIO TUBO IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)), - "leak_1": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)) + "leak_1": Test_Assembly(img_path=None, text=None, widget=Test_Leak(config=self.config,components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)) if self.config["hardware_config"]["tecna_t3"] != "absent" or self.config["hardware_config"]["furness_controls"] !="absent" else None, - "leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)) + "leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(config=self.config,components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces, parent=self)) if self.config["hardware_config"]["tecna_t3"] != "absent" or self.config["hardware_config"]["furness_controls"] != "absent" else None, "flush": Test_Assembly(img_path=None, text=u"SCARICO ARIA IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)), "instruction": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", widget=Test_Instructions(config=self.config,components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)), + "instruction_extra": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", + widget=Test_Instructions(config=self.config, components=self.components,recipe=self.recipe, bench_name=self.config.machine_id,step=self.step)), "piece_removal": Test_Assembly(img_path=None, text=u"RIMUOVERE IL PEZZO APRENDO TUTTE LE CHIUSURE", widget=Test_Instructions(config=self.config,components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)), "print": Test_Assembly(img_path=self.select_step_img("print"), text=u"STAMPA ETICHETTA IN CORSO", widget=None), @@ -375,6 +377,7 @@ class Test(Widget): def set_recipe(self, recipe=None): self.recipe = recipe + inserted_instruction = None self.require_discard_piece = False if self.recipe is None: self.cycle_steps = None @@ -434,6 +437,13 @@ class Test(Widget): steps.append(Steps(type="piece_removal")) if count_found: steps.append(Steps(type="count_end")) + if step.type == "leak_2": + if self.config["hardware_config"].get("second_leak_test", "absent") == "present" and self.config[ + "hardware_config"].get("dual_channel", "absent") == "absent" and not inserted_instruction: + steps.insert(i, Steps(type="instruction_extra")) + inserted_instruction = True # Step inserted + + self.leak_step = step if step.type in ("leak_1", "leak_2"): self.leak_step = step diff --git a/src/ui/test_leak/test_leak.py b/src/ui/test_leak/test_leak.py index 24b77b1..4fc8bd1 100644 --- a/src/ui/test_leak/test_leak.py +++ b/src/ui/test_leak/test_leak.py @@ -12,13 +12,14 @@ from ui.test_test import Test_Test VALVE_TIME=0.5 class Test_Leak(Test_Test): - def __init__(self, components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False,parent=None): + def __init__(self, config,components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False,parent=None): super().__init__(components=components, recipe=recipe, step=step, pieces=pieces, run_once=run_once, reset_on_start=reset_on_start, enable_override=enable_override) self.get_connection = None self.io_ok = True self.blow_on = False self.parent=parent self.step=step + self.config = config self.recipe_written = False self.start_b.clicked.connect(self.start_test) self.stop_b.clicked.connect(self.stop_test) @@ -144,10 +145,15 @@ class Test_Leak(Test_Test): # AUTO START SECOND TEST if step.type == "leak_2": - self.recipe_written = False - time.sleep(1) - self.start_b.setEnabled(True) - self.start_b.click() + if self.config["hardware_config"].get("dual_chanel","absent") == "present": + self.recipe_written = False + time.sleep(1) + self.start_b.setEnabled(True) + self.start_b.click() + else: + self.recipe_written = False + time.sleep(1) + self.start_b.setEnabled(True) return show From f7355805e7f831fb507ff1f8129ed1f7ef798da6 Mon Sep 17 00:00:00 2001 From: st-ten-13 Date: Mon, 7 Oct 2024 11:49:40 +0200 Subject: [PATCH 15/88] Add default value to 'codice_prodotto' if missing Ensure 'codice_prodotto' has a default value in recipe selection. Additionally, appended 'archived' column in st-ten-11.csv to indicate archived status. --- config/csv_import/st-ten-11.csv | 6 +++--- src/ui/recipe_selection/recipe_selection.py | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/csv_import/st-ten-11.csv b/config/csv_import/st-ten-11.csv index 1b4c3dc..ceda131 100644 --- a/config/csv_import/st-ten-11.csv +++ b/config/csv_import/st-ten-11.csv @@ -1,3 +1,3 @@ -codice_ricetta,cliente,codice_prodotto,descrizione,dimensione_lotto_abilitata,dimensione_lotto,verifica_connettore_abilitata,connettore,verifica_codice_a_barre_abilitata,codice_a_barre,verifica_resistenza_connettore_abilitata,scala_resistenza,r nominale,tolleranza_resistenza_pos,tolleranza_resistenza_neg,avvitatura_abilitata,viti,prova_tenuta_abilitata,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,prova_tenuta_abilitata_2,tempo_pre_riempimento_2,pressione_pre_riempimento_2,tempo_riempimento_2,tempo_assestamento_2,percentuale_minima_pressione_assestamento_2,percentuale_massima_pressione_assestamento_2,tempo_di_test_2,pressione_di_test_delta_minimo_2,pressione_di_test_2,pressione_di_test_delta_massimo_2,tempo_svuotamento_2,pressione_svuotamento_2,test_visione_abilitato,ricetta_visione,stampa_etichetta_abilitata,modello_etichetta -07N131597,Lamborghini,07N131597,nuova dima grande,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn -07N131628,Lamborghini,07N131628,nuova dima piccola,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn +codice_ricetta,cliente,codice_prodotto,descrizione,dimensione_lotto_abilitata,dimensione_lotto,verifica_connettore_abilitata,connettore,verifica_codice_a_barre_abilitata,codice_a_barre,verifica_resistenza_connettore_abilitata,scala_resistenza,r nominale,tolleranza_resistenza_pos,tolleranza_resistenza_neg,avvitatura_abilitata,viti,prova_tenuta_abilitata,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,prova_tenuta_abilitata_2,tempo_pre_riempimento_2,pressione_pre_riempimento_2,tempo_riempimento_2,tempo_assestamento_2,percentuale_minima_pressione_assestamento_2,percentuale_massima_pressione_assestamento_2,tempo_di_test_2,pressione_di_test_delta_minimo_2,pressione_di_test_2,pressione_di_test_delta_massimo_2,tempo_svuotamento_2,pressione_svuotamento_2,test_visione_abilitato,ricetta_visione,stampa_etichetta_abilitata,modello_etichetta,archived +07N131597,Lamborghini,07N131597,nuova dima grande,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn,False +07N131628,Lamborghini,07N131628,nuova dima piccola,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,15,15,5,5,10,30,7000,30,0,100,,0,1000,20,20,5,5,10,30,15000,30,0,100,False,000952054.ini,x,ETA013L.prn,False diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 314b155..1e7e8ee 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -275,6 +275,9 @@ class Recipe_Selection(Widget): if defaults is None: global noner defaults = self.config.get("recipes_defaults", noner) + + if 'codice_prodotto' not in defaults: + defaults['codice_prodotto'] = "VALORE_PREDEFINITO" if csv_path is None: csv_path, _ = QFileDialog.getOpenFileName( None, From eb0c876aeb562ed872f165590c8cce58b38c4c01 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 8 Oct 2024 09:35:29 +0200 Subject: [PATCH 16/88] second test instruction step for st-ten-11 tbt sim ok --- .../st-ten-11/5802820548-extra.svg | 78 +++++++++++++++++++ config/machine_settings/st-ten-11.ini | 3 +- src/ui/recipe_selection/recipe_selection.py | 2 +- .../recipe_spec_and_step_editor.py | 2 +- src/ui/test/test.py | 28 ++++--- src/ui/test_instructions/test_instructions.py | 6 +- 6 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 config/instruction_images/st-ten-11/5802820548-extra.svg diff --git a/config/instruction_images/st-ten-11/5802820548-extra.svg b/config/instruction_images/st-ten-11/5802820548-extra.svg new file mode 100644 index 0000000..ea572d1 --- /dev/null +++ b/config/instruction_images/st-ten-11/5802820548-extra.svg @@ -0,0 +1,78 @@ + + + + diff --git a/config/machine_settings/st-ten-11.ini b/config/machine_settings/st-ten-11.ini index bf60f4c..8fae059 100644 --- a/config/machine_settings/st-ten-11.ini +++ b/config/machine_settings/st-ten-11.ini @@ -15,7 +15,7 @@ vision: absent screwdriver: absent digital_io: present barcode_recipe_selection: present -fixture_id: present +#fixture_id: present discard_box: absent second_leak_test: present dual_channel: absent @@ -77,6 +77,7 @@ pressione_svuotamento_2: 100 canale_di_prova_2: 2 modello_etichetta: EtichettaR5_Montaggio_1prova.prn pid_pressure_correction: 105 +istruzione_abilitata_extra: [autotest_leak] enabled: true diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index aaaea72..94791ec 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -94,7 +94,7 @@ class Recipe_Selection(Widget): self.config.get("recipes_defaults", noner)["verifica_resistenza_connettore_abilitata"]) and "resistance" not in self.unsupported_steps, "screws": len(self.config.get("recipes_defaults", noner)["avvitatura_abilitata"]) and "screws" not in self.unsupported_steps, "instruction": len(self.config.get("recipes_defaults", noner)["istruzione_abilitata"]) and "instruction" not in self.unsupported_steps, - "instruction_extra": len(self.config.get("recipes_defaults", noner)["istruzione_abilitata_extra"]) and "instruction" not in self.unsupported_steps, + "instruction_extra": len(self.config.get("recipes_defaults", noner)["istruzione_abilitata_extra"]) and "instruction_extra" not in self.unsupported_steps, "leak_1": len(self.config.get("recipes_defaults", noner)["prova_tenuta_abilitata"]) and "leak_1" not in self.unsupported_steps, "leak_2": len(self.config.get("recipes_defaults", noner)["prova_tenuta_abilitata_2"]) and "leak_2" not in self.unsupported_steps, "vision": len(self.config.get("recipes_defaults", noner)["test_visione_abilitato"]) and "vision" not in self.unsupported_steps, diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index 1f272da..c42b30d 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -62,7 +62,7 @@ class Recipe_Spec_And_Step_Editor(Editor): "instruction_extra": { "type": "instruction_extra", "enable": self.instruction_extra_enabled_cb, - "widget": "instruction_editor_w", + "widget": "instruction_extra_editor_w", "editor": Instruction_Step_Editor(), "tab": self.instruction_extra_t, }, diff --git a/src/ui/test/test.py b/src/ui/test/test.py index e615456..1c08976 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -113,7 +113,7 @@ class Test(Widget): "flush": Test_Assembly(img_path=None, text=u"SCARICO ARIA IN CORSO - ATTENDERE...", widget=Test_Warning_Img(components=self.components, recipe=self.recipe, step=self.step)), "instruction": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", widget=Test_Instructions(config=self.config,components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)), - "instruction_extra": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", + "instruction_extra": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO EXTRA INDICATE IN FIGURA", widget=Test_Instructions(config=self.config, components=self.components,recipe=self.recipe, bench_name=self.config.machine_id,step=self.step)), "piece_removal": Test_Assembly(img_path=None, text=u"RIMUOVERE IL PEZZO APRENDO TUTTE LE CHIUSURE", widget=Test_Instructions(config=self.config,components=self.components, recipe=self.recipe, bench_name=self.config.machine_id, step=self.step)), @@ -377,7 +377,7 @@ class Test(Widget): def set_recipe(self, recipe=None): self.recipe = recipe - inserted_instruction = None + inserted_instruction = False self.require_discard_piece = False if self.recipe is None: self.cycle_steps = None @@ -400,7 +400,6 @@ class Test(Widget): n_pieces_adapted -= 1 new_barcode_step = copy.deepcopy(step) new_barcode_step.spec["n_pieces"] = str(n_pieces_adapted) - n_pieces_adapted -= 1 steps.insert(i + 1, new_barcode_step) if i in skip: continue @@ -437,16 +436,25 @@ class Test(Widget): steps.append(Steps(type="piece_removal")) if count_found: steps.append(Steps(type="count_end")) - if step.type == "leak_2": - if self.config["hardware_config"].get("second_leak_test", "absent") == "present" and self.config[ - "hardware_config"].get("dual_channel", "absent") == "absent" and not inserted_instruction: - steps.insert(i, Steps(type="instruction_extra")) - inserted_instruction = True # Step inserted - - self.leak_step = step if step.type in ("leak_1", "leak_2"): self.leak_step = step + step_types = [step.type for step in steps] + if "leak_1" in step_types and "leak_2" in step_types: + leak1_index = step_types.index("leak_1") + leak2_index = step_types.index("leak_2") + if leak1_index + 1 == leak2_index: # Ensure 'leak_1' is immediately followed by 'leak_2' + steps.insert(leak2_index, Steps(type="instruction_extra", spec={})) + inserted_instruction = True + + # Insert 'instruction_extra' after the first 'instructions' if not inserted between leaks + if not inserted_instruction: + for i, step in enumerate(steps): + if step.type == "instructions": + steps.insert(i + 1, Steps(type="instruction_extra", spec={})) + inserted_instruction = True + break + if not print_found: steps.append(Steps(type="done")) if count_found: diff --git a/src/ui/test_instructions/test_instructions.py b/src/ui/test_instructions/test_instructions.py index 94239ee..f87bce7 100644 --- a/src/ui/test_instructions/test_instructions.py +++ b/src/ui/test_instructions/test_instructions.py @@ -48,7 +48,11 @@ class Test_Instructions(Test_Test): self.get_connection = self.components["digital_io"].out.connect(self.get) if step is not None: - svg_path=f"{self.svg_path}{self.recipe}.svg" + if step.type == "instruction": + svg_path = f"{self.svg_path}{self.recipe}.svg" + elif step.type == "instruction_extra": + svg_path = f"{self.svg_path}{self.recipe}-extra.svg" + if not os.path.exists(svg_path): svg_path=f"{self.svg_path}DEFAULT.svg" self.svg_root = etree.parse(svg_path) From 6113da2f7bf43a5bd4855a19fe7c6270729fbdcd Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 8 Oct 2024 09:35:47 +0200 Subject: [PATCH 17/88] unit test usb586x --- src/test/test_usb586x.py | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/test_usb586x.py diff --git a/src/test/test_usb586x.py b/src/test/test_usb586x.py new file mode 100644 index 0000000..33c1212 --- /dev/null +++ b/src/test/test_usb586x.py @@ -0,0 +1,43 @@ +import os +import platform +import sys +import time + +if platform.system() == "Windows": + sys.path.append(f"{os.getcwd()}\\src\\components") +else: + sys.path.append(f"{os.getcwd()}/src/components") + +from src.components.usb_586x import USB_586x +from lib.helpers import ConfigReader + +test_config = ConfigReader() + +if "--5862" in sys.argv: + test_config["digital_io"]["id"] = "USB-5862,BID#0" + out_size = in_size = 16 +else: + test_config["digital_io"]["id"] = "USB-5860,BID#0" + out_size = in_size = 8 + +digital_io = USB_586x(test_config) +digital_io.start() +# READ CONFIG + +out_num = 0 +n_in_bytes = int(in_size / 8) +while True: + out_bit = out_num % 8 + out_byte = int(out_num / 8) + res = digital_io.set_bit(out_byte, out_bit, 1) + time.sleep(0.5) + res2 = digital_io.set_bit(out_byte, out_bit, 0) + input_data = digital_io.get() + if "--5862" in sys.argv: + print("in:{} {} out:{}".format(bytes(input_data[0]), bytes(input_data[1]), out_num)) + else: + print("in:{} out:{}".format(bytes(input_data[0]), out_num)) + time.sleep(0.5) + out_num += 1 + if out_num == out_size: + out_num = 0 From a239765bbbe6677d22615988dadca9c7046e8378 Mon Sep 17 00:00:00 2001 From: eduardo Date: Tue, 8 Oct 2024 14:27:59 +0200 Subject: [PATCH 18/88] dev --- .../st-ten-11/07N131597.svg | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/config/instruction_images/st-ten-11/07N131597.svg b/config/instruction_images/st-ten-11/07N131597.svg index be47551..8688065 100644 --- a/config/instruction_images/st-ten-11/07N131597.svg +++ b/config/instruction_images/st-ten-11/07N131597.svg @@ -8,7 +8,7 @@ height="420.79999" viewBox="0 0 678.40002 420.79999" sodipodi:docname="07N131597.svg" - inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -28,11 +28,11 @@ showgrid="false" inkscape:zoom="1.8882664" inkscape:cx="339.72961" - inkscape:cy="210.24576" - inkscape:window-width="2490" - inkscape:window-height="1016" - inkscape:window-x="70" - inkscape:window-y="27" + inkscape:cy="210.51055" + inkscape:window-width="1920" + inkscape:window-height="1009" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="g1" /> From 3a163bfab40e6c9bd73db017afe6d3abb676e660 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 8 Oct 2024 16:24:35 +0200 Subject: [PATCH 19/88] dima Mclaren --- .../st-ten-11/98FA186CP-extra.svg | 90 +++++++++++++++++++ .../st-ten-11/98FA186CP.svg | 90 +++++++++++++++++++ config/machine_settings/st-ten-11.ini | 2 +- src/ui/test_instructions/test_instructions.ui | 9 +- 4 files changed, 182 insertions(+), 9 deletions(-) create mode 100644 config/instruction_images/st-ten-11/98FA186CP-extra.svg create mode 100644 config/instruction_images/st-ten-11/98FA186CP.svg diff --git a/config/instruction_images/st-ten-11/98FA186CP-extra.svg b/config/instruction_images/st-ten-11/98FA186CP-extra.svg new file mode 100644 index 0000000..bc400d1 --- /dev/null +++ b/config/instruction_images/st-ten-11/98FA186CP-extra.svg @@ -0,0 +1,90 @@ + + + + diff --git a/config/instruction_images/st-ten-11/98FA186CP.svg b/config/instruction_images/st-ten-11/98FA186CP.svg new file mode 100644 index 0000000..0693c82 --- /dev/null +++ b/config/instruction_images/st-ten-11/98FA186CP.svg @@ -0,0 +1,90 @@ + + + + diff --git a/config/machine_settings/st-ten-11.ini b/config/machine_settings/st-ten-11.ini index 8fae059..68bbacf 100644 --- a/config/machine_settings/st-ten-11.ini +++ b/config/machine_settings/st-ten-11.ini @@ -15,7 +15,7 @@ vision: absent screwdriver: absent digital_io: present barcode_recipe_selection: present -#fixture_id: present +fixture_id: present discard_box: absent second_leak_test: present dual_channel: absent diff --git a/src/ui/test_instructions/test_instructions.ui b/src/ui/test_instructions/test_instructions.ui index 736ba1c..24fc0e7 100644 --- a/src/ui/test_instructions/test_instructions.ui +++ b/src/ui/test_instructions/test_instructions.ui @@ -48,14 +48,7 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - OK - - - - + From 7ee96d63dd37f502c66b1e39d9ad1cea5b94c208 Mon Sep 17 00:00:00 2001 From: neo Date: Tue, 8 Oct 2024 15:36:05 +0200 Subject: [PATCH 20/88] advantech digital I/O ok on linux, tbt --- config/machine_settings/hostnames.ini | 1 + config/machine_settings/test-linux.ini | 2 + init.sh | 10 +- src/components/usb_586x.py | 127 ++++++++----------------- src/test_usb586x.py | 2 +- 5 files changed, 50 insertions(+), 92 deletions(-) diff --git a/config/machine_settings/hostnames.ini b/config/machine_settings/hostnames.ini index dfdc1c7..3299c30 100644 --- a/config/machine_settings/hostnames.ini +++ b/config/machine_settings/hostnames.ini @@ -12,4 +12,5 @@ st-ten-10: st-ten-10 st-ten-11: st-ten-11 st-ten-12: st-ten-12 st-ten-13: st-ten-13 +test-linux: test-linux diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index 490c522..97e9295 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -27,6 +27,8 @@ model: t3p port: COM5 [digital_io] +# OUTPUT MAP FOR VALVE CONTROL UNITS +id: USB-5862,BID#0 # OUTPUT MAP FOR FIXTURE CONNECTOR id_fixture: USB-5862,BID#0 discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING diff --git a/init.sh b/init.sh index 9b612e6..dc2528c 100755 --- a/init.sh +++ b/init.sh @@ -2,6 +2,7 @@ set -x here="$(realpath "$(dirname "$0")")" cd "$here" +mkdir -p "$here/tmp" echo "---------- initialize venv ----------" sudo apt-get install python3 python3-venv python-is-python3 python3-pip @@ -30,8 +31,6 @@ source "./venv/bin/activate" || source "./venv/Scripts/activate" || : # # echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list # # sudo apt-get update # sudo apt install -y build-essential docker # bazel libusb-1.0-0-dev libabsl-dev libflatbuffers-dev -# mkdir -p "$here/tmp" -# cd "$here/tmp" # # git clone https://github.com/tensorflow/tensorflow || : # # cd tensorflow # # git pull @@ -61,4 +60,11 @@ source "./venv/bin/activate" || source "./venv/Scripts/activate" || : #python3 setup.py install #cd "$here" +echo "---------- INSTALL ADVANTECH DAQNAVI DRIVER ----------" +cd "$here/tmp" +wget --continue "https://advdownload.advantech.com/productfile/Downloadfile5/1-2MULY66/DAQ_Linux_4.0.11.0_64bit.run" +chmod +x DAQ_Linux_4.0.11.0_64bit.run +sudo ./DAQ_Linux_4.0.11.0_64bit.run + +echo "---------- INIT DONE ----------" cd "$here" diff --git a/src/components/usb_586x.py b/src/components/usb_586x.py index c4a954b..af8c073 100644 --- a/src/components/usb_586x.py +++ b/src/components/usb_586x.py @@ -9,21 +9,14 @@ from PyQt5.QtWidgets import QMessageBox, QApplication from .component import Component -is_win = platform.system().lower() == "windows" - if "--sim-io" not in sys.argv: - if is_win: - from components.Automation.BDaq import * - from components.Automation.BDaq.InstantDoCtrl import InstantDoCtrl - from components.Automation.BDaq.InstantDiCtrl import InstantDiCtrl - else: - libbiodaq = ctypes.CDLL("/opt/advantech/libs/libbiodaq.so") + from components.Automation.BDaq import * + from components.Automation.BDaq.InstantDoCtrl import InstantDoCtrl + from components.Automation.BDaq.InstantDiCtrl import InstantDiCtrl else: from components.dummies.Automation.BDaq import * from components.dummies.Automation.BDaq.InstantDoCtrl import InstantDoCtrl from components.dummies.Automation.BDaq.InstantDiCtrl import InstantDiCtrl - #is_win=False - #import components.dummies.libbiodaq as libbiodaq from components.dummies.libbiodaq import ErrorCode class USB_586x(Component): @@ -77,52 +70,19 @@ class USB_586x(Component): # DIGITAL I/O CLASS if not self.simulate: self.log.info("OPENING USB MODULE...") - if is_win: - try: - self.di_ctrl = InstantDiCtrl(self.info.Description) - self.do_ctrl = InstantDoCtrl(self.info.Description) - self.di_read = self.di_ctrl.readAny - self.do_write_bit = self.do_ctrl.writeBit - self.buffer = ctypes.create_string_buffer(2) - self.io_ok=True - except ValueError: - QMessageBox.critical(None, "ERRORE", f"ERRORE I/O DIGITALE - VERIFICARE CONNESSIONE USB") - exit(-1) - self.io_ok = False - - time.sleep(1) - else: - self.di_create = libbiodaq.AdxInstantDiCtrlCreate - self.di_create.restype = ctypes.c_void_p - self.di_setSelectedDevice = libbiodaq.InstantDiCtrl_setSelectedDevice - self.di_setSelectedDevice.argtypes = [ctypes.c_void_p, ctypes.POINTER(self.DeviceInformation)] - self.di_setSelectedDevice.restype = ctypes.c_uint32 - # DIGITAL INPUTS READ FUNCTION - self.di_read = libbiodaq.InstantDiCtrl_ReadAny - self.di_read.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_char_p] - self.di_read.restype = ctypes.c_int32 - # DIGITAL OUTPUTS CLASS - self.do_create = libbiodaq.AdxInstantDoCtrlCreate - self.do_create.restype = ctypes.c_void_p - # SET SELECTED DEVICE - self.do_setSelectedDevice = libbiodaq.InstantDoCtrl_setSelectedDevice - self.do_setSelectedDevice.argtypes = [ctypes.c_void_p, ctypes.POINTER(self.DeviceInformation)] - self.do_setSelectedDevice.restype = ctypes.c_uint32 - # get ports - self.get_ports = libbiodaq.InstantDoCtrl_getPortDirection - self.get_ports.argtypes = [ctypes.c_void_p] - self.get_ports.restype = ctypes.POINTER(ctypes.c_void_p) - # DIGITAL OUTPUTS WRITE FUNCTION - self.do_write_bit = libbiodaq.InstantDoCtrl_WriteBit - self.do_write_bit.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.c_int32, ctypes.c_char] - self.do_write_bit.restype = ctypes.c_int32 + try: + self.di_ctrl = InstantDiCtrl(self.info.Description) + self.do_ctrl = InstantDoCtrl(self.info.Description) + self.di_read = self.di_ctrl.readAny + self.do_write_bit = self.do_ctrl.writeBit self.buffer = ctypes.create_string_buffer(2) - # INIT OBJECTS - self.di_ctrl = self.di_create() - self.do_ctrl = self.do_create() - self.di_init_status = self.di_setSelectedDevice(self.di_ctrl, ctypes.byref(self.info)) - self.do_init_status = self.do_setSelectedDevice(self.do_ctrl, ctypes.byref(self.info)) - self.io_ok = True + self.io_ok=True + except ValueError: + QMessageBox.critical(None, "ERRORE", f"ERRORE I/O DIGITALE - VERIFICARE CONNESSIONE USB") + exit(-1) + self.io_ok = False + + time.sleep(1) else: self.di_ctrl = InstantDiCtrl(self.info.Description) self.do_ctrl = InstantDoCtrl(self.info.Description) @@ -177,38 +137,30 @@ class USB_586x(Component): max_retry = 3 while retry < max_retry: - if is_win or self.simulate: - if self.simulate: - read = self.sim_in + if self.simulate: + read = self.sim_in + break + else: + if self.io_ok: + ret = self.di_read(0, self.in_size) + if ret[0].value == ErrorCode.Success.value: + self.buffer = ret[1] + for byte_num in range(len(self.buffer)): + byte = self.buffer[byte_num] + read.append([bool(byte & m) for m in self.masks]) + else: + self.buffer = None + self.log.error(f"READ ERROR") + self.di_ctrl.dispose() + self.do_ctrl.dispose() + self.io_ok = False + + + if self.io_ok: break else: - if self.io_ok: - ret = self.di_read(0, self.in_size) - if ret[0].value == ErrorCode.Success.value: - self.buffer = ret[1] - for byte_num in range(len(self.buffer)): - byte = self.buffer[byte_num] - read.append([bool(byte & m) for m in self.masks]) - else: - self.buffer = None - self.log.error(f"READ ERROR") - self.di_ctrl.dispose() - self.do_ctrl.dispose() - self.io_ok = False - - - if self.io_ok: - break - else: - time.sleep(1) - self.open_device() - else: - self.di_read(self.di_ctrl, 0, self.in_size, self.buffer) - - for byte_num in range(len(self.buffer)): - byte = int.from_bytes(self.buffer[byte_num], "little") - read.append([bool(byte & m) for m in self.masks]) - + time.sleep(1) + self.open_device() self.mutex.unlock() return read @@ -239,10 +191,7 @@ class USB_586x(Component): # print("set", byte, bit, not val, flush=True) if self.io_ok: if not self.simulate: - if is_win: - ret=self.do_write_bit(byte, bit, int(val)) - else: - ret=self.do_write_bit(self.do_ctrl, byte, bit, int(val)) + ret=self.do_write_bit(byte, bit, int(val)) else: ret = ErrorCode.Success diff --git a/src/test_usb586x.py b/src/test_usb586x.py index 0d55c44..b055474 100644 --- a/src/test_usb586x.py +++ b/src/test_usb586x.py @@ -9,7 +9,7 @@ from src.components.usb_586x import USB_586x from lib.helpers import ConfigReader -test_config = ConfigReader() +test_config = ConfigReader(system_id="test-linux") if "USB-5862" in test_config["digital_io"]["id"]: out_size = in_size = 16 From 1255ba84d8bbea21efc6a2f8ad3034db1778a0a6 Mon Sep 17 00:00:00 2001 From: ST-TEN-11 Date: Wed, 9 Oct 2024 10:55:03 +0200 Subject: [PATCH 21/88] dev --- config/machine_settings/st-ten-11.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/machine_settings/st-ten-11.ini b/config/machine_settings/st-ten-11.ini index 197651a..bbb3d5b 100644 --- a/config/machine_settings/st-ten-11.ini +++ b/config/machine_settings/st-ten-11.ini @@ -29,7 +29,7 @@ printer: zd421 [digital_io] # OUTPUT MAP FOR FIXTURE CONNECTOR -id: USB-5862,BID#0 +id: USB-5860,BID#0 [fixture_rfid] port: COM5 From bbb3086c90aa512cbdf1a041dd5740c07a8c84eb Mon Sep 17 00:00:00 2001 From: ST-TEN-11 Date: Wed, 9 Oct 2024 11:17:36 +0200 Subject: [PATCH 22/88] dev --- config/machine_settings/st-ten-11.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/machine_settings/st-ten-11.ini b/config/machine_settings/st-ten-11.ini index 68bbacf..3ec7183 100644 --- a/config/machine_settings/st-ten-11.ini +++ b/config/machine_settings/st-ten-11.ini @@ -32,7 +32,7 @@ printer: zd421 [digital_io] # OUTPUT MAP FOR FIXTURE CONNECTOR -id_fixture: USB-5862,BID#0 +id_fixture: USB-5860,BID#0 discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING [fixture_rfid] From c9226d40ab24ff351519ed32e9b589b19a7c3aef Mon Sep 17 00:00:00 2001 From: ST-TEN-11 Date: Wed, 9 Oct 2024 11:51:31 +0200 Subject: [PATCH 23/88] ricette tecna t3p serial 20060720 --- .../csv_import/ricette tecna t3p st-te-11.csv | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 config/csv_import/ricette tecna t3p st-te-11.csv diff --git a/config/csv_import/ricette tecna t3p st-te-11.csv b/config/csv_import/ricette tecna t3p st-te-11.csv new file mode 100644 index 0000000..7fdc224 --- /dev/null +++ b/config/csv_import/ricette tecna t3p st-te-11.csv @@ -0,0 +1,102 @@ +codice_ricetta,part_number,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,template_di_stampa,campo1,campo2 +TEST FUGA 7 BAR,B1619X,0.0,1400,5.0,10.0,10,10,5.0,16.8,7000,11.200000000000001,0.1,0,,DA 11.2 A 16.8 M, +16LA773CP REV01,,0.0,0,10.0,15.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +5803112815 REV01,COMPL.MAN,0.0,0,5.0,5.0,15,15,10.0,30.0,5000,1.0,0.0,0,,5803112815 REV01, +5803112816 REV01,COMPL.MAN,0.0,0,5.0,5.0,15,15,10.0,30.0,5000,1.0,0.1,0,,5803112816 REV01, +PY83-6B747-BA,ENGINE OIL ASSY,0.0,0,10.0,10.0,10,10,30.0,20.0,7000,10.0,0.0,0,,PY83-6B747-BA,ASTON MARTIN +PY83-6B748-BA,ENGINE OIL ASSY,0.0,0,10.0,10.0,10,10,30.0,20.0,7000,5.0,0.0,0,,PY83-6B748-BA,ASTON MARTIN +5802729983 REV0,,0.0,0,5.0,5.0,10,10,10.0,20.0,8000,0.0,0.0,0,,, +MY83-6L701-AB,TRASMISSION OIL,0.0,0,5.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,MY83-6L701-AB,ASTON MARTIN +16FC246CP REV1,,0.0,0,10.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-OIL FILL,P16 +MY83-6L694-AB,TRASMISSION OIL,0.0,0,5.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,MY83-6L694-AB,ASTON MARTIN +16FC250CP REV02,ASSY CCV,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,ASSY CCV - PCV,T16C-Z0800-001 +5801970064 REV2,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970064 REV2,LANCIA BOLZANO +5801970067 REV1,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970067 REV1,LANCIA BOLZANO +5801384839 REV1,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801384839 REV1,LANCIA BOLZANO +5801384838 REV1,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801384838 REV1,LANCIA BOLZANO +12970-13-2382,TUBEASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,12970-13-2382,MULTIMATIC +12970-13-2384,TUBEASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,12970-13-2384,MULTIMATIC +12970-13-2386,TUBEASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,12970-13-2386,MULTIMATIC +12970-13-2388,TUBEASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,7000,5.0,0.0,0,,12970-13-2388,MULTIMATIC +16FC256CP REV01,,0.0,0,5.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-MAKE UP AIR,P16 +5801384841 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801384841 REV01,LANCIA BOLZANO +5801384842 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801384842 REV01,LANCIA BOLZANO +5801970063 REV2,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970063 REV2,LANCIA BOLZANO + 16FB157CP REV03,,0.0,0,5.0,5.0,10,10,20.0,50.0,1000,2.0,0.0,0,,ASSY CCV-OIL TAN,P16 + 16L0002CP REV03,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-RH-HT-RADIA,P16 + 16L0007CP REV03,,0.0,0,5.0,5.0,10,10,30.0,20.0,3000,4.0,0.0,0,,HOSE-IPU-JNCTN-T,P16 +16L0043CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,PIPE-OUTLET-PRE-,P16 +16L0045CP REV02,,0.0,0,5.0,5.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-HT-RADIATOR,P16 +16L0046CP REV03,,0.0,0,15.0,10.0,10,10,20.0,20.0,3500,5.0,0.0,0,,HOSE-LH-HT-RADIA,P16 +16L0058CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,5.0,0.0,0,,HOSE-LT-TUNNEL-T,P16 +16L0059CP REV03,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-COOLANT-FIL,P16 +16L0075CP REVO3,,0.0,0,20.0,15.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-HEADER-TANK,P16 +16L0145CP REV03,,0.0,0,5.0,15.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-HOSE-PUMP-T,P16 +16L0151CP REV03,,0.0,0,5.0,15.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-IPU-OUTLET-,P16 +16L0154CP REV03,,0.0,0,10.0,20.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-RH-LTR-OUTL,P16 +16L0161CP REV04,,0.0,0,5.0,15.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-WCACS-TO-ME,P16 +16L0164CP REV02,,0.0,0,10.0,15.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-LH-LTR-OUT,P16 +16L0167CP REV02,,0.0,0,10.0,20.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-TO-MCU,P16 +16L0170CP REV03,,0.0,0,10.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-IPU-OUTLET-,P16 +16L0174CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK,P16 +16L0177CP REV03,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-JNCTN TO WC,P16 +16L0180CP REV04,,0.0,0,15.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-LH-LTR-OUTL,P16 +16LA259CP REV03,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-LT-MECH-PUM,P16 +16LA336CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-E-MOTOR-OUT,P16 +16LA353CP REV02,,0.0,0,20.0,15.0,5,20,10.0,20.0,3500,5.0,0.0,0,,HOSE-RH-HT-RADIA,P16 +16LA372CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,PIPE-IN-PRE-COOL,P16 +16LA397CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-HT-RADIATOR,P16 +16LA449CP REV02,,0.0,0,15.0,15.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-ENGINE-TO-P,P16 +16LA451CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE PRE COOLER ,P16 +16LA648CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-RH-LTR-OUT-,P16 +16LA452CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE PRE COOLERS,P16 +16LA461CP REV02,,0.0,0,5.0,10.0,10,10,20.0,20.0,3000,0.0,0.0,0,,ASSY-HOSE-HT-RTN,P16 +16LA680CP REV01,,0.0,0,10.0,15.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +16LA490CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-RH-LTR-OUT-,P16 +16LA515CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +16LA518CP REV02,,0.0,0,5.0,10.0,10,10,20.0,20.0,3000,0.0,0.0,0,,HOSE-TO-E-MOTOR,P16 +16LA573CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-MCU-TO-MOTO,P16 +16LA579CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK ,P16 +16LA668CP REV01,,0.0,0,10.0,20.0,10,10,30.0,20.0,3500,5.0,0.0,0,,HOSE-LH WCAC AND,P16 +16LA615CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-RH WCAC HOS,P16 +16LA584CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +16LA695CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,1.0,0.0,0,,HOSE PRE COOLERS,P16 +16LA586CP REV01,,0.0,0,5.0,10.0,10,10,20.0,20.0,3000,0.0,0.0,0,,HOSE PRE COOLERS,P16 +16LA642CP REV01,,0.0,0,5.0,5.0,10,10,20.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK ,P16 +16LA643CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK ,P16 + 16FC069CP REV01,,0.0,0,10.0,15.0,10,10,20.0,50.0,1000,5.0,0.0,0,,ASSY CCV-INTAKE,P16 + 16FC084CP REV02,,0.0,0,5.0,5.0,10,10,20.0,50.0,3000,0.0,0.0,0,,BALANCE PIPE-INL,P16 + 16FB394CP REV04,,0.0,0,5.0,5.0,10,10,20.0,50.0,3000,5.0,0.0,0,,ASSY INLET PURGE,P16 +5801970066 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970066 REV01,LANCIA BOLZANO +5801970021 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970021 REV01,LANCIA BOLZANO +5801862227 REV00,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801862227 REV00,LANCIA BOLZANO + 16LA661CP REV01,,0.0,0,5.0,10.0,10,10,20.0,20.0,3500,0.0,0.0,0,,HOSE-RH-HT-RADIA,P16 +16FC056CX REV01,,0.0,0,5.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-MAKE UP AIR,P16 +16FC201CX REV01, ASSY CCV-PCV,0.0,0,5.0,5.0,20,20,20.0,50.0,300,2.0,0.0,0," +",ASSY CCV - PCV,T16C-Z0800-001 +16LA718CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,HOSE-E-MOTOR-OUT,P16 +16FA849CP REV02,,0.0,0,10.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-OIL FILL,P16 +5803112815,COMPL.MAN,0.0,0,5.0,10.0,15,15,10.0,30.0,5000,1.0,0.1,0,,5803112815, +5801970065 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970065 REV01,LANCIA BOLZANO +MY83-6B748-BA,TRASMISSION OIL,0.0,0,10.0,10.0,10,10,20.0,20.0,7000,5.0,0.0,0,,MY83-6B748-BA,ASTON MARTIN +16FC256CP REV01,,0.0,0,5.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-MAKE UP AIR,P16 +5803112816,COMPL.MAN,0.0,0,5.0,10.0,15,15,10.0,30.0,5000,1.0,0.1,0,,5803112816, +16LA459CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +MY83-6B747-BA,TRASMISSION OIL,0.0,0,10.0,10.0,10,10,20.0,20.0,7000,5.0,0.0,0,,MY83-6B747-BA,ASTON MARTIN +16FA849CP REV02,,0.0,0,10.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-OIL FILL, +16FA849CX REV01,,0.0,0,10.0,5.0,10,10,20.0,20.0,1000,5.0,0.0,0,,ASSY-OIL FILL, +16LA027SP REV02,,0.0,0,20.0,30.0,10,10,30.0,20.0,3500,5.0,0.0,0,,HOSE-LH WCAC AND,P16 +5801970065 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801970065 REV01,LANCIA BOLZANO +16FA026SP REV1,OIL FIL LINE-FED,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,FED,T16C-Z0800-001 +5801384840 REV01,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5801384840 REV01,LANCIA BOLZANO +16FC446CP REV01,ASSY CCV,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,FED,T16C-Z0800-001 +16FA026SP,,0.0,0,5.0,10.0,10,10,30.0,20.0,3000,0.0,0.0,0,,FED,P16 +5802170779 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5802170779 REV0,LANCIA BOLZANO +16FC469CP REV.01,ASSY CCV,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,FED,T16C-Z0800-001 +5802170804 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,8000,5.0,0.0,0,,5802170804 REV0,LANCIA BOLZANO +16LA459CP REV1,,0.0,0,10.0,15.0,10,10,30.0,20.0,3500,0.0,0.0,0,,HOSE-TRANS HX-RT,P16 +16FC541CT REV01,ASSY CCV,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,FED,T16C-Z0800-001 +16LA735CP REV01,,0.0,0,5.0,5.0,10,10,20.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK ,P16 +16FA026SP REV01,ASSY CCV,0.0,0,5.0,5.0,20,20,20.0,50.0,200,2.0,0.0,0,,FED,T16C-Z0800-001 +5802980014 REV0,,0.0,0,15.0,10.0,10,10,25.0,20.0,7000,0.0,0.0,0,,UNITE GASOIL PI,IVECO +16LA765CP REV1,,0.0,0,5.0,5.0,10,10,20.0,20.0,3500,0.0,0.0,0,,HOSE-WCACS LINK ,P16 From 6467307957862904f1511daa70e59ae58a92fd6a Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 9 Oct 2024 12:07:41 +0200 Subject: [PATCH 24/88] dev --- config/instruction_images/generic/DEFAULT.svg | 49 +++++++++++++++++++ config/machine_settings/test-linux.ini | 4 +- src/requirements.txt | 2 +- src/scripts/save_tecna_recipes_to_csv.py | 6 ++- src/ui/test_instructions/test_instructions.py | 6 +-- 5 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 config/instruction_images/generic/DEFAULT.svg diff --git a/config/instruction_images/generic/DEFAULT.svg b/config/instruction_images/generic/DEFAULT.svg new file mode 100644 index 0000000..facc0bb --- /dev/null +++ b/config/instruction_images/generic/DEFAULT.svg @@ -0,0 +1,49 @@ + + + +DISEGNO NON DISPONIBILE diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index 97e9295..978f515 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -1,6 +1,6 @@ [machine] description = TEST-LINUX -instruction_folder = st-ten-1 +#instruction_folder = st-ten-1 image_for_warning= st-ten-1 @@ -16,7 +16,7 @@ vision_saver: absent vision: absent screwdriver: absent fixture_id: absent -digital_io: absent +digital_io: present external_flush_blow: absent [tecna_t3] diff --git a/src/requirements.txt b/src/requirements.txt index 214557b..c9321ad 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -10,7 +10,7 @@ opencv-python-headless peewee pillow pycoral -pymodbus +pymodbus==3.6.8 pyqt5 pyqt5-tools pyserial diff --git a/src/scripts/save_tecna_recipes_to_csv.py b/src/scripts/save_tecna_recipes_to_csv.py index f312bdc..f3cd05f 100644 --- a/src/scripts/save_tecna_recipes_to_csv.py +++ b/src/scripts/save_tecna_recipes_to_csv.py @@ -8,7 +8,7 @@ import platform import signal import sys sys.argv.append("--sim-io") -sys.argv.append("--system-id=test-windows") +#sys.argv.append("--system-id=test-windows") if platform.system().lower() == "windows": sys.path.append(f"{os.getcwd()}\src\components") @@ -124,7 +124,9 @@ try: def read_recipes(self): self.recipes = {} - for recipe_num in range(1, self.components["tecna_t3"].max_program_number+1): + max_num_recipes=self.components["tecna_t3"].max_program_number + logging.info(f"NUMBER OF RECIPES TO BE READ: {max_num_recipes}") + for recipe_num in range(1, max_num_recipes+1): logging.info(f"READING RECIPE #{recipe_num}") self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num) diff --git a/src/ui/test_instructions/test_instructions.py b/src/ui/test_instructions/test_instructions.py index 94239ee..88505bc 100644 --- a/src/ui/test_instructions/test_instructions.py +++ b/src/ui/test_instructions/test_instructions.py @@ -28,7 +28,7 @@ class Test_Instructions(Test_Test): self.layout = QVBoxLayout() self.layout.addWidget(self.svg_widget) self.svg_w.setLayout(self.layout) - self.svg_path=os.path.join("config","instruction_images",self.config["machine"]["instruction_folder"],"") + self.svg_path=os.path.join("config","instruction_images",self.config["machine"].get("instruction_folder","generic"),"") self.timer = QTimer() self.timer.timeout.connect(self.toggle_icons) self.expected_input_state=True @@ -54,7 +54,7 @@ class Test_Instructions(Test_Test): self.svg_root = etree.parse(svg_path) self.svg_str = etree.tostring(self.svg_root) self.svg_str=etree.tostring(self.svg_root) - self.expected_input_state = True if step.type == "instruction" else False + self.expected_input_state = True if step.step_type == "instruction" else False self.monitored_ids=self.svg_root.xpath(f'''.//*[starts-with(@id, 'sensor_')]''') @@ -152,7 +152,7 @@ class Test_Instructions(Test_Test): QApplication.processEvents() def get(self, data=None, override=False): - if self.parent_assembly_widget().parent().step.type == "select_recipe": + if self.parent_assembly_widget().parent().step.step_type == "select_recipe": self.stop() return if self.done: # avoid proccessing if completed From 62c21573cd30797bdf2f0736c5d4e9c6240429ba Mon Sep 17 00:00:00 2001 From: ST-TEN-11 Date: Wed, 9 Oct 2024 12:24:41 +0200 Subject: [PATCH 25/88] ricette tecna t3l --- .../ricette tecna st-ten-11 030022040361.csv | 308 ++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 config/csv_import/ricette tecna st-ten-11 030022040361.csv diff --git a/config/csv_import/ricette tecna st-ten-11 030022040361.csv b/config/csv_import/ricette tecna st-ten-11 030022040361.csv new file mode 100644 index 0000000..892c91f --- /dev/null +++ b/config/csv_import/ricette tecna st-ten-11 030022040361.csv @@ -0,0 +1,308 @@ +codice_ricetta,part_number,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,template_di_stampa,campo1,campo2 +TEST FUGA 7 BAR,B1619X,0.0,0,5.0,10.0,10,10,5.0,12.0,0,8.0,0.0,0,,DA 14.4 A 21.6 , +5803217628 REV.,UNIT GASOIL PIPE,0.0,0,5.0,10.0,10,10,20.0,20.0,0,0.0,0.0,0,,UNITE GASOIL PI,IVECO +5802915822,COMPL.MAN,0.0,0,5.0,15.0,15,15,10.0,20.0,0,10.0,1.0,100,,5802915822 R.02,5802915822 R.02 +PY83-6B747-BA,ENGINE OIL ASSY,0.0,0,5.0,15.0,10,10,30.0,20.0,0,10.0,0.1,1," +",PY83-6B747-BA,ASTON MARTIN +PY83-6B748-BA,ENGINE OIL ASSY,0.0,0,5.0,15.0,10,10,30.0,20.0,0,10.0,0.1,1," +",PY83-6B748-BA,ASTON MARTIN +MY83-6B747-BA,ENGINE OIL ASSY,0.0,0,30.0,20.0,10,10,30.0,20.0,0,10.0,0.1,1," +",MY83-6B747-BA,ASTON MARTIN +MY83-6B748-BA,ENGINE OIL ASSY,0.0,0,5.0,15.0,10,10,30.0,20.0,0,10.0,0.1,1," +",MY83-6B748-BA,ASTON MARTIN +MY83-6L701-AB, ENGINE OIL ASSY,0.0,0,10.0,10.0,10,10,30.0,20.0,0,10.0,0.1,1,,MY83-6L701-AB,ASTON MARTIN +MY83-6L694-AB,ENGINE OIL ASSY,0.0,0,10.0,10.0,10,10,30.0,25.0,0,10.0,0.1,1," +",MY83-6L694-AB,ASTON MARTIN +000746453,000746453,0.0,0,10.0,20.0,10,10,20.0,25.0,0,5.0,0.1,0, ,000746453 REV05,FERRARI +5802889710 REV3,FUEL HOSE,0.0,0,20.0,25.0,10,10,20.0,20.0,0,0.0,0.1,0,,FUEL HOSE,IVECO +5802953113 REV.,FUEL HOSE,0.0,0,5.0,25.0,10,10,20.0,20.0,0,0.0,0.0,0,,FUEL HOSE,IVECO +5802980014 REV.,UNIT GASOIL PIPE,0.0,0,15.0,10.0,10,10,20.0,20.0,0,0.0,0.0,0,,UNITE GASOIL PI,IVECO +5802981174 REV.,UNIT GASOIL PIPE,0.0,0,5.0,20.0,10,10,60.0,20.0,0,0.0,0.0,0,,UNIT GASOIL PIP,IVECO +5802889709 REV3,FUEL HOSE,0.0,0,25.0,30.0,10,10,20.0,20.0,0,0.0,0.0,0,,FUEL HOSE,IVECO +12970-13-2382,TUBE-ASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,30.0,0,5.0,0.0,0,,12970-13-2382,MULTIMATIC +12970-13-2384,TUBE-ASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,12970-13-2384,MULTIMATIC +12970-13-2386,TUBEASSY-CLUTCH,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,12970-13-2386,MULTIMATIC +5801384838,full hose,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801384838,lancia bz +16L0043CP REV02,,0.0,0,5.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,PIPE-OUTLET-PRE,P16 +16LA027SP REV02,,0.0,0,15.0,15.0,10,10,30.0,30.0,0,0.0,0.0,0,,HOSE-LH WCAC AN,P16 +16LA648CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-RH-LTR-OUT,P16 + 16LA661CP REV1,HOSE-RH-HT-RADIATOR-BOT,0.0,0,20.0,20.0,20,20,30.0,20.0,0,5.0,1.0,1,,HOSE-RH-HT-RADI,P16 + 16LA449CP REV2,,0.0,0,5.0,10.0,10,10,30.0,30.0,0,0.0,0.0,0,,HOSE-ENGINE-TO-,P16 + 16L0045CP REV2,,0.0,0,10.0,10.0,10,10,30.0,20.0,0,10.0,0.0,0,,HOSE-HT-RADIATO,P16 +16LA718CP REV02,MCLAREN,0.0,0,10.0,10.0,10,10,30.0,20.0,0,10.0,0.0,0,,HOSE-E-MOTOR-OU,P16 + 16L0075CP REV3,,0.0,0,5.0,10.0,10,10,20.0,30.0,0,0.0,0.0,0,,HOSE-HEADER-TAN,P16 +5803112815 R.1,COMPL.MAN,0.0,0,5.0,5.0,15,15,10.0,30.0,0,5.0,1.0,1000,,5803112815 R1, +5803112816 R.1,COMPL.MAN,0.0,0,5.0,5.0,15,15,10.0,20.0,0,10.0,1.0,100,, 5803112816 R.1, +16LA397CP REV02,,0.0,0,5.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,HOSE-HT-RADIATO,P16 +16LA765CP REV01,,0.0,0,5.0,5.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-WCACS LINK,P16 +16LA695CP REV02,,0.0,0,15.0,15.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE PRE COOLER,P16 +5801384840 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801384840 REV0,LANCIA BOLZANO +60175799 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,60175799 REV0,LANCIA BOLZANO +5803103147 REV0,UNIT GASOIL PIPE FILTER,0.0,0,25.0,30.0,10,10,20.0,20.0,0,0.0,0.0,0,,UNIT GASOIL PIL,IVECO +5803103150 REV0,UNIT GASOIL PIPE FILTER,0.0,0,20.0,30.0,10,10,20.0,20.0,0,10.0,0.0,0,,UNIT GASOIL PIL,IVECO +5801970063 REV0,,0.0,0,5.0,10.0,10,10,30.0,30.0,0,10.0,0.0,0,,5801970063,"LANCIA,BOLZANO" +5801616061,,0.0,0,5.0,10.0,10,10,30.0,30.0,0,10.0,0.0,0," +",5801616061,"LANCIA,BOLZANO" + 16LA584CP REV1,,0.0,0,5.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-TRANS HX-R,P16 +5801384842 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801384842 REV0,LANCIA BOLZANO +5801970066 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801970066,LANCIA BOLZANO +16LA372CP REV01,MCLAREN,0.0,0,5.0,10.0,10,10,30.0,20.0,0,10.0,0.0,0,,PIPE-IN-PRE-COO,P16 +16LA518CP REV02,P16,0.0,0,5.0,10.0,10,10,20.0,20.0,0,10.0,0.0,0,,HOSE-TO-E-MOTOR,P16 +16LA680CP REV01,,0.0,0,20.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-TRANS- HX-,P16 +16FB157CP REV 3,MCLAREN,0.0,0,15.0,5.0,10,10,30.0,50.0,0,2.0,0.0,0,,ASSY CCV-OIL TA,P16 +16FC256CP REV01,ASSY CCV,0.0,17000,15.0,10.0,20,20,20.0,50.0,0,2.0,0.0,0,,ASSY MAKE UP AI,P16 +16L0151CP REV03,,0.0,0,20.0,25.0,10,10,30.0,20.0,0,5.0,0.0,0,,HOSE-IPU-OUTLET,P16 +16L0170CP REV03,,0.0,0,5.0,10.0,10,10,30.0,25.0,0,5.0,0.0,0,,HOSE-IPU-OUTLET,P16 +16L0161CP REV04,,0.0,0,15.0,15.0,10,10,30.0,20.0,0,5.0,0.0,0,,HOSE-WCACS-TO-M,P16 +16L0167CP REV02,,0.0,0,10.0,20.0,10,10,30.0,20.0,0,5.0,0.0,0,,HOSE-TO-MCU,16L0167CP REV02 +504321531,,0.0,0,5.0,10.0,10,10,30.0,30.0,0,10.0,0.0,0," +",504321531,"LANCIA,BOLZANO" +16L0180CP REV04,,0.0,0,15.0,10.0,10,10,30.0,20.0,0,0.0,1.0,0,,HOSE-LH-LTR-OUT,P16 +16L0154CP REV03,,0.0,0,15.0,25.0,10,10,30.0,20.0,0,5.0,1.0,0,,HOSE-RH-LTR-OUT,P16 +5801970064 REV0,,0.0,0,5.0,10.0,10,10,30.0,30.0,0,10.0,0.0,0,,5801970064 REV0,"LANCIA,BOLZANO" +16FC446CP REV01,ASSY CCV,0.0,17000,5.0,5.0,20,20,20.0,50.0,0,2.0,0.0,0,,FED,T16C-Z0800-001 + 16LA397CP REV2,,0.0,0,5.0,5.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-HT-RADIATO,P16 +16L0164CP REV02,,0.0,0,10.0,15.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-LH-LTR-OUT,P16 +16LA461CP REV02,,0.0,0,10.0,10.0,10,10,20.0,20.0,0,0.0,0.0,0,,ASSY-HOSE-HT-RT,P16 +16L0177CP REV03,,0.0,0,15.0,10.0,10,10,30.0,20.0,0,0.0,1.0,0,,HOSE-JNCTN TO W,P16 +16L0007CP RE3,,0.0,0,5.0,5.0,10,10,30.0,20.0,0,5.0,0.0,0,,HOSE-IPU-JNCTN-,P16 +16LA586CP REV1,,0.0,0,15.0,15.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE PRE COOLER,P16 +16FA849CP REV02,,0.0,17000,5.0,5.0,20,20,20.0,50.0,0,2.0,0.0,0,,ASSY OIL FILL,P16 +16FC084CP REV2,,0.0,0,5.0,5.0,10,10,20.0,50.0,0,0.0,0.0,0,,BALANCE PIPE-IN,P16 +16LA573CP REV01,,0.0,0,5.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE MCU-TO-MOT,P16 +16L0145CP REV3,,0.0,0,5.0,15.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-HOSE-PUMP-,P16 +16FB394CP REV04,,0.0,0,5.0,5.0,10,10,30.0,30.0,0,5.0,0.0,0,,ASSY INLET PURG,P16 +16FC069CP REV1,,0.0,0,10.0,15.0,10,10,20.0,50.0,0,5.0,0.0,0,,ASSY CCV-INTAKE,P16 +60192056 REV1,FUEL HOSE,0.0,0,20.0,10.0,10,10,20.0,20.0,0,5.0,0.0,0,,60192056 REV1,LANCIA BOLZANO +5801970065 REV0,,0.0,0,20.0,20.0,10,10,30.0,30.0,0,0.0,0.0,0,,5801970065 RE0,"LANCIA,BOLZANO" +5801384841 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801384841 REV0,LANCIA BOLZANO +5801384839 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801384839 REV0,LANCIA BOLZANO +5803112815 R.1,COMPL.MAN,0.0,0,5.0,5.0,15,15,10.0,30.0,0,5.0,1.0,1000,,5803112815 R1, +16JA605CP,,10.0,500,10.0,30.0,10,10,10.0,20.0,0,10.0,0.0,0,,16JA603CP, +5803112815,,0.0,0,5.0,5.0,5,10,10.0,30.0,0,5.0,0.0,0,,5803112816, +5801970067 REV1,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801970067 REV0,LANCIA BOLZANO +000746453,000746453,0.0,0,10.0,20.0,10,10,30.0,30.0,0,10.0,0.0,0,,, +5801862227 REV0,FUEL HOSE,0.0,0,10.0,5.0,10,10,20.0,20.0,0,5.0,0.0,0,,5801862227 REV0,LANCIA BOLZANO +5803018239,PIPE,0.0,0,5.0,10.0,10,10,10.0,10.0,0,5.0,0.0,0,,5803018239,PIPE +5803018238,PIPE,0.0,0,5.0,10.0,10,10,10.0,10.0,0,5.0,0.0,0,,5803018238,PIPE +5803018244,PIPE,0.0,0,5.0,10.0,10,10,10.0,10.0,0,5.0,0.0,0,,5803018244,PIPE +5803018243,PIPE,0.0,0,5.0,10.0,10,10,10.0,10.0,0,5.0,0.0,0,,5803018243,PIPE +16LA668CP REV01,,0.0,0,15.0,15.0,10,10,30.0,30.0,0,0.0,0.0,0,,HOSE-LH WCAC AN,P16 +16LA773CP REV01,,0.0,0,20.0,10.0,10,10,30.0,20.0,0,0.0,0.0,0,,HOSE-TRANS- HX-,P16 +98FA644CP,,10.0,2000,10.0,10.0,20,20,20.0,150.0,0,0.0,0.0,0,,,P98 + 16LA353CP REV2,HOSE-RH-HT-RADIATOR-TOP,0.0,0,20.0,15.0,20,20,30.0,20.0,0,5.0,2.0,1,,HOSE-RH-HT-RADI,P16 + 98FB081CP REV1,,0.0,0,10.0,10.0,10,10,20.0,10.0,0,10.0,0.0,0,,ASSY-PIPE-CCV-T, +98FB342CP,,0.0,0,10.0,10.0,10,10,20.0,10.0,0,0.0,0.0,0,,18FB342CP, +16L0046CP REV3,HOSE-RH-HT-RADIATOR-BOT,0.0,0,20.0,10.0,10,10,20.0,20.0,0,5.0,1.0,1,,HOSE-LH-HT-RADI,P16 +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +NESSUN NOME,,0.0,0,1.0,1.0,10,10,1.0,0.0,0,0.0,0.0,0,,, +98FB080CP,,0.0,0,10.0,10.0,10,10,20.0,10.0,0,20.0,0.0,0,,98FB080CP, +98FA186CP,98FA186CP,0.0,0,5.0,10.0,10,10,20.0,15.0,0,15.0,0.0,0,,98FA186CP, +5802991065,,0.0,0,5.0,5.0,10,10,10.0,30.0,0,5.0,0.0,0,,IVECO, +TENUTA 20 bar,,0.0,0,5.0,40.0,10,10,10.0,1.0,0,1.0,2.0,0,,, +FUGA,,0.0,0,5.0,40.0,10,10,5.0,5.0,0,0.0,2.0,0,,, +112247,j112247,0.0,1000,15.0,15.0,5,5,10.0,30.0,7000,30.0,1.0,100,,112247, From a3903678a155b456c59c3330a5df19dd99b9ea6e Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 9 Oct 2024 12:44:11 +0200 Subject: [PATCH 26/88] ref --- .../T3P20RR SN 20060720 09 10 2024.csv} | 0 ... Tubi riscaldati - COMPLETA rev09_27-10-2022.csv | 0 ... Tubi riscaldati - COMPLETA rev19_29-12-2022.csv | 0 ...Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx | Bin ...13-03-2024.xlsx - Tubi riscaldati costampati.csv | 0 ...19-04-2024.xlsx - Tubi riscaldati costampati.csv | 0 ...07-05-2024.xlsx - Tubi riscaldati costampati.csv | 0 ...13-05-2024.xlsx - Tubi riscaldati costampati.csv | 0 .../Tabella Tubi riscaldati - campi extra.csv | 0 .../{ => TEST}/test_doppia_prova_tenuta.csv | 0 .../{ => TEST}/test_import_himatic my24.csv | 0 .../csv_import/{ => TEST}/test_import_himatic.csv | 0 .../csv_import/{ => TEST}/test_import_himatic.xlsx | Bin .../csv_import/{ => TEST}/test_import_leak_only.csv | 0 config/csv_import/{ => TEST}/test_tecna_upload.csv | 0 config/csv_import/{ => TEST}/tst.csv | 0 config/csv_import/test.py | 12 ------------ 17 files changed, 12 deletions(-) rename config/csv_import/{ricette tecna t3p st-te-11.csv => EXTRACTIONS/T3P20RR SN 20060720 09 10 2024.csv} (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => HEATED PIPES}/Tabella Tubi riscaldati - campi extra.csv (100%) rename config/csv_import/{ => TEST}/test_doppia_prova_tenuta.csv (100%) rename config/csv_import/{ => TEST}/test_import_himatic my24.csv (100%) rename config/csv_import/{ => TEST}/test_import_himatic.csv (100%) rename config/csv_import/{ => TEST}/test_import_himatic.xlsx (100%) rename config/csv_import/{ => TEST}/test_import_leak_only.csv (100%) rename config/csv_import/{ => TEST}/test_tecna_upload.csv (100%) rename config/csv_import/{ => TEST}/tst.csv (100%) delete mode 100644 config/csv_import/test.py diff --git a/config/csv_import/ricette tecna t3p st-te-11.csv b/config/csv_import/EXTRACTIONS/T3P20RR SN 20060720 09 10 2024.csv similarity index 100% rename from config/csv_import/ricette tecna t3p st-te-11.csv rename to config/csv_import/EXTRACTIONS/T3P20RR SN 20060720 09 10 2024.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - campi extra.csv b/config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - campi extra.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - campi extra.csv rename to config/csv_import/HEATED PIPES/Tabella Tubi riscaldati - campi extra.csv diff --git a/config/csv_import/test_doppia_prova_tenuta.csv b/config/csv_import/TEST/test_doppia_prova_tenuta.csv similarity index 100% rename from config/csv_import/test_doppia_prova_tenuta.csv rename to config/csv_import/TEST/test_doppia_prova_tenuta.csv diff --git a/config/csv_import/test_import_himatic my24.csv b/config/csv_import/TEST/test_import_himatic my24.csv similarity index 100% rename from config/csv_import/test_import_himatic my24.csv rename to config/csv_import/TEST/test_import_himatic my24.csv diff --git a/config/csv_import/test_import_himatic.csv b/config/csv_import/TEST/test_import_himatic.csv similarity index 100% rename from config/csv_import/test_import_himatic.csv rename to config/csv_import/TEST/test_import_himatic.csv diff --git a/config/csv_import/test_import_himatic.xlsx b/config/csv_import/TEST/test_import_himatic.xlsx similarity index 100% rename from config/csv_import/test_import_himatic.xlsx rename to config/csv_import/TEST/test_import_himatic.xlsx diff --git a/config/csv_import/test_import_leak_only.csv b/config/csv_import/TEST/test_import_leak_only.csv similarity index 100% rename from config/csv_import/test_import_leak_only.csv rename to config/csv_import/TEST/test_import_leak_only.csv diff --git a/config/csv_import/test_tecna_upload.csv b/config/csv_import/TEST/test_tecna_upload.csv similarity index 100% rename from config/csv_import/test_tecna_upload.csv rename to config/csv_import/TEST/test_tecna_upload.csv diff --git a/config/csv_import/tst.csv b/config/csv_import/TEST/tst.csv similarity index 100% rename from config/csv_import/tst.csv rename to config/csv_import/TEST/tst.csv diff --git a/config/csv_import/test.py b/config/csv_import/test.py deleted file mode 100644 index cf35294..0000000 --- a/config/csv_import/test.py +++ /dev/null @@ -1,12 +0,0 @@ -import csv -import itertools - -# DOES NOT WORK -def lower_first(iterator): - return itertools.chain([next(iterator).lower()], iterator) - -with open("Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv", 'rU') as datafile: - csvDict = csv.DictReader(lower_first(datafile)) - for ucrow in csvDict: - row = dict((k.lower(), v) for k, v in ucrow.items()) # WORKS - print(row) \ No newline at end of file From 7a7c2b6f5d2821c0553c350d4d22891e23b32558 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 9 Oct 2024 13:12:40 +0200 Subject: [PATCH 27/88] simple leak test on linux tested OK --- .../T3LP20RR SN 030022040361 09 10 2024.csv} | 0 config/label_templates/ETA30x16_203dpi.prn | 14 ++++++++++++++ config/machine_settings/test-linux.ini | 9 ++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) rename config/csv_import/{ricette tecna st-ten-11 030022040361.csv => EXTRACTIONS/T3LP20RR SN 030022040361 09 10 2024.csv} (100%) create mode 100644 config/label_templates/ETA30x16_203dpi.prn diff --git a/config/csv_import/ricette tecna st-ten-11 030022040361.csv b/config/csv_import/EXTRACTIONS/T3LP20RR SN 030022040361 09 10 2024.csv similarity index 100% rename from config/csv_import/ricette tecna st-ten-11 030022040361.csv rename to config/csv_import/EXTRACTIONS/T3LP20RR SN 030022040361 09 10 2024.csv diff --git a/config/label_templates/ETA30x16_203dpi.prn b/config/label_templates/ETA30x16_203dpi.prn new file mode 100644 index 0000000..4612fb0 --- /dev/null +++ b/config/label_templates/ETA30x16_203dpi.prn @@ -0,0 +1,14 @@ +CT~~CD,~CC^~CT~ +^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR2,2~SD20^JUS^LRN^CI0^XZ +^XA +^MMT +^PW256 +^LL0144 +^LS0 +^FT148,125^BQN,2,4 +^FH\^FDLA,{PART}^FS +^FT19,40^A0N,23,21^FH\^FD{PART}^FS +^FT19,71^A0N,23,21^FH\^FDNum:{SN5}^FS +^FT19,101^A0N,23,21^FH\^FD{DATE}^FS +^FT19,126^A0N,23,21^FH\^FD{TIME}^FS +^PQ1,0,1,Y^XZ diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index 978f515..fa0aeab 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -19,6 +19,9 @@ fixture_id: absent digital_io: present external_flush_blow: absent +[archive_synchronizer] +archive_endpoint: https://dev.r5portal.it/api/st-ten-save/ + [tecna_t3] port: /dev/ttyUSB0 model: t3p @@ -40,8 +43,8 @@ label_template_field: modello_etichetta description_field: descrizione [label_printer] -platform: windows -printer: zd420 +platform: linux +printer: Zebra_Technologies_ZTC_ZD421-203dpi_ZPL [recipes_defaults] tester_discharge_enable: yes @@ -50,7 +53,7 @@ cliente: IVECO part_number: specificare part number canale_di_prova: 0 warning_img: - +pid_pressure_correction: 105 dimensione_lotto_abilitata: n_componenti:1 istruzione_abilitata: x From 88c45fc9c4e1c06a560b4269a82ad90e12b264fe Mon Sep 17 00:00:00 2001 From: eduardo Date: Thu, 10 Oct 2024 08:49:36 +0200 Subject: [PATCH 28/88] dev --- .../st-ten-11/Mclaren _label.prn | 29 +++++++++++++++++++ src/requirements.txt | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 config/label_templates/st-ten-11/Mclaren _label.prn diff --git a/config/label_templates/st-ten-11/Mclaren _label.prn b/config/label_templates/st-ten-11/Mclaren _label.prn new file mode 100644 index 0000000..f427d11 --- /dev/null +++ b/config/label_templates/st-ten-11/Mclaren _label.prn @@ -0,0 +1,29 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD25 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW320 +^LL1039 +^LS0 +^FO71,44^GFA,333,672,24,:Z64:eJx10DGOhDAMBdBEKVKyN8hRcrTQcS06rgE7BeUgUYCE4e93YBaNFKB7jp3vGFP6/FRkAylyhaPoqewOZa8ePD44UMzjHjzUDqW9Lndi2GXvzh/e0PIthBXjvhKoB6nE4nVYwMQ2Hg69STXT0h1m9Tr1CTo8aY9EidjUB8xAxzqHWkgSnD5jAUagXXULwcc3bqSlvmcc7Pw5nwk2vCXQB43DIzs0pzZVEhdJQ50f73SbnfMl/jJOGrFkd5d3EnuN2WHcUd/eZHdo0O0aZbvn5DgNmoJX4uHl3/3Hw+oPL+n0WS+5fPLiJVBX4MWHxTgF+h/c8Rx8:87AE +^FO88,85^GFA,181,224,8,:Z64:eJxjqGAAAjkGhh/yHyx45BkYD8j/sOBhbmBskJCx4WEE0XxQms0ESpuh0UZQ2hiJZmaQ4DPkYTjAziAhY9jD8ECOQf6HQQ9DBZD+YHCGoQIozgCkHzA3AGkfxgOMIDoHrB9B60BpGzRaBpkGuR9IHwDRzA0MP0C0PAMD1F8A62MrVg==:19A1 +^FO93,119^GFA,241,560,20,:Z64:eJyd0jEKwzAMBVAJQbwEunYo8RU85jg5RrboaDqKj9DRQwn1txKKodASf7A/D4QdCK1U14SttdbLMixDpG2nwi8kElsa0yi67WxuoqwwVoRGBO1e1z9WR9NVq89bfpuQmBgZmhtZcMus4bQ8UZtaWafT1m8W3NosvjzVWWk3Mu5QN/RPDtMrNj+Q3hrNvd2eSG8hI+29dWH3hpMNp8DMrfaCM2IrbvH4I/p/4w1W22oA:A9D8 +^FO66,186^GFA,389,896,32,:Z64:eJyF00tuhDAMBmCjqWATwdYLq7lCRpVaFkjtUTjCLLsrR8tROAJLFtGodmwegzRMNujXF4VgG4An61cfCD5dhlAD+MmnagwO4e/OMGs2R/bZp2ZevIiakU8oYwh8EiFQJ14M7INm8xt7jdC6nedsPrKXCAF2nrP6NZ6566/DuX+AOh4czT/N6eBk3oHev4HH+zdSvwlDdvITV8r8YnlzrtcE4+KV5XyDIO/nfQC3xd8tq3/J+T+caXPN4t9z/r6es9vO16ye6yNNLNf7DTm/5ZpgiEcvHl36gwfHxXsX+hcu88ES6pZWd9qN7KjeEbV778gnn9hJ+iPz1vBULv2RLB5LmV+sZF6rcfWcn42/7DlbRTx3mF+4/V//Fzl49A==:0843 +^PQ1,0,1,Y +^XZ diff --git a/src/requirements.txt b/src/requirements.txt index 214557b..b4946f4 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -10,7 +10,7 @@ opencv-python-headless peewee pillow pycoral -pymodbus +pymodbus~=3.6.8 pyqt5 pyqt5-tools pyserial From a32515ff094e062ae613102febc99a69e09f77d2 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Thu, 10 Oct 2024 10:15:17 +0200 Subject: [PATCH 29/88] Label Lamborghini --- .../LAMBORGHINI/Lamborghini_test.nlbl | Bin 0 -> 3700 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 config/label_designs/LAMBORGHINI/Lamborghini_test.nlbl diff --git a/config/label_designs/LAMBORGHINI/Lamborghini_test.nlbl b/config/label_designs/LAMBORGHINI/Lamborghini_test.nlbl new file mode 100644 index 0000000000000000000000000000000000000000..d2c10bad5851496b91ea83156343e4c39e6589b7 GIT binary patch literal 3700 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 KfAl5rpXy&piO?kg literal 0 HcmV?d00001 From 9a6d88047c78ed401f804b4df8bdf72bedbd2df4 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Thu, 10 Oct 2024 10:26:34 +0200 Subject: [PATCH 30/88] Label Lamborghini --- .../st-ten-11/Lamborghini_lable.prn | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 config/label_templates/st-ten-11/Lamborghini_lable.prn diff --git a/config/label_templates/st-ten-11/Lamborghini_lable.prn b/config/label_templates/st-ten-11/Lamborghini_lable.prn new file mode 100644 index 0000000..7349e8b --- /dev/null +++ b/config/label_templates/st-ten-11/Lamborghini_lable.prn @@ -0,0 +1,34 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD20 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW192 +^LL240 +^LS0 +^FT19,173^BXN,7,200,0,0,1,_,1 +^FH\^FD#{RECIPE}###{DD}{MO}{YY}*\0D\0A^FS +^FT9,204^A0N,24,23^FH\^CI28^FD#^FS^CI27 +^FT20,205^A0N,25,25^FH\^CI28^FD{RECIPE}^FS^CI27 +^FT118,204^A0N,24,23^FH\^CI28^FD#^FS^CI27 +^FT129,204^A0N,24,23^FH\^CI28^FD#^FS^CI27 +^FT141,204^A0N,24,23^FH\^CI28^FD#^FS^CI27 +^FT2,227^A0N,22,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT170,232^A0N,28,28^FH\^CI28^FD*^FS^CI27 +^PQ1,0,1,Y +^XZ From 26a59ac60002d4df92ceb96709f9d851873b6c6a Mon Sep 17 00:00:00 2001 From: eduardo Date: Thu, 10 Oct 2024 10:35:36 +0200 Subject: [PATCH 31/88] Mclaren labels --- .../MCLAREN/MCLAREN_TEMPLATE.nlbl | Bin 0 -> 3215 bytes .../st-ten-11/Mclaren_label.prn | 29 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 config/label_designs/MCLAREN/MCLAREN_TEMPLATE.nlbl create mode 100644 config/label_templates/st-ten-11/Mclaren_label.prn diff --git a/config/label_designs/MCLAREN/MCLAREN_TEMPLATE.nlbl b/config/label_designs/MCLAREN/MCLAREN_TEMPLATE.nlbl new file mode 100644 index 0000000000000000000000000000000000000000..43434466bc7bf520432d2e81da9d87a126f92707 GIT binary patch literal 3215 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 k|7rT?CH> Date: Thu, 10 Oct 2024 10:35:53 +0200 Subject: [PATCH 32/88] Mclaren labels --- .../st-ten-11/Mclaren _label.prn | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 config/label_templates/st-ten-11/Mclaren _label.prn diff --git a/config/label_templates/st-ten-11/Mclaren _label.prn b/config/label_templates/st-ten-11/Mclaren _label.prn deleted file mode 100644 index f427d11..0000000 --- a/config/label_templates/st-ten-11/Mclaren _label.prn +++ /dev/null @@ -1,29 +0,0 @@ -CT~~CD,~CC^~CT~ -^XA -~TA000 -~JSN -^LT0 -^MNW -^MTT -^PON -^PMN -^LH0,0 -^JMA -^PR2,2 -~SD25 -^JUS -^LRN -^CI27 -^PA0,1,1,0 -^XZ -^XA -^MMT -^PW320 -^LL1039 -^LS0 -^FO71,44^GFA,333,672,24,:Z64:eJx10DGOhDAMBdBEKVKyN8hRcrTQcS06rgE7BeUgUYCE4e93YBaNFKB7jp3vGFP6/FRkAylyhaPoqewOZa8ePD44UMzjHjzUDqW9Lndi2GXvzh/e0PIthBXjvhKoB6nE4nVYwMQ2Hg69STXT0h1m9Tr1CTo8aY9EidjUB8xAxzqHWkgSnD5jAUagXXULwcc3bqSlvmcc7Pw5nwk2vCXQB43DIzs0pzZVEhdJQ50f73SbnfMl/jJOGrFkd5d3EnuN2WHcUd/eZHdo0O0aZbvn5DgNmoJX4uHl3/3Hw+oPL+n0WS+5fPLiJVBX4MWHxTgF+h/c8Rx8:87AE -^FO88,85^GFA,181,224,8,:Z64:eJxjqGAAAjkGhh/yHyx45BkYD8j/sOBhbmBskJCx4WEE0XxQms0ESpuh0UZQ2hiJZmaQ4DPkYTjAziAhY9jD8ECOQf6HQQ9DBZD+YHCGoQIozgCkHzA3AGkfxgOMIDoHrB9B60BpGzRaBpkGuR9IHwDRzA0MP0C0PAMD1F8A62MrVg==:19A1 -^FO93,119^GFA,241,560,20,:Z64:eJyd0jEKwzAMBVAJQbwEunYo8RU85jg5RrboaDqKj9DRQwn1txKKodASf7A/D4QdCK1U14SttdbLMixDpG2nwi8kElsa0yi67WxuoqwwVoRGBO1e1z9WR9NVq89bfpuQmBgZmhtZcMus4bQ8UZtaWafT1m8W3NosvjzVWWk3Mu5QN/RPDtMrNj+Q3hrNvd2eSG8hI+29dWH3hpMNp8DMrfaCM2IrbvH4I/p/4w1W22oA:A9D8 -^FO66,186^GFA,389,896,32,:Z64:eJyF00tuhDAMBmCjqWATwdYLq7lCRpVaFkjtUTjCLLsrR8tROAJLFtGodmwegzRMNujXF4VgG4An61cfCD5dhlAD+MmnagwO4e/OMGs2R/bZp2ZevIiakU8oYwh8EiFQJ14M7INm8xt7jdC6nedsPrKXCAF2nrP6NZ6566/DuX+AOh4czT/N6eBk3oHev4HH+zdSvwlDdvITV8r8YnlzrtcE4+KV5XyDIO/nfQC3xd8tq3/J+T+caXPN4t9z/r6es9vO16ye6yNNLNf7DTm/5ZpgiEcvHl36gwfHxXsX+hcu88ES6pZWd9qN7KjeEbV778gnn9hJ+iPz1vBULv2RLB5LmV+sZF6rcfWcn42/7DlbRTx3mF+4/V//Fzl49A==:0843 -^PQ1,0,1,Y -^XZ From 4ad66b3b59a06b9e41553e93470718c581546919 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Thu, 10 Oct 2024 10:37:59 +0200 Subject: [PATCH 33/88] Label Lamborghini --- .../LAMBORGHINI/Lamborghini_label.nlbl | Bin 0 -> 3323 bytes .../st-ten-11/Lamborghini_label.prn | 29 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 config/label_designs/LAMBORGHINI/Lamborghini_label.nlbl create mode 100644 config/label_templates/st-ten-11/Lamborghini_label.prn diff --git a/config/label_designs/LAMBORGHINI/Lamborghini_label.nlbl b/config/label_designs/LAMBORGHINI/Lamborghini_label.nlbl new file mode 100644 index 0000000000000000000000000000000000000000..39959e5502372e93062eed35ee0f1a09031ede49 GIT binary patch literal 3323 zcmb`KS5y;-5{4590V&e4(IG&jN)?bGy@VoFB!Ki1x)cGa(xZkZU22dj9TDk-CJ;hL zDItO&N|z!?iFbD&_ME%-?Ax6=XZ|w}Gylsxd~**@4q^cS0S*9pQ{4yMU1UwzO8`KC z698}xAP&&yo%k80uoxPI>Fq`s^Ar%dBDgZTr8}MfU0apRq z2co>Y*B5~Q)ZXj!mA;4D!>7_9**5jjJHgYkJ(K6D5eynoyQ40cNvJzDr~?^sASHX= zOXu?r&(J$3XjIWasfVG2#b&Ckl3EN(WYM2R(i5^_0|mXUP^`>GSr&@Dva^P)6%7Qz zOBTwX8a!7Ts=y-T=0Q4DvO*M;l9q%r!Ak`Qe6aJ_Kf6~*JboJmYA##n<-wr z7j_pf?)dSDVg%IOJIgsQzGJO8mYL{}0BN+;X0CpWE``Fd@S=7js`#<{DWY*HoktA> z)-7rpv8+{oNlBmNuYh{P0rQANX`tm@lq;hN!~68Xu|a2uciFN2sP?n@q49JCsj(Lm zv)|T;cx^;wxLuXRE#^5_`TAMAm^=TTc_@c`q`=j8%Q|F&DQROrk=i`=>X@2bpV7s7 zdjwjcU+l_P61E?a1-wD}Vw|ookvJ^phz{p=(godD@NCdv`^$gJ3IB zlk4}7623(h+Nw`_xqH>RwP5wqu%TT}yZcMW_jlAeh^%hiPxMi-yK!&%7VSZNs7QrX z4JRP(d;W1k{)O0ldz9+EHZscZgpBe;A?I!{lTfy0dIz}bepG!++nbJL_HimT3`KD? zeLmDw@{)jQ5mw-fB$Dk6njGB!d>876AgEi9nX|hRJ3t-f0oHpoyozh~SWGeKUUPC# z7@K`h*@pquw(G8K*e$-^XfA0BMODC1t{89oB_o`vgy!-m9+Ha%AjjLlwsVh+%%00cUhLL;07pxV6ShOqy z)8ad1*dBakeO@<{T3BBS@y}`|w`UWkL`n)z&K8S14X6E-sk@-06+Yeiaz#VdLBEsE z=prwTKcCoxf7nbWbe{AD77K;UJiuA2>F9Cbm2V`*p*_5um4M+zCa+W`Zu!OCmUZpO z63@4&y&n}uFc_8dR^s8oC9EWTCp)ex`DXRzW=yUlcz&ab{%3OjCA0??1NgZiX z#1B~sG&SU$i6j@*FVt`^P<4#zN|3rQ->FGRj;2zsX-fw=o7z#y5z_mb&gPTG!j^V8 z5N3yMYd5Zhq6Ec)tA8eaiXOZkPr`NNqToKiLKp{JJKIaPQa&CA!p>oGxjkku6sN*D7kZ zm-8kGLufoBhk|zjVgDR=x!D%yIRl+7A2&z$A9^aqV~Y!U1uqAZ+B+?4mbg1!xKw2` z`l1l83%z_L;$g5IEj6>o&$@Weg;GNHg&AC8cLjeuUX3H+)edPsEjHD+k1Ig@l4x+@ zBAhhS$zRjvoPpv@W>oOhJFkO;6y%2-U6p@^C%Y8$(TRs#llj^1#b-?elN}mLcSmQL}TvyQf-aqG0Dr8rMUUUjxbs zUG(z&{DvIL%yl3Wb8+sD;G@Z--#pdpd%xd2-;%y%*$ue=G4Xk3! ziIP6ng)NsIi3GI}BmD_rZ(GVtVgbGO#DKN{<{v%s%^H|@!2Os_+p0Am`HxzGxo z8SzFGW18+cTkP1O>PP!ONFIFhYqe#4aL6oQ#>14@`rk%6nOxE1aSrAwR$O0XHUyz1vLVhQ5irV(vvd|0GW3g>nmg@FEWB)QT2zJ}2vA+$rUU6d>kSv% zqTQjE-da7|ym0CKD92P;#@0cY^jdvr?>1P`#l;bh1ZG>Jd9_vRX(FFgEHGgxb9w;F zTE53?kyWmVM#T3)=b&q4RL8#lk|wGE@EA_R?mWcb|8aM9`Oi2-K23GyK|e(^UXy;g zY0V*S#)qFWdB9n+ISy!E!o(6y`kfmUjh>`ZNx_(Gon$?eSQyWb1+dL%+O07=!@7Pu zM=M+JfQua-TiQ@7=A8ZnR*=&5*>dKQiM9av+!Wd3h}ecqp|7&jCLJY4=xZ0(fQ^|9 zz#x9{Wa2|b>AG8BL;;E1J>X3~@qAD~S|>iwB2Jar=}dr<_8PNI{Q6EB{v|l{=42?+ z`+K-kE0nH4H)6%TvfyKyMsKzm`OgrR8vl(nZ)Z=W{F{V5#`4L$v}P+vb(VMS%NOXEun5uLKEW#=Su<3BE{qwAs@ro0gL&U5-A3g@(G?4TLT5lLdb$Dk_BzY zkS=v<=6)fxFG8Z>Xf8aauBnluHMvrIidQ&s6LS7WbTUiS0cad4;8_TVZ@bMqqrh}eJc&W=b2F{9UW1|Fn1fSbKRdZmiVQ>8es78-HgDEW!V(!<uuB0_pA_};)Kp!eJn9)gjm4?wrDv9H>f2=ouyiVworeLouZlu2)od{R2 z*s!y~*L(lPiN_co4qqSu@PiBhVEcm;|A!C7{5-sZ{sj^%2x5Oh;y)Ffs~y{^i5+nw zEvB8AgQXS2@yG4<0f*>L_4Y4shj(6`HBQ-$?9)m!^(|Q{ZXe;J0^f7~5Z>mCGxgh( zlsjxc)2EoQa4kXN$uMZOl!Fi|U=Ghg@Y~Ny1t0xWdZ$w<_CDv(J z)x6ctklHlW4|&X(6P9`Gvr^<%W6)>FhJ;+>d=oiVZTy&|XVZHyC?y1zmLsO-C5zx_8=g*Z@?Bz${e2`l)OF_;A0-d2 zotA_VmQ6&N>QjTG<*peXM2~pD1&h0EIfZM&(u8v*Ce#dQuk^1j$+T<5?v46#luHYZ)q6r!GUC= vfPbg|zp(!A^8fk;{^|P9Tl(7&AVdxL|6JBRI0g96wPb(f_doQU=Fjdw({l!p literal 0 HcmV?d00001 diff --git a/config/label_templates/st-ten-11/Lamborghini_label.prn b/config/label_templates/st-ten-11/Lamborghini_label.prn new file mode 100644 index 0000000..77eac97 --- /dev/null +++ b/config/label_templates/st-ten-11/Lamborghini_label.prn @@ -0,0 +1,29 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD20 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW192 +^LL240 +^LS0 +^FT19,173^BXN,7,200,0,0,1,_,1 +^FH\^FD#{RECIPE}###{DD}{MO}{YY}*\0D\0A^FS +^FT20,205^A0N,25,25^FH\^CI28^FD#{RECIPE}###^FS^CI27 +^FT2,227^A0N,22,23^FH\^CI28^FD{DD}/{MO}/{YY}*^FS^CI27 +^PQ1,0,1,Y +^XZ From 3acbbe85086db91cca0564a698f0f2c491da5273 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Thu, 10 Oct 2024 10:43:23 +0200 Subject: [PATCH 34/88] Label Lamborghini --- .../LAMBORGHINI/Lamborghini_label.nlbl | Bin 3323 -> 3325 bytes .../st-ten-11/Lamborghini_label.prn | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/label_designs/LAMBORGHINI/Lamborghini_label.nlbl b/config/label_designs/LAMBORGHINI/Lamborghini_label.nlbl index 39959e5502372e93062eed35ee0f1a09031ede49..3644cb5755e13e24dbb3666cc7bc0162d869a577 100644 GIT binary patch delta 3109 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 literal 3323 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 diff --git a/config/label_templates/st-ten-11/Lamborghini_label.prn b/config/label_templates/st-ten-11/Lamborghini_label.prn index 77eac97..fc7b766 100644 --- a/config/label_templates/st-ten-11/Lamborghini_label.prn +++ b/config/label_templates/st-ten-11/Lamborghini_label.prn @@ -1,4 +1,4 @@ -CT~~CD,~CC^~CT~ +CT~~CD,~CC^~CT~ ^XA ~TA000 ~JSN @@ -24,6 +24,6 @@ ^FT19,173^BXN,7,200,0,0,1,_,1 ^FH\^FD#{RECIPE}###{DD}{MO}{YY}*\0D\0A^FS ^FT20,205^A0N,25,25^FH\^CI28^FD#{RECIPE}###^FS^CI27 -^FT2,227^A0N,22,23^FH\^CI28^FD{DD}/{MO}/{YY}*^FS^CI27 +^FT19,230^A0N,22,23^FH\^CI28^FD{DD}/{MO}/{YY}*^FS^CI27 ^PQ1,0,1,Y ^XZ From c4e83468c815eeedb2305cc47160d4834131e557 Mon Sep 17 00:00:00 2001 From: neo Date: Fri, 18 Oct 2024 12:37:07 +0200 Subject: [PATCH 35/88] new extra synchronizer endpoint wip --- config/machine_settings/defaults.ini | 8 ++++++++ config/machine_settings/test-linux.ini | 2 -- src/components/archive_synchronizer.py | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index 73f8223..305e028 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -57,6 +57,14 @@ hold_time: 30 service_account_json: config/machine_settings/gcloud_default.json bucket_id: st_ten_img +[archive_synchronizer_extra] +archive_endpoint: https://r5portal.it/api/st-ten-save/ +images_path: data/images +poll_time: 60 +hold_time: 30 +service_account_json: config/machine_settings/gcloud_default.json +bucket_id: st_ten_img + [label_printer] platform: windows printer: ttp247 diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index fa0aeab..0d614f0 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -32,8 +32,6 @@ port: COM5 [digital_io] # OUTPUT MAP FOR VALVE CONTROL UNITS id: USB-5862,BID#0 -# OUTPUT MAP FOR FIXTURE CONNECTOR -id_fixture: USB-5862,BID#0 discard_idx:12 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING [recipe] diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 3cfff6b..53e8158 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -42,8 +42,10 @@ class ArchiveSynchronizer(Component): def _get(self): for record in list(Archive.select().where((Archive.archived != True) | (Archive.uploaded != True))): # using "is not True" breaks the query.. # list() forces the complete execution of the query unlocking the db unlike __enter__() if not self.simulate: + # save data on DB if record.archived is not True: record.archived = self.remote_archive(record) is True + # save images on google buckets if record.uploaded is not True: record.uploaded = self.remote_store(record) is True else: From 847338984dd36e8371f508f18f3145b515f9de22 Mon Sep 17 00:00:00 2001 From: neo Date: Mon, 21 Oct 2024 12:50:44 +0200 Subject: [PATCH 36/88] fixme prod server status --- config/machine_settings/test-linux.ini | 7 +++++-- src/components/archive_synchronizer.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index 0d614f0..01516f5 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -5,7 +5,7 @@ image_for_warning= st-ten-1 [hardware_config] -archive_synchronizer: absent +archive_synchronizer: present galaxy_camera: absent uvc_camera: absent label_printer: present @@ -20,7 +20,10 @@ digital_io: present external_flush_blow: absent [archive_synchronizer] -archive_endpoint: https://dev.r5portal.it/api/st-ten-save/ +#archive_endpoint: https://dev.r5portal.it/api/st-ten-save/ +archive_endpoint: https://r5portal.it/api/st-ten-save/ +poll_time: 10 +hold_time: 10 [tecna_t3] port: /dev/ttyUSB0 diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 53e8158..80984ca 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -42,10 +42,10 @@ class ArchiveSynchronizer(Component): def _get(self): for record in list(Archive.select().where((Archive.archived != True) | (Archive.uploaded != True))): # using "is not True" breaks the query.. # list() forces the complete execution of the query unlocking the db unlike __enter__() if not self.simulate: - # save data on DB + # SAVE DATA ON DB if record.archived is not True: record.archived = self.remote_archive(record) is True - # save images on google buckets + # SAVE IMAGES ON GOOGLE BUCKETS if record.uploaded is not True: record.uploaded = self.remote_store(record) is True else: @@ -54,11 +54,14 @@ class ArchiveSynchronizer(Component): if self.hold_time > 0: QThread.msleep(self.hold_time) self.gcs_bucket = None - if "--dev-portal" in sys.argv: - self.update_machine_status() + + # SEND MACHINE STATUS TO SERVER + self.update_machine_status() + super()._get() def update_machine_status(self): + # FIXME self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" status_dict = {"last_status": self.machine_status} @@ -89,6 +92,7 @@ class ArchiveSynchronizer(Component): self.log.info(f"Status: {self.machine_status}: Machine Status Updated Successfully") return True + def remote_archive(self, record): r = None try: From a54935fcad4a52ee188a128a848afd25dd1b2845 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Mon, 21 Oct 2024 17:17:10 +0200 Subject: [PATCH 37/88] initial commit dev.r5portal upload system --- src/components/archive_synchronizer.py | 71 ++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index f68a693..9177ac2 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -6,7 +6,7 @@ import threading import time import requests import traceback - +from bs4 import BeautifulSoup import requests from google.api_core.exceptions import Forbidden from google.cloud import storage @@ -28,11 +28,11 @@ class ArchiveSynchronizer(Component): def config_changed(self): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: - self.archive_endpoint =f"https://dev.r5portal.it/api/st-ten-save/" + self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" + self.base_media_url = f"https://dev.r5portal.it/media/uploads/" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] - #self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id_endpoint}&status={self.status}" - # self.images_path = self.config[self.name]["images_path"] + #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] self._do_set_period({"period": float(self.config[self.name]["poll_time"])}) self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000) self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"]) @@ -57,6 +57,7 @@ class ArchiveSynchronizer(Component): self.gcs_bucket = None if "--dev-portal" in sys.argv: self.update_machine_status() + self.remote_fetch(self.machine_id) super()._get() def update_machine_status(self): @@ -153,3 +154,65 @@ class ArchiveSynchronizer(Component): self.log.error(f"id: {record.id}: failed to store remotely:\n{traceback.format_exc()}") self.log.info(f"id: {record.id}: stored remotely") return True + + + def remote_fetch(self, machine_id, subfolder="warning_images"): + """ + Fetch and download all files from the server's folder. + + :param machine_id: The machine ID used to construct the folder path. + :param subfolder: The subfolder within the machine-specific path to fetch files from. + :return: A list of downloaded file paths, or False if an error occurs. + """ + base_url = f"{self.base_media_url}/{subfolder}/{machine_id}" + responses = [] + try: + if not self.simulate: + with requests.Session() as s: + s.mount("", HTTPAdapter(max_retries=Retry(total=0))) + + # Get directory listing + response = s.get(base_url, timeout=5, verify=False) + + if response.status_code == 403: + self.log.warning(f"Access forbidden for directory listing: {base_url}") + return False + elif response.status_code != 200: + raise AssertionError(f"bad status response for directory listing: {base_url}") + + # Parse the response content to get all file URLs. + soup = BeautifulSoup(response.content, 'html.parser') + file_urls = [] + for link in soup.find_all('a'): + href = link.get('href') + if href and re.search(r'\.(png|csv|svg)$', href, + re.IGNORECASE): # Adjust file extensions as needed + file_urls.append(f"{self.base_media_url}/{machine_id}/{href}") + + for file_url in file_urls: + file_response = s.get(file_url, timeout=5, verify=False) + + if file_response.status_code == 403: + self.log.warning(f"Access forbidden for file URL: {file_url}") + continue + elif file_response.status_code != 200: + raise AssertionError(f"bad status response for {file_url}") + + local_file_path = os.path.join("downloaded_files", os.path.basename(file_url)) + os.makedirs(os.path.dirname(local_file_path), exist_ok=True) + + with open(local_file_path, "wb") as f: + f.write(file_response.content) + + responses.append((file_url, local_file_path)) + + except AssertionError as e: + self.log.warning(f"Failed to download files: {str(e)}") + return False + except (requests.ConnectionError, requests.Timeout) as e: + self.log.warning(f"Failed to download files, base_media_url might be unreachable: {str(e)}") + return False + except Exception as e: + self.log.error(f"An unexpected error occurred: {str(e)}") + return False + return responses \ No newline at end of file From 5464f9a9c4a36af2d25467220e62551773dc15f8 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 22 Oct 2024 12:11:56 +0200 Subject: [PATCH 38/88] dev.r5portal upload system wip --- src/components/archive_synchronizer.py | 42 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 9177ac2..d7dc30f 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -29,7 +29,7 @@ class ArchiveSynchronizer(Component): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" - self.base_media_url = f"https://dev.r5portal.it/media/uploads/" + self.base_media_url = f"https://dev.r5portal.it/media/uploads" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] @@ -155,7 +155,6 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_id, subfolder="warning_images"): """ Fetch and download all files from the server's folder. @@ -171,24 +170,35 @@ class ArchiveSynchronizer(Component): with requests.Session() as s: s.mount("", HTTPAdapter(max_retries=Retry(total=0))) - # Get directory listing + self.log.info(f"Attempting to fetch directory listing from: {base_url}") + + # Make the HTTP GET request to the directory URL response = s.get(base_url, timeout=5, verify=False) - if response.status_code == 403: + # Log response details + self.log.info(f"HTTP Status Code: {response.status_code}") + self.log.info(f"Response Headers: {response.headers}") + + # Handle HTTP errors appropriately + if response.status_code == 404: + self.log.warning( + f"Directory not found: {base_url}. Please check the URL path and ensure the server has the expected directory structure.") + return False + elif response.status_code == 403: self.log.warning(f"Access forbidden for directory listing: {base_url}") return False elif response.status_code != 200: - raise AssertionError(f"bad status response for directory listing: {base_url}") + self.log.error(f"Unexpected HTTP response status: {response.status_code} for URL: {base_url}") + return False - # Parse the response content to get all file URLs. - soup = BeautifulSoup(response.content, 'html.parser') + # Manually parse the response content to get all file URLs + content = response.content.decode('iso-8859-1') # or appropriate charset file_urls = [] - for link in soup.find_all('a'): - href = link.get('href') - if href and re.search(r'\.(png|csv|svg)$', href, - re.IGNORECASE): # Adjust file extensions as needed - file_urls.append(f"{self.base_media_url}/{machine_id}/{href}") + matches = re.findall(r'href="([^"]+\.(?:png|csv|svg))"', content, re.IGNORECASE) + for href in matches: + file_urls.append(f"{base_url}{href}") + # Download each file for file_url in file_urls: file_response = s.get(file_url, timeout=5, verify=False) @@ -196,9 +206,11 @@ class ArchiveSynchronizer(Component): self.log.warning(f"Access forbidden for file URL: {file_url}") continue elif file_response.status_code != 200: - raise AssertionError(f"bad status response for {file_url}") + self.log.error( + f"Unexpected HTTP response status: {file_response.status_code} for file URL: {file_url}") + continue - local_file_path = os.path.join("downloaded_files", os.path.basename(file_url)) + local_file_path = os.path.join("downloaded_files", machine_id, os.path.basename(file_url)) os.makedirs(os.path.dirname(local_file_path), exist_ok=True) with open(local_file_path, "wb") as f: @@ -215,4 +227,4 @@ class ArchiveSynchronizer(Component): except Exception as e: self.log.error(f"An unexpected error occurred: {str(e)}") return False - return responses \ No newline at end of file + return responses From e1289065c87e413f40802fc2a68a3a6c15de897a Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 22 Oct 2024 16:37:55 +0200 Subject: [PATCH 39/88] dev.r5portal upload system wip 2 --- src/components/archive_synchronizer.py | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index d7dc30f..8dc543d 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -29,7 +29,7 @@ class ArchiveSynchronizer(Component): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" - self.base_media_url = f"https://dev.r5portal.it/media/uploads" + self.base_media_url = f"https://dev.r5portal.it" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] @@ -161,19 +161,21 @@ class ArchiveSynchronizer(Component): :param machine_id: The machine ID used to construct the folder path. :param subfolder: The subfolder within the machine-specific path to fetch files from. - :return: A list of downloaded file paths, or False if an error occurs. + :return: A list of downloaded file paths or False if an error occurs. """ - base_url = f"{self.base_media_url}/{subfolder}/{machine_id}" + base_url = f"{self.base_media_url}/list-files/" responses = [] try: if not self.simulate: with requests.Session() as s: s.mount("", HTTPAdapter(max_retries=Retry(total=0))) - self.log.info(f"Attempting to fetch directory listing from: {base_url}") + # Construct the request to the new API endpoint + params = {"machine_id": machine_id, "subfolder": subfolder} + self.log.info(f"Attempting to fetch file list from: {base_url} with params: {params}") - # Make the HTTP GET request to the directory URL - response = s.get(base_url, timeout=5, verify=False) + # Make the HTTP GET request to fetch the file URLs + response = s.get(base_url, params=params, timeout=5, verify=False) # Log response details self.log.info(f"HTTP Status Code: {response.status_code}") @@ -185,18 +187,19 @@ class ArchiveSynchronizer(Component): f"Directory not found: {base_url}. Please check the URL path and ensure the server has the expected directory structure.") return False elif response.status_code == 403: - self.log.warning(f"Access forbidden for directory listing: {base_url}") + self.log.warning(f"Access forbidden for file list: {base_url}") return False elif response.status_code != 200: self.log.error(f"Unexpected HTTP response status: {response.status_code} for URL: {base_url}") return False - # Manually parse the response content to get all file URLs - content = response.content.decode('iso-8859-1') # or appropriate charset - file_urls = [] - matches = re.findall(r'href="([^"]+\.(?:png|csv|svg))"', content, re.IGNORECASE) - for href in matches: - file_urls.append(f"{base_url}{href}") + # Parse the JSON response to get the list of file URLs + file_data = response.json() + if "file_urls" not in file_data: + self.log.error(f"Invalid response structure: {file_data}") + return False + + file_urls = file_data["file_urls"] # Download each file for file_url in file_urls: @@ -210,7 +213,7 @@ class ArchiveSynchronizer(Component): f"Unexpected HTTP response status: {file_response.status_code} for file URL: {file_url}") continue - local_file_path = os.path.join("downloaded_files", machine_id, os.path.basename(file_url)) + local_file_path = os.path.join("downloaded_files", machine_id, os.path.basename(file_url)) #further adjust os.makedirs(os.path.dirname(local_file_path), exist_ok=True) with open(local_file_path, "wb") as f: From d5a4813b5895cc2884f57021933a4d5cba230aa2 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 09:20:41 +0200 Subject: [PATCH 40/88] dev.r5portal upload system unit test ok --- ...nshot_from_2024-10-21_11-45-58_N4sYNgA.png | Bin 0 -> 31014 bytes src/components/archive_synchronizer.py | 66 ++++++------------ src/data/database/sqlite.db | Bin 0 -> 53248 bytes src/test/data/database/sqlite.db | Bin 0 -> 53248 bytes src/test/remote_fetch_test.py | 14 ++++ 5 files changed, 35 insertions(+), 45 deletions(-) create mode 100644 downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png create mode 100644 src/data/database/sqlite.db create mode 100644 src/test/data/database/sqlite.db create mode 100644 src/test/remote_fetch_test.py diff --git a/downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png b/downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png new file mode 100644 index 0000000000000000000000000000000000000000..b0cb9337c278ad0d1a2ace941b04316783d3090d GIT binary patch literal 31014 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 UMyA1E?hT}-q^(#h|LXn!0#d!brvLx| literal 0 HcmV?d00001 diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 8dc543d..37966b5 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -155,27 +155,20 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_id, subfolder="warning_images"): + def remote_fetch(self, specific_file_url): """ - Fetch and download all files from the server's folder. + Fetch and download a specific file from the server. - :param machine_id: The machine ID used to construct the folder path. - :param subfolder: The subfolder within the machine-specific path to fetch files from. - :return: A list of downloaded file paths or False if an error occurs. + :param specific_file_url: The full URL of the file to download. + :return: The downloaded file path or False if an error occurs. """ - base_url = f"{self.base_media_url}/list-files/" - responses = [] try: if not self.simulate: with requests.Session() as s: - s.mount("", HTTPAdapter(max_retries=Retry(total=0))) + self.log.info(f"Attempting to fetch file from: {specific_file_url}") - # Construct the request to the new API endpoint - params = {"machine_id": machine_id, "subfolder": subfolder} - self.log.info(f"Attempting to fetch file list from: {base_url} with params: {params}") - - # Make the HTTP GET request to fetch the file URLs - response = s.get(base_url, params=params, timeout=5, verify=False) + # Make the HTTP GET request to fetch the specific file URL + response = s.get(specific_file_url, timeout=5, verify=False) # Log response details self.log.info(f"HTTP Status Code: {response.status_code}") @@ -184,50 +177,33 @@ class ArchiveSynchronizer(Component): # Handle HTTP errors appropriately if response.status_code == 404: self.log.warning( - f"Directory not found: {base_url}. Please check the URL path and ensure the server has the expected directory structure.") + f"File not found: {specific_file_url}. Please check the URL path and ensure the server has the expected file.") return False elif response.status_code == 403: - self.log.warning(f"Access forbidden for file list: {base_url}") + self.log.warning(f"Access forbidden for file: {specific_file_url}") return False elif response.status_code != 200: - self.log.error(f"Unexpected HTTP response status: {response.status_code} for URL: {base_url}") + self.log.error( + f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") return False - # Parse the JSON response to get the list of file URLs - file_data = response.json() - if "file_urls" not in file_data: - self.log.error(f"Invalid response structure: {file_data}") - return False + # Save the file to /tmp/ + local_file_path = os.path.join("/tmp/", os.path.basename(specific_file_url)) + os.makedirs(os.path.dirname(local_file_path), exist_ok=True) - file_urls = file_data["file_urls"] + with open(local_file_path, "wb") as f: + f.write(response.content) - # Download each file - for file_url in file_urls: - file_response = s.get(file_url, timeout=5, verify=False) - - if file_response.status_code == 403: - self.log.warning(f"Access forbidden for file URL: {file_url}") - continue - elif file_response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {file_response.status_code} for file URL: {file_url}") - continue - - local_file_path = os.path.join("downloaded_files", machine_id, os.path.basename(file_url)) #further adjust - os.makedirs(os.path.dirname(local_file_path), exist_ok=True) - - with open(local_file_path, "wb") as f: - f.write(file_response.content) - - responses.append((file_url, local_file_path)) + self.log.info(f"File downloaded successfully: {local_file_path}") + return local_file_path except AssertionError as e: - self.log.warning(f"Failed to download files: {str(e)}") + self.log.warning(f"Failed to download file: {str(e)}") return False except (requests.ConnectionError, requests.Timeout) as e: - self.log.warning(f"Failed to download files, base_media_url might be unreachable: {str(e)}") + self.log.warning(f"Failed to download file, the URL might be unreachable: {str(e)}") return False except Exception as e: self.log.error(f"An unexpected error occurred: {str(e)}") return False - return responses + diff --git a/src/data/database/sqlite.db b/src/data/database/sqlite.db new file mode 100644 index 0000000000000000000000000000000000000000..9b2a17bc11fa06528f15cee58ed2574687220ef4 GIT binary patch literal 53248 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 Date: Wed, 23 Oct 2024 09:22:30 +0200 Subject: [PATCH 41/88] dev.r5portal upload system unit test ok --- ...eenshot_from_2024-10-21_11-45-58_N4sYNgA.png | Bin 31014 -> 0 bytes src/data/database/sqlite.db | Bin 53248 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png delete mode 100644 src/data/database/sqlite.db diff --git a/downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png b/downloaded_files/st-ten-10/screenshot_from_2024-10-21_11-45-58_N4sYNgA.png deleted file mode 100644 index b0cb9337c278ad0d1a2ace941b04316783d3090d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31014 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 UMyA1E?hT}-q^(#h|LXn!0#d!brvLx| diff --git a/src/data/database/sqlite.db b/src/data/database/sqlite.db deleted file mode 100644 index 9b2a17bc11fa06528f15cee58ed2574687220ef4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeI*TTk0o00(e8h6EC_v_r^~qHdN))ka*F3keAl(gHCd1rkWexD7=nHmSEHPHl%m zr#=K}(mutW_7V0C_BHmjmq~lr>)xiFW1NgY+A(c{ivEwV9iN+he&^T_I}W9-b-1njHXK%{;>)R_pDg+<^0SG_<0uX?}J0j4T@_KllXV2r7d{kFWOKq9< zY;3tGrMD$vJH50n38Eb*3QxtR+)zbfTiV?g@&z)L*Vl#3Vs0Z{+!NNMy=g(T&RSP< zkXW;&Rz=}isgUoLBe9BVRt>FXX?pXbQW7T{)#uuYs)#}^zb$2@Vy{3bL#=8p)pQo#{>C}6H)~$CuBlC{ zx3?|Xuqw@V<485Gu>4<*o*8xX>EN3h?d*Fc;=J&Yfi*%0SJva^AC0pO+orD9Dwftz z$#T?bdpV!mDoeyTBkc-eH-jjU4x(!mgO(6O9iQ97kB_sR*R~`{BR?bkf=&T#K&M?D z9kfm%Lx$FNZbRyIEy2>7$9iS(;Gszux}m*cH$N3*zp(JIIA9K-<+mh z$#l^|Cz7_(DJ+I|hTQz)Ap5$nYHHwQb`O;6R&Qh3dY9_H5IjHR?6LUmLtD^EcNW9_ zl9vkqC(UlF`VUpYY^Y|tPR8%mgNr2TC#qp+ilUN(aX_*~P7f7Dw&d%_aa}%A>%C*b zX~TfQKsM5D)pc1Jba+n-D}|zz%jW5cF( z!FD*i=V%7g9uhQ}t_=!{U17oljX0KQY0chwQ$i8R*3I_gc5y4Z4hG9dHsQ zGA-FOU+M;7>pQ*DKGVsm`9htn9mz^f?K|g$>^JfMe)f+162fjk00Izz00bZa0SG_< z0uX=z1R!t|0eU0f75In=d`D&o5P$##AOHafKmY;|fB*y_0D<>RpvifdiB936zg&`v zld@6Mn^8@fJXwsSCL4>1cs!PvwiaX4t;M;?scbcBCgwNWc_muiO0MXc%~E}9a%r{H zu0CH`vLdP2O5v-$a<~zn$`*_1lhoeke(CtkDtwW9nXeVr^n=3_*2D0f!YBT8W+RvX zhYdDUEoC`bZymiTXt8;{{`Gpe_G)XgnA=F)t2P1obv^4ZF( z_Ws;w&$6eh%F<5tK$I2o0UzX_&>M@O+ynP009U<00Izz00bZa0SG_<0uXqk0KNZDzVr_P z0uX=z1Rwwb2tWV=5P$##AOL}TEP(g__qcP>GzdTd0uX=z1Rwwb2tWV=5P*OqKtKP_ z1)eg29|KLYK!5-QAOHafKmY;|fB*y_009WR*8&-Cm`Mk7(QtHbCK8?rCxu94A)Hu< z#Ad_EXe>Eb(rQhi-Rl06z6C*~588{ Date: Wed, 23 Oct 2024 09:36:55 +0200 Subject: [PATCH 42/88] dev.r5portal upload system unit test ok --- src/components/archive_synchronizer.py | 83 +++++++++++++------------- src/test/remote_fetch_test.py | 4 +- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 37966b5..e80fe46 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -29,7 +29,7 @@ class ArchiveSynchronizer(Component): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" - self.base_media_url = f"https://dev.r5portal.it" + self.url = f"https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] @@ -57,7 +57,7 @@ class ArchiveSynchronizer(Component): self.gcs_bucket = None if "--dev-portal" in sys.argv: self.update_machine_status() - self.remote_fetch(self.machine_id) + self.remote_fetch(self.url) super()._get() def update_machine_status(self): @@ -155,55 +155,58 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, specific_file_url): + def remote_fetch(self, machine_status): """ Fetch and download a specific file from the server. :param specific_file_url: The full URL of the file to download. :return: The downloaded file path or False if an error occurs. """ - try: - if not self.simulate: - with requests.Session() as s: - self.log.info(f"Attempting to fetch file from: {specific_file_url}") + if machine_status == "logged-in": + try: + specific_file_url = "https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" + if not self.simulate: + with requests.Session() as s: + self.log.info(f"Attempting to fetch file from: {specific_file_url}") - # Make the HTTP GET request to fetch the specific file URL - response = s.get(specific_file_url, timeout=5, verify=False) + # Make the HTTP GET request to fetch the specific file URL + response = s.get(specific_file_url, timeout=5, verify=False) - # Log response details - self.log.info(f"HTTP Status Code: {response.status_code}") - self.log.info(f"Response Headers: {response.headers}") + # Log response details + self.log.info(f"HTTP Status Code: {response.status_code}") + self.log.info(f"Response Headers: {response.headers}") - # Handle HTTP errors appropriately - if response.status_code == 404: - self.log.warning( - f"File not found: {specific_file_url}. Please check the URL path and ensure the server has the expected file.") - return False - elif response.status_code == 403: - self.log.warning(f"Access forbidden for file: {specific_file_url}") - return False - elif response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") - return False + # Handle HTTP errors appropriately + if response.status_code == 404: + self.log.warning( + f"File not found: {specific_file_url}. Please check the URL path and ensure the server has the expected file.") + return False + elif response.status_code == 403: + self.log.warning(f"Access forbidden for file: {specific_file_url}") + return False + elif response.status_code != 200: + self.log.error( + f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") + return False - # Save the file to /tmp/ - local_file_path = os.path.join("/tmp/", os.path.basename(specific_file_url)) - os.makedirs(os.path.dirname(local_file_path), exist_ok=True) + # Save the file to /tmp/ + local_file_path = os.path.join("/tmp/", os.path.basename(specific_file_url)) + os.makedirs(os.path.dirname(local_file_path), exist_ok=True) - with open(local_file_path, "wb") as f: - f.write(response.content) + with open(local_file_path, "wb") as f: + f.write(response.content) - self.log.info(f"File downloaded successfully: {local_file_path}") - return local_file_path + self.log.info(f"File downloaded successfully: {local_file_path}") + return local_file_path + + except AssertionError as e: + self.log.warning(f"Failed to download file: {str(e)}") + return False + except (requests.ConnectionError, requests.Timeout) as e: + self.log.warning(f"Failed to download file, the URL might be unreachable: {str(e)}") + return False + except Exception as e: + self.log.error(f"An unexpected error occurred: {str(e)}") + return False - except AssertionError as e: - self.log.warning(f"Failed to download file: {str(e)}") - return False - except (requests.ConnectionError, requests.Timeout) as e: - self.log.warning(f"Failed to download file, the URL might be unreachable: {str(e)}") - return False - except Exception as e: - self.log.error(f"An unexpected error occurred: {str(e)}") - return False diff --git a/src/test/remote_fetch_test.py b/src/test/remote_fetch_test.py index e9a0f7c..a51c3be 100644 --- a/src/test/remote_fetch_test.py +++ b/src/test/remote_fetch_test.py @@ -9,6 +9,6 @@ config = ConfigReader(system_id="st-ten-10") app = QApplication(sys.argv) test= ArchiveSynchronizer(config=config, name="remote_fetch_test") -specific_file_url = "https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/screenshot_from_2024-10-21_11-45-58.png" -result = test.remote_fetch(specific_file_url) +status = "logged-in" +result = test.remote_fetch(status) print(result) \ No newline at end of file From 7261f2d1e0a6ee7c90a9a729fa02ec142f23185b Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 09:45:57 +0200 Subject: [PATCH 43/88] dev.r5portal upload system unit test ok --- src/components/archive_synchronizer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index e80fe46..05326d4 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -190,7 +190,8 @@ class ArchiveSynchronizer(Component): return False # Save the file to /tmp/ - local_file_path = os.path.join("/tmp/", os.path.basename(specific_file_url)) + project_tmp_path = "/home/edo-neo/PycharmProjects/st-ten-1/tmp" + local_file_path = os.path.join(project_tmp_path, os.path.basename(specific_file_url)) os.makedirs(os.path.dirname(local_file_path), exist_ok=True) with open(local_file_path, "wb") as f: From 2c018106854bb28be8003b0bb7f5f15f6228c0be Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 11:30:30 +0200 Subject: [PATCH 44/88] dev.r5portal remote_fetch ok --- src/components/archive_synchronizer.py | 120 +++++++++++++++++-------- 1 file changed, 84 insertions(+), 36 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 05326d4..0ab74c6 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -29,7 +29,7 @@ class ArchiveSynchronizer(Component): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" - self.url = f"https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" + #self.url = f"https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] @@ -57,7 +57,7 @@ class ArchiveSynchronizer(Component): self.gcs_bucket = None if "--dev-portal" in sys.argv: self.update_machine_status() - self.remote_fetch(self.url) + self.remote_fetch(self.machine_status) super()._get() def update_machine_status(self): @@ -155,59 +155,107 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_status): + def remote_fetch(self, machine_status="logged-in"): """ - Fetch and download a specific file from the server. + Fetch and download files from the server. - :param specific_file_url: The full URL of the file to download. - :return: The downloaded file path or False if an error occurs. + :param machine_status: Status of the machine (e.g., 'logged-in'). + :return: A list of downloaded file paths or a dictionary with errors if any occur. """ + # URLs endpoint from your Django server + urls_endpoint = "http://dev.r5portal.it/get-file-urls/" + if machine_status == "logged-in": try: - specific_file_url = "https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" + # Fetching the list of specific file URLs from the Django server if not self.simulate: with requests.Session() as s: - self.log.info(f"Attempting to fetch file from: {specific_file_url}") + self.log.info(f"Fetching list of file URLs from: {urls_endpoint}") - # Make the HTTP GET request to fetch the specific file URL - response = s.get(specific_file_url, timeout=5, verify=False) + # Make the HTTP GET request to fetch the list of URLs + response = s.get(urls_endpoint, timeout=5, verify=False) # Log response details self.log.info(f"HTTP Status Code: {response.status_code}") self.log.info(f"Response Headers: {response.headers}") - - # Handle HTTP errors appropriately + self.log.info(f"Response Content: {response.content}") + # Handle HTTP errors for the list of URLs fetch if response.status_code == 404: - self.log.warning( - f"File not found: {specific_file_url}. Please check the URL path and ensure the server has the expected file.") - return False + self.log.warning(f"URLs endpoint not found: {urls_endpoint}. Please check the URL path.") + return {"error": "URLs endpoint not found"} elif response.status_code == 403: - self.log.warning(f"Access forbidden for file: {specific_file_url}") - return False + self.log.warning(f"Access forbidden for URLs endpoint: {urls_endpoint}") + return {"error": "Access forbidden"} elif response.status_code != 200: self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") - return False + f"Unexpected HTTP response status: {response.status_code} for URL: {urls_endpoint}") + return {"error": "Unexpected HTTP response status"} - # Save the file to /tmp/ - project_tmp_path = "/home/edo-neo/PycharmProjects/st-ten-1/tmp" - local_file_path = os.path.join(project_tmp_path, os.path.basename(specific_file_url)) - os.makedirs(os.path.dirname(local_file_path), exist_ok=True) + # Parse the list of URLs (assuming the response contains a JSON array of URLs) + try: + file_urls = response.json() + self.log.info(f"Fetched file URLs: {file_urls}") + except ValueError as e: + self.log.error(f"Error parsing JSON response: {str(e)}") + self.log.error(f"Response Content: {response.content}") + return {"error": "Failed to parse JSON response"} + downloaded_files = [] + errors = {} - with open(local_file_path, "wb") as f: - f.write(response.content) + # Iterate over the list of URLs to download each file + for specific_file_url in file_urls: + try: + self.log.info(f"Attempting to fetch file from: {specific_file_url}") - self.log.info(f"File downloaded successfully: {local_file_path}") - return local_file_path + # Make the HTTP GET request to fetch the file URL + response = s.get(specific_file_url, timeout=5, verify=False) + + # Log response details + self.log.info(f"HTTP Status Code: {response.status_code}") + self.log.info(f"Response Headers: {response.headers}") + + # Handle HTTP errors appropriately for each file + if response.status_code == 404: + self.log.warning(f"File not found: {specific_file_url}. Please check the URL path.") + errors[specific_file_url] = "File not found" + continue + elif response.status_code == 403: + self.log.warning(f"Access forbidden for file: {specific_file_url}") + errors[specific_file_url] = "Access forbidden" + continue + elif response.status_code != 200: + self.log.error( + f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") + errors[specific_file_url] = f"Unexpected status {response.status_code}" + continue + + # Save the file to /tmp/ + project_tmp_path = "/home/edo-neo/PycharmProjects/st-ten-1/tmp" + local_file_path = os.path.join(project_tmp_path, os.path.basename(specific_file_url)) + os.makedirs(os.path.dirname(local_file_path), exist_ok=True) + + with open(local_file_path, "wb") as f: + f.write(response.content) + + self.log.info(f"File downloaded successfully: {local_file_path}") + downloaded_files.append(local_file_path) + + except (requests.ConnectionError, requests.Timeout) as e: + self.log.warning( + f"Failed to download file from {specific_file_url}, the URL might be unreachable: {str(e)}") + errors[specific_file_url] = "URL unreachable" + except Exception as e: + self.log.error( + f"An unexpected error occurred while downloading {specific_file_url}: {str(e)}") + errors[specific_file_url] = "Unexpected error" + + # Return the list of downloaded files and any errors + return { + "downloaded_files": downloaded_files, + "errors": errors + } - except AssertionError as e: - self.log.warning(f"Failed to download file: {str(e)}") - return False - except (requests.ConnectionError, requests.Timeout) as e: - self.log.warning(f"Failed to download file, the URL might be unreachable: {str(e)}") - return False except Exception as e: - self.log.error(f"An unexpected error occurred: {str(e)}") - return False - + self.log.error(f"An unexpected error occurred while fetching URLs: {str(e)}") + return {"error": "Unexpected error"} From e6c7b76ccd6949eda1b494113e8a7e4160ef7067 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 11:46:57 +0200 Subject: [PATCH 45/88] dev.r5portal remote_fetch fix --- src/components/archive_synchronizer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 0ab74c6..cc404d0 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -4,6 +4,8 @@ import re import sys import threading import time +from pathlib import Path + import requests import traceback from bs4 import BeautifulSoup @@ -230,8 +232,8 @@ class ArchiveSynchronizer(Component): continue # Save the file to /tmp/ - project_tmp_path = "/home/edo-neo/PycharmProjects/st-ten-1/tmp" - local_file_path = os.path.join(project_tmp_path, os.path.basename(specific_file_url)) + self.download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1", "tmp") + local_file_path = os.path.join(self.download_path, os.path.basename(specific_file_url)) os.makedirs(os.path.dirname(local_file_path), exist_ok=True) with open(local_file_path, "wb") as f: From 1da8c3ae39ea3590b942112bd305e968c28cd335 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 15:00:17 +0200 Subject: [PATCH 46/88] Add machine_id parameter to remote_fetch method Updated the remote_fetch method to accept a mandatory machine_id parameter and adjusted the URL endpoint accordingly. Modified relevant invocation and added error handling for missing machine_id. Updated the corresponding tests to include the machine_id parameter. --- src/components/archive_synchronizer.py | 13 +++++++++---- src/test/remote_fetch_test.py | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index cc404d0..546d038 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -59,7 +59,7 @@ class ArchiveSynchronizer(Component): self.gcs_bucket = None if "--dev-portal" in sys.argv: self.update_machine_status() - self.remote_fetch(self.machine_status) + self.remote_fetch(self.machine_status,self.machine_id) super()._get() def update_machine_status(self): @@ -157,15 +157,18 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_status="logged-in"): + def remote_fetch(self, machine_status="logged-in", machine_id=None): """ Fetch and download files from the server. :param machine_status: Status of the machine (e.g., 'logged-in'). + :param machine_id: ID of the machine. :return: A list of downloaded file paths or a dictionary with errors if any occur. """ - # URLs endpoint from your Django server - urls_endpoint = "http://dev.r5portal.it/get-file-urls/" + # URLs endpoint from your Django server with machine_id as a query parameter + if machine_id is None: + raise ValueError("machine_id cannot be None") + urls_endpoint = f"http://dev.r5portal.it/get-file-urls/?machine_id={machine_id}" if machine_status == "logged-in": try: @@ -181,6 +184,7 @@ class ArchiveSynchronizer(Component): self.log.info(f"HTTP Status Code: {response.status_code}") self.log.info(f"Response Headers: {response.headers}") self.log.info(f"Response Content: {response.content}") + # Handle HTTP errors for the list of URLs fetch if response.status_code == 404: self.log.warning(f"URLs endpoint not found: {urls_endpoint}. Please check the URL path.") @@ -201,6 +205,7 @@ class ArchiveSynchronizer(Component): self.log.error(f"Error parsing JSON response: {str(e)}") self.log.error(f"Response Content: {response.content}") return {"error": "Failed to parse JSON response"} + downloaded_files = [] errors = {} diff --git a/src/test/remote_fetch_test.py b/src/test/remote_fetch_test.py index a51c3be..bdd0037 100644 --- a/src/test/remote_fetch_test.py +++ b/src/test/remote_fetch_test.py @@ -10,5 +10,6 @@ app = QApplication(sys.argv) test= ArchiveSynchronizer(config=config, name="remote_fetch_test") status = "logged-in" -result = test.remote_fetch(status) +machine_id = "st-ten-6" +result = test.remote_fetch(status,machine_id) print(result) \ No newline at end of file From fce0151ecc8d4030113f1f2ea7791597fd67a3e3 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 23 Oct 2024 16:51:27 +0200 Subject: [PATCH 47/88] Refactor remote_fetch method to improve file management Updated remote_fetch to allow flexible machine_status input and reorganized file saving logic to categorize downloads based on file types. Modified test configuration to ensure compatibility with the new changes. --- src/components/archive_synchronizer.py | 22 +++++++++++++++++----- src/test/remote_fetch_test.py | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 546d038..c836bce 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -157,7 +157,7 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_status="logged-in", machine_id=None): + def remote_fetch(self, machine_status=None, machine_id=None): """ Fetch and download files from the server. @@ -209,6 +209,9 @@ class ArchiveSynchronizer(Component): downloaded_files = [] errors = {} + # Setup the base download path + base_download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1") + # Iterate over the list of URLs to download each file for specific_file_url in file_urls: try: @@ -236,11 +239,20 @@ class ArchiveSynchronizer(Component): errors[specific_file_url] = f"Unexpected status {response.status_code}" continue - # Save the file to /tmp/ - self.download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1", "tmp") - local_file_path = os.path.join(self.download_path, os.path.basename(specific_file_url)) - os.makedirs(os.path.dirname(local_file_path), exist_ok=True) + # Determine the subdirectory based on the file URL or other criteria + if "warning_images" in specific_file_url: + sub_dir = os.path.join("config", "warning_images", machine_id) + elif "ricette" in specific_file_url: + sub_dir = os.path.join("config", "csv_import", "auto_csv_import") + else: + sub_dir = "tmp" # Save others under the temporary folder + # Ensure the directory exists + download_path = os.path.join(base_download_path, sub_dir) + os.makedirs(download_path, exist_ok=True) + + # Save the file to the determined directory + local_file_path = os.path.join(download_path, os.path.basename(specific_file_url)) with open(local_file_path, "wb") as f: f.write(response.content) diff --git a/src/test/remote_fetch_test.py b/src/test/remote_fetch_test.py index bdd0037..84bcfd1 100644 --- a/src/test/remote_fetch_test.py +++ b/src/test/remote_fetch_test.py @@ -10,6 +10,6 @@ app = QApplication(sys.argv) test= ArchiveSynchronizer(config=config, name="remote_fetch_test") status = "logged-in" -machine_id = "st-ten-6" +machine_id = "st-ten-10" result = test.remote_fetch(status,machine_id) print(result) \ No newline at end of file From 27fd430a0bcf2534c31500bd207d1811c0a88fb5 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 24 Oct 2024 11:11:03 +0200 Subject: [PATCH 48/88] auto import wip Updated remote_fetch to allow flexible machine_status input and reorganized file saving logic to categorize downloads based on file types. Modified test configuration to ensure compatibility with the new changes. --- .../{ => manual_csv_import}/ST-TEN-6.csv | 0 ...riscaldati - COMPLETA rev09_27-10-2022.csv | 0 ...riscaldati - COMPLETA rev19_29-12-2022.csv | 0 ...iscaldati - COMPLETA rev19_29-12-2022.xlsx | Bin ...2024.xlsx - Tubi riscaldati costampati.csv | 0 ...2024.xlsx - Tubi riscaldati costampati.csv | 0 ...2024.xlsx - Tubi riscaldati costampati.csv | 0 ...2024.xlsx - Tubi riscaldati costampati.csv | 0 .../Tabella Tubi riscaldati - campi extra.csv | 0 .../Tabella_e_daily.csv | 0 .../importazione da banco montaggio.ods | Bin .../importazione da banco preformatura.csv | 0 .../ricette MULTIMATIC.csv | 0 .../ricette st-ten-8 19-09-2024.csv | 0 .../{ => manual_csv_import}/st-ten-11.csv | 0 .../{ => manual_csv_import}/st-ten-8.csv | 0 .../{ => manual_csv_import}/st-ten-9.csv | 0 .../{ => manual_csv_import}/test.py | 0 .../test_doppia_prova_tenuta.csv | 0 .../test_import_himatic my24.csv | 0 .../test_import_himatic.csv | 0 .../test_import_himatic.xlsx | Bin .../test_import_leak_only.csv | 0 .../test_tecna_upload.csv | 0 .../{ => manual_csv_import}/tst.csv | 0 src/components/archive_synchronizer.py | 21 ++++---- src/ui/recipe_selection/recipe_selection.py | 45 +++++++++++++++++- 27 files changed, 52 insertions(+), 14 deletions(-) rename config/csv_import/{ => manual_csv_import}/ST-TEN-6.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella Tubi riscaldati - campi extra.csv (100%) rename config/csv_import/{ => manual_csv_import}/Tabella_e_daily.csv (100%) rename config/csv_import/{ => manual_csv_import}/importazione da banco montaggio.ods (100%) rename config/csv_import/{ => manual_csv_import}/importazione da banco preformatura.csv (100%) rename config/csv_import/{ => manual_csv_import}/ricette MULTIMATIC.csv (100%) rename config/csv_import/{ => manual_csv_import}/ricette st-ten-8 19-09-2024.csv (100%) rename config/csv_import/{ => manual_csv_import}/st-ten-11.csv (100%) rename config/csv_import/{ => manual_csv_import}/st-ten-8.csv (100%) rename config/csv_import/{ => manual_csv_import}/st-ten-9.csv (100%) rename config/csv_import/{ => manual_csv_import}/test.py (100%) rename config/csv_import/{ => manual_csv_import}/test_doppia_prova_tenuta.csv (100%) rename config/csv_import/{ => manual_csv_import}/test_import_himatic my24.csv (100%) rename config/csv_import/{ => manual_csv_import}/test_import_himatic.csv (100%) rename config/csv_import/{ => manual_csv_import}/test_import_himatic.xlsx (100%) rename config/csv_import/{ => manual_csv_import}/test_import_leak_only.csv (100%) rename config/csv_import/{ => manual_csv_import}/test_tecna_upload.csv (100%) rename config/csv_import/{ => manual_csv_import}/tst.csv (100%) diff --git a/config/csv_import/ST-TEN-6.csv b/config/csv_import/manual_csv_import/ST-TEN-6.csv similarity index 100% rename from config/csv_import/ST-TEN-6.csv rename to config/csv_import/manual_csv_import/ST-TEN-6.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev09_27-10-2022.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev19_29-12-2022.xlsx diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev46_13-03-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev49_19-04-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev50_07-05-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - COMPLETA rev50_13-05-2024.xlsx - Tubi riscaldati costampati.csv diff --git a/config/csv_import/Tabella Tubi riscaldati - campi extra.csv b/config/csv_import/manual_csv_import/Tabella Tubi riscaldati - campi extra.csv similarity index 100% rename from config/csv_import/Tabella Tubi riscaldati - campi extra.csv rename to config/csv_import/manual_csv_import/Tabella Tubi riscaldati - campi extra.csv diff --git a/config/csv_import/Tabella_e_daily.csv b/config/csv_import/manual_csv_import/Tabella_e_daily.csv similarity index 100% rename from config/csv_import/Tabella_e_daily.csv rename to config/csv_import/manual_csv_import/Tabella_e_daily.csv diff --git a/config/csv_import/importazione da banco montaggio.ods b/config/csv_import/manual_csv_import/importazione da banco montaggio.ods similarity index 100% rename from config/csv_import/importazione da banco montaggio.ods rename to config/csv_import/manual_csv_import/importazione da banco montaggio.ods diff --git a/config/csv_import/importazione da banco preformatura.csv b/config/csv_import/manual_csv_import/importazione da banco preformatura.csv similarity index 100% rename from config/csv_import/importazione da banco preformatura.csv rename to config/csv_import/manual_csv_import/importazione da banco preformatura.csv diff --git a/config/csv_import/ricette MULTIMATIC.csv b/config/csv_import/manual_csv_import/ricette MULTIMATIC.csv similarity index 100% rename from config/csv_import/ricette MULTIMATIC.csv rename to config/csv_import/manual_csv_import/ricette MULTIMATIC.csv diff --git a/config/csv_import/ricette st-ten-8 19-09-2024.csv b/config/csv_import/manual_csv_import/ricette st-ten-8 19-09-2024.csv similarity index 100% rename from config/csv_import/ricette st-ten-8 19-09-2024.csv rename to config/csv_import/manual_csv_import/ricette st-ten-8 19-09-2024.csv diff --git a/config/csv_import/st-ten-11.csv b/config/csv_import/manual_csv_import/st-ten-11.csv similarity index 100% rename from config/csv_import/st-ten-11.csv rename to config/csv_import/manual_csv_import/st-ten-11.csv diff --git a/config/csv_import/st-ten-8.csv b/config/csv_import/manual_csv_import/st-ten-8.csv similarity index 100% rename from config/csv_import/st-ten-8.csv rename to config/csv_import/manual_csv_import/st-ten-8.csv diff --git a/config/csv_import/st-ten-9.csv b/config/csv_import/manual_csv_import/st-ten-9.csv similarity index 100% rename from config/csv_import/st-ten-9.csv rename to config/csv_import/manual_csv_import/st-ten-9.csv diff --git a/config/csv_import/test.py b/config/csv_import/manual_csv_import/test.py similarity index 100% rename from config/csv_import/test.py rename to config/csv_import/manual_csv_import/test.py diff --git a/config/csv_import/test_doppia_prova_tenuta.csv b/config/csv_import/manual_csv_import/test_doppia_prova_tenuta.csv similarity index 100% rename from config/csv_import/test_doppia_prova_tenuta.csv rename to config/csv_import/manual_csv_import/test_doppia_prova_tenuta.csv diff --git a/config/csv_import/test_import_himatic my24.csv b/config/csv_import/manual_csv_import/test_import_himatic my24.csv similarity index 100% rename from config/csv_import/test_import_himatic my24.csv rename to config/csv_import/manual_csv_import/test_import_himatic my24.csv diff --git a/config/csv_import/test_import_himatic.csv b/config/csv_import/manual_csv_import/test_import_himatic.csv similarity index 100% rename from config/csv_import/test_import_himatic.csv rename to config/csv_import/manual_csv_import/test_import_himatic.csv diff --git a/config/csv_import/test_import_himatic.xlsx b/config/csv_import/manual_csv_import/test_import_himatic.xlsx similarity index 100% rename from config/csv_import/test_import_himatic.xlsx rename to config/csv_import/manual_csv_import/test_import_himatic.xlsx diff --git a/config/csv_import/test_import_leak_only.csv b/config/csv_import/manual_csv_import/test_import_leak_only.csv similarity index 100% rename from config/csv_import/test_import_leak_only.csv rename to config/csv_import/manual_csv_import/test_import_leak_only.csv diff --git a/config/csv_import/test_tecna_upload.csv b/config/csv_import/manual_csv_import/test_tecna_upload.csv similarity index 100% rename from config/csv_import/test_tecna_upload.csv rename to config/csv_import/manual_csv_import/test_tecna_upload.csv diff --git a/config/csv_import/tst.csv b/config/csv_import/manual_csv_import/tst.csv similarity index 100% rename from config/csv_import/tst.csv rename to config/csv_import/manual_csv_import/tst.csv diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index c836bce..d7eb7bf 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -25,7 +25,7 @@ class ArchiveSynchronizer(Component): def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv - self.status= ArchiveSynchronizer.machine_status + self.machine_status = "offline" def config_changed(self): self.machine_id = self.config.machine_id @@ -57,20 +57,16 @@ class ArchiveSynchronizer(Component): if self.hold_time > 0: QThread.msleep(self.hold_time) self.gcs_bucket = None + if "--dev-portal" in sys.argv: self.update_machine_status() self.remote_fetch(self.machine_status,self.machine_id) super()._get() def update_machine_status(self): - self.status = ArchiveSynchronizer.machine_status - #print(f"machine_status_global: {ArchiveSynchronizer.machine_status}") # TESTING - self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.status}" + self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" - if self.status not in ["working", "logged-in", "logged-out"]: - status_dict = {"last_status": "offline"} - else: - status_dict = {"last_status": self.status} + status_dict = {"last_status": self.machine_status} response = None try: @@ -82,21 +78,21 @@ class ArchiveSynchronizer(Component): raise AssertionError("bad status response") except AssertionError as e: self.log.warning( - f"Status: {self.status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}" + f"Status: {self.machine_status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}" ) return False except (requests.ConnectionError, requests.Timeout) as e: self.log.warning( - f"Status: {self.status}: failed to update machine status, archive_endpoint might be unreachable: {str(e)}" + f"Status: {self.machine_status}: failed to update machine status, archive_endpoint might be unreachable: {str(e)}" ) return False except Exception: self.log.error( - f"Status: {self.status}: failed to update machine status:\n{traceback.format_exc()}:\n{response.status_code if response else 'no response'}: {response.content if response else 'no response'}" + f"Status: {self.machine_status}: failed to update machine status:\n{traceback.format_exc()}:\n{response.status_code if response else 'no response'}: {response.content if response else 'no response'}" ) return False - self.log.info(f"Status: {self.status}: Machine Status Updated Successfully") + self.log.info(f"Status: {self.machine_status}: Machine Status Updated Successfully") return True def remote_archive(self, record): r = None @@ -268,7 +264,6 @@ class ArchiveSynchronizer(Component): f"An unexpected error occurred while downloading {specific_file_url}: {str(e)}") errors[specific_file_url] = "Unexpected error" - # Return the list of downloaded files and any errors return { "downloaded_files": downloaded_files, "errors": errors diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 94791ec..977f7b3 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -1,6 +1,7 @@ import csv import locale import os +import shutil import sys import weakref from glob import glob @@ -13,6 +14,8 @@ from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget from ui.helpers import replace_widget from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor from ui.widget import Widget +from datetime import datetime +from src.components import ArchiveSynchronizer class Noner: @@ -30,6 +33,7 @@ class Recipe_Selection(Widget): global noner super().__init__() self.config = config + self.archive_sync = ArchiveSynchronizer() self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps @@ -282,7 +286,7 @@ class Recipe_Selection(Widget): if csv_path is None: csv_path, _ = QFileDialog.getOpenFileName( None, - "Esportazione ricette", + "Importazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", ) @@ -508,3 +512,42 @@ class Recipe_Selection(Widget): Recipes.delete().execute() Steps.delete().execute() self.crud.refresh() + + def backup_current_recipes(self): + # Define the backup directory and file name + backup_dir = os.path.join('config', 'csv_import', 'backup_csv') + timestamp = datetime.now().strftime("%d%m%y") + backup_file = f"backup_{timestamp}.csv" + backup_path = os.path.join(backup_dir, backup_file) + + # Ensure the backup directory exists + os.makedirs(backup_dir, exist_ok=True) + + # Export current recipes to backup file + self.export_recipes(csv_path=backup_path) + + def move_imported_csv(self, csv_path): + # Move the imported CSV to the 'imported_csv' directory + imported_dir = os.path.join('config', 'csv_import', 'imported_csv') + os.makedirs(imported_dir, exist_ok=True) + imported_path = os.path.join(imported_dir, os.path.basename(csv_path)) + shutil.move(csv_path, imported_path) + self.log.info(f"Imported CSV moved to {imported_path}") + return imported_path + + def check_and_import_auto_csv(self): + if self.archive_sync.machine_status ==" logged-in": + # Define the directory to check + auto_import_dir = os.path.join('config', 'csv_import', 'auto_csv_import') + + # Check if the directory exists and is not empty + if os.path.exists(auto_import_dir) and os.listdir(auto_import_dir): + # Perform backup + self.backup_current_recipes() + + # Move and import each CSV file in the directory + for csv_file in os.listdir(auto_import_dir): + csv_path = os.path.join(auto_import_dir, csv_file) + if os.path.isfile(csv_path) and csv_file.endswith(".csv"): + self.import_recipes(csv_path=csv_path) + self.move_imported_csv(csv_path) From a60a2d945ec0ffac1db99f5bc874fbbec226ff71 Mon Sep 17 00:00:00 2001 From: gg Date: Thu, 24 Oct 2024 12:42:03 +0200 Subject: [PATCH 49/88] ferrari label 203dpi --- config/label_templates/F164F169_203.prn | 53 ++++++++++++++++++++++++ config/machine_settings/test-windows.ini | 2 +- src/test/label_printer_ferrari.py | 50 ++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 config/label_templates/F164F169_203.prn create mode 100644 src/test/label_printer_ferrari.py diff --git a/config/label_templates/F164F169_203.prn b/config/label_templates/F164F169_203.prn new file mode 100644 index 0000000..e28cda1 --- /dev/null +++ b/config/label_templates/F164F169_203.prn @@ -0,0 +1,53 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD15 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW320 +^LL1119 +^LS0 +^FT27,493^A0N,25,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT175,493^A0N,25,23^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 +^FT18,1013^A0N,31,30^FH\^CI28^FDESITO:^FS^CI27 +^FT144,1013^A0N,31,30^FH\^CI28^FDCONFORME^FS^CI27 +^FT29,87^A0N,25,25^FH\^CI28^FDNumero Disegno^FS^CI27 +^FT27,462^A0N,25,25^FH\^CI28^FDData/Ora Prova^FS^CI27 +^FT27,530^A0N,25,25^FH\^CI28^FDStazione: {STATION}^FS^CI27 +^FT27,416^A0N,25,25^FH\^CI28^FDN. Pezzo:^FS^CI27 +^FT135,417^A0N,25,25^FH\^CI28^FD{SN5}^FS^CI27 +^FT27,562^A0N,25,25^FH\^CI28^FDOPERATORE: {OPERATOR}^FS^CI27 +^FO52,649^GB215,0,8^FS +^FT19,705^A0N,25,25^FH\^CI28^FDP. prova:^FS^CI27 +^FT19,737^A0N,25,25^FH\^CI28^FDP. rilevata:^FS^CI27 +^FT145,737^A0N,25,25^FH\^CI28^FD{RESPSET}mbar^FS^CI27 +^FT19,764^A0N,25,25^FH\^CI28^FDCaduta ammessa:^FS^CI27 +^FT206,764^A0N,25,25^FH\^CI28^FD{PMIN} mbar^FS^CI27 +^FT19,797^A0N,25,25^FH\^CI28^FDCaduta rilevata:^FS^CI27 +^FT179,797^A0N,25,25^FH\^CI28^FD{RESLEAK} mbar^FS^CI27 +^FT19,908^A0N,25,25^FH\^CI28^FDT.Prova^FS^CI27 +^FT207,912^A0N,25,25^FH\^CI28^FD{TTEST} s^FS^CI27 +^FT18,864^A0N,25,25^FH\^CI28^FDT.Riempim.^FS^CI27 +^FT207,864^A0N,25,25^FH\^CI28^FD{TFILL} s^FS^CI27 +^FT19,886^A0N,25,25^FH\^CI28^FDT.Stabilizzazione^FS^CI27 +^FT207,888^A0N,25,25^FH\^CI28^FD{TSET} s^FS^CI27 +^FT145,705^A0N,25,25^FH\^CI28^FD{PTEST} mbar^FS^CI27 +^FT31,236^BXN,6,200,0,0,1,_,1 +^FH\^FD{PART}{MO}{YY}{SN5}^FS +^FT29,287^A0N,25,25^FH\^CI28^FD{PART}{MO}{YY}{SN5}^FS^CI27 +^PQ1,0,1,Y +^XZ diff --git a/config/machine_settings/test-windows.ini b/config/machine_settings/test-windows.ini index 7d88955..6a5d5e9 100644 --- a/config/machine_settings/test-windows.ini +++ b/config/machine_settings/test-windows.ini @@ -39,7 +39,7 @@ description_field: descrizione [label_printer] platform: windows -printer: zd420 +printer: zd421 [recipes_defaults] tester_discharge_enable: yes diff --git a/src/test/label_printer_ferrari.py b/src/test/label_printer_ferrari.py new file mode 100644 index 0000000..c171181 --- /dev/null +++ b/src/test/label_printer_ferrari.py @@ -0,0 +1,50 @@ +import sys +from datetime import datetime +from PyQt5.QtWidgets import QApplication + +from components import Os_Label_Printer +from lib.helpers import ConfigReader + +config = ConfigReader(system_id="test-windows") +time =datetime.now() +context = { + # RECIPE DATA + "RECIPE": "000948653", + "PART": "000948653", + "TFILL": "5", + "TSET": "10", + "TTEST": "10", + "PSETMINP_A": "4750", + "PSETMAXP_A": "5250", + "PTEST": "1500", + "PMIN": "30", + "RESPSET": "1512", + "RESLEAK": "12.34", + "SN4": "1234", + "SN5": "12345", + # TIME DEFINITION + "DATETIME": time.strftime("%d/%m/%Y %H:%M:%S"), + "DATE": time.strftime("%d/%m/%Y"), + "TIME": time.strftime("%H:%M:%S"), + "YYYY": time.strftime("%Y"), + "YY": time.strftime("%y"), + "MO": time.strftime("%m"), + "DD": time.strftime("%d"), + "HH": time.strftime("%H"), + "MI": time.strftime("%M"), + "SS": time.strftime("%S"), + "JJJ": time.strftime("%j"), + # EXTRA DATA + "SHIFT": "1", + "STATION": "ST-TEN-1", + "OPERATOR": "MARIO", + "BADGE_NUM": "999", + +} + +app = QApplication(sys.argv) + +# TEST STANDARD PRINTER +printer = Os_Label_Printer(config=config, name="label_printer") +printer.config_changed() +printer.print_label("F164F169_203.prn", context=context) From 7b316bad187280ac5dfb7fdc67b9b590ae907dbf Mon Sep 17 00:00:00 2001 From: neo Date: Thu, 24 Oct 2024 13:14:52 +0200 Subject: [PATCH 50/88] fix QFileDialog.getSaveFileName --- src/ui/recipe_selection/recipe_selection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 614400d..5530cfb 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -281,7 +281,7 @@ class Recipe_Selection(Widget): defaults = self.config.get("recipes_defaults", noner) if csv_path is None: csv_path, _ = QFileDialog.getOpenFileName( - None, + self, "Esportazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", @@ -347,7 +347,7 @@ class Recipe_Selection(Widget): def export_recipes(self, csv_path=None): if csv_path is None: csv_path, _ = QFileDialog.getSaveFileName( - None, + self, "Esportazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", From 0a6edec384e1db03ce3afada1f66831ea4386a72 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 24 Oct 2024 15:57:49 +0200 Subject: [PATCH 51/88] fix q dialog linux --- src/ui/recipe_selection/recipe_selection.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 977f7b3..4412b27 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -284,11 +284,14 @@ class Recipe_Selection(Widget): if 'codice_prodotto' not in defaults: defaults['codice_prodotto'] = "VALORE_PREDEFINITO" if csv_path is None: + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog csv_path, _ = QFileDialog.getOpenFileName( - None, + self, "Importazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", + options=options, ) csv_path = str(csv_path) if not len(csv_path): @@ -370,11 +373,14 @@ class Recipe_Selection(Widget): def export_recipes(self, csv_path=None): if csv_path is None: + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog csv_path, _ = QFileDialog.getSaveFileName( - None, + self, "Esportazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", + options=options, ) csv_path = str(csv_path) if not len(csv_path): From 62f602c62013dc97cf3b199066dd25d765ffc6c9 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 24 Oct 2024 16:45:53 +0200 Subject: [PATCH 52/88] merge --- designer.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/designer.sh b/designer.sh index 1fdd748..4062f94 100755 --- a/designer.sh +++ b/designer.sh @@ -1 +1,14 @@ -pyqt5-tools designer +#!/bin/bash + +# Path to your virtual environment +VENV_PATH=/home/edo-neo/PycharmProjects/st-ten-1/venv + +# Set environment variables +export LD_LIBRARY_PATH=$VENV_PATH/lib/python3.11/site-packages/PyQt5/Qt5/lib:/usr/lib/x86_64-linux-gnu +export PYQTDESIGNERPATH=$VENV_PATH/lib/python3.11/site-packages +export PYTHONPATH=$VENV_PATH/bin:$PYTHONPATH +export PATH=$VENV_PATH/bin:$PATH +export QT_PLUGIN_PATH=$VENV_PATH/lib/python3.11/site-packages/PyQt5/Qt5/plugins + +# Execute Qt Designer +$VENV_PATH/lib/python3.11/site-packages/qt5_applications/Qt/bin/designer \ No newline at end of file From 84c22c803589863bb7bce5a88fe50e4b381b3617 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 24 Oct 2024 16:55:55 +0200 Subject: [PATCH 53/88] fix merge --- src/ui/recipe_selection/recipe_selection.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 5530cfb..d5663dc 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -280,11 +280,14 @@ class Recipe_Selection(Widget): global noner defaults = self.config.get("recipes_defaults", noner) if csv_path is None: + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog csv_path, _ = QFileDialog.getOpenFileName( self, "Esportazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", + options=options, ) csv_path = str(csv_path) if not len(csv_path): @@ -346,11 +349,14 @@ class Recipe_Selection(Widget): # EXPORT RECIPES TABLE TO CSV FILE def export_recipes(self, csv_path=None): if csv_path is None: + options = QFileDialog.Options() + options |= QFileDialog.DontUseNativeDialog csv_path, _ = QFileDialog.getSaveFileName( self, "Esportazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", + options=options, ) csv_path = str(csv_path) if not len(csv_path): From cb9abeb46f17456399e7b0ee078604fe98db699c Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 24 Oct 2024 16:58:31 +0200 Subject: [PATCH 54/88] fix merge --- src/ui/recipe_selection/recipe_selection.py | 44 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index d5663dc..ff3182e 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -9,13 +9,15 @@ from lib.db import Recipes, Users, db from PyQt5.QtCore import QTimer, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QFileDialog, QMessageBox, QShortcut - +import shutil from lib.helpers.step import Step from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget from ui.helpers import replace_widget from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor from ui.widget import Widget +from datetime import datetime +from src.components import ArchiveSynchronizer class Noner: def __getitem__(self, key): @@ -284,7 +286,7 @@ class Recipe_Selection(Widget): options |= QFileDialog.DontUseNativeDialog csv_path, _ = QFileDialog.getOpenFileName( self, - "Esportazione ricette", + "Importazione ricette", "ricette.csv", "CSV data (*.csv);;All Files (*)", options=options, @@ -489,3 +491,41 @@ class Recipe_Selection(Widget): if ret == QMessageBox.Ok: Recipes.delete().execute() self.crud.refresh() + def backup_current_recipes(self): + # Define the backup directory and file name + backup_dir = os.path.join('config', 'csv_import', 'backup_csv') + timestamp = datetime.now().strftime("%d%m%y") + backup_file = f"backup_{timestamp}.csv" + backup_path = os.path.join(backup_dir, backup_file) + + # Ensure the backup directory exists + os.makedirs(backup_dir, exist_ok=True) + + # Export current recipes to backup file + self.export_recipes(csv_path=backup_path) + + def move_imported_csv(self, csv_path): + # Move the imported CSV to the 'imported_csv' directory + imported_dir = os.path.join('config', 'csv_import', 'imported_csv') + os.makedirs(imported_dir, exist_ok=True) + imported_path = os.path.join(imported_dir, os.path.basename(csv_path)) + shutil.move(csv_path, imported_path) + self.log.info(f"Imported CSV moved to {imported_path}") + return imported_path + + def check_and_import_auto_csv(self): + if self.archive_sync.machine_status ==" logged-in": + # Define the directory to check + auto_import_dir = os.path.join('config', 'csv_import', 'auto_csv_import') + + # Check if the directory exists and is not empty + if os.path.exists(auto_import_dir) and os.listdir(auto_import_dir): + # Perform backup + self.backup_current_recipes() + + # Move and import each CSV file in the directory + for csv_file in os.listdir(auto_import_dir): + csv_path = os.path.join(auto_import_dir, csv_file) + if os.path.isfile(csv_path) and csv_file.endswith(".csv"): + self.import_recipes(csv_path=csv_path) + self.move_imported_csv(csv_path) From 32e858f0f7e15374f44de66d5a9a9be5428f2565 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 09:18:10 +0200 Subject: [PATCH 55/88] fix merge --- src/ui/test/test.py | 4 ++-- src/ui/test_leak/test_leak.py | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/ui/test/test.py b/src/ui/test/test.py index a5ed93c..b4ae8e7 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -448,14 +448,14 @@ class Test(Widget): leak1_index = step_types.index("leak_1") leak2_index = step_types.index("leak_2") if leak1_index + 1 == leak2_index: # Ensure 'leak_1' is immediately followed by 'leak_2' - steps.insert(leak2_index, Steps(type="instruction_extra", spec={})) + steps.insert(leak2_index, Step(step_type="instruction_extra", spec={})) inserted_instruction = True # Insert 'instruction_extra' after the first 'instructions' if not inserted between leaks if not inserted_instruction: for i, step in enumerate(steps): if step.type == "instructions": - steps.insert(i + 1, Steps(type="instruction_extra", spec={})) + steps.insert(i + 1, Step(step_type="instruction_extra", spec={})) inserted_instruction = True break diff --git a/src/ui/test_leak/test_leak.py b/src/ui/test_leak/test_leak.py index 0728174..72a7391 100644 --- a/src/ui/test_leak/test_leak.py +++ b/src/ui/test_leak/test_leak.py @@ -12,13 +12,14 @@ from ui.test_test import Test_Test VALVE_TIME=0.5 class Test_Leak(Test_Test): - def __init__(self, components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False,parent=None): + def __init__(self, config,components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False,parent=None): super().__init__(components=components, recipe=recipe, step=step, pieces=pieces, run_once=run_once, reset_on_start=reset_on_start, enable_override=enable_override) self.get_connection = None self.io_ok = True self.blow_on = False self.parent=parent self.step=step + self.config = config self.recipe_written = False self.start_b.clicked.connect(self.start_test) self.stop_b.clicked.connect(self.stop_test) @@ -143,11 +144,16 @@ class Test_Leak(Test_Test): time.sleep(2) # AUTO START SECOND TEST - if step.step_type == "leak_2": - self.recipe_written = False - time.sleep(1) - self.start_b.setEnabled(True) - self.start_b.click() + if step.type == "leak_2": + if self.config["hardware_config"].get("dual_chanel", "absent") == "present": + self.recipe_written = False + time.sleep(1) + self.start_b.setEnabled(True) + self.start_b.click() + else: + self.recipe_written = False + time.sleep(1) + self.start_b.setEnabled(True) return show From 4853e7883c4584629092fc318c78981d510e5a9a Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 09:18:44 +0200 Subject: [PATCH 56/88] new export logic --- src/ui/recipe_selection/recipe_selection.py | 133 +++++++++++++------- 1 file changed, 88 insertions(+), 45 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index ff3182e..781ffa5 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -34,6 +34,7 @@ class Recipe_Selection(Widget): global noner super().__init__() self.config = config + self.archive_sync = ArchiveSynchronizer() self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps @@ -420,66 +421,108 @@ class Recipe_Selection(Widget): "ricetta_visione", "stampa_etichetta_abilitata", print_template_field, + "etichette_supplementari", ] for recipe in list(Recipes.select()): steps = recipe.get_steps_map() exportable = { + # BASE SECTION recipe_name_field: recipe.name, "cliente": recipe.client, "part_number": recipe.part_number, - # "dimensione_lotto_abilitata": "x" if recipe.spec["count"] else "", - # "dimensione_lotto": steps["count"].spec["amount"], - "verifica_connettore_abilitata": "x" if recipe.spec["connector"] else "", - "connettore": steps["connector"].spec["connector"], - barcode_enable_field: "x" if recipe.spec["barcodes"] else "", - barcode_serial_field: steps["barcodes"].spec["serial"], - "verifica_resistenza_connettore_abilitata": "x" if recipe.spec["resistance"] else "", - "scala_resistenza": steps["resistance"].spec["scale"], - "r nominale": steps["resistance"].spec["expected"], - "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], - "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"], - # "avvitatura_abilitata": "x" if recipe.spec["screws"] else "", - # "viti": steps["screws"].spec["quantity"], - "prova_tenuta_abilitata": "x" if recipe.spec["leak_1"] else "", - "tempo_pre_riempimento": steps["leak_1"].spec["pre_filling_time"], - "pressione_pre_riempimento": steps["leak_1"].spec["pre_filling_pressure"], - "tempo_riempimento": steps["leak_1"].spec["filling_time"], - "tempo_assestamento": steps["leak_1"].spec["settling_time"], - "percentuale_minima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_min_percent"], - "percentuale_massima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_max_percent"], - "tempo_di_test": steps["leak_1"].spec["test_time"], - "pressione_di_test_delta_minimo": steps["leak_1"].spec["test_pressure_qneg"], - "pressione_di_test": steps["leak_1"].spec["test_pressure"], - "pressione_di_test_delta_massimo": steps["leak_1"].spec["test_pressure_qpos"], - "tempo_svuotamento": steps["leak_1"].spec["flush_time"], - "pressione_svuotamento": steps["leak_1"].spec["flush_pressure"], - "prova_tenuta_abilitata_2": "x" if recipe.spec["leak_2"] else "", - "tempo_pre_riempimento_2": steps["leak_2"].spec["pre_filling_time"], - "pressione_pre_riempimento_2": steps["leak_2"].spec["pre_filling_pressure"], - "tempo_riempimento_2": steps["leak_2"].spec["filling_time"], - "tempo_assestamento_2": steps["leak_2"].spec["settling_time"], - "percentuale_minima_pressione_assestamento_2": steps["leak_2"].spec["settling_pressure_min_percent"], - "percentuale_massima_pressione_assestamento_2": steps["leak_2"].spec["settling_pressure_max_percent"], - "tempo_di_test_2": steps["leak_2"].spec["test_time"], - "pressione_di_test_delta_minimo_2": steps["leak_2"].spec["test_pressure_qneg"], - "pressione_di_test_2": steps["leak_2"].spec["test_pressure"], - "pressione_di_test_delta_massimo_2": steps["leak_2"].spec["test_pressure_qpos"], - "tempo_svuotamento_2": steps["leak_2"].spec["flush_time"], - "pressione_svuotamento_2": steps["leak_2"].spec["flush_pressure"], - "test_visione_abilitato": recipe.spec["vision"], - "ricetta_visione": steps["vision"].spec["recipe"], - "stampa_etichetta_abilitata": "x" if recipe.spec["print"] else "", - print_template_field: steps["print"].spec["template"], } + + # Check and add fields conditionally for each section + + # MULTICOMP SECTION + if recipe.spec.get("connector"): + exportable.update({ + "verifica_connettore_abilitata": "x", + "connettore": steps["connector"].spec["connector"] + }) + if recipe.spec.get("resistance"): + exportable.update({ + "verifica_resistenza_connettore_abilitata": "x", + "scala_resistenza": steps["resistance"].spec["scale"], + "r nominale": steps["resistance"].spec["expected"], + "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], + "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"] + }) + + # BARCODE SECTION + if recipe.spec.get("barcodes"): + exportable.update({ + barcode_enable_field: "x", + barcode_serial_field: steps["barcodes"].spec["serial"] + }) + if recipe.spec.get("screws"): + exportable.update({ + "avvitatura_abilitata": "x", + "viti": steps["screws"].spec["quantity"] + }) + + # TECNA SECTION + if recipe.spec.get("leak_1"): + exportable.update({ + "prova_tenuta_abilitata": "x", + "tempo_pre_riempimento": steps["leak_1"].spec["pre_filling_time"], + "pressione_pre_riempimento": steps["leak_1"].spec["pre_filling_pressure"], + "tempo_riempimento": steps["leak_1"].spec["filling_time"], + "tempo_assestamento": steps["leak_1"].spec["settling_time"], + "percentuale_minima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_min_percent"], + "percentuale_massima_pressione_assestamento": steps["leak_1"].spec["settling_pressure_max_percent"], + "tempo_di_test": steps["leak_1"].spec["test_time"], + "pressione_di_test_delta_minimo": steps["leak_1"].spec["test_pressure_qneg"], + "pressione_di_test": steps["leak_1"].spec["test_pressure"], + "pressione_di_test_delta_massimo": steps["leak_1"].spec["test_pressure_qpos"], + "tempo_svuotamento": steps["leak_1"].spec["flush_time"], + "pressione_svuotamento": steps["leak_1"].spec["flush_pressure"], + }) + if recipe.spec.get("leak_2"): + exportable.update({ + "prova_tenuta_abilitata_2": "x", + "tempo_pre_riempimento_2": steps["leak_2"].spec["pre_filling_time"], + "pressione_pre_riempimento_2": steps["leak_2"].spec["pre_filling_pressure"], + "tempo_riempimento_2": steps["leak_2"].spec["filling_time"], + "tempo_assestamento_2": steps["leak_2"].spec["settling_time"], + "percentuale_minima_pressione_assestamento_2": steps["leak_2"].spec[ + "settling_pressure_min_percent"], + "percentuale_massima_pressione_assestamento_2": steps["leak_2"].spec[ + "settling_pressure_max_percent"], + "tempo_di_test_2": steps["leak_2"].spec["test_time"], + "pressione_di_test_delta_minimo_2": steps["leak_2"].spec["test_pressure_qneg"], + "pressione_di_test_2": steps["leak_2"].spec["test_pressure"], + "pressione_di_test_delta_massimo_2": steps["leak_2"].spec["test_pressure_qpos"], + "tempo_svuotamento_2": steps["leak_2"].spec["flush_time"], + "pressione_svuotamento_2": steps["leak_2"].spec["flush_pressure"], + }) + + # VISION SECTION + if recipe.spec.get("vision"): + exportable.update({ + "test_visione_abilitato": recipe.spec["vision"], + "ricetta_visione": steps["vision"].spec["recipe"] + }) + + # PRINT SECTION + if recipe.spec.get("print"): + exportable.update({ + "stampa_etichetta_abilitata": "x", + print_template_field: steps["print"].spec["template"], + "etichette_supplementari": steps["print"].spec["extra_label"] + }) + + # Append the exportable dictionary to the data list data.append(exportable) + + # Export to CSV if there is data if len(data): self.log.info(f"recipes: exporting recipes to {csv_path}") with open(csv_path, "w", newline="") as f: - w = csv.DictWriter(f, fieldnames, extrasaction="ignore") + w = csv.DictWriter(f, fieldnames=exportable.keys(), extrasaction="ignore") w.writeheader() w.writerows(data) self.log.info(f"recipes: exported {len(data)} rows.") - def delete_recipes(self): ret = QMessageBox.warning( None, From e9d83f1fcee58708dec9daeb0cc87daa15bd5adc Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 09:29:22 +0200 Subject: [PATCH 57/88] fix merge --- src/ui/test/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/test/test.py b/src/ui/test/test.py index b4ae8e7..adc2fc4 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -287,7 +287,7 @@ class Test(Widget): # if recipe not set: select_recipe if self.recipe_selection_mode == "barcode": self.log.info(f"returning to barcode recipe selection") - self.step = {"type":"barcode_recipe_selection","spec":{}} + self.step = Step(step_type="barcode_recipe_selection") else: self.log.info(f"returning to recipe selection table") self.step = Step(step_type="select_recipe") From bfa5ee8d744ad67707d12fe5ca3286439308b1c0 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 10:07:22 +0200 Subject: [PATCH 58/88] fix merge --- src/ui/test/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/test/test.py b/src/ui/test/test.py index adc2fc4..cbd35b8 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -443,7 +443,7 @@ class Test(Widget): if step.step_type in ("leak_1", "leak_2"): self.leak_step = step - step_types = [step.type for step in steps] + step_types = [step.step_type for step in steps] if "leak_1" in step_types and "leak_2" in step_types: leak1_index = step_types.index("leak_1") leak2_index = step_types.index("leak_2") @@ -454,7 +454,7 @@ class Test(Widget): # Insert 'instruction_extra' after the first 'instructions' if not inserted between leaks if not inserted_instruction: for i, step in enumerate(steps): - if step.type == "instructions": + if step.step_type == "instructions": steps.insert(i + 1, Step(step_type="instruction_extra", spec={})) inserted_instruction = True break From ec546362576d362a909e6d5134a0d6f7db528b99 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 11:34:25 +0200 Subject: [PATCH 59/88] fix dynamic export --- src/lib/db/models/recipes.py | 2 +- src/ui/recipe_selection/recipe_selection.py | 104 ++++++++------------ 2 files changed, 41 insertions(+), 65 deletions(-) diff --git a/src/lib/db/models/recipes.py b/src/lib/db/models/recipes.py index 0cd5a90..fb0e37a 100644 --- a/src/lib/db/models/recipes.py +++ b/src/lib/db/models/recipes.py @@ -25,7 +25,7 @@ class Recipes(BaseModel): def get_steps_map(self): steps = {} - for step_name, step_pk in self.spec.get("available_steps", {}).items(): + for step_name, step_pk in self.spec.get("steps", {}).items(): steps[step_name] = Step(step_type=step_name,spec=self.spec["steps"][step_name]) return steps diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 781ffa5..77f8a98 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -374,55 +374,7 @@ class Recipe_Selection(Widget): barcode_serial_field = self.config.get("recipe", {}).get("barcode_serial_field", "codice_a_barre").strip() print_template_field = self.config.get("recipe", {}).get("label_template_field", "modello_etichetta").strip() data = [] - fieldnames = [ - recipe_name_field, - "cliente", - "part_number", - "dimensione_lotto_abilitata", - "dimensione_lotto", - "verifica_connettore_abilitata", - "connettore", - barcode_enable_field, - barcode_serial_field, - "verifica_resistenza_connettore_abilitata", - "scala_resistenza", - "r nominale", - "tolleranza_resistenza_pos", - "tolleranza_resistenza_neg", - "avvitatura_abilitata", - "viti", - "prova_tenuta_abilitata", - "tempo_pre_riempimento", - "pressione_pre_riempimento", - "tempo_riempimento", - "tempo_assestamento", - "percentuale_minima_pressione_assestamento", - "percentuale_massima_pressione_assestamento", - "tempo_di_test", - "pressione_di_test_delta_minimo", - "pressione_di_test", - "pressione_di_test_delta_massimo", - "tempo_svuotamento", - "pressione_svuotamento", - "prova_tenuta_abilitata_2", - "tempo_pre_riempimento_2", - "pressione_pre_riempimento_2", - "tempo_riempimento_2", - "tempo_assestamento_2", - "percentuale_minima_pressione_assestamento_2", - "percentuale_massima_pressione_assestamento_2", - "tempo_di_test_2", - "pressione_di_test_delta_minimo_2", - "pressione_di_test_2", - "pressione_di_test_delta_massimo_2", - "tempo_svuotamento_2", - "pressione_svuotamento_2", - "test_visione_abilitato", - "ricetta_visione", - "stampa_etichetta_abilitata", - print_template_field, - "etichette_supplementari", - ] + fieldnames = set() # Use a set to avoid duplicates for recipe in list(Recipes.select()): steps = recipe.get_steps_map() exportable = { @@ -432,15 +384,18 @@ class Recipe_Selection(Widget): "part_number": recipe.part_number, } - # Check and add fields conditionally for each section + # Add base fields to the fieldnames + fieldnames.update([recipe_name_field, "cliente", "part_number"]) - # MULTICOMP SECTION - if recipe.spec.get("connector"): + # Check and add fields conditionally for each section + if "connector" in steps: exportable.update({ "verifica_connettore_abilitata": "x", "connettore": steps["connector"].spec["connector"] }) - if recipe.spec.get("resistance"): + fieldnames.update(["verifica_connettore_abilitata", "connettore"]) + + if "resistance" in steps: exportable.update({ "verifica_resistenza_connettore_abilitata": "x", "scala_resistenza": steps["resistance"].spec["scale"], @@ -448,21 +403,24 @@ class Recipe_Selection(Widget): "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"] }) + fieldnames.update(["verifica_resistenza_connettore_abilitata", "scala_resistenza", "r nominale", + "tolleranza_resistenza_pos", "tolleranza_resistenza_neg"]) - # BARCODE SECTION - if recipe.spec.get("barcodes"): + if "barcodes" in steps: exportable.update({ barcode_enable_field: "x", barcode_serial_field: steps["barcodes"].spec["serial"] }) - if recipe.spec.get("screws"): + fieldnames.update([barcode_enable_field, barcode_serial_field]) + + if recipe.spec.get("steps", {}).get("screws") and "screws" in steps: exportable.update({ "avvitatura_abilitata": "x", "viti": steps["screws"].spec["quantity"] }) + fieldnames.update(["avvitatura_abilitata", "viti"]) - # TECNA SECTION - if recipe.spec.get("leak_1"): + if "leak_1" in steps: exportable.update({ "prova_tenuta_abilitata": "x", "tempo_pre_riempimento": steps["leak_1"].spec["pre_filling_time"], @@ -478,7 +436,15 @@ class Recipe_Selection(Widget): "tempo_svuotamento": steps["leak_1"].spec["flush_time"], "pressione_svuotamento": steps["leak_1"].spec["flush_pressure"], }) - if recipe.spec.get("leak_2"): + fieldnames.update(["prova_tenuta_abilitata", "tempo_pre_riempimento", "pressione_pre_riempimento", + "tempo_riempimento", "tempo_assestamento", + "percentuale_minima_pressione_assestamento", + "percentuale_massima_pressione_assestamento", "tempo_di_test", + "pressione_di_test_delta_minimo", + "pressione_di_test", "pressione_di_test_delta_massimo", "tempo_svuotamento", + "pressione_svuotamento"]) + + if "leak_2" in steps: exportable.update({ "prova_tenuta_abilitata_2": "x", "tempo_pre_riempimento_2": steps["leak_2"].spec["pre_filling_time"], @@ -496,30 +462,40 @@ class Recipe_Selection(Widget): "tempo_svuotamento_2": steps["leak_2"].spec["flush_time"], "pressione_svuotamento_2": steps["leak_2"].spec["flush_pressure"], }) + fieldnames.update(["prova_tenuta_abilitata_2", "tempo_pre_riempimento_2", "pressione_pre_riempimento_2", + "tempo_riempimento_2", "tempo_assestamento_2", + "percentuale_minima_pressione_assestamento_2", + "percentuale_massima_pressione_assestamento_2", "tempo_di_test_2", + "pressione_di_test_delta_minimo_2", "pressione_di_test_2", + "pressione_di_test_delta_massimo_2", + "tempo_svuotamento_2", "pressione_svuotamento_2"]) - # VISION SECTION - if recipe.spec.get("vision"): + if "vision" in steps: exportable.update({ "test_visione_abilitato": recipe.spec["vision"], "ricetta_visione": steps["vision"].spec["recipe"] }) + fieldnames.update(["test_visione_abilitato", "ricetta_visione"]) - # PRINT SECTION - if recipe.spec.get("print"): + if "print" in steps: exportable.update({ "stampa_etichetta_abilitata": "x", print_template_field: steps["print"].spec["template"], "etichette_supplementari": steps["print"].spec["extra_label"] }) + fieldnames.update(["stampa_etichetta_abilitata", print_template_field, "etichette_supplementari"]) # Append the exportable dictionary to the data list data.append(exportable) + # Convert the set to a list for CSV writing + fieldnames = list(fieldnames) + # Export to CSV if there is data if len(data): self.log.info(f"recipes: exporting recipes to {csv_path}") with open(csv_path, "w", newline="") as f: - w = csv.DictWriter(f, fieldnames=exportable.keys(), extrasaction="ignore") + w = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore") w.writeheader() w.writerows(data) self.log.info(f"recipes: exported {len(data)} rows.") From 1722ad260d5c0c8e7644ddfc5bf71c5f4f55672b Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 14:38:28 +0200 Subject: [PATCH 60/88] auto import wip --- src/ui/recipe_selection/recipe_selection.py | 3 ++- .../recipe_spec_and_step_editor.py | 20 +++++++++++++++---- src/ui/test/test.py | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 77f8a98..aef1cf4 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -38,6 +38,7 @@ class Recipe_Selection(Widget): self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps + self.unsupported_steps = set() if not self.second_leak_test_enabled: self.unsupported_steps.add("leak_2") session = Users.get_session() @@ -533,7 +534,7 @@ class Recipe_Selection(Widget): return imported_path def check_and_import_auto_csv(self): - if self.archive_sync.machine_status ==" logged-in": + #if self.archive_sync.machine_status ==" logged-in": # Define the directory to check auto_import_dir = os.path.join('config', 'csv_import', 'auto_csv_import') diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index dc0f5e1..9a97adf 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -133,11 +133,23 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) - self.crud=crud - for step_name,step_def in self.steps_map.items(): + self.crud = crud + + # Debugging output + print("Data received in render method:", data) + + for step_name, step_def in self.steps_map.items(): if not step_def.get("hidden", False): - step_def["enable"].setChecked(data.get(step_name,{}) in (True,1,"x") ) - self.steps_map[step_name]["spec"]=data["steps"].get(step_name,{}) + step_def["enable"].setChecked(data.get(step_name, {}) in (True, 1, "x")) + + # Ensure 'steps' key exists in the data dictionary + if "steps" in data: + print(f"Key 'steps' found in data. Processing step_name: {step_name}") + self.steps_map[step_name]["spec"] = data["steps"].get(step_name, {}) + else: + print(f"Key 'steps' not found in data. Assigning empty dict for step_name: {step_name}") + self.steps_map[step_name]["spec"] = {} + self.render_steps() def parse(self, action=None, row_number=None, crud=None): diff --git a/src/ui/test/test.py b/src/ui/test/test.py index cbd35b8..6fcbc00 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -50,6 +50,7 @@ class Test(Widget): self.refresh_time(init=True) # INIT RECIPE self.recipe = None + self.auto_import = Recipe_Selection(config=config) if self.config["hardware_config"]["barcode_recipe_selection"] == "present": @@ -291,6 +292,7 @@ class Test(Widget): else: self.log.info(f"returning to recipe selection table") self.step = Step(step_type="select_recipe") + self.auto_import.check_and_import_auto_csv() elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested From 087d3a48d64c1d43cf8ec0d38f03b62f00c20283 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 25 Oct 2024 17:11:00 +0200 Subject: [PATCH 61/88] Refactor ArchiveSynchronizer usage and clean up code Refactor code to properly utilize `ArchiveSynchronizer` class across multiple modules. Adjust conditional statements and imports for consistency. Remove unnecessary debug outputs and redundant code, ensuring more streamlined and maintainable codebase. --- src/components/archive_synchronizer.py | 1 - src/ui/login/login.py | 4 ++-- src/ui/recipe_selection/recipe_selection.py | 6 +----- .../recipe_spec_and_step_editor.py | 15 ++------------- src/ui/test/test.py | 9 +++++++-- src/ui/test_instructions/test_instructions.py | 4 ++-- src/ui/test_leak/test_leak.py | 2 +- 7 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index d7eb7bf..adf942a 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -21,7 +21,6 @@ from .component import Component # Suppress insecure request warning requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) class ArchiveSynchronizer(Component): - machine_status = "offline" def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv diff --git a/src/ui/login/login.py b/src/ui/login/login.py index dbded52..9aa3da2 100755 --- a/src/ui/login/login.py +++ b/src/ui/login/login.py @@ -21,8 +21,8 @@ class Login(Widget): super().__init__() self.welcome_l.setText("BENVENUTO, PER INIZIARE IL COLLAUDO, EFFETTUA L'ACCESSO:") self.user_cb.addItems(Users.get_usernames()) - - ArchiveSynchronizer.machine_status = "logged-in" + self.archive_synch= ArchiveSynchronizer() + self.archive_synch.machine_status = "logged-in" QShortcut(QKeySequence("Return"), self).activated.connect(self.login_b.click) QShortcut(QKeySequence("Enter"), self).activated.connect(self.login_b.click) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index aef1cf4..5c671f4 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -38,9 +38,6 @@ class Recipe_Selection(Widget): self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps - self.unsupported_steps = set() - if not self.second_leak_test_enabled: - self.unsupported_steps.add("leak_2") session = Users.get_session() if session.is_admin: readonly = False @@ -514,7 +511,7 @@ class Recipe_Selection(Widget): def backup_current_recipes(self): # Define the backup directory and file name backup_dir = os.path.join('config', 'csv_import', 'backup_csv') - timestamp = datetime.now().strftime("%d%m%y") + timestamp = datetime.now().strftime("%d%m%y%H%M%S") backup_file = f"backup_{timestamp}.csv" backup_path = os.path.join(backup_dir, backup_file) @@ -534,7 +531,6 @@ class Recipe_Selection(Widget): return imported_path def check_and_import_auto_csv(self): - #if self.archive_sync.machine_status ==" logged-in": # Define the directory to check auto_import_dir = os.path.join('config', 'csv_import', 'auto_csv_import') diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index 9a97adf..e176ef2 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -134,21 +134,10 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) self.crud = crud - - # Debugging output - print("Data received in render method:", data) - for step_name, step_def in self.steps_map.items(): if not step_def.get("hidden", False): - step_def["enable"].setChecked(data.get(step_name, {}) in (True, 1, "x")) - - # Ensure 'steps' key exists in the data dictionary - if "steps" in data: - print(f"Key 'steps' found in data. Processing step_name: {step_name}") - self.steps_map[step_name]["spec"] = data["steps"].get(step_name, {}) - else: - print(f"Key 'steps' not found in data. Assigning empty dict for step_name: {step_name}") - self.steps_map[step_name]["spec"] = {} + step_def["enable"].setChecked(data.get(step_name,{}) in (True,1,"x") ) + self.steps_map[step_name]["spec"]=data["steps"].get(step_name,{}) self.render_steps() diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 6fcbc00..c1644e4 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -26,6 +26,7 @@ from ui.test_screws import Test_Screws from ui.test_vision import Test_Vision from ui.test_warning_img import Test_Warning_Img from ui.widget import Widget +from components import ArchiveSynchronizer class Test(Widget): @@ -50,7 +51,8 @@ class Test(Widget): self.refresh_time(init=True) # INIT RECIPE self.recipe = None - self.auto_import = Recipe_Selection(config=config) + self.auto_import = Recipe_Selection + self.archive_sync = ArchiveSynchronizer() if self.config["hardware_config"]["barcode_recipe_selection"] == "present": @@ -292,7 +294,7 @@ class Test(Widget): else: self.log.info(f"returning to recipe selection table") self.step = Step(step_type="select_recipe") - self.auto_import.check_and_import_auto_csv() + self.archive_sync.machine_status = "stand-by" elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested @@ -326,6 +328,8 @@ class Test(Widget): self.config["autotest_done"] = True if not self.autotesting: if len(self.cycle_steps): + if self.archive_sync.machine_status == "stand-by": + self.auto_import.check_and_import_auto_csv() # 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] @@ -333,6 +337,7 @@ class Test(Widget): else: self.cycle_index = -1 self.step = Step(step_type=None) + self.archive_sync.machine_status = "working" # enable/disable cycle controls self.change_recipe_b.setEnabled(self.recipe is not None) self.cancel_b.setEnabled(self.step.step_type is not None and self.step.step_type not in { diff --git a/src/ui/test_instructions/test_instructions.py b/src/ui/test_instructions/test_instructions.py index 89f5c18..4b58ec7 100644 --- a/src/ui/test_instructions/test_instructions.py +++ b/src/ui/test_instructions/test_instructions.py @@ -48,9 +48,9 @@ class Test_Instructions(Test_Test): self.get_connection = self.components["digital_io"].out.connect(self.get) if step is not None: - if step.type == "instruction": + if step.step_type == "instruction": svg_path = f"{self.svg_path}{self.recipe}.svg" - elif step.type == "instruction_extra": + elif step.step_type == "instruction_extra": svg_path = f"{self.svg_path}{self.recipe}-extra.svg" if not os.path.exists(svg_path): diff --git a/src/ui/test_leak/test_leak.py b/src/ui/test_leak/test_leak.py index 72a7391..992727a 100644 --- a/src/ui/test_leak/test_leak.py +++ b/src/ui/test_leak/test_leak.py @@ -144,7 +144,7 @@ class Test_Leak(Test_Test): time.sleep(2) # AUTO START SECOND TEST - if step.type == "leak_2": + if step.step_type == "leak_2": if self.config["hardware_config"].get("dual_chanel", "absent") == "present": self.recipe_written = False time.sleep(1) From d3b7fcaecdaddd428d3f669f37c5d8a668d70550 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Mon, 28 Oct 2024 09:30:47 +0100 Subject: [PATCH 62/88] fix --- src/components/archive_synchronizer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index adf942a..8276e85 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -8,7 +8,6 @@ from pathlib import Path import requests import traceback -from bs4 import BeautifulSoup import requests from google.api_core.exceptions import Forbidden from google.cloud import storage From 58bc7c0477c2a77804777904b27b576d4a7dde0e Mon Sep 17 00:00:00 2001 From: Eduardo Date: Mon, 28 Oct 2024 15:58:46 +0100 Subject: [PATCH 63/88] fix --- src/components/archive_synchronizer.py | 2 +- src/components/modbus_component.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 8276e85..02992bb 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -23,7 +23,7 @@ class ArchiveSynchronizer(Component): def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv - self.machine_status = "offline" + #self.machine_status = "offline" def config_changed(self): self.machine_id = self.config.machine_id diff --git a/src/components/modbus_component.py b/src/components/modbus_component.py index 1c34453..32650e5 100644 --- a/src/components/modbus_component.py +++ b/src/components/modbus_component.py @@ -1,5 +1,6 @@ import sys import traceback +import warnings if "--sim-serial" in sys.argv: from components.dummies.serial import serial @@ -48,7 +49,10 @@ class ModbusComponent(Component): strict=False, ) if not self.client.connect(): + warnings.warn("device not reachable (could not connect): {} ({})".format(self.name, self.port), + RuntimeWarning) raise ConnectionError("device not reachable (could not connect): {} ({})".format(self.name, self.port)) + if not self.client.is_socket_open(): raise ConnectionError("device not reachable (socket not open): {} ({})".format(self.name, self.port)) self.lock.unlock() From 3f8630bd7fa73715f358f134ba54dd28507553b7 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 09:15:35 +0100 Subject: [PATCH 64/88] Add error dialogs for USB connection issues Introduce `QMessageBox` dialogs to notify users of USB connection errors in `modbus_component.py`. This provides immediate feedback to users, improving the usability and troubleshooting process. The change replaces previous warnings with more visible error messages. --- src/components/modbus_component.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/modbus_component.py b/src/components/modbus_component.py index 32650e5..6bf920b 100644 --- a/src/components/modbus_component.py +++ b/src/components/modbus_component.py @@ -2,6 +2,8 @@ import sys import traceback import warnings +from PyQt5.QtWidgets import QMessageBox + if "--sim-serial" in sys.argv: from components.dummies.serial import serial else: @@ -49,11 +51,11 @@ class ModbusComponent(Component): strict=False, ) if not self.client.connect(): - warnings.warn("device not reachable (could not connect): {} ({})".format(self.name, self.port), - RuntimeWarning) + QMessageBox.critical(None, "ERRORE", "CONNESSIONE ASSENTE ALLA TECNA - VERIFICARE CONNESSIONE USB",) raise ConnectionError("device not reachable (could not connect): {} ({})".format(self.name, self.port)) if not self.client.is_socket_open(): + QMessageBox.critical(None, "ERRORE", "CONNESSIONE ASSENTE ALLA TECNA - VERIFICARE CONNESSIONE USB",) raise ConnectionError("device not reachable (socket not open): {} ({})".format(self.name, self.port)) self.lock.unlock() From a73fa2c66ed5a3a8eccd5fa281ac1ef22df5ccd8 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 10:00:56 +0100 Subject: [PATCH 65/88] fix error during import --- src/ui/recipe_selection/recipe_selection.py | 6 ------ .../recipe_spec_and_step_editor.py | 7 +++++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 5c671f4..f30d06b 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -310,14 +310,9 @@ class Recipe_Selection(Widget): # create recipe or update existing one in DB try: recipe = Recipes.get_by_id(recipe_name) - steps = recipe.get_steps_map() recipe_is_new = False except Recipes.DoesNotExist: recipe = Recipes(name=recipe_name, part_number="TEMPORARY") - steps = {} - for step_name, step_spec in steps_specs.items(): - if step_name not in self.unsupported_steps: - steps[step_name] = step_spec recipe_is_new = True recipe.client = row.get("cliente", defaults["cliente"]) @@ -336,7 +331,6 @@ class Recipe_Selection(Widget): "leak_2": len(row.get("prova_tenuta_abilitata_2", defaults["prova_tenuta_abilitata_2"])) and "leak_2" not in self.unsupported_steps, "vision": len(row.get("test_visione_abilitato", defaults["test_visione_abilitato"])) and "vision" not in self.unsupported_steps, "print": len(row.get("stampa_etichetta_abilitata", defaults["stampa_etichetta_abilitata"])) and "print" not in self.unsupported_steps, - "steps": steps, } if recipe_is_new: recipe.save(force_insert=True) diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index e176ef2..b20c941 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -134,10 +134,13 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) self.crud = crud + steps_data = data.get("steps", {}) + for step_name, step_def in self.steps_map.items(): if not step_def.get("hidden", False): - step_def["enable"].setChecked(data.get(step_name,{}) in (True,1,"x") ) - self.steps_map[step_name]["spec"]=data["steps"].get(step_name,{}) + step_enabled = data.get(step_name, {}) in (True, 1, "x") + step_def["enable"].setChecked(step_enabled) + step_def["spec"] = steps_data.get(step_name, {}) self.render_steps() From bd0ea025f7580f9447eda40de8d24bbcf746e26f Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 11:41:42 +0100 Subject: [PATCH 66/88] Update machine status handling and fix archive synchronizer init Refactor machine status updates to include more states such as working" for better control. Also, ensure `ArchiveSynchronizer` is initialized with the `config` parameter where needed, improving consistency in object creation across multiple UI components. --- config/machine_settings/st-ten-1.ini | 2 +- src/components/archive_synchronizer.py | 1 + src/ui/login/login.py | 2 -- src/ui/recipe_selection/recipe_selection.py | 15 +++++++++++++-- src/ui/test/test.py | 10 +++++----- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/config/machine_settings/st-ten-1.ini b/config/machine_settings/st-ten-1.ini index 034f829..063f5c1 100644 --- a/config/machine_settings/st-ten-1.ini +++ b/config/machine_settings/st-ten-1.ini @@ -14,7 +14,7 @@ tecna_t3: present vision_saver: absent vision: absent screwdriver: absent -fixture_id: present +#fixture_id: present digital_io: present external_flush_blow: absent diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 02992bb..3aaad5b 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -26,6 +26,7 @@ class ArchiveSynchronizer(Component): #self.machine_status = "offline" def config_changed(self): + self.machine_status = "stand-by" self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" diff --git a/src/ui/login/login.py b/src/ui/login/login.py index 9aa3da2..f101a71 100755 --- a/src/ui/login/login.py +++ b/src/ui/login/login.py @@ -22,7 +22,6 @@ class Login(Widget): self.welcome_l.setText("BENVENUTO, PER INIZIARE IL COLLAUDO, EFFETTUA L'ACCESSO:") self.user_cb.addItems(Users.get_usernames()) self.archive_synch= ArchiveSynchronizer() - self.archive_synch.machine_status = "logged-in" QShortcut(QKeySequence("Return"), self).activated.connect(self.login_b.click) QShortcut(QKeySequence("Enter"), self).activated.connect(self.login_b.click) @@ -59,7 +58,6 @@ class Login(Widget): login_count += 1 # /TESTING self.successful_login.emit() - ArchiveSynchronizer.machine_status = "logged-in" def show_osk(self): self.password_le.setFocus() diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index f30d06b..cf02f31 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -34,7 +34,7 @@ class Recipe_Selection(Widget): global noner super().__init__() self.config = config - self.archive_sync = ArchiveSynchronizer() + self.archive_synch = ArchiveSynchronizer(config=config) self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps @@ -139,6 +139,12 @@ class Recipe_Selection(Widget): self.import_b.setVisible(False) self.export_b.setVisible(False) self.delete_all_b.setVisible(False) + + self.archive_synch.machine_status = "logged-in" + self.archive_synch.machine_id = self.archive_synch.config.machine_id + self.archive_synch.update_machine_status() + #self.archive_synch.remote_fetch( self.archive_synch.machine_id ) + print("trying to import") # TESTING if "--auto-select" in sys.argv: recipe = "R56738/1" @@ -310,11 +316,15 @@ class Recipe_Selection(Widget): # create recipe or update existing one in DB try: recipe = Recipes.get_by_id(recipe_name) + steps = recipe.get_steps_map() recipe_is_new = False except Recipes.DoesNotExist: recipe = Recipes(name=recipe_name, part_number="TEMPORARY") + steps = {} + for step_name, step_spec in steps_specs.items(): + if step_name not in self.unsupported_steps: + steps[step_name] = step_spec recipe_is_new = True - recipe.client = row.get("cliente", defaults["cliente"]) recipe.part_number = row.get(part_number_field, defaults["part_number"]) recipe.description = row.get(description_field, defaults["descrizione"]) @@ -331,6 +341,7 @@ class Recipe_Selection(Widget): "leak_2": len(row.get("prova_tenuta_abilitata_2", defaults["prova_tenuta_abilitata_2"])) and "leak_2" not in self.unsupported_steps, "vision": len(row.get("test_visione_abilitato", defaults["test_visione_abilitato"])) and "vision" not in self.unsupported_steps, "print": len(row.get("stampa_etichetta_abilitata", defaults["stampa_etichetta_abilitata"])) and "print" not in self.unsupported_steps, + "steps": steps, } if recipe_is_new: recipe.save(force_insert=True) diff --git a/src/ui/test/test.py b/src/ui/test/test.py index c1644e4..1b3fc9c 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -52,7 +52,7 @@ class Test(Widget): # INIT RECIPE self.recipe = None self.auto_import = Recipe_Selection - self.archive_sync = ArchiveSynchronizer() + self.archive_synch = ArchiveSynchronizer(config=config) if self.config["hardware_config"]["barcode_recipe_selection"] == "present": @@ -261,6 +261,10 @@ class Test(Widget): current_w = self.centralWidget if hasattr(current_w, "stop"): current_w.stop() + if action != "change_recipe": + self.archive_synch.machine_status = "working" + self.archive_synch.machine_id = self.archive_synch.config.machine_id + self.archive_synch.update_machine_status() if action == "change_recipe": self.log.info(f"cycle next: action: {action!r}") self.set_recipe(recipe=None) @@ -294,7 +298,6 @@ class Test(Widget): else: self.log.info(f"returning to recipe selection table") self.step = Step(step_type="select_recipe") - self.archive_sync.machine_status = "stand-by" elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested @@ -328,8 +331,6 @@ class Test(Widget): self.config["autotest_done"] = True if not self.autotesting: if len(self.cycle_steps): - if self.archive_sync.machine_status == "stand-by": - self.auto_import.check_and_import_auto_csv() # 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] @@ -337,7 +338,6 @@ class Test(Widget): else: self.cycle_index = -1 self.step = Step(step_type=None) - self.archive_sync.machine_status = "working" # enable/disable cycle controls self.change_recipe_b.setEnabled(self.recipe is not None) self.cancel_b.setEnabled(self.step.step_type is not None and self.step.step_type not in { From 82c09a8ceda1060f495463b6992cb5c1cad660f5 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 12:03:20 +0100 Subject: [PATCH 67/88] Refactor machine status updates Removed unnecessary machine status update to "stand-by" and streamlined status changes to "working" and "logged-in" based on specific actions. This helps in maintaining a cleaner and more accurate status flow within the application logic. --- src/components/archive_synchronizer.py | 2 +- src/ui/test/test.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 3aaad5b..f31d5a2 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -25,8 +25,8 @@ class ArchiveSynchronizer(Component): self.simulate = "--sim-archiver" in sys.argv #self.machine_status = "offline" + def config_changed(self): - self.machine_status = "stand-by" self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 1b3fc9c..2fef0c1 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -184,6 +184,7 @@ class Test(Widget): self.next_timer.timeout.connect(self.next) self.next() + def refresh_time(self, init=False): if init: self.time_timer = QTimer() @@ -261,11 +262,10 @@ class Test(Widget): current_w = self.centralWidget if hasattr(current_w, "stop"): current_w.stop() - if action != "change_recipe": - self.archive_synch.machine_status = "working" - self.archive_synch.machine_id = self.archive_synch.config.machine_id - self.archive_synch.update_machine_status() if action == "change_recipe": + self.archive_synch.machine_status = "logged-in" + self.archive_synch.machine_id = self.archive_synch.config.machine_id + self.archive_synch.update_machine_status() self.log.info(f"cycle next: action: {action!r}") self.set_recipe(recipe=None) if self.config["hardware_config"]["tecna_t3"] == "present" or self.config["hardware_config"]["furness_controls"] == "present": @@ -298,6 +298,7 @@ class Test(Widget): else: self.log.info(f"returning to recipe selection table") self.step = Step(step_type="select_recipe") + elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested @@ -334,6 +335,9 @@ class Test(Widget): # 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] + self.archive_synch.machine_status = "working" + self.archive_synch.machine_id = self.archive_synch.config.machine_id + self.archive_synch.update_machine_status() else: self.cycle_index = -1 From 3f4f0aab82449389721b04748bf5ff6e3583ba92 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 12:04:28 +0100 Subject: [PATCH 68/88] Set machine status to "logged-in" by default Updated the default machine status from "offline" to "logged-in" in the ArchiveSynchronizer class. This ensures the correct initial status is set when the object is instantiated. --- src/components/archive_synchronizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index f31d5a2..13ea82d 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -24,7 +24,7 @@ class ArchiveSynchronizer(Component): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv #self.machine_status = "offline" - + self.machine_status = "logged-in" def config_changed(self): self.machine_id = self.config.machine_id From f6b9bc568cf62fdabe37e938a798da4f45da6a02 Mon Sep 17 00:00:00 2001 From: gg Date: Tue, 29 Oct 2024 13:17:15 +0100 Subject: [PATCH 69/88] ferrari label flag qr only --- .../FERRARI/ferrari_flag_qr_only.nlbl | Bin 0 -> 3903 bytes config/label_templates/ferrari_30x16_203.prn | 30 ++++++++++++++++ .../label_templates/ferrari_flag_qr_only.prn | 34 ++++++++++++++++++ src/scripts/print_labels.py | 16 ++++----- src/test/label_printer_ferrari.py | 2 +- 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 config/label_designs/FERRARI/ferrari_flag_qr_only.nlbl create mode 100644 config/label_templates/ferrari_30x16_203.prn create mode 100644 config/label_templates/ferrari_flag_qr_only.prn diff --git a/config/label_designs/FERRARI/ferrari_flag_qr_only.nlbl b/config/label_designs/FERRARI/ferrari_flag_qr_only.nlbl new file mode 100644 index 0000000000000000000000000000000000000000..0975990d01c715b0075a8a2d9705c2a010b138da GIT binary patch literal 3903 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", diff --git a/src/test/label_printer_ferrari.py b/src/test/label_printer_ferrari.py index c171181..e598921 100644 --- a/src/test/label_printer_ferrari.py +++ b/src/test/label_printer_ferrari.py @@ -47,4 +47,4 @@ app = QApplication(sys.argv) # TEST STANDARD PRINTER printer = Os_Label_Printer(config=config, name="label_printer") printer.config_changed() -printer.print_label("F164F169_203.prn", context=context) +printer.print_label("ferrari_30x16_203.prn", context=context) From 118c0367b9d9d03a05a63855a371dd79b982579d Mon Sep 17 00:00:00 2001 From: edo-neo Date: Tue, 29 Oct 2024 17:28:35 +0100 Subject: [PATCH 70/88] Refactor remote_fetch and add check_actions_to_do Simplify the remote_fetch method by removing machine_status parameter and updating error handling. Introduce check_actions_to_do method to determine necessary actions for the machine, including invoking remote_fetch as a required action. --- src/components/archive_synchronizer.py | 212 +++++++++++++------------ 1 file changed, 113 insertions(+), 99 deletions(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 13ea82d..8fdc591 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -11,6 +11,8 @@ import traceback import requests from google.api_core.exceptions import Forbidden from google.cloud import storage +from requests import JSONDecodeError + from lib.db import Archive, db from PyQt5.QtCore import QThread from requests.adapters import HTTPAdapter, Retry @@ -59,7 +61,7 @@ class ArchiveSynchronizer(Component): if "--dev-portal" in sys.argv: self.update_machine_status() - self.remote_fetch(self.machine_status,self.machine_id) + self.check_actions_to_do(self.machine_id) super()._get() def update_machine_status(self): @@ -152,123 +154,135 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_status=None, machine_id=None): + def remote_fetch(self, machine_id=None): """ Fetch and download files from the server. - :param machine_status: Status of the machine (e.g., 'logged-in'). :param machine_id: ID of the machine. :return: A list of downloaded file paths or a dictionary with errors if any occur. """ - # URLs endpoint from your Django server with machine_id as a query parameter if machine_id is None: raise ValueError("machine_id cannot be None") urls_endpoint = f"http://dev.r5portal.it/get-file-urls/?machine_id={machine_id}" - if machine_status == "logged-in": - try: - # Fetching the list of specific file URLs from the Django server - if not self.simulate: - with requests.Session() as s: - self.log.info(f"Fetching list of file URLs from: {urls_endpoint}") + try: + if not self.simulate: + with requests.Session() as s: + self.log.info(f"Fetching list of file URLs from: {urls_endpoint}") - # Make the HTTP GET request to fetch the list of URLs - response = s.get(urls_endpoint, timeout=5, verify=False) + # Make the HTTP GET request to fetch the list of URLs + response = s.get(urls_endpoint, timeout=5, verify=False) - # Log response details - self.log.info(f"HTTP Status Code: {response.status_code}") - self.log.info(f"Response Headers: {response.headers}") - self.log.info(f"Response Content: {response.content}") + # Log response details + self.log.info(f"HTTP Status Code: {response.status_code}") + self.log.info(f"Response Headers: {response.headers}") + self.log.info(f"Response Content: {response.content}") - # Handle HTTP errors for the list of URLs fetch - if response.status_code == 404: - self.log.warning(f"URLs endpoint not found: {urls_endpoint}. Please check the URL path.") - return {"error": "URLs endpoint not found"} - elif response.status_code == 403: - self.log.warning(f"Access forbidden for URLs endpoint: {urls_endpoint}") - return {"error": "Access forbidden"} - elif response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {urls_endpoint}") - return {"error": "Unexpected HTTP response status"} + # Handle HTTP errors for the list of URLs fetch + if response.status_code == 404: + self.log.warning(f"URLs endpoint not found: {urls_endpoint}. Please check the URL path.") + return {"error": "URLs endpoint not found"} + elif response.status_code == 403 or response.status_code == 401: + self.log.warning(f"Access forbidden or not logged in for URLs endpoint: {urls_endpoint}") + return {"error": "Access forbidden or not logged in"} + elif response.status_code != 200: + self.log.error( + f"Unexpected HTTP response status: {response.status_code} for URL: {urls_endpoint}") + return {"error": "Unexpected HTTP response status"} - # Parse the list of URLs (assuming the response contains a JSON array of URLs) + # Parse the list of URLs (assuming the response contains a JSON array of URLs) + try: + file_urls = response.json() + self.log.info(f"Fetched file URLs: {file_urls}") + except ValueError as e: + self.log.error(f"Error parsing JSON response: {str(e)}") + self.log.error(f"Response Content: {response.content}") + return {"error": "Failed to parse JSON response"} + + downloaded_files = [] + errors = {} + + # Setup the base download path + base_download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1") + + # Iterate over the list of URLs to download each file + for specific_file_url in file_urls: try: - file_urls = response.json() - self.log.info(f"Fetched file URLs: {file_urls}") - except ValueError as e: - self.log.error(f"Error parsing JSON response: {str(e)}") - self.log.error(f"Response Content: {response.content}") - return {"error": "Failed to parse JSON response"} + self.log.info(f"Attempting to fetch file from: {specific_file_url}") - downloaded_files = [] - errors = {} + # Make the HTTP GET request to fetch the file URL + response = s.get(specific_file_url, timeout=5, verify=False) - # Setup the base download path - base_download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1") + # Log response details + self.log.info(f"HTTP Status Code: {response.status_code}") + self.log.info(f"Response Headers: {response.headers}") - # Iterate over the list of URLs to download each file - for specific_file_url in file_urls: - try: - self.log.info(f"Attempting to fetch file from: {specific_file_url}") - - # Make the HTTP GET request to fetch the file URL - response = s.get(specific_file_url, timeout=5, verify=False) - - # Log response details - self.log.info(f"HTTP Status Code: {response.status_code}") - self.log.info(f"Response Headers: {response.headers}") - - # Handle HTTP errors appropriately for each file - if response.status_code == 404: - self.log.warning(f"File not found: {specific_file_url}. Please check the URL path.") - errors[specific_file_url] = "File not found" - continue - elif response.status_code == 403: - self.log.warning(f"Access forbidden for file: {specific_file_url}") - errors[specific_file_url] = "Access forbidden" - continue - elif response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") - errors[specific_file_url] = f"Unexpected status {response.status_code}" - continue - - # Determine the subdirectory based on the file URL or other criteria - if "warning_images" in specific_file_url: - sub_dir = os.path.join("config", "warning_images", machine_id) - elif "ricette" in specific_file_url: - sub_dir = os.path.join("config", "csv_import", "auto_csv_import") - else: - sub_dir = "tmp" # Save others under the temporary folder - - # Ensure the directory exists - download_path = os.path.join(base_download_path, sub_dir) - os.makedirs(download_path, exist_ok=True) - - # Save the file to the determined directory - local_file_path = os.path.join(download_path, os.path.basename(specific_file_url)) - with open(local_file_path, "wb") as f: - f.write(response.content) - - self.log.info(f"File downloaded successfully: {local_file_path}") - downloaded_files.append(local_file_path) - - except (requests.ConnectionError, requests.Timeout) as e: - self.log.warning( - f"Failed to download file from {specific_file_url}, the URL might be unreachable: {str(e)}") - errors[specific_file_url] = "URL unreachable" - except Exception as e: + # Handle HTTP errors appropriately for each file + if response.status_code == 404: + self.log.warning(f"File not found: {specific_file_url}. Please check the URL path.") + errors[specific_file_url] = "File not found" + continue + elif response.status_code == 403: + self.log.warning(f"Access forbidden for file: {specific_file_url}") + errors[specific_file_url] = "Access forbidden" + continue + elif response.status_code != 200: self.log.error( - f"An unexpected error occurred while downloading {specific_file_url}: {str(e)}") - errors[specific_file_url] = "Unexpected error" + f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") + errors[specific_file_url] = f"Unexpected status {response.status_code}" + continue - return { - "downloaded_files": downloaded_files, - "errors": errors - } + # Determine the subdirectory based on the file URL or other criteria + if "warning_images" in specific_file_url: + sub_dir = os.path.join("config", "warning_images", machine_id) + elif "ricette" in specific_file_url: + sub_dir = os.path.join("config", "csv_import", "auto_csv_import") + else: + sub_dir = "tmp" # Save others under the temporary folder - except Exception as e: - self.log.error(f"An unexpected error occurred while fetching URLs: {str(e)}") - return {"error": "Unexpected error"} + # Ensure the directory exists + download_path = os.path.join(base_download_path, sub_dir) + os.makedirs(download_path, exist_ok=True) + # Save the file to the determined directory + local_file_path = os.path.join(download_path, os.path.basename(specific_file_url)) + with open(local_file_path, "wb") as f: + f.write(response.content) + + self.log.info(f"File downloaded successfully: {local_file_path}") + downloaded_files.append(local_file_path) + + except (requests.ConnectionError, requests.Timeout) as e: + self.log.warning( + f"Failed to download file from {specific_file_url}, the URL might be unreachable: {str(e)}") + errors[specific_file_url] = "URL unreachable" + except Exception as e: + self.log.error( + f"An unexpected error occurred while downloading {specific_file_url}: {str(e)}") + errors[specific_file_url] = "Unexpected error" + + return { + "downloaded_files": downloaded_files, + "errors": errors + } + + except Exception as e: + self.log.error(f"An unexpected error occurred while fetching URLs: {str(e)}") + return {"error": "Unexpected error"} + + def check_actions_to_do(self, machine_id: str) : + update_url = f"http://dev.r5portal.it/device/?machine-id={machine_id}" + response = requests.get(update_url) + + if response.status_code == 200: + try: + #json_response = response.json() + #action_to_do = json_response.get("ACTIONS_TO_DO", "NO_ACTION") + #if action_to_do == "DOWNLOAD_FILES": + self.remote_fetch(machine_id) + #else: + # self.log.info(f"No action required: {json_response}") + except JSONDecodeError as e: + self.log.error(f"JSON decode error: {str(e)} - Content: {response.content}") + else: + self.log.error(f"Failed to update device info: {response.status_code} - {response.content}") From 994c9958a4d08fac287aecda2ca019536c32e944 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 30 Oct 2024 14:52:03 +0100 Subject: [PATCH 71/88] labels --- src/scripts/print_labels_csv.py | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/scripts/print_labels_csv.py diff --git a/src/scripts/print_labels_csv.py b/src/scripts/print_labels_csv.py new file mode 100644 index 0000000..cba8602 --- /dev/null +++ b/src/scripts/print_labels_csv.py @@ -0,0 +1,53 @@ +import csv +import time +from datetime import datetime + +from PyQt5.QtWidgets import QApplication + +from src.components.os_label_printer import * +from src.lib.helpers import ConfigReader + +SYSTEM_ID = "test-linux" +CSV_PATH="tmp/ferrari_labels3.csv" +TEMPLATE="ferrari_flag_qr_only.prn" +config = ConfigReader(system_id=SYSTEM_ID) +printer=Os_Label_Printer(config=config,name="label_printer") + + +# timenow = datetime.now() +app = QApplication(sys.argv) + +with open(CSV_PATH, "r", encoding="utf-8-sig") as f: + reader = csv.DictReader(f) + for row in reader: + START_SN = 1 + STOP_SN = int(row["quantity"]) + PN = row["part_number"] + print(f"PART NUMBER # {PN}") + for sn in range(START_SN,STOP_SN+2): + timenow = datetime.now() + print(f"PRINTING LABEL # {sn}") + context = { + # RECIPE DATA + "PART": PN, + # SERIAL DEFINITION + "SN": str(sn), + "SN4": f"{sn:0>4}", + "SN5": f"{sn:0>5}", + "SN6": f"{sn:0>6}", + # TIME DEFINITION + "DATETIME": timenow.strftime("%d/%m/%Y %H:%M:%S"), + "DATE": timenow.strftime("%d/%m/%Y"), + "TIME": timenow.strftime("%H:%M:%S"), + "YYYY": timenow.strftime("%Y"), + "YY": timenow.strftime("%y"), + "MO": timenow.strftime("%m"), + "DD": timenow.strftime("%d"), + "HH": timenow.strftime("%H"), + "MI": timenow.strftime("%M"), + "SS": timenow.strftime("%S"), + "JJJ": timenow.strftime("%j"), + } + printer.print_label(TEMPLATE,context) + + time.sleep(1) \ No newline at end of file From 8324f34ca37e8ef7671002c20380d067d16d0dc2 Mon Sep 17 00:00:00 2001 From: neo Date: Thu, 31 Oct 2024 11:51:18 +0100 Subject: [PATCH 72/88] labels --- src/scripts/print_labels_csv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/print_labels_csv.py b/src/scripts/print_labels_csv.py index cba8602..f636886 100644 --- a/src/scripts/print_labels_csv.py +++ b/src/scripts/print_labels_csv.py @@ -8,7 +8,7 @@ from src.components.os_label_printer import * from src.lib.helpers import ConfigReader SYSTEM_ID = "test-linux" -CSV_PATH="tmp/ferrari_labels3.csv" +CSV_PATH="tmp/ferrari_labels4.csv" TEMPLATE="ferrari_flag_qr_only.prn" config = ConfigReader(system_id=SYSTEM_ID) printer=Os_Label_Printer(config=config,name="label_printer") @@ -24,6 +24,7 @@ with open(CSV_PATH, "r", encoding="utf-8-sig") as f: STOP_SN = int(row["quantity"]) PN = row["part_number"] print(f"PART NUMBER # {PN}") + input("Press Enter to continue...") for sn in range(START_SN,STOP_SN+2): timenow = datetime.now() print(f"PRINTING LABEL # {sn}") From edd09bfbddc0baa688651f4c9972a7db737f9999 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Tue, 5 Nov 2024 10:02:38 +0100 Subject: [PATCH 73/88] dev --- config/label_templates/ferrari_30x16_203.prn | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/label_templates/ferrari_30x16_203.prn b/config/label_templates/ferrari_30x16_203.prn index 53b6b78..f54e10b 100644 --- a/config/label_templates/ferrari_30x16_203.prn +++ b/config/label_templates/ferrari_30x16_203.prn @@ -9,8 +9,8 @@ ^PMN ^LH0,0 ^JMA -^PR2,2 -~SD15 +^PR4,4 +~SD25 ^JUS ^LRN ^CI27 @@ -18,13 +18,13 @@ ^XZ ^XA ^MMT -^PW256 -^LL144 +^PW248 +^LL136 ^LS0 -^FT21,129^BQN,2,4 +^FT123,148^BQN,2,4 ^FH\^FDLA,{PART}{SN5}{MO}{YY}^FS -^FT234,104^A0I,23,23^FH\^CI28^FD{PART}^FS^CI27 -^FT234,50^A0I,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 -^FT234,23^A0I,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT11,39^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 +^FT13,90^A0N,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 +^FT11,121^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 ^PQ1,0,1,Y ^XZ From ed6e449238bdf55455e24ae5a9afed394c4d74e0 Mon Sep 17 00:00:00 2001 From: germano laptop Date: Tue, 5 Nov 2024 10:07:33 +0100 Subject: [PATCH 74/88] dev --- config/label_templates/ferrari_30x16_203.prn | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/label_templates/ferrari_30x16_203.prn b/config/label_templates/ferrari_30x16_203.prn index f54e10b..8371740 100644 --- a/config/label_templates/ferrari_30x16_203.prn +++ b/config/label_templates/ferrari_30x16_203.prn @@ -23,8 +23,8 @@ ^LS0 ^FT123,148^BQN,2,4 ^FH\^FDLA,{PART}{SN5}{MO}{YY}^FS -^FT11,39^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 -^FT13,90^A0N,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 -^FT11,121^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT6,66^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 +^FT9,103^A0N,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 +^FT6,137^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 ^PQ1,0,1,Y ^XZ From 7a7cd3817e028aa325d99142f8911355c29ed45d Mon Sep 17 00:00:00 2001 From: germano laptop Date: Tue, 5 Nov 2024 10:14:13 +0100 Subject: [PATCH 75/88] dev --- config/label_templates/ferrari_30x16_203.prn | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/label_templates/ferrari_30x16_203.prn b/config/label_templates/ferrari_30x16_203.prn index 8371740..5c99bc3 100644 --- a/config/label_templates/ferrari_30x16_203.prn +++ b/config/label_templates/ferrari_30x16_203.prn @@ -21,10 +21,10 @@ ^PW248 ^LL136 ^LS0 -^FT123,148^BQN,2,4 +^FT123,147^BQN,2,4 ^FH\^FDLA,{PART}{SN5}{MO}{YY}^FS -^FT6,66^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 -^FT9,103^A0N,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 -^FT6,137^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT6,55^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 +^FT9,101^A0N,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 +^FT6,133^A0N,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 ^PQ1,0,1,Y ^XZ From 54f5ade0ca03ec6b699982b9f1edf1c579bb737f Mon Sep 17 00:00:00 2001 From: eduardo Date: Tue, 5 Nov 2024 15:11:36 +0100 Subject: [PATCH 76/88] dev --- .../PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl | Bin 0 -> 4220 bytes .../ERRECINQUE_flag_qr_only.prn | 36 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl create mode 100644 config/label_templates/ERRECINQUE_flag_qr_only.prn diff --git a/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl b/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl new file mode 100644 index 0000000000000000000000000000000000000000..eb649e95925991ff69d92d8fb5dfd7ff9ae5c26f GIT binary patch literal 4220 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 Date: Tue, 5 Nov 2024 15:51:08 +0100 Subject: [PATCH 77/88] dev --- .../PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl | Bin 4220 -> 3972 bytes .../ERRECINQUE_flag_qr_only.prn | 44 ++++++------------ 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl b/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl index eb649e95925991ff69d92d8fb5dfd7ff9ae5c26f..9d7e7f978dc9771e1ee4603644dcee9ee09cf3a9 100644 GIT binary patch literal 3972 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 literal 4220 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 Date: Tue, 5 Nov 2024 17:19:17 +0100 Subject: [PATCH 78/88] FIX and labels --- config/label_templates/ERRECINQUE_flag_qr_only.prn | 2 +- src/ui/recipe_selection/recipe_selection.py | 2 -- .../recipe_spec_and_step_editor/recipe_spec_and_step_editor.py | 3 ++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/config/label_templates/ERRECINQUE_flag_qr_only.prn b/config/label_templates/ERRECINQUE_flag_qr_only.prn index ee4c6b3..0e07ea9 100644 --- a/config/label_templates/ERRECINQUE_flag_qr_only.prn +++ b/config/label_templates/ERRECINQUE_flag_qr_only.prn @@ -30,7 +30,7 @@ ^FT31,236^BXN,6,200,0,0,1,_,1 ^FH\^FD{PART}{MO}{YY}{SN5}^FS ^FT29,287^A0N,25,25^FH\^CI28^FD{PART}{MO}{YY}{SN5}^FS^CI27 -^FO90,965^GFA,653,1887,17,:Z64:eJyNVTFuwzAMpKLBQDO4nTrqCflB3ZdFfkrnLn1C/YQ+wWPRyWMQGFYpiaRFGgXKybqcyNOJYgB8otigRmAgfVVA1mkb89rtQCoE3wBzBroGWDLQp5/3Gh+1TliBIxZgmAXoUy4TXwVwKX8XlKKUSfsaIpZxWwMMNwTWBugQ8LcGOCPdLw2Q9ytGrtC1DIg1T8MYDSNM0M0tgAczjBl6xcCV3oJ8A9xMDtStdXjLwLN7y/AHRmsQwKYdA1i1p5mRLWjiqu+lMibDGO4GCOmpxmMGYr5yjrHm2DtoqgyvOuwlg4YBagu26t6nVKVLd+pC0tG1LZQZQVmGOoKy7Kr69L9+qCLoKShPnXUdVxrAmzsAh7t1Sij2gmZgjznbhZqBB9P9MUz2NYwmRzTvxeNJXQscXlS/mVdZ5oB9ty3g4gzK03NpgMb1UPwd3nh9ogkzMfCcVskMtZPKZ89CqGVo8GRq7UOkTlxjob3fdBD+iOSIq5MP97L4dOPyfLS1PQHGpc5T3EtJOq6XRCtRZV5yPdH6uZm9geqdkqXGlbVOvHfU9eRBMFUEXOgXFxdD5T+OXasksQLYG2e1ioC/tV6Eas3iNyqXI6+YBYh7A08EBoIFegs4C8ickcbmJBMDDzRmxl/m/KgQ:B2BA +^FO90,965^GFA,3053,1887,17,:Z64:eJyNVTFuwzAMpKLBQDO4nTrqCflB3ZdFfkrnLn1C/YQ+wWPRyWMQGFYpiaRFGgXKybqcyNOJYgB8otigRmAgfVVA1mkb89rtQCoE3wBzBroGWDLQp5/3Gh+1TliBIxZgmAXoUy4TXwVwKX8XlKKUSfsaIpZxWwMMNwTWBugQ8LcGOCPdLw2Q9ytGrtC1DIg1T8MYDSNM0M0tgAczjBl6xcCV3oJ8A9xMDtStdXjLwLN7y/AHRmsQwKYdA1i1p5mRLWjiqu+lMibDGO4GCOmpxmMGYr5yjrHm2DtoqgyvOuwlg4YBagu26t6nVKVLd+pC0tG1LZQZQVmGOoKy7Kr69L9+qCLoKShPnXUdVxrAmzsAh7t1Sij2gmZgjznbhZqBB9P9MUz2NYwmRzTvxeNJXQscXlS/mVdZ5oB9ty3g4gzK03NpgMb1UPwd3nh9ogkzMfCcVskMtZPKZ89CqGVo8GRq7UOkTlxjob3fdBD+iOSIq5MP97L4dOPyfLS1PQHGpc5T3EtJOq6XRCtRZV5yPdH6uZm9geqdkqXGlbVOvHfU9eRBMFUEXOgXFxdD5T+OXasksQLYG2e1ioC/tV6Eas3iNyqXI6+YBYh7A08EBoIFegs4C8ickcbmJBMDDzRmxl/m/KgQ:B2BA ^FT27,506^A0N,25,25^FH\^CI28^FDESITO : CONFORME^FS^CI27 ^PQ1,0,1,Y ^XZ diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index cf02f31..5daaf38 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -143,8 +143,6 @@ class Recipe_Selection(Widget): self.archive_synch.machine_status = "logged-in" self.archive_synch.machine_id = self.archive_synch.config.machine_id self.archive_synch.update_machine_status() - #self.archive_synch.remote_fetch( self.archive_synch.machine_id ) - print("trying to import") # TESTING if "--auto-select" in sys.argv: recipe = "R56738/1" diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index b20c941..006c17c 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -173,7 +173,8 @@ class Recipe_Spec_And_Step_Editor(Editor): self.steps_map[step_name]["spec"]=step_dict else: self.steps_map[step_name]["spec"] = {} - self.crud().set_modified() + if self.crud is not None: + self.crud.set_modified() parsed_value=self.parse() self.cell_widget().value = parsed_value self.reset_steps() From d5c4fe420f418d7ac6722fe0ada173db3f7d4286 Mon Sep 17 00:00:00 2001 From: neo-2 Date: Wed, 6 Nov 2024 08:57:08 +0100 Subject: [PATCH 79/88] ST TEN 14 --- .../T3LP20RR SN030022100512 4 11 2024.csv | 303 +++++++++++++++++ .../manual_csv_import/ricette prototipi.csv | 305 ++++++++++++++++++ config/machine_settings/hostnames.ini | 1 + config/machine_settings/st-ten-14.ini | 93 ++++++ make_desktop_file.sh | 26 ++ make_desktop_file_noautotest.sh | 26 ++ runmenoautotest.sh | 4 + src/components/tecna_marposs_provaset_t3.py | 12 +- src/requirements.txt | 2 +- src/scripts/save_tecna_recipes_to_csv.py | 1 + src/ui/recipe_selection/recipe_selection.py | 3 +- 11 files changed, 772 insertions(+), 4 deletions(-) create mode 100644 config/csv_import/EXTRACTIONS/T3LP20RR SN030022100512 4 11 2024.csv create mode 100644 config/csv_import/manual_csv_import/ricette prototipi.csv create mode 100644 config/machine_settings/st-ten-14.ini create mode 100644 make_desktop_file.sh create mode 100644 make_desktop_file_noautotest.sh create mode 100755 runmenoautotest.sh diff --git a/config/csv_import/EXTRACTIONS/T3LP20RR SN030022100512 4 11 2024.csv b/config/csv_import/EXTRACTIONS/T3LP20RR SN030022100512 4 11 2024.csv new file mode 100644 index 0000000..b0d73ef --- /dev/null +++ b/config/csv_import/EXTRACTIONS/T3LP20RR SN030022100512 4 11 2024.csv @@ -0,0 +1,303 @@ +codice_ricetta,codice_prodotto,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,modello_etichetta,testo_etich_1,testo_etich_2 +07N.131.628.A,,10,200,20,20,10,10,10,5,200,5,20,0,ferrari_30x16_203.prn,07N.131.628.A, +V04.030.057.BE,P18 BATTERY COOLING,0,0,20,20,10,10,20,5,4100,5,1,0,ferrari_30x16_203.prn,V04.030.057.BE, +000990502,,0,0,10,10,10,10,10,30,1500,20,0,0,ferrari_30x16_203.prn,000990502, +98FA644CP,,0,0,5,10,10,10,20,15,3000,15,0,0,ferrari_30x16_203.prn,98FA644CP, +5803158246,CPLGASOLIO LP,5,2000,5,10,10,10,20,30,2000,0,0,0,ferrari_30x16_203.prn,5803158246,C9 CCM FPT +BLOW BY WOKO,000781499,10,1000,10,10,99,99,10,600,1000,20,0,0,ferrari_30x16_203.prn,000781499, +SY9Y-2976-B,SY9Y-2976-A,0,5000,10,10,10,10,10,20,3000,15,10,0,ferrari_30x16_203.prn,SY9Y-2976-B, +SY9Y-2976-A,SY9Y-2976-A,0,0,10,10,10,10,10,20,3000,0,0,0,ferrari_30x16_203.prn,SY9Y-2976-A, +SY9Y-9S331-B,SY9Y-9S331-B,10,0,10,10,10,10,10,20,3000,15,0,0,ferrari_30x16_203.prn,SY9Y-9S331-B, +SY9Y-9S331-A,SY9Y-9S331-A,10,0,10,10,10,10,10,20,3000,0,0,0,ferrari_30x16_203.prn,SY9Y-9S331-A, +18JA708CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA708CP, +18JA757CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA757CP, +18JA750CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA750CP, +18JA712CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA712CP, +18JA710CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA710CP, +18JA718CP,,0,5,5,5,10,10,30,20,3000,20,30,0,ferrari_30x16_203.prn,18JA718CP, +18JA713CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA713CP, +18JA709CP,,0,0,5,5,10,10,30,20,3000,20,0,0,ferrari_30x16_203.prn,18JA709CP, +000904357,,0,0,10,10,10,10,20,20,4200,20,0,0,ferrari_30x16_203.prn,000904357, +05534288,,0,0,10,10,10,10,20,20,6900,20,0,0,ferrari_30x16_203.prn,05534288, +5802031904,,0,0,5,5,10,10,20,20,2100,20,0,0,ferrari_30x16_203.prn,5802031904, +000894372,,10,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000894372, +000957630,,0,0,10,10,10,10,10,30,3400,10,0,0,ferrari_30x16_203.prn,000957630, +000957631,,0,0,10,10,10,10,10,30,3400,10,0,0,ferrari_30x16_203.prn,000957631, +000958439,,0,0,5,10,10,10,30,30,2200,10,0,0,ferrari_30x16_203.prn,000958439, +000986619,,0,0,5,15,10,10,10,30,1600,10,0,0,ferrari_30x16_203.prn,000986619, +S3130E132,,0,0,7,15,10,10,5,2,4100,1,0,0,ferrari_30x16_203.prn,S3130E132, +18KA144CT,,0,0,5,5,10,10,30,10,3100,10,0,0,ferrari_30x16_203.prn,18KA144CT, +5803148261,,2,5000,5,10,10,10,10,30,5000,15,1,0,ferrari_30x16_203.prn,5803148261, +98FB080CP,,5,200,10,10,10,10,20,10,200,15,30,1,ferrari_30x16_203.prn,98FB080CP, +590.2.418.1A,,0,5000,3,5,10,10,5,5,1000,15,0,0,ferrari_30x16_203.prn,590.2.418.1A, +055000044,,0,3000,5,5,10,10,30,20,2100,15,0,0,ferrari_30x16_203.prn,055000044, +000975576,TUBO INLET,5,2000,30,80,10,10,10,0,2000,1,0,0,ferrari_30x16_203.prn,000975576, +000975575,TUBO OUTLET,5,2000,10,80,10,10,10,0,2000,1,0,0,ferrari_30x16_203.prn,000975575, +5803223742,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223742, +5803223740,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223740, +5803223741,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223741, +5803223736,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223736, +5803223745,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223745, +000884945,,0,0,10,5,10,10,10,30,1500,0,0,0,ferrari_30x16_203.prn,000884945, +5803223739,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223739, +000960322,000960322,0,0,5,10,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000960322, +000960324,000960324,0,0,5,10,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000960324, +000960275,000960275,0,0,5,10,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000960275, +000960281,000960281,0,0,5,10,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000960281, +055055934,,0,0,10,10,10,10,20,20,6800,20,0,0,ferrari_30x16_203.prn,055055934, +5803228585,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803228585, +5803223755,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223755, +5803120375,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803120375, +5803083634,,0,5000,5,10,10,10,10,30,3000,15,0,0,ferrari_30x16_203.prn,5803083634, +742722-15,742722-15,0,0,5,10,10,10,20,30,6000,10,0,0,ferrari_30x16_203.prn,74222-15, +90383952,90383952,0,10,5,10,10,10,20,30,6100,0,0,0,ferrari_30x16_203.prn,90383952, +90383805,90383805,0,0,5,20,10,20,20,30,6100,0,0,0,ferrari_30x16_203.prn,90383805, +90459069,90459069,0,0,5,10,10,10,20,30,5100,0,0,0,ferrari_30x16_203.prn,90459069, +001031-R5,,0,0,10,30,10,10,30,10,5100,5,0,0,ferrari_30x16_203.prn,001031-R5, +5803036739,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803036739, +000990010,000990010,2,200,10,10,10,10,10,20,200,20,0,0,ferrari_30x16_203.prn,000990010, +SY9Y-18D553AAM1,,0,0,5,5,10,10,30,20,7000,20,0,0,ferrari_30x16_203.prn,SY9Y-18D553AAM1, +SY9Y-18D552AAM1,,10,7000,5,5,10,10,30,20,7100,20,0,0,ferrari_30x16_203.prn,SY9Y-18D552AAM1, +5803037202,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803037202, +5803108366,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5703108366, +5803108365,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803108365, +PT00051126,,2,800,5,10,10,10,10,30,800,15,0,0,ferrari_30x16_203.prn,PT00051126, +000985807,,0,0,5,10,10,10,10,30,1600,10,0,0,ferrari_30x16_203.prn,000985807, +055038005,,0,300,5,10,40,40,10,20,200,20,10,0,ferrari_30x16_203.prn,055038005, +5803034811,,0,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803034811, +5803037201,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803037201, +5803223749,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223749, +5803223748,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223748, +055000045,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,055000045, +5803223747,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803223747, +5803223746,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803223746, +000951612,,0,0,5,5,10,10,30,20,2200,20,0,0,ferrari_30x16_203.prn,000951612, +000951613,,0,0,5,5,10,10,30,20,2200,20,0,0,ferrari_30x16_203.prn,000951613, +5803223750,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223750, +5803223751,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223751, +5803223752,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223752, +5803223753,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803223753, +014093,014093,5,6000,10,1,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,014093, +7076213,7076213,0,0,10,1,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,7026213, +M28090912174,M280909-12174,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,M28090912174, +M28O90912174ECL,,0,0,1,1,10,10,1,0,0,0,0,0,ferrari_flag_qr_only.prn,, +5802815391,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5802815391, +5803101541,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803101541, +5803101542,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803101542, +5803406514,,2,5000,5,10,10,10,10,30,5000,15,1,0,ferrari_30x16_203.prn,5803406514, +5803108310,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803108310, +5803101537,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803101537, +5803101538,,2,5000,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803101538, +SY9Y-7F113AAM1,,10,7000,5,5,10,10,30,20,7100,20,0,0,ferrari_30x16_203.prn,SY9Y-7F113AAM1, +SY9Y-7F114AAM1,,10,7000,5,5,10,10,30,20,7100,20,0,0,ferrari_30x16_203.prn,SY9Y-7F114AAM1, +5803108305,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803108305, +5803108311,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803108311, +5802932524,,0,0,5,25,10,10,10,50,5000,50,0,0,ferrari_30x16_203.prn,5802932524, +200116-13-1610,,5,5000,10,10,10,10,10,30,7000,0,0,0,ferrari_30x16_203.prn,200116-13-1610, +5803108369,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803108369, + ENT.791.057.MT,,0,8000,5,5,10,10,10,30,8000,32,0,0,ferrari_30x16_203.prn,ENT.791.057.MT, + ENT.791.057.MR,,0,8000,5,5,10,10,10,30,8000,32,0,0,ferrari_30x16_203.prn,ENT.791.057.MR, +5803036736,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803036736, +5803036738,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803036738, +A46107017000,,0,0,10,10,10,10,15,10,5100,15,0,0,ferrari_30x16_203.prn,A46107017000, +000975406,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000975406, +000982127,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000982127, +98KA125CT,,0,0,5,5,10,10,30,50,3000,50,0,0,ferrari_30x16_203.prn,98KA125CT, +000976097,,0,0,5,5,10,10,10,30,3500,30,0,0,ferrari_30x16_203.prn,000976097, +000904357,,0,0,10,10,10,10,20,20,4100,20,0,0,ferrari_30x16_203.prn,000904357, +TEST F250,,0,0,10,10,10,10,30,10,6000,0,0,0,ferrari_flag_qr_only.prn,, +000779625,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000779625, +000951611,,0,0,5,5,10,10,30,20,2200,20,0,0,ferrari_30x16_203.prn,000951611, +000748845,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000748845, + 055034288,,0,6800,10,10,10,10,20,20,6800,20,0,0,ferrari_30x16_203.prn, 055034288, +5803223735,,0,0,5,10,10,10,10,30,5100,15,0,0,ferrari_30x16_203.prn,5803223735, +LIEBHERR R55240,,0,0,10,40,10,10,10,30,5000,30,0,0,ferrari_flag_qr_only.prn,, +000298261,,0,0,3,3,10,10,3,30,6000,30,0,0,ferrari_30x16_203.prn,000298261, +18LB033CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB033CT, +18LA995CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LA995CT, +18LA994CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LA994CT, +5803120373,,0,0,5,10,10,10,10,30,5100,15,0,0,ferrari_30x16_203.prn,5803120373, +18LB034CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB034CT, +18LB069CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB069CT, +18LB032CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB032CT, +5803025117,,0,0,5,10,10,10,10,30,5100,15,0,0,ferrari_30x16_203.prn,583025117, +5803025116,,5,2000,10,10,10,10,10,30,5100,15,0,0,ferrari_30x16_203.prn,5803025116, +000990688,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990688, +000990696,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990696, +000990684,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990684, +000990685,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990685, +000990679,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990679, +0000825276,,0,0,5,10,10,10,10,30,1500,30,0,0,ferrari_30x16_203.prn,0000825276, +000990691,,0,0,5,10,10,10,10,20,3000,20,0,0,ferrari_30x16_203.prn,000990691, +000990704,,0,0,5,10,10,10,10,20,1500,20,0,0,ferrari_30x16_203.prn,000990704, +000990700,,0,0,5,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000990700, +000990681,,0,0,5,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000990681, +000990703,,0,0,5,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990703, +000990692,,0,0,5,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000990692, +000990690,,0,0,5,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000990690, +000990708,,0,0,10,10,10,10,30,20,5000,20,0,0,ferrari_30x16_203.prn,000990708, +055045415,,0,0,5,5,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,055045415, +000990686,,0,0,5,5,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990686, +18LB058CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB058CT, +000990680,,0,0,5,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000990680, +000990687,,0,0,10,10,10,10,30,20,5000,20,0,0,ferrari_30x16_203.prn,000990687, +000907313,000907313,0,0,10,10,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000907313, +000987924,,5,0,10,10,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000987924, +18LB051CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB051CT, +18LB044CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB044CT, +000987923,,0,0,10,10,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000987923, +000987571,,0,0,10,10,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000987571, +000987572,,0,0,10,10,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000987572, +18LB027CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB027CT, +18LA990CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LA990CT, +18LB561CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB561CT, +000990702,,0,0,5,5,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000990702, +000991064,,0,0,5,5,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000991064, +000991211,,0,0,5,5,10,10,10,20,1600,20,0,0,ferrari_30x16_203.prn,000991211, +000990689,,0,0,5,5,10,10,30,20,1600,20,0,0,ferrari_30x16_203.prn,000990689, +000991211,,0,0,10,10,10,10,30,20,2100,20,0,0,ferrari_30x16_203.prn,000991211, +000991064,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000991064, +000990689,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990689, +055000046,,0,0,5,10,10,10,30,20,2150,20,0,0,ferrari_30x16_203.prn,055000046, +000990701,,0,0,10,10,10,10,30,20,2000,20,0,0,ferrari_30x16_203.prn,000990701, +000990706,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990706, +000990697,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990697, +BUCHER 7076213,7076213,0,0,10,30,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,7076213, +000990694,,0,0,5,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990694, +000990699,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990699, +SP031.053-R2,,0,0,5,10,10,10,10,30,3100,10,0,0,ferrari_30x16_203.prn,SP031.053-R2, +SP031.051-R2,SP031.051-R2,0,0,5,10,10,10,10,30,3100,10,0,0,ferrari_30x16_203.prn,SP031.051-R2, +SP031.050-R3,,0,0,5,10,10,10,10,30,3100,10,0,0,ferrari_30x16_203.prn,SP031.050-R3, +SP031.052-R2,,0,0,5,10,10,10,10,30,3100,10,0,0,ferrari_30x16_203.prn,SP031.052-R2, +16JA603CP,,10,500,10,30,10,10,10,20,500,10,0,0,ferrari_30x16_203.prn,16JA603CP, +16JA605CP,,10,500,10,30,10,10,10,20,500,10,0,0,ferrari_30x16_203.prn,16JA605CP, +18LB348CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB348CT, +18LB347CT,,0,0,10,10,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB347CT, +18LB349CT,,0,0,20,20,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB349CT, +18LB348CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB348CT, +18LB349CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB349CT, +18LB347CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB347CT, +000990693,,0,0,5,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990693, +18LB346CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB346CT, +18LB350CT,,0,0,30,30,10,10,30,20,3500,20,0,0,ferrari_30x16_203.prn,18LB350CT, +000990698,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990698, +000990695,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990695, +000990707,,0,0,5,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990707, + 055017119,,0,0,5,10,10,10,10,4,2600,10,0,0,ferrari_30x16_203.prn, 055017119, +3915370,,0,0,10,10,10,10,20,4,3500,15,0,0,ferrari_30x16_203.prn, 3915370, +055017118,,0,0,5,10,10,10,10,4,2600,10,0,0,ferrari_30x16_203.prn, 055017118, +055017120,,0,0,5,10,10,10,60,3,2500,10,0,0,ferrari_30x16_203.prn, 055017120, +055017125,,0,0,5,10,10,10,60,3,2600,10,0,0,ferrari_30x16_203.prn, 055017125, +000990705,,0,0,10,10,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000990705, +055024035,,0,0,5,10,10,10,20,5,2600,10,0,0,ferrari_30x16_203.prn, 055024035, +R56414,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56414, +R56418,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56418, +R56413,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56413, +R56405,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56405, +R56411,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56411, +R56410,,0,0,5,10,10,10,10,10,3000,10,0,0,ferrari_30x16_203.prn,R56410, +07N.131.597.A,,5,4000,10,10,10,10,10,30,3000,10,0,0,ferrari_30x16_203.prn,07N.131.597.A, +000784883,,0,0,5,5,10,10,10,30,1600,10,0,0,ferrari_30x16_203.prn, 000784883, +000985807,,0,0,5,5,10,10,10,30,1600,10,0,0,ferrari_30x16_203.prn, 000985807, +SP031.077R1,,0,0,7,15,10,10,5,30,4100,30,0,0,ferrari_30x16_203.prn,SP031.077-R1, +800.P.850.1A,,0,0,5,10,10,10,10,30,4000,30,0,0,ferrari_30x16_203.prn,800.P.850.1A, +800.P.851.1A,,0,0,5,10,10,10,10,30,4000,30,0,0,ferrari_30x16_203.prn,800.P.851.1A, +055018630,,0,200,5,5,10,10,10,50,2000,50,10,0,ferrari_30x16_203.prn,055018630, +5803229239,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803229239, +000952005,,0,0,5,10,10,10,10,30,2100,15,0,0,ferrari_30x16_203.prn,000952005, +92172962,,0,0,10,20,10,10,10,30,2000,30,0,0,ferrari_30x16_203.prn,92172962, +5803229240,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803229240, +PROVA VA0017,,0,0,2,3,10,10,5,0,4000,5,0,0,ferrari_30x16_203.prn,VA0017, +V04.030.057.AD,,0,0,5,10,10,10,10,20,200,20,0,0,ferrari_30x16_203.prn,V04.030.057.AD, +5803184400,,0,0,5,10,10,10,10,20,5000,20,0,0,ferrari_30x16_203.prn,5803184400, +5803329396,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803329396, +5803329398,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803329398, +5803329442,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803329442, +5803329443,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803329443, +5803313275,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803313275, +5803330518,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803330518, +5803313274,,0,0,5,10,10,10,10,30,5000,30,0,0,ferrari_30x16_203.prn,5803313274, +000742336,,0,0,5,5,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000742336, +000742332,,0,0,5,5,10,10,10,20,2100,20,0,0,ferrari_30x16_203.prn,000742332, +5803293153,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293153, +5803293154,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293154, +5803293158,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293158, +5803293162,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293162, +5803293142,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293142, +5803293141,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293141, +5803293149,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293149, +5803293157,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293157, +5803229244,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803229244, +5803229245,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803229245, +5803293143,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293143, +5803293144,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293144, +5803293147,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293147, +5803293148,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293148, +5803293149,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293149, +PROVA RIMAC,,0,0,5,10,10,10,20,20,3000,20,0,0,ferrari_30x16_203.prn,PROVA RIMAC, +5803293151,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293151, +5803293150,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293150, +5803293155,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293155, +5803293159,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293159, +055019161,,0,0,5,10,10,10,10,20,1500,20,0,0,ferrari_30x16_203.prn,055019161, +5803293156,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293156, +5803293161,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293161, +5803293160,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293160, +5803328789,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803328789, +5803328788,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803328788, +5803439351,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803439351, +5803442534,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803442534, +5803439352,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803439352, +5803442535,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803442535, +5803328907,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803328907, +5803328906,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803328906, +5803293145,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293145, +5803293155,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293155, +5803293152,,0,0,5,10,10,10,10,30,5000,15,0,0,ferrari_30x16_203.prn,5803293152, +PT00044318,,0,0,5,10,10,10,10,30,1000,15,0,0,ferrari_30x16_203.prn,PT00044318, +PT00045408,,0,0,5,10,10,10,10,30,1000,15,0,0,ferrari_30x16_203.prn,PT00045408, +5803311633,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311633, +5803312417,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803312417, +5803312373,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803312373, +5803312291,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803312291, +5803311634,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311634, +5803311630,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311630, +5803311632,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311632, +5803311636,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311636, +5803312839,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803312839, +5803312781,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803312781, +5803316610,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803316610, +5803316729,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803316729, +5803316718,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803316718, +5803317742,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803317742, +5803321O38,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803321038, +5803311635,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311635, +5803311631,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803311631, +PT00049591,,0,0,5,10,10,10,10,30,1000,15,0,0,ferrari_30x16_203.prn,PT00049591, +PT00049590,,0,0,5,10,10,10,10,30,1000,15,0,0,ferrari_30x16_203.prn,PT00049590, +1636050157,,0,0,5,10,10,10,10,30,6000,0,0,0,ferrari_30x16_203.prn,1636050157, +580051500,,0,0,5,5,10,10,10,30,6100,30,0,0,ferrari_30x16_203.prn,580051500, +5803350485,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803350485, +5803315085,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803315085, +5803350411,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803350411, +5803350392,,0,0,5,5,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803350392, +580051376,,0,0,5,10,10,10,10,30,6100,30,0,0,ferrari_30x16_203.prn,580051376, +055020340,,0,0,5,10,10,10,10,20,2000,20,0,0,ferrari_30x16_203.prn,055020340, +G04-030-057-BF,VO4-030-057-BF,0,0,5,5,10,10,10,30,2100,30,0,0,ferrari_30x16_203.prn,V04-030-057-BF, +5803350506,,0,0,5,10,10,10,10,30,6100,15,0,0,ferrari_30x16_203.prn,5803350506, +5803350485,,0,0,5,10,10,10,10,30,6100,15,0,0,ferrari_30x16_203.prn,5803350485, +1636050164,,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050164, +1636050159,,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050159, +1636050042,,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050042, +403/S2662,,0,0,10,10,10,10,10,10,2000,10,0,0,ferrari_30x16_203.prn,403/S2662, +1636050042,,0,0,5,1,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050042, +1636050162,,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050162, +1636050158,,0,0,5,10,10,10,10,30,6000,15,0,0,ferrari_30x16_203.prn,1636050158, +98FA186CP,98FA186CP,0,2000,5,5,10,10,20,15,3000,15,0,0,ferrari_30x16_203.prn,98FA186CP, +5803358645,,0,5000,5,10,10,10,10,30,5100,30,0,0,ferrari_30x16_203.prn,5803358646, +5803158291,CPL GASOLIO LP,5,2000,5,10,10,10,20,30,2000,0,0,0,ferrari_30x16_203.prn,5803158291,C9 CCM FPT +000784883,,0,0,5,5,10,10,30,20,1500,20,0,0,ferrari_30x16_203.prn,000784883, + FUGA CAL 7 BAR,24001,0,0,5,5,10,10,10,9,7000,6,20,1,ferrari_30x16_203.prn,FUGA 24001 8MBA, +5802814210 R.3,j5802814210 R.3,5,3000,5,10,20,20,20,30,3000,30,10,100,ferrari_flag_qr_only.prn,5802814210 R.3, +403/S2664,j5802814210 R.3,5,3000,5,10,5,5,10,10,2000,10,10,100,ferrari_30x16_203.prn,"", +403/S2666,jcb,0,3000,5,10,5,5,10,10,2000,10,10,100,ferrari_30x16_203.prn,"", diff --git a/config/csv_import/manual_csv_import/ricette prototipi.csv b/config/csv_import/manual_csv_import/ricette prototipi.csv new file mode 100644 index 0000000..0dcc407 --- /dev/null +++ b/config/csv_import/manual_csv_import/ricette prototipi.csv @@ -0,0 +1,305 @@ +codice_ricetta,codice_prodotto,tempo_pre_riempimento,pressione_di_test,tempo_di_test,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_pre_rimepimento,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,template_di_stampa,descrizione,campo2 +07N.131.628.A,,10,200,20,20,10,10,10,5,0,5,2,0,,07N.131.628.A, +V04.030.057.BE,P18 BATTERY COOLING,0,0,20,20,10,10,20,5,0,5,0,0,,V04.030.057.BE, +000990502,,0,0,10,10,10,10,10,30,0,20,0,0,,000990502, +98FA644CP,,0,0,5,10,10,10,20,15,0,15,0,0,,98FA644CP, +5803158246,CPLGASOLIO LP,5,2000,5,10,10,10,20,30,0,0,0,0,,5803158246,C9 CCM FPT +BLOW BY WOKO,000781499,10,1000,10,10,99,99,10,600,0,20,0,0,,000781499, +SY9Y-2976-B,SY9Y-2976-A,0,5000,10,10,10,10,10,20,0,15,1,0,,SY9Y-2976-B, +SY9Y-2976-A,SY9Y-2976-A,0,0,10,10,10,10,10,20,0,0,0,0,,SY9Y-2976-A, +SY9Y-9S331-B,SY9Y-9S331-B,10,0,10,10,10,10,10,20,0,15,0,0,,SY9Y-9S331-B, +SY9Y-9S331-A,SY9Y-9S331-A,10,0,10,10,10,10,10,20,0,0,0,0,,SY9Y-9S331-A, +18JA708CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA708CP, +18JA757CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA757CP, +18JA750CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA750CP, +18JA712CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA712CP, +18JA710CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA710CP, +18JA718CP,,0,5,5,5,10,10,30,20,0,20,3,0,,18JA718CP, +18JA713CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA713CP, +18JA709CP,,0,0,5,5,10,10,30,20,0,20,0,0,,18JA709CP, +000904357,,0,0,10,10,10,10,20,20,0,20,0,0,,000904357, +05534288,,0,0,10,10,10,10,20,20,0,20,0,0,,05534288, +5802031904,,0,0,5,5,10,10,20,20,0,20,0,0,,5802031904, +000894372,,10,0,5,5,10,10,30,20,0,20,0,0,,000894372, +000957630,,0,0,10,10,10,10,10,30,0,10,0,0,,000957630, +000957631,,0,0,10,10,10,10,10,30,0,10,0,0,,000957631, +000958439,,0,0,5,10,10,10,30,30,0,10,0,0,,000958439, +000986619,,0,0,5,15,10,10,10,30,0,10,0,0,,000986619, +S3130E132,,0,0,7,15,10,10,5,2,0,1,0,0,,S3130E132, +18KA144CT,,0,0,5,5,10,10,30,10,0,10,0,0,,18KA144CT, +5803148261,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803148261, +98FB080CP,,5,200,10,10,10,10,20,10,0,15,3,1,,98FB080CP, +590.2.418.1A,,0,5000,3,5,10,10,5,5,0,15,0,0,,590.2.418.1A, +055000044,,0,3000,5,5,10,10,30,20,0,15,0,0,,055000044, +000975576,TUBO INLET,5,2000,30,80,10,10,10,1,0,1,0,0,,000975576, +000975575,TUBO OUTLET,5,2000,10,80,10,10,10,1,0,1,0,0,,000975575, +5803223742,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223742, +5803223740,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223740, +5803223741,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223741, +5803223736,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223736, +5803223745,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223745, +000884945,,0,0,10,5,10,10,10,30,0,0,0,0,,000884945, +5803223739,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223739, +000960322,000960322,0,0,5,10,10,10,10,20,0,20,0,0,,000960322, +000960324,000960324,0,0,5,10,10,10,10,20,0,20,0,0,,000960324, +000960275,000960275,0,0,5,10,10,10,10,20,0,20,0,0,,000960275, +000960281,000960281,0,0,5,10,10,10,10,20,0,20,0,0,,000960281, +055055934,,0,0,10,10,10,10,20,20,0,20,0,0,,055055934, +5803228585,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803228585, +5803223755,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803223755, +5803120375,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803120375, +5803083634,,0,5000,5,10,10,10,10,30,0,15,0,0,,5803083634, +742722-15,742722-15,0,0,5,10,10,10,20,30,0,10,0,0,,74222-15, +90383952,90383952,0,10,5,10,10,10,20,30,0,0,0,0,,90383952, +90383805,90383805,0,0,5,20,10,20,20,30,0,0,0,0,,90383805, +90459069,90459069,0,0,5,10,10,10,20,30,0,0,0,0,,90459069, +001031-R5,,0,0,10,30,10,10,30,10,0,5,0,0,,001031-R5, +5803036739,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803036739, +000990010,000990010,2,200,10,10,10,10,10,20,0,20,0,0,,000990010, +SY9Y-18D553AAM1,,0,0,5,5,10,10,30,20,0,20,0,0,,SY9Y-18D553AAM1, +SY9Y-18D552AAM1,,10,7000,5,5,10,10,30,20,0,20,0,0,,SY9Y-18D552AAM1, +5803037202,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803037202, +5803108366,,2,5000,5,10,10,10,10,30,0,15,0,0,,5703108366, +5803108365,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803108365, +PT00051126,,2,800,5,10,10,10,10,30,0,15,0,0,,PT00051126, +000985807,,0,0,5,10,10,10,10,30,0,10,0,0,,000985807, +055038005,,0,300,5,10,40,40,10,20,0,20,1,0,,055038005, +5803034811,,0,5000,5,10,10,10,10,30,0,15,0,0,,5803034811, +5803037201,,0,0,5,10,10,10,10,30,0,15,0,0,,5803037201, +5803223749,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223749, +5803223748,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223748, +055000045,,0,0,5,5,10,10,30,20,0,20,0,0,,055000045, +5803223747,,0,0,5,10,10,10,10,30,0,30,0,0,,5803223747, +5803223746,,0,0,5,10,10,10,10,30,0,30,0,0,,5803223746, +000951612,,0,0,5,5,10,10,30,20,0,20,0,0,,000951612, +000951613,,0,0,5,5,10,10,30,20,0,20,0,0,,000951613, +5803223750,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223750, +5803223751,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223751, +5803223752,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223752, +5803223753,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223753, +014093,014093,5,6000,10,1,10,10,10,30,0,15,0,0,,014093, +7076213,7076213,0,0,10,1,10,10,10,30,0,15,0,0,,7026213, +M28090912174,M280909-12174,0,0,5,10,10,10,10,30,0,15,0,0,,M28090912174, +M28O90912174ECL,,0,0,1,1,10,10,1,0,0,0,0,0,,, +5802815391,,0,0,5,10,10,10,10,30,0,15,0,0,,5802815391, +5803101541,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803101541, +5803101542,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803101542, +5803406514,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803406514, +5803108310,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803108310, +5803101537,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803101537, +5803101538,,2,5000,5,10,10,10,10,30,0,15,0,0,,5803101538, +SY9Y-7F113AAM1,,10,7000,5,5,10,10,30,20,0,20,0,0,,SY9Y-7F113AAM1, +SY9Y-7F114AAM1,,10,7000,5,5,10,10,30,20,0,20,0,0,,SY9Y-7F114AAM1, +5803108305,,0,0,5,10,10,10,10,30,0,15,0,0,,5803108305, +5803108311,,0,0,5,10,10,10,10,30,0,15,0,0,,5803108311, +5802932524,,0,0,5,25,10,10,10,50,0,50,0,0,,5802932524, +200116-13-1610,,5,5000,10,10,10,10,10,30,0,0,0,0,,200116-13-1610, +5803108369,,0,0,5,10,10,10,10,30,0,15,0,0,,5803108369, + ENT.791.057.MT,,0,8000,5,5,10,10,10,30,0,32,0,0,,ENT.791.057.MT, + ENT.791.057.MR,,0,8000,5,5,10,10,10,30,0,32,0,0,,ENT.791.057.MR, +5803036736,,0,0,5,10,10,10,10,30,0,15,0,0,,5803036736, +5803036738,,0,0,5,10,10,10,10,30,0,15,0,0,,5803036738, +A46107017000,,0,0,10,10,10,10,15,10,0,15,0,0,,A46107017000, +000975406,,0,0,5,"5 +",10,10,30,20,0,20,0,0,,000975406, +000982127,,0,0,5,"5 +",10,10,30,20,0,20,0,0,,000982127, +98KA125CT,,0,0,5,"5 +",10,10,30,50,0,50,0,0,,98KA125CT, +000976097,,0,0,5,"5 +",10,10,10,30,0,30,0,0,,000976097, +000904357,,0,0,10,10,10,10,20,20,0,20,0,0,,000904357, +TEST F250,,0,0,10,10,10,10,30,10,0,0,0,0,,, +000779625,,0,0,5,5,10,10,30,20,0,20,0,0,,000779625, +000951611,,0,0,5,5,10,10,30,20,0,20,0,0,,000951611, +000748845,,0,0,5,5,10,10,30,20,0,20,0,0,,000748845, + 055034288,,0,6800,10,10,10,10,20,20,0,20,0,0,, 055034288, +5803223735,,0,0,5,10,10,10,10,30,0,15,0,0,,5803223735, +LIEBHERR R55240,,0,0,10,40,10,10,10,30,0,30,0,0,,, +000298261,,0,0,3,3,10,10,3,30,0,30,0,0,,000298261, +18LB033CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB033CT, +18LA995CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LA995CT, +18LA994CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LA994CT, +5803120373,,0,0,5,10,10,10,10,30,0,15,0,0,,5803120373, +18LB034CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB034CT, +18LB069CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB069CT, +18LB032CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB032CT, +5803025117,,0,0,5,10,10,10,10,30,0,15,0,0,,583025117, +5803025116,,5,2000,10,10,10,10,10,30,0,15,0,0,,5803025116, +000990688,,0,0,5,5,10,10,30,20,0,20,0,0,,000990688, +000990696,,0,0,5,5,10,10,30,20,0,20,0,0,,000990696, +000990684,,0,0,5,5,10,10,30,20,0,20,0,0,,000990684, +000990685,,0,0,5,5,10,10,30,20,0,20,0,0,,000990685, +000990679,,0,0,5,5,10,10,30,20,0,20,0,0,,000990679, +0000825276,,0,0,5,10,10,10,10,30,0,30,0,0,,0000825276, +000990691,,0,0,5,10,10,10,10,20,0,20,0,0,,000990691, +000990704,,0,0,5,10,10,10,10,20,0,20,0,0,,000990704, +000990700,,0,0,5,10,10,10,30,20,0,20,0,0,,000990700, +000990681,,0,0,5,10,10,10,30,20,0,20,0,0,,000990681, +000990703,,0,0,5,10,10,10,30,20,0,20,0,0,,000990703, +000990692,,0,0,5,10,10,10,30,20,0,20,0,0,,000990692, +000990690,,0,0,5,10,10,10,30,20,0,20,0,0,,000990690, +000990708,,0,0,10,10,10,10,30,20,0,20,0,0,,000990708, +055045415,,0,0,5,5,10,10,30,20,0,20,0,0,,055045415, +000990686,,0,0,5,5,10,10,30,20,0,20,0,0,,000990686, +18LB058CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB058CT, +000990680,,0,0,5,10,10,10,30,20,0,20,0,0,,000990680, +000990687,,0,0,10,10,10,10,30,20,0,20,0,0,,000990687, +000907313,000907313,0,0,10,10,10,10,10,20,0,20,0,0,,000907313, +000987924,,5,0,10,10,10,10,10,20,0,20,0,0,,000987924, +18LB051CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB051CT, +18LB044CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB044CT, +000987923,,0,0,10,10,10,10,10,20,0,20,0,0,,000987923, +000987571,,0,0,10,10,10,10,10,20,0,20,0,0,,000987571, +000987572,,0,0,10,10,10,10,10,20,0,20,0,0,,000987572, +18LB027CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB027CT, +18LA990CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LA990CT, +18LB561CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB561CT, +000990702,,0,0,5,5,10,10,10,20,0,20,0,0,,000990702, +000991064,,0,0,5,5,10,10,10,20,0,20,0,0,,000991064, +000991211,,0,0,5,5,10,10,10,20,0,20,0,0,,000991211, +000990689,,0,0,5,5,10,10,30,20,0,20,0,0,,000990689, +000991211,,0,0,10,10,10,10,30,20,0,20,0,0,,000991211, +000991064,,0,0,10,10,10,10,30,20,0,20,0,0,,000991064, +000990689,,0,0,10,10,10,10,30,20,0,20,0,0,,000990689, +055000046,,0,0,5,10,10,10,30,20,0,20,0,0,,055000046, +000990701,,0,0,10,10,10,10,30,20,0,20,0,0,,000990701, +000990706,,0,0,10,10,10,10,30,20,0,20,0,0,,000990706, +000990697,,0,0,10,10,10,10,30,20,0,20,0,0,,000990697, +BUCHER 7076213,7076213,0,0,10,30,10,10,10,30,0,30,0,0,,7076213, +000990694,,0,0,5,10,10,10,30,20,0,20,0,0,,000990694, +000990699,,0,0,10,10,10,10,30,20,0,20,0,0,,000990699, +SP031.053-R2,,0,0,5,10,10,10,10,30,0,10,0,0,,SP031.053-R2, +SP031.051-R2,SP031.051-R2,0,0,5,10,10,10,10,30,0,10,0,0,,SP031.051-R2, +SP031.050-R3,,0,0,5,10,10,10,10,30,0,10,0,0,,SP031.050-R3, +SP031.052-R2,,0,0,5,10,10,10,10,30,0,10,0,0,,SP031.052-R2, +16JA603CP,,10,500,10,30,10,10,10,20,0,10,0,0,,16JA603CP, +16JA605CP,,10,500,10,30,10,10,10,20,0,10,0,0,,16JA605CP, +18LB348CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB348CT, +18LB347CT,,0,0,10,10,10,10,30,20,0,20,0,0,,18LB347CT, +18LB349CT,,0,0,20,20,10,10,30,20,0,20,0,0,,18LB349CT, +18LB348CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB348CT, +18LB349CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB349CT, +18LB347CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB347CT, +000990693,,0,0,5,10,10,10,30,20,0,20,0,0,,000990693, +18LB346CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB346CT, +18LB350CT,,0,0,30,30,10,10,30,20,0,20,0,0,,18LB350CT, +000990698,,0,0,10,10,10,10,30,20,0,20,0,0,,000990698, +000990695,,0,0,10,10,10,10,30,20,0,20,0,0,,000990695, +000990707,,0,0,5,10,10,10,30,20,0,20,0,0,,000990707, + 055017119,,0,0,5,10,10,10,10,4,0,10,0,0,, 055017119, +3915370,,0,0,10,10,10,10,20,4,0,15,0,0,, 3915370, +055017118,,0,0,5,10,10,10,10,4,0,10,0,0,, 055017118, +055017120,,0,0,5,10,10,10,60,3,0,10,0,0,, 055017120, +055017125,,0,0,5,10,10,10,60,3,0,10,0,0,, 055017125, +000990705,,0,0,10,10,10,10,30,20,0,20,0,0,,000990705, +055024035,,0,0,5,10,10,10,20,5,0,10,0,0,, 055024035, +R56414,,0,0,5,10,10,10,10,10,0,10,0,0,,R56414, +R56418,,0,0,5,10,10,10,10,10,0,10,0,0,,R56418, +R56413,,0,0,5,10,10,10,10,10,0,10,0,0,,R56413, +R56405,,0,0,5,10,10,10,10,10,0,10,0,0,,R56405, +R56411,,0,0,5,10,10,10,10,10,0,10,0,0,,R56411, +R56410,,0,0,5,10,10,10,10,10,0,10,0,0,,R56410, +07N.131.597.A,,5,4000,10,10,10,10,10,30,0,10,0,0,,07N.131.597.A, +000784883,,0,0,5,5,10,10,10,30,0,10,0,0,, 000784883, +000985807,,0,0,5,5,10,10,10,30,0,10,0,0,, 000985807, +SP031.077R1,,0,0,7,15,10,10,5,30,0,30,0,0,,SP031.077-R1, +800.P.850.1A,,0,0,5,10,10,10,10,30,0,30,0,0,,800.P.850.1A, +800.P.851.1A,,0,0,5,10,10,10,10,30,0,30,0,0,,800.P.851.1A, +055018630,,0,200,5,5,10,10,10,50,0,50,1,0,,055018630, +5803229239,,0,0,5,10,10,10,10,30,0,15,0,0,,5803229239, +000952005,,0,0,5,10,10,10,10,30,0,15,0,0,,000952005, +92172962,,0,0,10,20,10,10,10,30,0,30,0,0,,92172962, +5803229240,,0,0,5,10,10,10,10,30,0,15,0,0,,5803229240, +PROVA VA0017,,0,0,2,3,10,10,5,0,0,5,0,0,,VA0017, +V04.030.057.AD,,0,0,5,10,10,10,10,20,0,20,0,0,,V04.030.057.AD, +5803184400,,0,0,5,10,10,10,10,20,0,20,0,0,,5803184400, +5803329396,,0,0,5,10,10,10,10,30,0,30,0,0,,5803329396, +5803329398,,0,0,5,10,10,10,10,30,0,30,0,0,,5803329398, +5803329442,,0,0,5,10,10,10,10,30,0,30,0,0,,5803329442, +5803329443,,0,0,5,10,10,10,10,30,0,30,0,0,,5803329443, +5803313275,,0,0,5,10,10,10,10,30,0,30,0,0,,5803313275, +5803330518,,0,0,5,10,10,10,10,30,0,30,0,0,,5803330518, +5803313274,,0,0,5,10,10,10,10,30,0,30,0,0,,5803313274, +000742336,,0,0,5,5,10,10,10,20,0,20,0,0,,000742336, +000742332,,0,0,5,5,10,10,10,20,0,20,0,0,,000742332, +5803293153,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293153, +5803293154,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293154, +5803293158,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293158, +5803293162,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293162, +5803293142,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293142, +5803293141,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293141, +5803293149,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293149, +5803293157,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293157, +5803229244,,0,0,5,10,10,10,10,30,0,15,0,0,,5803229244, +5803229245,,0,0,5,10,10,10,10,30,0,15,0,0,,5803229245, +5803293143,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293143, +5803293144,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293144, +5803293147,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293147, +5803293148,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293148, +5803293149,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293149, +PROVA RIMAC,,0,0,5,10,10,10,20,20,0,20,0,0,,PROVA RIMAC, +5803293151,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293151, +5803293150,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293150, +5803293155,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293155, +5803293159,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293159, +055019161,,0,0,5,10,10,10,10,20,0,20,0,0,,055019161, +5803293156,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293156, +5803293161,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293161, +5803293160,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293160, +5803328789,,0,0,5,10,10,10,10,30,0,15,0,0,,5803328789, +5803328788,,0,0,5,10,10,10,10,30,0,15,0,0,,5803328788, +5803439351,,0,0,5,10,10,10,10,30,0,15,0,0,,5803439351, +5803442534,,0,0,5,10,10,10,10,30,0,15,0,0,,5803442534, +5803439352,,0,0,5,10,10,10,10,30,0,15,0,0,,5803439352, +5803442535,,0,0,5,10,10,10,10,30,0,15,0,0,,5803442535, +5803328907,,0,0,5,10,10,10,10,30,0,15,0,0,,5803328907, +5803328906,,0,0,5,10,10,10,10,30,0,15,0,0,,5803328906, +5803293145,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293145, +5803293155,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293155, +5803293152,,0,0,5,10,10,10,10,30,0,15,0,0,,5803293152, +PT00044318,,0,0,5,10,10,10,10,30,0,15,0,0,,PT00044318, +PT00045408,,0,0,5,10,10,10,10,30,0,15,0,0,,PT00045408, +5803311633,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311633, +5803312417,,0,0,5,5,10,10,10,30,0,30,0,0,,5803312417, +5803312373,,0,0,5,5,10,10,10,30,0,30,0,0,,5803312373, +5803312291,,0,0,5,5,10,10,10,30,0,30,0,0,,5803312291, +5803311634,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311634, +5803311630,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311630, +5803311632,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311632, +5803311636,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311636, +5803312839,,0,0,5,5,10,10,10,30,0,30,0,0,,5803312839, +5803312781,,0,0,5,5,10,10,10,30,0,30,0,0,,5803312781, +5803316610,,0,0,5,5,10,10,10,30,0,30,0,0,,5803316610, +5803316729,,0,0,5,5,10,10,10,30,0,30,0,0,,5803316729, +5803316718,,0,0,5,5,10,10,10,30,0,30,0,0,,5803316718, +5803317742,,0,0,5,5,10,10,10,30,0,30,0,0,,5803317742, +5803321O38,,0,0,5,5,10,10,10,30,0,30,0,0,,5803321038, +5803311635,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311635, +5803311631,,0,0,5,5,10,10,10,30,0,30,0,0,,5803311631, +PT00049591,,0,0,5,10,10,10,10,30,0,15,0,0,,PT00049591, +PT00049590,,0,0,5,10,10,10,10,30,0,15,0,0,,PT00049590, +1636050157,,0,0,5,10,10,10,10,30,0,0,0,0,,1636050157, +580051500,,0,0,5,5,10,10,10,30,0,30,0,0,,580051500, +5803350485,,0,0,5,5,10,10,10,30,0,30,0,0,,5803350485, +5803315085,,0,0,5,5,10,10,10,30,0,30,0,0,,5803315085, +5803350411,,0,0,5,5,10,10,10,30,0,30,0,0,,5803350411, +5803350392,,0,0,5,5,10,10,10,30,0,30,0,0,,5803350392, +580051376,,0,0,5,10,10,10,10,30,0,30,0,0,,580051376, +055020340,,0,0,5,10,10,10,10,20,0,20,0,0,,055020340, +G04-030-057-BF,VO4-030-057-BF,0,0,5,5,10,10,10,30,0,30,0,0,,V04-030-057-BF, +5803350506,,0,0,5,10,10,10,10,30,0,15,0,0,,5803350506, +5803350485,,0,0,5,10,10,10,10,30,0,15,0,0,,5803350485, +1636050164,,0,0,5,10,10,10,10,30,0,15,0,0,,1636050164, +1636050159,,0,0,5,10,10,10,10,30,0,15,0,0,,1636050159, +1636050042,,0,0,5,10,10,10,10,30,0,15,0,0,,1636050042, +403/S2662,,0,0,10,10,10,10,10,10,0,10,0,0,,403/S2662, +1636050042,,0,0,5,1,10,10,10,30,0,15,0,0,,1636050042, +1636050162,,0,0,5,10,10,10,10,30,0,15,0,0,,1636050162, +1636050158,,0,0,5,10,10,10,10,30,0,15,0,0,,1636050158, +98FA186CP,98FA186CP,0,2000,5,5,10,10,20,15,0,15,0,0,,98FA186CP, +5803358645,,0,5000,5,10,10,10,10,30,0,30,0,0,,5803358646, +5803158291,CPL GASOLIO LP,5,2000,5,10,10,10,20,30,0,0,0,0,,5803158291,C9 CCM FPT +000784883,,0,0,5,5,10,10,30,20,0,20,0,0,,000784883, + FUGA CAL 7 BAR,24001,0,0,5,5,10,10,10,10,0,6,2,1,,FUGA 24001 8MBA, +5802814210 R.3,j5802814210 R.3,5,3000,5,10,20,20,20,30,3000,30,1,100,,5802814210 R.3, diff --git a/config/machine_settings/hostnames.ini b/config/machine_settings/hostnames.ini index 3299c30..481d08c 100644 --- a/config/machine_settings/hostnames.ini +++ b/config/machine_settings/hostnames.ini @@ -12,5 +12,6 @@ st-ten-10: st-ten-10 st-ten-11: st-ten-11 st-ten-12: st-ten-12 st-ten-13: st-ten-13 +st-ten-14: st-ten-14 test-linux: test-linux diff --git a/config/machine_settings/st-ten-14.ini b/config/machine_settings/st-ten-14.ini new file mode 100644 index 0000000..b60d9d8 --- /dev/null +++ b/config/machine_settings/st-ten-14.ini @@ -0,0 +1,93 @@ +[machine] +description = ST-TEN-14 +instruction_folder = st-ten-14 +image_for_warning= st-ten-14 + +[hardware_config] +archive_synchronizer: present +uvc_camera: absent +label_printer: present +neo_pixels: absent +remote_api: absent +tecna_t3: present +vision_saver: absent +vision: absent +screwdriver: absent +digital_io: absent +barcode_recipe_selection: present +fixture_id: absent +discard_box: absent +enforce_piece_removal: no + +[tecna_t3] +port: /dev/ttyUSB1 +model: t3l + +[label_printer] +platform: linux +printer: ZTC-ZD421-203dpi-ZPL + +[digital_io] +# OUTPUT MAP FOR FIXTURE CONNECTOR +id: USB-5860,BID#0 + +[fixture_rfid] +port: dev/ttyUSB0 + +[recipe] +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[recipes_defaults] +tester_discharge_enable: yes +dimensione_lotto_abilitata: x +tempo_pre_riempimento: 0 +pressione_pre_riempimento: 1000 +tempo_riempimento: 15 +tempo_assestamento: 15 +tempo_di_test: 10 +n_componenti:1 +percentuale_minima_pressione_assestamento: 5 +percentuale_massima_pressione_assestamento: 5 +pressione_di_test_delta_minimo: 30 +pressione_di_test: 7000 +pressione_di_test_delta_massimo: 30 +tempo_svuotamento: 0 +pressione_svuotamento: 100 +canale_di_prova: 1 +prova_tenuta_abilitata_2: +tempo_pre_riempimento_2: 0 +pressione_pre_riempimento_2: 1000 +tempo_riempimento_2: 20 +tempo_assestamento_2: 20 +tempo_di_test_2: 10 +percentuale_minima_pressione_assestamento_2: 5 +percentuale_massima_pressione_assestamento_2: 5 +pressione_di_test_delta_minimo_2: 30 +pressione_di_test_2: 15000 +pressione_di_test_delta_massimo_2: 30 +tempo_svuotamento_2: 0 +pressione_svuotamento_2: 100 +canale_di_prova_2: 2 +modello_etichetta: EtichettaR5_Montaggio_1prova.prn +pid_pressure_correction: 100 + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 10 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_pressure: 5000 +test_time: 10 +test_pressure_qpos: 3 #Q+ Upper test leak limit +test_pressure_qneg: 10 #Q- Lower test leak limit +test_pressure_tt_qpos: 1 # Q+ Upper test leak limit (tube-tube) +test_pressure_tt_qneg: 5 # Q- Lower test leak limit (tube-tube) +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/make_desktop_file.sh b/make_desktop_file.sh new file mode 100644 index 0000000..14a4fdc --- /dev/null +++ b/make_desktop_file.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Define the temporary file name for the .desktop file +SCRIPT="/tmp/shortcut-$(date +%s).desktop" + +# Create the .desktop file with the required content +echo "[Desktop Entry]" >> $SCRIPT +echo "Version=1.0" >> $SCRIPT +echo "Name=AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT +echo "Comment=Shortcut to AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT +echo "Exec=$HOME/PycharmProjects/st-ten-1/runme.sh" >> $SCRIPT +echo "Icon=$HOME/PycharmProjects/st-ten-1/src/ui/imgs/neo.ico" >> $SCRIPT +echo "Terminal=false" >> $SCRIPT +echo "Type=Application" >> $SCRIPT +echo "Categories=Utility;" >> $SCRIPT + +# Prompt for sudo password and copy the .desktop file to the user's Desktop +sudo cp $SCRIPT "$HOME/Desktop/AVVIO PROGRAMMA COLLAUDO.desktop" + +# Make the .desktop file executable +sudo chmod +x "$HOME/Desktop/AVVIO PROGRAMMA COLLAUDO.desktop" + +# Remove the temporary .desktop file +rm $SCRIPT + +echo "Shortcut created on Desktop" \ No newline at end of file diff --git a/make_desktop_file_noautotest.sh b/make_desktop_file_noautotest.sh new file mode 100644 index 0000000..fccb42f --- /dev/null +++ b/make_desktop_file_noautotest.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Define the temporary file name for the .desktop file +SCRIPT="/tmp/shortcut-$(date +%s).desktop" + +# Create the .desktop file with the required content +echo "[Desktop Entry]" >> $SCRIPT +echo "Version=1.0" >> $SCRIPT +echo "Name=AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT +echo "Comment=Shortcut to AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT +echo "Exec=$HOME/PycharmProjects/st-ten-1/runmenoautotest.sh" >> $SCRIPT +echo "Icon=$HOME/PycharmProjects/st-ten-1/src/ui/imgs/neo_red.ico" >> $SCRIPT +echo "Terminal=false" >> $SCRIPT +echo "Type=Application" >> $SCRIPT +echo "Categories=Utility;" >> $SCRIPT + +# Prompt for sudo password and copy the .desktop file to the user's Desktop +sudo cp $SCRIPT "$HOME/Desktop/AVVIO PROGRAMMA COLLAUDO NO AUTOTEST.desktop" + +# Make the .desktop file executable +sudo chmod +x "$HOME/Desktop/AVVIO PROGRAMMA COLLAUDO NO AUTOTEST.desktop" + +# Remove the temporary .desktop file +rm $SCRIPT + +echo "Shortcut created on Desktop" \ No newline at end of file diff --git a/runmenoautotest.sh b/runmenoautotest.sh new file mode 100755 index 0000000..c0b63c8 --- /dev/null +++ b/runmenoautotest.sh @@ -0,0 +1,4 @@ +#!/bin/bash -e +cd "$(dirname "$0")" +source "./venv/bin/activate" || source "./venv/Scripts/activate" || : +python -O "./src/main.py" --no-edgetpu --no-tflite --no-autotest $* diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index e89e60e..617f7a6 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -388,7 +388,7 @@ class TecnaMarpossProvasetT3(ModbusComponent): }) elif self.model == "t3l": spec.update({ - "Nominal peak pressure": "test_pressure", + "PREL - Nominal test pressure": "test_pressure", }) else: raise NotImplementedError(f"tecna t3 model {self.model!r} not implemented.") @@ -410,7 +410,15 @@ class TecnaMarpossProvasetT3(ModbusComponent): recipe_data["recipe_code"]=recipe_code recipe_data["recipe_f1"]=recipe_f1 recipe_data["recipe_f2"]=recipe_f2 - recipe_data["print_template"] = chr(recipe_data["print_options"] & 0xFF) + recipe_data["print_template"] = int(recipe_data["print_options"] & 0xFF) + if self.model == "t3p": + recipe_data["test_time"]=int(recipe_data["test_time"]/10) + recipe_data["pre_filling_time"] = int(recipe_data["pre_filling_time"] / 10) + recipe_data["filling_time"] = int(recipe_data["filling_time"] / 10) + recipe_data["settling_time"] = int(recipe_data["settling_time"] / 10) + recipe_data["test_pressure_qneg"] = int(recipe_data["test_pressure_qneg"] / 100) + recipe_data["test_pressure_qpos"] = int(recipe_data["test_pressure_qpos"] / 100) + return recipe_data @staticmethod diff --git a/src/requirements.txt b/src/requirements.txt index b4946f4..72f5f29 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -12,7 +12,7 @@ pillow pycoral pymodbus~=3.6.8 pyqt5 -pyqt5-tools +#pyqt5-tools pyserial pyserial-asyncio qrcode diff --git a/src/scripts/save_tecna_recipes_to_csv.py b/src/scripts/save_tecna_recipes_to_csv.py index f3cd05f..2d41a96 100644 --- a/src/scripts/save_tecna_recipes_to_csv.py +++ b/src/scripts/save_tecna_recipes_to_csv.py @@ -125,6 +125,7 @@ try: def read_recipes(self): self.recipes = {} max_num_recipes=self.components["tecna_t3"].max_program_number + max_num_recipes=300 logging.info(f"NUMBER OF RECIPES TO BE READ: {max_num_recipes}") for recipe_num in range(1, max_num_recipes+1): logging.info(f"READING RECIPE #{recipe_num}") diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index cf02f31..d127855 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -17,7 +17,7 @@ from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor from ui.widget import Widget from datetime import datetime -from src.components import ArchiveSynchronizer +from components import ArchiveSynchronizer class Noner: def __getitem__(self, key): @@ -343,6 +343,7 @@ class Recipe_Selection(Widget): "print": len(row.get("stampa_etichetta_abilitata", defaults["stampa_etichetta_abilitata"])) and "print" not in self.unsupported_steps, "steps": steps, } + recipe.spec["steps"]=steps_specs if recipe_is_new: recipe.save(force_insert=True) else: From 5015d3a4ea661aa3ec6dd31fef5206430b3f6d48 Mon Sep 17 00:00:00 2001 From: neo-2 Date: Wed, 6 Nov 2024 09:37:54 +0100 Subject: [PATCH 80/88] ST TEN 14 --- config/machine_settings/st-ten-14.ini | 6 +++--- src/components/archive_synchronizer.py | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/config/machine_settings/st-ten-14.ini b/config/machine_settings/st-ten-14.ini index b60d9d8..c30cbc9 100644 --- a/config/machine_settings/st-ten-14.ini +++ b/config/machine_settings/st-ten-14.ini @@ -14,13 +14,13 @@ vision_saver: absent vision: absent screwdriver: absent digital_io: absent -barcode_recipe_selection: present +barcode_recipe_selection: absent fixture_id: absent discard_box: absent enforce_piece_removal: no [tecna_t3] -port: /dev/ttyUSB1 +port: /dev/ttyUSB0 model: t3l [label_printer] @@ -32,7 +32,7 @@ printer: ZTC-ZD421-203dpi-ZPL id: USB-5860,BID#0 [fixture_rfid] -port: dev/ttyUSB0 +port: dev/ttyUSB1 [recipe] recipe_name_field: codice_ricetta diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 8fdc591..395c8d0 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -59,13 +59,12 @@ class ArchiveSynchronizer(Component): QThread.msleep(self.hold_time) self.gcs_bucket = None - if "--dev-portal" in sys.argv: - self.update_machine_status() - self.check_actions_to_do(self.machine_id) + + self.update_machine_status() super()._get() def update_machine_status(self): - self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" + self.status_endpoint = f"https://r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" status_dict = {"last_status": self.machine_status} From b0510d205aba8d29cf78062d3118a0b31bdf9f42 Mon Sep 17 00:00:00 2001 From: eduardo Date: Wed, 6 Nov 2024 11:28:58 +0100 Subject: [PATCH 81/88] labels ptototipi --- .../PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl | Bin 3972 -> 3975 bytes .../ERRECINQUE_flag_qr_only.prn | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl b/config/label_designs/PROTOTIPI/ERRECINQUE_flag_qr_only.nlbl index 9d7e7f978dc9771e1ee4603644dcee9ee09cf3a9..447cfa91e23584932a8f3d5a004c3861be6b30dc 100644 GIT binary patch literal 3975 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 A_W%F@ literal 3972 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 diff --git a/config/label_templates/ERRECINQUE_flag_qr_only.prn b/config/label_templates/ERRECINQUE_flag_qr_only.prn index 54b68b8..1bb6d79 100644 --- a/config/label_templates/ERRECINQUE_flag_qr_only.prn +++ b/config/label_templates/ERRECINQUE_flag_qr_only.prn @@ -5,8 +5,8 @@ ^PW320 ^LL1039 ^LS0 -^FO64,96^GFA,03840,03840,00024,:Z64: -eJztVjuS2zAMJZeFSk0ql+q32SPwCmlS5xgpqaNsvZewjpAjqE7lIp5RIYuRxQ8eCGEnbWaCwmM/PxHvgQApY/5HihBL/GR4heOMcEf4irgjfFP4cQK8B3xW8JuCL2z9+7ccMTK8ZvNxPMUHFORIRY8JbHzQow/CDdhkjgOtGjCBpwRv6Hggm5f4GwUt9BVKbcmmZY7BJnM80MYOWNKeVDh03FE2y/YYHWMC5hiaqMeSzoR3pKLDBMwxlBQdNyUd6SskGHCPmeP6Q3eMJQUVV8Uxa6I3pYku6Bia6AVIimPeREFxHLCJwHHEklKuLqJjSuwj+1EpAYeXHL+w4XUVf878/SslKPg+w++kzdRHAxssE4oB1mW7oKUsiHu0C1qLgIXh/VIE3xjerUUOW964rcgxnL/x/A3fNsvvQJY/c9wU/nTKd42cfYGUvpFT+P3W4Jk/rAq+CPxI6G8CPz79fI4HBVf4NkwNnPULu6k+VuCF39LdBv8invKK8iS+E3jqB4mn/ukeLZ4K7ESZU4E7gad+drL88yk/91PX8vN8CX6eR8G/5vY5cPujRMjTk6dDXKuJj9f2CnzE58S/tfgN+PLa/nx9eI2ITD/iE+g3Y4mrUp+LUk+TcVH/oPC9sr9aP6QBlfw00LLftP60Cj/Pl+j/PEEn/PGUb9KEynkMiT/9Ld+P9K/ky/PBH3gQ58/n/EHh93LDDj3yPMx8UaDDrzxvM//kfD6Ak/M8EUXhCl+5L0J7vxS8MVAE+sZA6ZChvb/qfffO8H4t63FBfi26uCDl/iU/niWgN2ofH19sje/4PvDrowbd9ng41HPgGRwm+4HhVK6e4XPFeYKp4vuZebb88wyhuKP5V9I/mn8o/gBhS7Qa:78C0 +^FO32,128^GFA,06144,06144,00032,:Z64: +eJzt10Fr5DYUAGAZw+gSoj2mNKC/sF1f9lDQsX8jS6H9FyuHwM4lsNfCHvI39laXwOZimp+wDoXtsQ65qCD0+mTLHrl+stIuhbZEF8/4G9vvSU+Sh7Gn9i9opdl2nrl+x54lpPj9snq4/XDvdg/vPpSMA4D1p/EIw5OLyxcvW1694dXXwU1wF/zspD2u2HH1si2ZCF7Ofn/5rbltK3ZUPW93ay8eTr+/37dV4/147aw6/fRV3Vb26LvnrSPu//Dbr79ctWen4tOry/H6Prgdeubu529urk7OjuSbVz/smAw+5Tn2Qc3Y6QljJ0e0++8G/Qub9h4v/jLt//G2y7jYVM3kVT18KlZ1zMGV0AnoeS+vjQAGcNOrt52WQz+iW44Ihht0CXXw1wcXiPgrIy+MgmZyNbv0P3HcomvoBheNCy4Gl8Fx8AD2XeSssPInKy2g73vHe6b2nUbHIQ+uzq2yWjg1ea9Fh95NXlvlBr+3pXejRT97aby/VwLwQj/R1QUARs1EN8Zv/P2feefeNZz7LsOQZy+sZkp8/DF4icnErr1r8RGCY5eLtctbwCdyzB+D9ymPjpWPrka/M3gLnzyGxGQT4h/cyZvJ5egieK99ik7unbiz+IjRzXQ971+jXzt5ge5kx0DeWXU9OQ4zuh8idBy8a3D4RWHUMLnzbuS5k83gQ3JLx/pS3jVckM6h8yE2CnvWdy6WFEA9eufKvoBaMSsbYdCZNoWvk3qz6J/aqg2bCrYm4Tx4l3ARPLUZTu4yDjlPBCjGGxdhZVh7WPF1IkAeApOJAHkoKZEorTIEVqYCnJasVIDaLo9/bvKRAfJkgN3imAqQfXaAiSF8bIBFNsDEECq7PK4ChMcG2PzDASaGcApMJAIUmQDVdoDFPDs1OcR8fi1SZAJynp2C7GE1512SCR7mdkF5PDOoDoiz1oTHvabqtUu77SrqFNmsXXcZr7c9zkmsfdEnhJf285ybjPfbLmIn8htfif6+L04R45P1+JRe++ISor5iLyiPPlP1HTsn5kfskvC4pKkFxHs5bYLE/PXONzZJ7/MmWmc8d32XeX4i/uklg/r7FedP7XGL/s04OX51/LB624n6Wnqz8kX95eo754vJQpzKOf/rvpj/lJttL3Nut32x/uWcyH+5vhIejznpzeEztX6rbttl1AHU/hJvmkT94eQ5fKb2v+jNkqrveP+k5gfedD5LrT9+/4aN+Tvu/+n1J5r9iX8JxcEbyqMASN5cXhYR1gl/ak/t/9P+AGyhc1w=:83DC ^FT293,614^A0I,25,21^FH\^FD{DD}/{MO}/{YY}^FS ^FT145,614^A0I,25,21^FH\^FD{HH}:{MI}:{SS}^FS ^FT291,952^A0I,25,24^FH\^FDNumero Disegno^FS From e20c85cc6213f357e23ed97e80f53ab982c63537 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 6 Nov 2024 12:37:19 +0100 Subject: [PATCH 82/88] status update rewrite wip --- config/machine_settings/test-linux.ini | 4 ++-- src/components/archive_synchronizer.py | 13 ++++++------- src/scripts/print_labels_csv.py | 2 +- src/ui/recipe_selection/recipe_selection.py | 6 ------ 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/config/machine_settings/test-linux.ini b/config/machine_settings/test-linux.ini index 01516f5..01e148a 100644 --- a/config/machine_settings/test-linux.ini +++ b/config/machine_settings/test-linux.ini @@ -20,8 +20,8 @@ digital_io: present external_flush_blow: absent [archive_synchronizer] -#archive_endpoint: https://dev.r5portal.it/api/st-ten-save/ -archive_endpoint: https://r5portal.it/api/st-ten-save/ +archive_endpoint: https://dev.r5portal.it/api/st-ten-save/ +status_endpoint: https://dev.r5portal.it/api/device-info-update/ poll_time: 10 hold_time: 10 diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 395c8d0..a9788b4 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -32,10 +32,10 @@ class ArchiveSynchronizer(Component): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" - #self.url = f"https://dev.r5portal.it/media/uploads/warning_images/st-ten-10/st-ten-11.csv" + self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update/" else: self.archive_endpoint = self.config[self.name]["archive_endpoint"] - #self.browse_folder_endpoint = self.config[self.name]["browse_folder_endpoint"] + self.status_endpoint = self.config[self.name]["status_endpoint"] self._do_set_period({"period": float(self.config[self.name]["poll_time"])}) self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000) self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"]) @@ -59,21 +59,20 @@ class ArchiveSynchronizer(Component): QThread.msleep(self.hold_time) self.gcs_bucket = None - + # UPDATE MACHINE STATUS self.update_machine_status() + super()._get() def update_machine_status(self): - self.status_endpoint = f"https://r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.machine_status}" - - status_dict = {"last_status": self.machine_status} + status_call = f"{self.status_endpoint}?machine-id={self.machine_id.upper()}&status={self.machine_status}" response = None try: if not self.simulate: with requests.Session() as s: s.mount("", HTTPAdapter(max_retries=Retry(total=0))) # this disables retries - response = requests.post(self.status_endpoint, json=status_dict, timeout=5, verify=False) + response = requests.post(status_call, timeout=5, verify=False) if response.status_code != 200: raise AssertionError("bad status response") except AssertionError as e: diff --git a/src/scripts/print_labels_csv.py b/src/scripts/print_labels_csv.py index f636886..e126191 100644 --- a/src/scripts/print_labels_csv.py +++ b/src/scripts/print_labels_csv.py @@ -8,7 +8,7 @@ from src.components.os_label_printer import * from src.lib.helpers import ConfigReader SYSTEM_ID = "test-linux" -CSV_PATH="tmp/ferrari_labels4.csv" +CSV_PATH="tmp/ferrari_labels5.csv" TEMPLATE="ferrari_flag_qr_only.prn" config = ConfigReader(system_id=SYSTEM_ID) printer=Os_Label_Printer(config=config,name="label_printer") diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index fb1bed3..b093cb9 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -10,14 +10,12 @@ from PyQt5.QtCore import QTimer, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QFileDialog, QMessageBox, QShortcut import shutil -from lib.helpers.step import Step from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget from ui.helpers import replace_widget from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor from ui.widget import Widget from datetime import datetime -from components import ArchiveSynchronizer class Noner: def __getitem__(self, key): @@ -34,7 +32,6 @@ class Recipe_Selection(Widget): global noner super().__init__() self.config = config - self.archive_synch = ArchiveSynchronizer(config=config) self.second_leak_test_enabled = self.config["hardware_config"]["second_leak_test"] == "present" self.defaults = self.config.get("recipes_defaults", noner) self.unsupported_steps = unsupported_steps @@ -140,9 +137,6 @@ class Recipe_Selection(Widget): self.export_b.setVisible(False) self.delete_all_b.setVisible(False) - self.archive_synch.machine_status = "logged-in" - self.archive_synch.machine_id = self.archive_synch.config.machine_id - self.archive_synch.update_machine_status() # TESTING if "--auto-select" in sys.argv: recipe = "R56738/1" From c791ba76e9ef17977718ab6dcad891c3b5abe8ba Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 6 Nov 2024 12:55:05 +0100 Subject: [PATCH 83/88] IMPROVED ERROR FOR USB CONNECTIONS TECNA --- src/components/modbus_component.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/modbus_component.py b/src/components/modbus_component.py index 6bf920b..a4cbe35 100644 --- a/src/components/modbus_component.py +++ b/src/components/modbus_component.py @@ -51,11 +51,11 @@ class ModbusComponent(Component): strict=False, ) if not self.client.connect(): - QMessageBox.critical(None, "ERRORE", "CONNESSIONE ASSENTE ALLA TECNA - VERIFICARE CONNESSIONE USB",) - raise ConnectionError("device not reachable (could not connect): {} ({})".format(self.name, self.port)) + QMessageBox.critical(None, "ERRORE", f"ERRORE TECNA - VERIFICARE CONNESSIONE USB") + exit(-1) + #raise ConnectionError("device not reachable (could not connect): {} ({})".format(self.name, self.port)) if not self.client.is_socket_open(): - QMessageBox.critical(None, "ERRORE", "CONNESSIONE ASSENTE ALLA TECNA - VERIFICARE CONNESSIONE USB",) raise ConnectionError("device not reachable (socket not open): {} ({})".format(self.name, self.port)) self.lock.unlock() From a38aea5e5c00c2d09f578525c8b3b9cfde001079 Mon Sep 17 00:00:00 2001 From: neo-nb3 Date: Wed, 6 Nov 2024 21:00:17 +0100 Subject: [PATCH 84/88] file download from server wip --- config/machine_settings/defaults.ini | 1 + src/components/archive_synchronizer.py | 43 ++++++++++++-------------- src/test/remote_fetch_test.py | 7 ++--- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index 56e714d..062cd7f 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -50,6 +50,7 @@ minimum_disk_free_space_gb: 20 resize_resolution: 612x512 [archive_synchronizer] +api_endpoint: https://r5portal.it/api/ archive_endpoint: https://r5portal.it/api/st-ten-save/ images_path: data/images poll_time: 60 diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index a9788b4..63d3bbe 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -21,19 +21,23 @@ from urllib3.exceptions import InsecureRequestWarning from .component import Component # Suppress insecure request warning requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) + + class ArchiveSynchronizer(Component): def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.simulate = "--sim-archiver" in sys.argv - #self.machine_status = "offline" self.machine_status = "logged-in" + self.machine_id = None def config_changed(self): self.machine_id = self.config.machine_id if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update/" + self.api_endpoint = f"https://dev.r5portal.it/api/" else: + self.api_endpoint = self.config[self.name]["api_endpoint"] self.archive_endpoint = self.config[self.name]["archive_endpoint"] self.status_endpoint = self.config[self.name]["status_endpoint"] self._do_set_period({"period": float(self.config[self.name]["poll_time"])}) @@ -93,6 +97,7 @@ class ArchiveSynchronizer(Component): self.log.info(f"Status: {self.machine_status}: Machine Status Updated Successfully") return True + def remote_archive(self, record): r = None try: @@ -152,24 +157,24 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, machine_id=None): + def remote_fetch(self, remote_path=None,local_path=None): """ - Fetch and download files from the server. + download a single file from the server. - :param machine_id: ID of the machine. - :return: A list of downloaded file paths or a dictionary with errors if any occur. + :param remote_path: path of where to download the file from + :param local_path: path of where to save the file to + :return: a dictionary with errors if any occur. """ - if machine_id is None: - raise ValueError("machine_id cannot be None") - urls_endpoint = f"http://dev.r5portal.it/get-file-urls/?machine_id={machine_id}" - + if remote_path is None: + raise ValueError("remote_path cannot be None") + call_url = f"{self.api_endpoint}uploads/{remote_path}" try: if not self.simulate: with requests.Session() as s: - self.log.info(f"Fetching list of file URLs from: {urls_endpoint}") + self.log.info(f"Fetching list of file URLs from: {call_url}") # Make the HTTP GET request to fetch the list of URLs - response = s.get(urls_endpoint, timeout=5, verify=False) + response = s.get(call_url, timeout=5, verify=False) # Log response details self.log.info(f"HTTP Status Code: {response.status_code}") @@ -178,14 +183,14 @@ class ArchiveSynchronizer(Component): # Handle HTTP errors for the list of URLs fetch if response.status_code == 404: - self.log.warning(f"URLs endpoint not found: {urls_endpoint}. Please check the URL path.") + self.log.warning(f"URLs endpoint not found: {call_url}. Please check the URL path.") return {"error": "URLs endpoint not found"} elif response.status_code == 403 or response.status_code == 401: - self.log.warning(f"Access forbidden or not logged in for URLs endpoint: {urls_endpoint}") + self.log.warning(f"Access forbidden or not logged in for URLs endpoint: {call_url}") return {"error": "Access forbidden or not logged in"} elif response.status_code != 200: self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {urls_endpoint}") + f"Unexpected HTTP response status: {response.status_code} for URL: {call_url}") return {"error": "Unexpected HTTP response status"} # Parse the list of URLs (assuming the response contains a JSON array of URLs) @@ -230,16 +235,8 @@ class ArchiveSynchronizer(Component): errors[specific_file_url] = f"Unexpected status {response.status_code}" continue - # Determine the subdirectory based on the file URL or other criteria - if "warning_images" in specific_file_url: - sub_dir = os.path.join("config", "warning_images", machine_id) - elif "ricette" in specific_file_url: - sub_dir = os.path.join("config", "csv_import", "auto_csv_import") - else: - sub_dir = "tmp" # Save others under the temporary folder - # Ensure the directory exists - download_path = os.path.join(base_download_path, sub_dir) + download_path = base_download_path os.makedirs(download_path, exist_ok=True) # Save the file to the determined directory diff --git a/src/test/remote_fetch_test.py b/src/test/remote_fetch_test.py index 84bcfd1..f4b5ba2 100644 --- a/src/test/remote_fetch_test.py +++ b/src/test/remote_fetch_test.py @@ -8,8 +8,7 @@ from lib.helpers import ConfigReader config = ConfigReader(system_id="st-ten-10") app = QApplication(sys.argv) -test= ArchiveSynchronizer(config=config, name="remote_fetch_test") -status = "logged-in" -machine_id = "st-ten-10" -result = test.remote_fetch(status,machine_id) +test = ArchiveSynchronizer(config=config, name="remote_fetch_test") +file_path = "/uploads/warning_images/test.png" +result = test.remote_fetch(file_path) print(result) \ No newline at end of file From 9942b5c542a2e527b9b26b693218cdf0755af988 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Fri, 8 Nov 2024 16:47:25 +0100 Subject: [PATCH 85/88] remote fecthing ok on sim wip on server --- .../st-ten-11/ferrari_30x16_203.prn | 30 ++++ config/machine_settings/defaults.ini | 7 +- src/components/archive_synchronizer.py | 163 +++++++----------- src/test/remote_fetch_test.py | 156 +++++++++++++++-- src/ui/test/test.py | 6 - 5 files changed, 244 insertions(+), 118 deletions(-) create mode 100644 config/label_templates/st-ten-11/ferrari_30x16_203.prn diff --git a/config/label_templates/st-ten-11/ferrari_30x16_203.prn b/config/label_templates/st-ten-11/ferrari_30x16_203.prn new file mode 100644 index 0000000..53b6b78 --- /dev/null +++ b/config/label_templates/st-ten-11/ferrari_30x16_203.prn @@ -0,0 +1,30 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD15 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW256 +^LL144 +^LS0 +^FT21,129^BQN,2,4 +^FH\^FDLA,{PART}{SN5}{MO}{YY}^FS +^FT234,104^A0I,23,23^FH\^CI28^FD{PART}^FS^CI27 +^FT234,50^A0I,23,23^FH\^CI28^FDN:{SN5}^FS^CI27 +^FT234,23^A0I,23,23^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^PQ1,0,1,Y +^XZ diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index 062cd7f..37534a4 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -50,8 +50,11 @@ minimum_disk_free_space_gb: 20 resize_resolution: 612x512 [archive_synchronizer] -api_endpoint: https://r5portal.it/api/ -archive_endpoint: https://r5portal.it/api/st-ten-save/ +portal_address: https://r5portal.it/ +archive_root:api/st-ten-save/ +status_root:api/device-info-update/ +download_root:media/uploads/ + images_path: data/images poll_time: 60 hold_time: 30 diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 63d3bbe..72bab43 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -35,11 +35,12 @@ class ArchiveSynchronizer(Component): if "--dev-portal" in sys.argv: self.archive_endpoint = f"https://dev.r5portal.it/api/st-ten-save/" self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update/" - self.api_endpoint = f"https://dev.r5portal.it/api/" + self.download_endpoint = f"https://dev.r5portal.it/media/uploads/" else: - self.api_endpoint = self.config[self.name]["api_endpoint"] - self.archive_endpoint = self.config[self.name]["archive_endpoint"] - self.status_endpoint = self.config[self.name]["status_endpoint"] + self.download_endpoint = self.config[self.name]["portal_address"] + self.config[self.name]["download_root"] + self.archive_endpoint = self.config[self.name]["portal_address"] + self.config[self.name]["archive_root"] + self.status_endpoint = self.config[self.name]["portal_address"] + self.config[self.name]["status_root"] + self._do_set_period({"period": float(self.config[self.name]["poll_time"])}) self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000) self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"]) @@ -64,9 +65,10 @@ class ArchiveSynchronizer(Component): self.gcs_bucket = None # UPDATE MACHINE STATUS - self.update_machine_status() + self.machine_status="working" super()._get() + self.update_machine_status() def update_machine_status(self): status_call = f"{self.status_endpoint}?machine-id={self.machine_id.upper()}&status={self.machine_status}" @@ -76,9 +78,11 @@ class ArchiveSynchronizer(Component): if not self.simulate: with requests.Session() as s: s.mount("", HTTPAdapter(max_retries=Retry(total=0))) # this disables retries - response = requests.post(status_call, timeout=5, verify=False) + response = s.post(status_call, timeout=5, verify=False) if response.status_code != 200: raise AssertionError("bad status response") + else: + self.parse_response_and_execute(response) except AssertionError as e: self.log.warning( f"Status: {self.machine_status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}" @@ -98,6 +102,30 @@ class ArchiveSynchronizer(Component): self.log.info(f"Status: {self.machine_status}: Machine Status Updated Successfully") return True + def parse_response_and_execute(self, response): + try: + data = response.json() + if not isinstance(data, dict): + raise ValueError("Parsed response is not a dictionary") + + actions = data.get("ACTIONS_TO_DO", []) + + # Ensure actions is a list + if isinstance(actions, dict): + actions = [actions] + + for action in actions: + remote_path = action.get("remote_path") + local_path = action.get("local_path") + self.log.info(f"Executing remote fetch with remote_path: {remote_path} and local_path: {local_path}") + result = self.remote_fetch(remote_path=remote_path, local_path=local_path) + self.log.info(f"Remote fetch result: {result}") + + except json.JSONDecodeError: + self.log.error("Failed to decode JSON response") + except Exception as e: + self.log.error(f"An unexpected error occurred while parsing response: {str(e)}") + def remote_archive(self, record): r = None try: @@ -157,7 +185,7 @@ class ArchiveSynchronizer(Component): self.log.info(f"id: {record.id}: stored remotely") return True - def remote_fetch(self, remote_path=None,local_path=None): + def remote_fetch(self, remote_path=None, local_path=None): """ download a single file from the server. @@ -167,117 +195,52 @@ class ArchiveSynchronizer(Component): """ if remote_path is None: raise ValueError("remote_path cannot be None") - call_url = f"{self.api_endpoint}uploads/{remote_path}" + if local_path is None: + raise ValueError("local_path cannot be None") + + call_url = f"{self.download_endpoint}{remote_path}" try: if not self.simulate: with requests.Session() as s: - self.log.info(f"Fetching list of file URLs from: {call_url}") + self.log.info(f"Fetching file from: {call_url}") - # Make the HTTP GET request to fetch the list of URLs + # Make the HTTP GET request to fetch the file response = s.get(call_url, timeout=5, verify=False) # Log response details self.log.info(f"HTTP Status Code: {response.status_code}") - self.log.info(f"Response Headers: {response.headers}") - self.log.info(f"Response Content: {response.content}") + #self.log.info(f"Response Headers: {response.headers}") + #self.log.info(f"Response Content: {response.content}") - # Handle HTTP errors for the list of URLs fetch + # Handle HTTP errors if response.status_code == 404: - self.log.warning(f"URLs endpoint not found: {call_url}. Please check the URL path.") - return {"error": "URLs endpoint not found"} + self.log.warning(f"File not found: {call_url}. Please check the URL path.") + return {"error": "File not found"} elif response.status_code == 403 or response.status_code == 401: - self.log.warning(f"Access forbidden or not logged in for URLs endpoint: {call_url}") + self.log.warning(f"Access forbidden or not logged in for file: {call_url}") return {"error": "Access forbidden or not logged in"} elif response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {call_url}") + self.log.error(f"Unexpected HTTP response status: {response.status_code} for URL: {call_url}") return {"error": "Unexpected HTTP response status"} - # Parse the list of URLs (assuming the response contains a JSON array of URLs) - try: - file_urls = response.json() - self.log.info(f"Fetched file URLs: {file_urls}") - except ValueError as e: - self.log.error(f"Error parsing JSON response: {str(e)}") - self.log.error(f"Response Content: {response.content}") - return {"error": "Failed to parse JSON response"} + # Ensure the directory exists + os.makedirs(local_path, exist_ok=True) - downloaded_files = [] - errors = {} + # Save the file to the local path + local_file_path = os.path.join(local_path, os.path.basename(remote_path)) + with open(local_file_path, "wb") as f: + f.write(response.content) - # Setup the base download path - base_download_path = os.path.join(Path.home(), "PycharmProjects", "st-ten-1") - - # Iterate over the list of URLs to download each file - for specific_file_url in file_urls: - try: - self.log.info(f"Attempting to fetch file from: {specific_file_url}") - - # Make the HTTP GET request to fetch the file URL - response = s.get(specific_file_url, timeout=5, verify=False) - - # Log response details - self.log.info(f"HTTP Status Code: {response.status_code}") - self.log.info(f"Response Headers: {response.headers}") - - # Handle HTTP errors appropriately for each file - if response.status_code == 404: - self.log.warning(f"File not found: {specific_file_url}. Please check the URL path.") - errors[specific_file_url] = "File not found" - continue - elif response.status_code == 403: - self.log.warning(f"Access forbidden for file: {specific_file_url}") - errors[specific_file_url] = "Access forbidden" - continue - elif response.status_code != 200: - self.log.error( - f"Unexpected HTTP response status: {response.status_code} for URL: {specific_file_url}") - errors[specific_file_url] = f"Unexpected status {response.status_code}" - continue - - # Ensure the directory exists - download_path = base_download_path - os.makedirs(download_path, exist_ok=True) - - # Save the file to the determined directory - local_file_path = os.path.join(download_path, os.path.basename(specific_file_url)) - with open(local_file_path, "wb") as f: - f.write(response.content) - - self.log.info(f"File downloaded successfully: {local_file_path}") - downloaded_files.append(local_file_path) - - except (requests.ConnectionError, requests.Timeout) as e: - self.log.warning( - f"Failed to download file from {specific_file_url}, the URL might be unreachable: {str(e)}") - errors[specific_file_url] = "URL unreachable" - except Exception as e: - self.log.error( - f"An unexpected error occurred while downloading {specific_file_url}: {str(e)}") - errors[specific_file_url] = "Unexpected error" - - return { - "downloaded_files": downloaded_files, - "errors": errors - } + self.log.info(f"File downloaded successfully: {local_file_path}") + return {"downloaded_file": local_file_path} + except requests.ConnectionError as e: + self.log.error(f"Connection error occurred while fetching the file: {str(e)}") + return {"error": "Connection error"} + except requests.Timeout as e: + self.log.error(f"Timeout error occurred while fetching the file: {str(e)}") + return {"error": "Timeout error"} except Exception as e: - self.log.error(f"An unexpected error occurred while fetching URLs: {str(e)}") + self.log.error(f"An unexpected error occurred: {str(e)}") return {"error": "Unexpected error"} - def check_actions_to_do(self, machine_id: str) : - update_url = f"http://dev.r5portal.it/device/?machine-id={machine_id}" - response = requests.get(update_url) - - if response.status_code == 200: - try: - #json_response = response.json() - #action_to_do = json_response.get("ACTIONS_TO_DO", "NO_ACTION") - #if action_to_do == "DOWNLOAD_FILES": - self.remote_fetch(machine_id) - #else: - # self.log.info(f"No action required: {json_response}") - except JSONDecodeError as e: - self.log.error(f"JSON decode error: {str(e)} - Content: {response.content}") - else: - self.log.error(f"Failed to update device info: {response.status_code} - {response.content}") diff --git a/src/test/remote_fetch_test.py b/src/test/remote_fetch_test.py index f4b5ba2..c9db1f3 100644 --- a/src/test/remote_fetch_test.py +++ b/src/test/remote_fetch_test.py @@ -1,14 +1,150 @@ -import sys -from datetime import datetime -from PyQt5.QtWidgets import QApplication +import unittest +from unittest.mock import patch, Mock +import requests +import json +import os from components import ArchiveSynchronizer -from lib.helpers import ConfigReader -config = ConfigReader(system_id="st-ten-10") -app = QApplication(sys.argv) -test = ArchiveSynchronizer(config=config, name="remote_fetch_test") -file_path = "/uploads/warning_images/test.png" -result = test.remote_fetch(file_path) -print(result) \ No newline at end of file +class TestArchiveSynchronizer(unittest.TestCase): + def setUp(self): + self.synchronizer = ArchiveSynchronizer(config=Mock(), name=None) + self.synchronizer.archive_endpoint = "https://dev.r5portal.it/api/st-ten-save/" + self.synchronizer.status_endpoint = "https://dev.r5portal.it/api/device-info-update/" + self.synchronizer.download_endpoint = "https://dev.r5portal.it/media/uploads/" + self.synchronizer.machine_id = "st-ten-1" + self.synchronizer.log = Mock() + + @patch('requests.Session') + @patch('os.makedirs') + @patch('builtins.open', new_callable=unittest.mock.mock_open) + def test_remote_fetch_success(self, mock_open, mock_makedirs, mock_session): + remote_path = "img-025.png" + local_path = "config/warning_images" + + mock_response = Mock() + mock_response.status_code = 200 + mock_response.content = b'Test content' + mock_session.return_value.__enter__.return_value.get.return_value = mock_response + + result = self.synchronizer.remote_fetch(remote_path, local_path) + + self.assertEqual(result, {"downloaded_file": f"{local_path}/{remote_path}"}) + mock_open.assert_called_with(f"{local_path}/{remote_path}", "wb") + mock_open().write.assert_called_with(b'Test content') + + @patch('requests.Session') + def test_remote_fetch_not_found(self, mock_session): + remote_path = "img-025.png" + local_path = "config/warning_images" + + mock_response = Mock() + mock_response.status_code = 404 + mock_session.return_value.__enter__.return_value.get.return_value = mock_response + + result = self.synchronizer.remote_fetch(remote_path, local_path) + self.assertEqual(result, {"error": "File not found"}) + + @patch('requests.Session') + def test_remote_fetch_forbidden(self, mock_session): + remote_path = "img-025.png" + local_path = "config/warning_images" + + mock_response = Mock() + mock_response.status_code = 403 + mock_session.return_value.__enter__.return_value.get.return_value = mock_response + + result = self.synchronizer.remote_fetch(remote_path, local_path) + self.assertEqual(result, {"error": "Access forbidden or not logged in"}) + + @patch('requests.Session') + @patch('requests.Session.get', side_effect=requests.ConnectionError("Connection error")) + def test_remote_fetch_connection_error(self, mock_get, mock_session): + remote_path = "img-025.png" + local_path = "config/warning_images" + + result = self.synchronizer.remote_fetch(remote_path, local_path) + self.assertEqual(result, {"error": "Connection error"}) + self.synchronizer.log.error.assert_called_with( + "Connection error occurred while fetching the file: Connection error") + + @patch('requests.Session') + @patch('requests.Session.get', side_effect=requests.Timeout("Timeout error")) + def test_remote_fetch_timeout_error(self, mock_get, mock_session): + remote_path = "img-025.png" + local_path = "config/warning_images" + + result = self.synchronizer.remote_fetch(remote_path, local_path) + self.assertEqual(result, {"error": "Timeout error"}) + self.synchronizer.log.error.assert_called_with("Timeout error occurred while fetching the file: Timeout error") + + @patch('requests.Session') + def test_parse_response_and_execute_success(self, mock_session): + mock_response = Mock() + mock_response.json.return_value = { + "STATUS": "OK", + "ACTIONS_TO_DO": [ + {"remote_path": "img-025.png", "local_path": "config/warning_images"} + ] + } + + with patch.object(self.synchronizer, 'remote_fetch', + return_value={"downloaded_file": "config/warning_images/img-025.png"}) as mock_rf: + self.synchronizer.parse_response_and_execute(mock_response) + mock_rf.assert_called_once_with(remote_path="img-025.png", local_path="config/warning_images") + + def test_parse_response_and_execute_json_error(self): + mock_response = Mock() + mock_response.json.side_effect = json.JSONDecodeError("Expecting value", "doc", 0) + + self.synchronizer.parse_response_and_execute(mock_response) + self.synchronizer.log.error.assert_called_with("Failed to decode JSON response") + + @patch('requests.Session') + @patch.object(ArchiveSynchronizer, 'parse_response_and_execute') + def test_update_machine_status_success(self, mock_parse_response, mock_session): + mock_response = Mock() + mock_response.status_code = 200 + mock_session.return_value.__enter__.return_value.post.return_value = mock_response + + self.synchronizer.machine_status = "running" + result = self.synchronizer.update_machine_status() + self.assertTrue(result) + mock_parse_response.assert_called_once_with(mock_response) + self.synchronizer.log.info.assert_called_with("Status: running: Machine Status Updated Successfully") + + @patch('requests.Session') + def test_update_machine_status_bad_status_response(self, mock_session): + mock_response = Mock() + mock_response.status_code = 500 + mock_session.return_value.__enter__.return_value.post.return_value = mock_response + + self.synchronizer.machine_status = "idle" + result = self.synchronizer.update_machine_status() + self.assertFalse(result) + self.synchronizer.log.warning.assert_called_with( + "Status: idle: failed to update machine status: bad status response: 500: no response" + ) + + @patch('requests.Session', side_effect=requests.ConnectionError("Connection error")) + def test_update_machine_status_connection_error(self, mock_session): + self.synchronizer.machine_status = "offline" + result = self.synchronizer.update_machine_status() + self.assertFalse(result) + self.synchronizer.log.warning.assert_called_with( + "Status: offline: failed to update machine status, archive_endpoint might be unreachable: Connection error" + ) + + @patch('requests.Session', side_effect=requests.Timeout("Timeout error")) + def test_update_machine_status_timeout_error(self, mock_session): + self.synchronizer.machine_status = "offline" + result = self.synchronizer.update_machine_status() + self.assertFalse(result) + self.synchronizer.log.warning.assert_called_with( + "Status: offline: failed to update machine status, archive_endpoint might be unreachable: Timeout error" + ) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 2fef0c1..c1bfaa3 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -263,9 +263,6 @@ class Test(Widget): if hasattr(current_w, "stop"): current_w.stop() if action == "change_recipe": - self.archive_synch.machine_status = "logged-in" - self.archive_synch.machine_id = self.archive_synch.config.machine_id - self.archive_synch.update_machine_status() self.log.info(f"cycle next: action: {action!r}") self.set_recipe(recipe=None) if self.config["hardware_config"]["tecna_t3"] == "present" or self.config["hardware_config"]["furness_controls"] == "present": @@ -335,9 +332,6 @@ class Test(Widget): # 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] - self.archive_synch.machine_status = "working" - self.archive_synch.machine_id = self.archive_synch.config.machine_id - self.archive_synch.update_machine_status() else: self.cycle_index = -1 From 5bb7dd66ce9145b7c0b14cf302793731c79b94af Mon Sep 17 00:00:00 2001 From: gg Date: Mon, 11 Nov 2024 10:11:24 +0100 Subject: [PATCH 86/88] new dime --- .../st-ten-11/07N131628.svg | 84 +++++++++--- .../st-ten-11/18JA708CP.svg | 68 ++++++++++ .../st-ten-11/18JA709CP.svg | 80 +++++++++++ .../st-ten-11/18JA710CP.svg | 48 +++++++ .../st-ten-11/18JA712CP.svg | 70 ++++++++++ .../st-ten-11/18JA713CP.svg | 128 ++++++++++++++++++ .../st-ten-11/18JA718CP.svg | 48 +++++++ .../st-ten-11/18JA750CP.svg | 48 +++++++ .../st-ten-11/18JA757CP.svg | 48 +++++++ 9 files changed, 606 insertions(+), 16 deletions(-) create mode 100644 config/instruction_images/st-ten-11/18JA708CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA709CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA710CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA712CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA713CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA718CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA750CP.svg create mode 100644 config/instruction_images/st-ten-11/18JA757CP.svg diff --git a/config/instruction_images/st-ten-11/07N131628.svg b/config/instruction_images/st-ten-11/07N131628.svg index 332702c..b62724a 100644 --- a/config/instruction_images/st-ten-11/07N131628.svg +++ b/config/instruction_images/st-ten-11/07N131628.svg @@ -4,9 +4,9 @@ + + + + + diff --git a/config/instruction_images/st-ten-11/18JA708CP.svg b/config/instruction_images/st-ten-11/18JA708CP.svg new file mode 100644 index 0000000..ee32042 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA708CP.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA709CP.svg b/config/instruction_images/st-ten-11/18JA709CP.svg new file mode 100644 index 0000000..a91c6be --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA709CP.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA710CP.svg b/config/instruction_images/st-ten-11/18JA710CP.svg new file mode 100644 index 0000000..2c2b0b9 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA710CP.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA712CP.svg b/config/instruction_images/st-ten-11/18JA712CP.svg new file mode 100644 index 0000000..8343eb1 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA712CP.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA713CP.svg b/config/instruction_images/st-ten-11/18JA713CP.svg new file mode 100644 index 0000000..7739628 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA713CP.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA718CP.svg b/config/instruction_images/st-ten-11/18JA718CP.svg new file mode 100644 index 0000000..3cf3f24 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA718CP.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA750CP.svg b/config/instruction_images/st-ten-11/18JA750CP.svg new file mode 100644 index 0000000..0b3bb27 --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA750CP.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/config/instruction_images/st-ten-11/18JA757CP.svg b/config/instruction_images/st-ten-11/18JA757CP.svg new file mode 100644 index 0000000..ba538cb --- /dev/null +++ b/config/instruction_images/st-ten-11/18JA757CP.svg @@ -0,0 +1,48 @@ + + + + + + + + + + From 65250d653323bb1316372f607b1453749f30750a Mon Sep 17 00:00:00 2001 From: edo-neo Date: Mon, 11 Nov 2024 16:57:51 +0100 Subject: [PATCH 87/88] wip remote fetch --- src/components/archive_synchronizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/archive_synchronizer.py b/src/components/archive_synchronizer.py index 72bab43..6e22717 100644 --- a/src/components/archive_synchronizer.py +++ b/src/components/archive_synchronizer.py @@ -198,7 +198,7 @@ class ArchiveSynchronizer(Component): if local_path is None: raise ValueError("local_path cannot be None") - call_url = f"{self.download_endpoint}{remote_path}" + call_url = f"https://dev.r5portal.it/{remote_path}" try: if not self.simulate: with requests.Session() as s: From 5f1189f2777dccb59267baea8cfe2aa0ecd4ef15 Mon Sep 17 00:00:00 2001 From: edo-neo Date: Thu, 14 Nov 2024 16:45:43 +0100 Subject: [PATCH 88/88] st-ten-6 ready for update --- .../manual_csv_import/ricette.stten6csv.csv | 291 ++++++++++++++++++ src/ui/recipe_selection/recipe_selection.py | 2 +- 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 config/csv_import/manual_csv_import/ricette.stten6csv.csv diff --git a/config/csv_import/manual_csv_import/ricette.stten6csv.csv b/config/csv_import/manual_csv_import/ricette.stten6csv.csv new file mode 100644 index 0000000..2010777 --- /dev/null +++ b/config/csv_import/manual_csv_import/ricette.stten6csv.csv @@ -0,0 +1,291 @@ +codice_ricetta,cliente,codice_prodotto,dimensione_lotto_abilitata,dimensione_lotto,verifica_connettore_abilitata,connettore,verifica_codice_a_barre_abilitata,codice_a_barre,verifica_resistenza_connettore_abilitata,scala_resistenza,r nominale,tolleranza_resistenza_pos,tolleranza_resistenza_neg,avvitatura_abilitata,viti,prova_tenuta_abilitata,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,prova_tenuta_abilitata_2,tempo_pre_riempimento_2,pressione_pre_riempimento_2,tempo_riempimento_2,tempo_assestamento_2,percentuale_minima_pressione_assestamento_2,percentuale_massima_pressione_assestamento_2,tempo_di_test_2,pressione_di_test_delta_minimo_2,pressione_di_test_2,pressione_di_test_delta_massimo_2,tempo_svuotamento_2,pressione_svuotamento_2,test_visione_abilitato,ricetta_visione,stampa_etichetta_abilitata,modello_etichetta +5801615767,IRISBUS,5801615767,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801615768,IRISBUS,5801615768,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801616061,IRISBUS,5801616061,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802278738,IVECO,5802278738,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802307397,IVECO,5802307397,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802783283,IVECO,5802783283,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820557,IVECO,5802820557,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802981174,IVECO BUS,5802981174,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6614258A2,argo,6614258A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6645424A2,ARGO TRACTRORS,6645424A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6694527A1,ARGO-TRACTORS,6694527A1,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +8626311,ROSENBAUR,8626311,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +8626312,ROSENBAUR,8626312,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6671546A3,ARGO TRACTOR,6671546A3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6703589A,AVONI,6703589A,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5PLH3000,BIMOTOR,BR5PLH3000,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5PLH2500,BIMOTOR,BR5PLH2500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5PLH1500,BIMOTOR,BR5PLH1500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5PLH1000,BIMOTOR,BR5PLH1000,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5SLH1500,BIMOTOR,BR5SLH1500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5SLH1000,BIMOTOR,BR5SLH1000,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5BLH2500,BIMOTOR,BR5BLH2500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5BLH1000,BIMOTOR,BR5BLH1000,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5BLH3500,BIMOTOR,BR5BLH3500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5SLH345,BIMOTOR,BR5SLH345,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +BR5BLH345,BIMOTOR,BR5BLH345,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +7064710,BUCHER,7064710,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +7076215,BUCHER,7076215,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +POS.050-R53581,BUCHER,POS.050-R53581,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +CHF-6157,SUTPHEN,CHF-6157,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +CHF-6158,SUTPHEN,CHF-6158,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +47723585,CNH,47723585,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +47723590,CNH,47723590,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802866956,iveco BRASILE,5802866956,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802867195,IVECO-BRASILE,5802867195,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820701,IVECO BRESC,5802820701,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820711,iveco BRESC,5802820711,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802845278,IVECO,5802845278,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801363631,IVECO,5801363631,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820457,IVECO,5802820457,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820464,IVECO,5802820464,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820493,IVECO,5802820493,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820512,IVECO,5802820512,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820516,IVECO,5802820516,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820525,IVECO,5802820525,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820534,IVECO,5802820534,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820538,IVECO,5802820538,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820548,IVECO,5802820548,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820590,IVECO,5802820590,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820596,IVECO,5802820596,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820681,IVECO,5802820681,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820697,IVECO,5802820697,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802820732,IVECO,5802820732,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801364872,IVECO,5801364872,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801402694,IVECO,5801402694,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801457865,IVECO,5801457865,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801521202,IVECO,5801521202,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53020608,MANITOU,53020608,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53020610,MANITOU,53020610,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53020612,MANITOU,53020612,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +80143869,MANITOWOC,80143869,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +80143870,MANITOWOC,80143870,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +80143871,MANITOWOC,80143871,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117346,MERLO,117346,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117347,MERLO,117347,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117536,MERLO,117536,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117537,MERLO,117537,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +13-2382,MULTIMATIC,13-2382,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +13-2384,MULTIMATIC,13-2384,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +13-2386,MULTIMATIC,13-2386,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +13-2388,MULTIMATIC,13-2388,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +B6336,MV AGUSTA,B6336,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +B8702,MV AGUSTA,B8702,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +32251,OTOKAR,32251,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +1B001316,PIAGGIO,1B001316,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +2B000116,PIAGGIO,2B000116,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +FUG CALIB3,TEST CIVETTA,FUG CALIB3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802513111,PREGNANA,5802513111,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +CHF-6156,SUTPHEN,CHF-6156,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +CHF-6157-200,SUTPHEN,CHF-6157-200,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +CHF-6158-200,SUTPHEN,CHF-6158-200,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801919616,SUZZARA,5801919616,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +46628006,ANTONIO CARRARO,46628006,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +46628008,ANTONIO CARRARO,46628008,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6623494A4,argo,6623494A4,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6628897A3,argo,6628897A3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6671549A3,ARGO TRACTOR,6671549A3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6673612A2,ARGO-TRACTORS,6673612A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6688903A2,ARGO TRACTOR,6688903A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6688904A2,ARGO TRACTOR,6688904A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6693686A3,ARGO TRACTOR,6693686A3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6693687A3,ARGO TRACTOR,6693687A3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +16L0167CP,mclaren,16L0167CP,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +MY83-6B747-BA,ASTON MARTIN,MY83-6B747-BA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +MY83-6B748-BA,ASTON MARTIN,MY83-6B748-BA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +MY83-6L694-AB,ASTON MARTIN,MY83-6L694-AB,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +MY83-6L701-AB,ASTON MARTIN,MY83-6L701-AB,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +MY83-6L694-AA,ASTON MARTIN,MY83-6L694-AA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +1636031851,ATLASCOPCO,1636031851,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +1636031854,ATLASCOPCO,1636031854,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +1636031855,ATLASCOPCO,1636031855,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53221,AUTOMARK,R53221,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +R53222,AUTOMARK,R53222,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +670053160,BEST HOSES,670053160,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR321.39-R1,BUGATTI,PR321.39-R1,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR499-33-R3,BUGATTI,PR499-33-R3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR499-40-R3,BUGATTI,PR499-40-R3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR499-41-R3,BUGATTI,PR499-41-R3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR499-42-R3,BUGATTI,PR499-42-R3,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +PR499-73-R2,BUGATTI,PR499-73-R2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +145-3810,CRANE CARRIER,145-3810,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +145-3811,CRANE CARRIER,145-3811,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +145-3812,CRANE CARRIER,145-3812,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +145-3813,CRANE CARRIER,145-3813,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52607933,MANITOU,52607933,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52607935,MANITOU,52607935,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52607941,MANITOU,52607941,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52631209,MANITOU,52631209,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52631210,MANITOU,52631210,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52631211,MANITOU,52631211,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +125584,MERLO,125584,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +128551,MERLO,128551,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +19P003_364,MERLO,19P003_364,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +19P003_365,MERLO,19P003_365,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R52444,MERLO,R52444,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R52445,MERLO,R52445,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +13M26-32252-AA,OTOKAR,13M26-32252-AA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +13R00-32252-AA,OTOKAR,13R00-32252-AA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802513100,PREGNANA,5802513100,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802513109,PREGNANA,5802513109,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802513113,PREGNANA,5802513113,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802513114,PREGNANA,5802513114,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026890,PRINOTH,28026890,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026891,PRINOTH,28026891,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026892,PRINOTH,28026892,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026893,PRINOTH,28026893,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026894,PRINOTH,28026894,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026895,PRINOTH,28026895,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026896,PRINOTH,28026896,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026897,PRINOTH,28026897,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28026898,PRINOTH,28026898,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +28054871,PRINOTH,28054871,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52706151,MANITOU,52706151,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52706152,MANITOU,52706152,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +52706153,MANITOU,52706153,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +63403,MAGNI,63403,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.827,VENIERI,180.3.827,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.828,VENIERI,180.3.828,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.829,VENIERI,180.3.829,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.830,VENIERI,180.3.830,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.831,VENIERI,180.3.831,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.832,VENIERI,180.3.832,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.838,VENIERI,180.3.838,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +180.3.839,VENIERI,180.3.839,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +A89020507,TECNOGEN,A89020507,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +A89090500,TECNOGEN,A89090500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +A89100500,TECNOGEN,A89100500,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11K0210CP,MCLAREN,11K0210CP,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11K0235RT,MCLAREN,11K0235RT,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11K0236RT,MCLAREN,11K0236RT,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11K0237RT,MCLAREN,11K0237RT,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +122109,MERLO,122109,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +128551-R54268,MERLO,128551-R54268,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +12970-13-8212,MULTIMATIC,12970-13-8212,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +12KO243CP,MCLAREN,12KO243CP,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +47723530,CNH,47723530,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +504385052,FPT,504385052,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801402690,IVECO,5801402690,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5801283144,IVECO,5801283144,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5801354164,Iveco,5801354164,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801355177,IVECO,5801355177,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5801376020,IVECO,5801376020,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5801372024,IVECO,5801372024,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5801436969,IVECO,5801436969,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801503729,IVECO,5801503729,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801615766,IRISBUS,5801615766,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5E.R52814,DIECI,5E.R52814,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5801668147,IVECO,5801668147,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801668141,IVECO,5801668141,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117345,MERLO,117345,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117344,MERLO,117344,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R55205,DEUTZ,R55205,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R55204,DEUTZ,R55204,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54893,ATLAS COPCO,R54893,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54822,BIMOTOR,R54822,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54800,ANDREOLI,R54800,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54762,ATLAS COPCO,R54762,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54761/ECL4,ATLAS COPCO,R54761/ECL4,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +R54258,BIMOTOR,R54258,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54026-1,AVONI,R54026-1,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54026,ARGO TRACTOR,R54026,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54021,ARGO TRACTOR,R54021,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R54020,ARGO TRACTOR,R54020,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53963,SOREMA,R53963,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53961,SOREMA,R53961,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53959,SOREMA,R53959,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53957,SOREMA,R53957,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53927,MERLO,R53927,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53861,ARGO TRACTOR,R53861,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53849,ARGO TRACTOR,R53849,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53848,ARGO TRACTOR,R53848,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53847,ARGO TRACTOR,R53847,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53390,DIECI,R53390,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53293,KAHA,R53293,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R53223,AUTOMARK,R53223,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5802951920,IVECO,5802951920,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5801690154,IVECO,5801690154,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801690155,IVECO,5801690155,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +B4901,MV AGUSTA,B4901,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +503146253,MAGIRUS,503146253,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +503146900 DX,MAGIRUS,503146900 DX,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +125637,MERLO,125637,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +13H30-32256-AA,OTOKAR,13H30-32256-AA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +13M26-32256-AA,OTOKAR,13M26-32256-AA,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +503146256 SX,MAGIRUS,503146256 SX,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +6703586A1,ARGO,6703586A1,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +19901416000,INTERPUMP,19901416000,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,2000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +36001,TEREX,36001,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +36002,TEREX,36002,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801460021,IVECO,5801460021,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801460025,IVECO,5801460025,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802845277,IVECO,5802845277,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,10000,30,1,100,x,0,1000,10,10,5,5,10,30,10000,30,3,100,False,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R55145,DEUTZ,R55145,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5803018238,IVECO,5803018238,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,10,10,10,30,18000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5803018239,IVECO,5803018239,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,10,10,10,30,18000,30,1,100,,0,1000,10,10,5,5,10,30,18000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5803018244,IVECO,5803018244,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,10,10,10,30,18000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +7064708,BUCHER,7064708,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +7067082,BUCHER,7067082,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +7080623,BUCHER,7080623,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53027246,MANITOU,53027246,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53027247,MANITOU,53027247,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53027248,MANITOU,53027248,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53027252,MANITOU,53027252,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +53027253,MANITOU,53027253,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802527206,PREGNANA,5802527206,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +7081272-ECL3,BUCHER,7081272-ECL3,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_2prove.prn +11K0218CP,MCLAREN,11K0218CP,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +51513901,CNH-LECCE,51513901,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +51513904,CNH-LECCE,51513904,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5801395749,IVECO,5801395749,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +6603139A4,ARGO-TRACTORS,6603139A4,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,20,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802540646,IVECO,5802540646,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,10,10,10,10,10,10,10,3,4300,30,0,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5802845274,IVECO,5802845274,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5802915400,IVECO,5802915400,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +6658115A2,ARGO-TRACTORS,6658115A2,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +6658115A4,ARGO-TRACTORS,6658115A4,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,15,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +125583,MERLO,125583,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +6683267A2,ARGO-TRACTORS,6683267A2,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,15,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +47886643,CNH-LECCE,47886643,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,20,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +R56763,STERKI,R56763,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +R56759,STERKI,R56759,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +6703537A2,ARGO,6703537A2,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5802752024,IVECO,5802752024,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5802754968,PREGNANA,5802754968,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5802845275,IVECO,5802845275,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +131295,MERLO,131295,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,15,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +5803143177,IVECO,5803143177,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,2500,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5802845276,IVECO FRANCE,5802845276,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +R52763,AUTOMARK,R52763,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +R52764,AUTOMARK,R52764,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +R52765,AUTOMARK,R52765,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_1prova.prn +5802892528,IVECO FRANCE,5802892528,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +5802892531,IVECO FRANCE,5802892531,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +19872.00.35,DELL ORTO,19872.00.35,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,20,30,9000,30,0,100,,0,1000,10,10,5,5,20,30,9000,5,1,100,False,000952054.ini,x,ETA30x16_203dpi.prn +19799.00.35,DELL ORTO,19799.00.35,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,20,30,9000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,ETA30x16_203dpi.prn +000746453,FERRARI,000746453,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,10500,30,1,100,,0,1000,10,10,5,5,10,30,10000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +10005330,CAPACITY TRUCKS,10005330,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +10006718,CAPACITY TRUCKS,10006718,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +112247,MERLO,112247,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +112248,MERLO,112248,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11519588,VAN HOOL,11519588,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11519589,VAN HOOL,11519589,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11519590,VAN HOOL,11519590,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11556236,VAN HOOL,11556236,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11556237,VAN HOOL,11556237,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11578030,VAN HOOL,11578030,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,000952054.ini,x,EtichettaR5_Montaggio_1prova.prn +11585242,VAN HOOL,11585242,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11604514,VAN HOOL,11604514,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,30,30,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11607305,VAN HOOL,11607305,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11627962,VAN HOOL,11627962,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,20,10,5,5,10,30,7000,30,1,100,x,0,1000,20,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11642860,VAN HOOL,11642860,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11642861,VAN HOOL,11642861,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650475,VAN HOOL,11650475,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650477,VAN HOOL,11650477,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650478,VAN HOOL,11650478,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650479,VAN HOOL,11650479,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650481,VAN HOOL,11650481,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +11650484,VAN HOOL,11650484,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117342,MERLO,117342,,,,SCRx,,,,500.0,1000000000.0,10.0,5.0,,,x,0,1000,10,10,5,5,10,30,7000,30,1,100,x,0,1000,10,10,5,5,10,30,15000,30,1,100,0,termorestringente_923578.ini,x,EtichettaR5_Montaggio_2prove.prn +117343,MERLO,117343,,,,SCRx,,,,500.0,9999999.99,10.0,5.0,,,x,0,1000,10,10,5,5,20,30,9000,30,1,100,,0,1000,10,10,5,5,10,30,15000,30,1,100,False,termorestringente_923578.ini,x,ETA30x16_203dpi.prn diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index b093cb9..9fc4f1b 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -293,7 +293,7 @@ class Recipe_Selection(Widget): return self.log.info(f"recipes: importing recipes from {csv_path}") recipe_name_field = self.config.get("recipe", {}).get("recipe_name_field", "codice_ricetta").strip() - part_number_field = self.config.get("recipe", {}).get("part_number_field", "part number").strip() + part_number_field = self.config.get("recipe", {}).get("part_number_field", "part_number").strip() description_field = self.config.get("recipe", {}).get("description_field", "descrizione").strip() barcode_enable_field = self.config.get("recipe", {}).get("barcode_enable_field", "verifica_codice_a_barre_abilitata").strip()