From b5d4a07ab2ba8aa2efc7938f1f47f3cdb5c45640 Mon Sep 17 00:00:00 2001 From: neo Date: Tue, 17 Sep 2024 15:19:36 +0200 Subject: [PATCH 01/78] 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/78] 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/78] 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/78] 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/78] 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 dd88b1eafaaa5e9fce00577b72a1627b0ee333fa Mon Sep 17 00:00:00 2001 From: neo Date: Fri, 4 Oct 2024 11:39:16 +0200 Subject: [PATCH 06/78] 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 07/78] 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 08/78] 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 09/78] 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 7ee96d63dd37f502c66b1e39d9ad1cea5b94c208 Mon Sep 17 00:00:00 2001 From: neo Date: Tue, 8 Oct 2024 15:36:05 +0200 Subject: [PATCH 10/78] 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 c9226d40ab24ff351519ed32e9b589b19a7c3aef Mon Sep 17 00:00:00 2001 From: ST-TEN-11 Date: Wed, 9 Oct 2024 11:51:31 +0200 Subject: [PATCH 11/78] 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 12/78] 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 13/78] 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 14/78] 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 15/78] 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 16/78] 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 17/78] 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 18/78] 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 19/78] 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 20/78] 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 21/78] 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 22/78] 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 23/78] 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 24/78] 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 25/78] 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 26/78] 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 27/78] 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 28/78] 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 29/78] 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 30/78] 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 31/78] 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 32/78] 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 33/78] 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 34/78] 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 35/78] 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 36/78] 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 37/78] 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 38/78] 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 39/78] 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 40/78] 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 41/78] 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 42/78] 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 43/78] 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 44/78] 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 45/78] 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 46/78] 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 47/78] 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 48/78] 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 49/78] 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 50/78] 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 51/78] 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 52/78] 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 53/78] 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 54/78] 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 55/78] 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 56/78] 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 57/78] 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 zcmb`KS5Om*wuVCy>4<;MXY10dDP(lRo)uW^R~ z0C*n?0B{4O06HF?Zg$>YQm7}Mo_3y35hzzXN5peagonE;nj-7+pF0h0Dp~+NfDiC@ zQ2>B|9$ICQ4#8Q9e`?}+S99Amd)~_~h6HM<8P%uj)2|0P9vkV#SF@>0U*~N9^)Q>- z{O|!h06O7uCS)7BVidK?TI2X5di`!A!^?WgwQljwd@HD)xqWL#0L zj&?fF8nfxodDOfks23p7G1zz{T2ft|E~yiN1J%&UYpsep^$v$TG%O)bKW=w$d^1+m z0Bq=RfnRP%JT3kp-qdNJ-3#*Cen+R64TZ2^3P-&7~pC zz==aC#$n=CF@#eN+mhqEN`cpa-vURStPX}bnc6K`#fwg}+eSjlR#<&svdNCBy}b!6 zcvEE@gNqbIwV}0(%KO4$?CvxirhqJz;!>28tWJJr~J$?ndTC_>@Tz3{cv0Tk+csI?i5FYRJX28Rw*G|0L^H|;)dkTfVpHF z!`LaT`PB~&`RvY%+~iv9!@-->eOJtD2aEGGT!rA1V=WztK5Q-7@nFE@B+d2s_0om4 zBiCrbh{W^4rs%@3iDL%aGU-NfuiH>pK0t7(^$=CipIoiXa4GK@XTX@>vlnY;uB=%T zh*DnQ7xAf}@W0Gq^tbli_eLHr=d|L~NG4$euvcW(di;y8>?-{SAc+im4__A2)rh;NR-VvP$s(hF0K1%cSbc~Y6NvyAiW6zYpDK|{A*Ed;ngcY+I zq{Dk8C)8uRoP%`YD5Mmym5hGSC$_O)2Y&l&Bqut&5sfW>YVukDRoKwlW4QXz?JMc5 zmX=q)T84Ammkwi-rdz*({CPOma!6gNCPhzLV}@VRkk2>5MQ>1IycHd@zbuODle!W< zd9*ZtOal$d*_c@z%rh38oF^dy471@@-&}8n3l$Do0^8bnZ@ig0Z)6e?3UQnAl5_1- zg{G#BE|~kLx2u!$Ca}C#>1m!`I@r|G8sBc5p$vK=%uQ(QHf^BOYC+gtFGSA#dTLY5 zi7ctf95a~3<6&KW(_%LC`)vVRdILL~8)ltKzH^J5PChJ`8w+t~DnZYKZtoOjiJe`7 znrWAXWFK%$6|FaO&=gyFiXxRhKTirk;uElw5Lo%=KENK~Dj*p3lp;J6q%e zvNKV2D&NWD+0)G25=Au^oM#Bx_FWw-sMHz>U^Y4Tifn1eNYphk3fJ-T9~INFm(bK9I9NGYVtoW^^&oa3kXm?t!Y zv#6tE@2`U}&5&P`z>$58fVM`hJ4*WQK#}CsA{hpO8f~C%!pQ8Lxu(;PAY3s^hPNlCsqU`Q$HbJ|1;;miPbB%oJnB9ZF zdo^Y4SZADWxKo5a-z&zq{uZc|GBM^5oek-(2(J35x{h{QeNK{0u~lZqv-3+_8wDRO zVNDw8iR+H^s~`A5dX<+7&Q7${E?o2N@dDpFYG@lm_%zxOc1Hf}Y`ipz|Nlq z#}Z4Qo}y}Fo^dna$We_6F)UaL8$|tYk%r^brwm_uae6*AMO;^4=fq^418f~K!?0F$ zfl8NLmDp-OtT^p~^OED24w%x#=cJC&k-R-R>1WJAoj+Hu6J!aaOO5?h6ritlIWf3lN zA`0C=@?`benjH)y^H!@^${VeUz#)67OZ~m+tj)uql^>3#A9uv+ ziK{&;4L34vs%BXrQQ|Ujz|G`vdn^C1n9SgwYX)N1e4ZkJ(iS|bJbsIJFg_L_>D}K1 zifN{r%Vm`lsAH~aWb+_r`JF0qv0kwxf23kA^z3`5U#y6{>Oscy$^4f>{Mw`*8h5B& z^rhxD_p(TjZm^&ha)O&;iM%$1o}6fMQ{qtLVaUpgS|K<)YSVSaOoWu?=B@<;CpN?x zh^+EbO}yhaLJ%50P@l)UC9Mb#o^Qf&&_|}QMSLK#VGFH6$wpvvq<>R zZT@@7nQZV)xc|n-y1+8Em`io?In*x#e}6fV^BqIv)-+24`?-6Zu_V#&V#*>EWA)F* za@asc+qg?9KMrIi3%nrk^2=;=A0PRh@6Fkd&Xs>ACP~e%n$LjLnnNrux1iQ}GV&i?HzY+ti>CfDU=$_kNk19%V6sSxlXT z?7qbchGn zFk~s-?6lTOOA3A!6=R`-U9XWJxcb|IY3bGBM}3W0StkQC;fO%I>x4;fuW<6~3WyF6ovG}?G29m*7sWDlg-S5n#6cw#yXGza4cJn^KhHG_t9-Qaw?pnX~ z9f_gezD>Xd9eMXE85R$Rl1nb&)N zPc@MZmR=`O{nRfd`i|p_3=vSn`jLK(JhY0@J?iZ^FSlLf%cwmxg8SZV*?LxY(D0&G z-%xt8Y5#+1AY&c)!fufLp}3V|a=cONbj56{VAareSk2m5GmY~|s$(s?D%cuKp; zf>$gqv3#LTs3x`fj^;8gvgMJNv5M;wVH-1t)`?95Gf#t- zQ|$_%7zTjfS%!71#(H!OTZhDH_Agyk=rg2ZMjW|+sElPFx&T3OD8R3G4dnVsj&C{Y z8FwY419Xs9(b=D_VRESL-|Bd$J8Iload9zZ)>Fz*=BFscGch{fY4*bTE1| zjz;z>GMDfS#L9W5SS_wZPv0O&#jY%+QT*gGdC`<6U4(j6yidCy_gG!$rNVrY7BAJ@ z%+PIdBB2lEW5Rtj8RQ3vwuZ|H5r7k%Rl+TNy9-egnqB_JTjEV>r*d3VC5vhzzh2+xd%JL|~SZr92U>0Lxe}w^WN9dC{ck8h!-aCz87+zerMKts= zY<(S7{Izir(!hH-cQJQAdRAxSP;9|i28wdNCo4l-^=hnV&6!Ff%TdQaR45CN3%#Yv zy_5BYxKyfI%YJXr0=C%{=M|;%4OX7Img;~+k*NwPvyu+)D5o#)i@YTqYAwM24_Hv_ zmnsEN004WG008I@Sp0uLA?fAn?)M+4Vm|19sp6kXfqKg)%0bCu|3MS)pEo{1r#g~} zs{NLP*t^G=>uPIT{qeEN3Jm593IZG_!At9eyGr=pCb_V~yQLHdnthT3T$8e9Y)5C^^luju7#yMQniF0> zzcq^E*a+Wy?bMB-vA@3*f4>;;{HN=n%Ja`8!xzXSW|5Inn*j*1Tk}qpqdbsegmzQi zgh}R|XPl}cIr!10UIhW%<>i)LML5}^R%U%M3Po`M#pbSmOWU!myZVkA&8hFCyxN>nzo29eq(uSjDM7ono^gzl1 zwQpaP_!-Q{4Uz#>kc#6NabvM>efU64}", 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 58/78] 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 1e9439268fbcfcabb8b3b5084b283b19109e3583 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Wed, 30 Oct 2024 14:51:18 +0100 Subject: [PATCH 59/78] io id --- config/machine_settings/st-ten-6.ini | 10 ++++++++++ src/components/usb_586x.py | 2 +- src/ui/recipe_selection/recipe_selection.py | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/config/machine_settings/st-ten-6.ini b/config/machine_settings/st-ten-6.ini index fb9a248..5eacccf 100644 --- a/config/machine_settings/st-ten-6.ini +++ b/config/machine_settings/st-ten-6.ini @@ -13,22 +13,31 @@ tecna_t3: present vision_saver: absent vision: absent screwdriver: absent +#digital_io: present digital_io_flush_blow: present second_leak_test: present external_flush_blow: present # EXTERNAL BOX CONTROLLING MULTI-CHANNEL TEST (IF PRESENT), BLOW-CLEANING AND EXTERNAL FLUSH dual_channel: present +#fixture_id: present [tecna_t3] port: COM4 model: t3l [neo_pixels] +port: COM6 + +[fixture_rfid] port: COM5 [label_printer] platform: windows printer: zd421 +[digital_io] +# OUTPUT MAP FOR FIXTURE CONNECTOR +id: USB-5862,BID#1 + [digital_io_flush_blow] id: USB-5860,BID#0 # OUTPUT MAP FOR EXTERNAL FLUSH/BLOW UNIT @@ -79,6 +88,7 @@ tempo_svuotamento_2: 1 pressione_svuotamento_2: 100 canale_di_prova_2: 1 modello_etichetta: EtichettaR5_Montaggio_1prova.prn +pid_pressure_correction: 105 [autotest_leak] enabled: true diff --git a/src/components/usb_586x.py b/src/components/usb_586x.py index c4a954b..52fc2e4 100644 --- a/src/components/usb_586x.py +++ b/src/components/usb_586x.py @@ -44,7 +44,7 @@ class USB_586x(Component): self.mutex = QMutex() self.simulate="--sim-io" in sys.argv # DEVICE INFORMATION - self.id=config["digital_io"]["id"] + self.id=config[self.name]["id"] if "5860" in self.id: self.type = "5860" self.in_size = 1 diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 9c7b2e1..f62b4f4 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -383,7 +383,7 @@ class Recipe_Selection(Widget): data = [] fieldnames = [ recipe_name_field, - "cliente", + "cliente", "part_number", "dimensione_lotto_abilitata", "dimensione_lotto", From 994c9958a4d08fac287aecda2ca019536c32e944 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 30 Oct 2024 14:52:03 +0100 Subject: [PATCH 60/78] 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 61/78] 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 62/78] 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 63/78] 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 64/78] 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 65/78] 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 66/78] 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 zcmb`LWl$6f*T;7kM5P5pY6HElg8#LB@H?r8PO!^#ce>I=-d|7TPlg7W}?4`2lR9Y6pT zp!WW{Up)UJ@Sh6X(ScR@Rh$pU*Di#Lwc!vC5AiMvWpa|aOn)?ba+r(0nfo3@e`1!t zwIaBq%El`y)*Q9=lhhnlw#D=zCRsLAQj+$aO|9=1ZR!wV@^4X&&jEaVhRrFPxcKJp zeHafqt<`b=qUBM5sCB(zEWnpY&&=@=%1+`Ed&_7+A;xwgjtoQ`pNKyl6kO)h8JT%} z{8B>1#9DRF07Eg#+66*jAv}Rpi+9CgGSLtSt9;k-V8eX4Fw;OD9h`=V9($I)cXj3J zb@SvVJjZ9k2;-drKJVWhmwM(BW8i)_+fVxwMRu?*0@r%q4sD5yNh!BZUMFIH z-GBES!Ky&AoPMj~n6?mWh0hK@Ts2NJCC~wnMQ)H-dqgY`M4NrFlyNoN{0jCBgO}bk zL`|h^-I#mV1rcSE|E8v_4_B!j{5bQ`n`ATBka)xH^TMF4xO?e))79aMAyHcgQrnZk zg^KJIM>dT0wBGj>=OBoJzq(lp5)Ez2qXr6`ye}k?eDvD|JJI~E}$7E1>DO)Hm6FYRWYqxZBP?3P17%)nedlAs#Z`sYm=$;EzHBlJXfVXd$lIeb!E1rQwa|B(T9mKA!JC$k zR3QiE3rPZOVuhT^s*C!Q@~Che{0{V#_(x#vJIuDtqZ&ff{G1J8Sa_`TGx1f%g^`jn zlGd%NJz6^?6;By~)An9Yp@Rz4Cw!KI-ZC=blFUlg>v<`tkDdw4Ti3}$R91P>eDBu- zPbxcYg>Mv$J&Tp!c3BOQ8bW?VL;4<`gbb6%o^fXqtt$s3yyZxz$3wMeUrGs_)T4Ob z^7xU8G(5J=`K%w;mJ5Gv=@uY6Jgro?caMJJLEW`AhxFqnRu>p5c66xs#$p}CvDs+V zvD{wZ*Zb-V`AvWuCv)Ve>6>Jmye?#}SZa$Z_>Gcc+v{Ja6A3=Xw+4b+Q@BsDW%nLWf)Jm9$GvSsbLlOfK)U}A5*vAHw( zb9&3IzGgf7dhpcR`-NbQ@`u{_tEE^Tg)Aa-2Rd@55$wA+{RKmufu;*u^%buz`O&3m=Ewe#Kl zC>DMQTXMMu2n%ZYdRfgLe;4_UD5!say?@ZBK>i`CHnU?B{Np9uiFvPQWQ0;9BL3_g znoP@@S3!38{6<1aGU2Iqha^ijEcGwd*eW+g=I-!I_1cN2`wT}eM_w3pW|xsOq)Y}b zEnocEt)SlWr&A)uFsfz8=IKKChqhe`U*DbWS-WDv7}~7n$Y`*%=X~u@wf6Spby!L; zzu%K$kLvxRRS$#iSxOf38l0fZ2Rjke3jsSczM7v?$|m)j(tHe-&aAno4PrK2Mu&En zYae}DVQWL^BquteaWn3jbz3wo`T4y$EEB>_+oEIQ=uqO=_;q?alu9wGa~eshfL;^B zv01Tl2yP1&5C|sIqtbB!V!iQD{M20ctB$@|JJgh4jn3?Reft@j zT%b@@OXW+=+QPs<=4hp37WfTP!~pZc@`B(h&NCX$&c#-x58|a~zu=l46V9XEj(b5f zBfsz|I|G~tNGzv0AgOPF$iK2f4CL6C+bj|FdITrpBUN?hI@L9C1Ki&?oYp&gha%Jq z_7SHCk~wJ(M`BY^4of~@%o&yOP}6;=sc|F|_Clr(cJ!v3Zxy1RZW%Ew1I-B94}YBQ zm@#!5X?@)pMbvJ}P_ljORWR9n?*p{}?&RkJKB`_QH;s0*eJ>>7z-?ahgieP78t0I* zm@kVmP-VK%E+p|jiaOf7C7Brx@gx{)zDg05`wQMI^eusXO2R?kY+ef9wnh+=3zUi; z$~WweaqyAaF{>-9X4rktLMqq}x|&@1&=pxsyE*n_V7SUvb(FFE?tS$tqi5IzE_NM+ zw+hUW&tktyy9v_C)^Ppe#j%hNxsELdvNW7?FC+!z!wG?vD6R&y^|*gjiBx2livpdy z3TuBs6n|1Y0d>kQLLlzW@O4B&AWxw;K|f_%dmh;@wd&19;VU@{qFR+@m>}^!_xKf= zr%At}8R;*Mvv+sF@ft6`1~BJ?AGwXJ8w3u3&TZdfh?>e?J}cbF?54{? zlWHaJ<_~3M4l~NBPh!j?bLkx@Yk~#Py4?xY#ys;y@11F=pVg1tl``JfV zMcefBFgQVD^7FeN)cimEB93|bj>Vli1J+|cOJP$S%1Bi9f_mgy93&?hr~Mgpyrb-$ ze;?ij6SIorRz`h4?Dc+6TooHd*YC3|Z#i(OfwR!NvRBkKVrUq-%3@KZ8;rJa4ko-^+tgXn zr;u(Q1+>1x7X4a>V+&$B|cG@AHOTbEfL!U#&P} zZ}hhVf}HrOKwV$(D~}B8sYDLm?!iFn9mAL_F|h|yXWCV)Gf9BnXCTYQk@6_skQ?WM zB}J@o*=m51n{X&}@hsg~qchpGuC&KOJudK4kjsuA1k|(NB;v1nTw#!GB(UwPQ0vFv zOzD+g7%jENrf*iJXy93KvR8cw&EnyGu9_ZCz>RRO-dxDpZO%2>4}I*~QhhG6nMXh> z78n7k zJ*7w=gGtuz!?76ekkzJ#`WaL&_Wf7Z@2u*~UeGkXdmk!C|xsSJPE^vrw8!3pLF<5pqU0e7#%QY zRNX5b{BhvnK6w39LUh~kNkekRySa=ml?-b3O~Y1eVqk((7}IMX8x<$adCP<00Q3*j zt%W{W;xkW{q*q-q@B~*t^njH*V{!Ptc&5=;T&PbM8dMS8Fd>qlZQJM_UC&Bnr9=1;3G|Qm6*6ezZK9;@g2VsWSUuRuyik0A&yapSSQ7`f>xn#^L>62*ZdlGc^ zWDTE|I~l-)fE`S+vVd`UE}@-+Q$hTwpXEb)Ow%Weu0g0^NMBG8LyDDEQ^qsi)0qM7(^LpL@tHq-V-@&%hp>o!oLDbg_IDEpCZ00!LXy-wDdme$q-CQZ z>n3|#8rnu`Jss|$ZlEJ0Dc1`rH9sfP)LdfdomOTlpFQ*k7kPTs1RIaa6UguRMV7bz z$W(G&UE5XUe`OtnPaxbLp!>94cCrthoiyz6i<5vTOwg@$G~v9UBt@ULi0^2Nd>*R? zuT#0}m;_71zI!H@l#p*zmLxV9!F*4dhO~YvBC|Hq`5e^6WH)B&(NesLyMCcLN%c3a z@UH>k>&b1`+NY}L<_vLHE%12@`4qztEYa?M!lCN)!6=s5E-jyEX+X^VaNH?-MWf@ z9M*m^e=ZX-=5)-XgDT%~=*fGRTgOSFo5r!o6}ax;j*fPAS_m?bT`!Ps zHg1651_Ixu#wD3Sk`9`xV0XhQ@&aB95j45nb1A-7Xj;SG&MNIG{5A8FD<`9e@H3 zQWDy&#;v=|yQg@v2Kp#4eiL-(P3eE3btrdCO=c7X5G5^@6o(qqx8|CLf8u+R*vh0hnai_irK Date: Tue, 5 Nov 2024 17:19:17 +0100 Subject: [PATCH 67/78] 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 68/78] 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 69/78] 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 70/78] 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 71/78] 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 72/78] 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 73/78] 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 74/78] 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 75/78] 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 76/78] 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 77/78] 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() From 8474729dd27cccd5066b63a3f63ae499cfde0d62 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Fri, 15 Nov 2024 12:28:28 +0100 Subject: [PATCH 78/78] fix --- config/machine_settings/st-ten-6.ini | 4 +-- src/ui/test/test.py | 44 ++++++++++++++-------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/config/machine_settings/st-ten-6.ini b/config/machine_settings/st-ten-6.ini index 5eacccf..4e3807f 100644 --- a/config/machine_settings/st-ten-6.ini +++ b/config/machine_settings/st-ten-6.ini @@ -36,7 +36,7 @@ printer: zd421 [digital_io] # OUTPUT MAP FOR FIXTURE CONNECTOR -id: USB-5862,BID#1 +id: USB-5860,BID#0 [digital_io_flush_blow] id: USB-5860,BID#0 @@ -88,7 +88,7 @@ tempo_svuotamento_2: 1 pressione_svuotamento_2: 100 canale_di_prova_2: 1 modello_etichetta: EtichettaR5_Montaggio_1prova.prn -pid_pressure_correction: 105 +pid_pressure_correction: 0 [autotest_leak] enabled: true diff --git a/src/ui/test/test.py b/src/ui/test/test.py index c1bfaa3..1107316 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -688,31 +688,31 @@ class Test(Widget): "DESCRIPTION": self.labellify(recipe.get("description", "-")), "RECIPE_TO_PRINT": self.labellify(self.print_step.spec.get("labeltxt_5", "-").replace('{N11}', '')), # STEP SPEC - "TPREFILL": self.labellify(leak_test_1_step_spec.get("pre_filling_time", "-")), - "PPREFILL": self.labellify(leak_test_1_step_spec.get("pre_filling_pressure", "-")), - "TFILL": self.labellify(leak_test_1_step_spec.get("filling_time", "-")), - "TSET": self.labellify(leak_test_1_step_spec.get("settling_time", "-")), - "TPREFILL2": self.labellify(leak_test_2_step_spec.get("pre_filling_time", "-")), - "PPREFILL2": self.labellify(leak_test_2_step_spec.get("pre_filling_pressure", "-")), - "TFILL2": self.labellify(leak_test_2_step_spec.get("filling_time", "-")), - "TSET2": self.labellify(leak_test_2_step_spec.get("settling_time", "-")), - "PSETMINP": self.labellify(leak_test_1_step_spec.get("settling_pressure_min_percent", " -")), - "PSETMAXP": self.labellify(leak_test_1_step_spec.get("settling_pressure_max_percent", " -")), - "PSETMINP2": self.labellify(leak_test_2_step_spec.get("settling_pressure_min_percent", " -")), - "PSETMAXP2": self.labellify(leak_test_2_step_spec.get("settling_pressure_max_percent", " -")), + "TPREFILL": self.labellify(leak_test_1_step.get("pre_filling_time", "-")), + "PPREFILL": self.labellify(leak_test_1_step.get("pre_filling_pressure", "-")), + "TFILL": self.labellify(leak_test_1_step.get("filling_time", "-")), + "TSET": self.labellify(leak_test_1_step.get("settling_time", "-")), + "TPREFILL2": self.labellify(leak_test_2_step.get("pre_filling_time", "-")), + "PPREFILL2": self.labellify(leak_test_2_step.get("pre_filling_pressure", "-")), + "TFILL2": self.labellify(leak_test_2_step.get("filling_time", "-")), + "TSET2": self.labellify(leak_test_2_step.get("settling_time", "-")), + "PSETMINP": self.labellify(leak_test_1_step.get("settling_pressure_min_percent", " -")), + "PSETMAXP": self.labellify(leak_test_1_step.get("settling_pressure_max_percent", " -")), + "PSETMINP2": self.labellify(leak_test_2_step.get("settling_pressure_min_percent", " -")), + "PSETMAXP2": self.labellify(leak_test_2_step.get("settling_pressure_max_percent", " -")), "PSETMINP_A": self.labellify(psetminp_a), "PSETMAXP_A": self.labellify(psetmaxp_a), "PSETMINP2_A": self.labellify(psetminp2_a), "PSETMAXP2_A": self.labellify(psetmaxp2_a), - "TTEST": self.labellify(leak_test_1_step_spec.get("test_time", "-")), - "TTEST2": self.labellify(leak_test_2_step_spec.get("test_time", "-")), - "PMIN": self.labellify(leak_test_1_step_spec.get("test_pressure_qneg", "-")), - "PMIN2": self.labellify(leak_test_2_step_spec.get("test_pressure_qneg", "-")), - "PTEST": self.labellify(leak_test_1_step_spec.get("test_pressure", "-")), - "PTEST2": self.labellify(leak_test_2_step_spec.get("test_pressure", "-")), - "PMAX": self.labellify(leak_test_1_step_spec.get("test_pressure_qpos", "-")), - "TFLUSH": self.labellify(leak_test_1_step_spec.get("flush_time", "-")), - "PFLUSH": self.labellify(leak_test_1_step_spec.get("flush_pressure", "-")), + "TTEST": self.labellify(leak_test_1_step.get("test_time", "-")), + "TTEST2": self.labellify(leak_test_2_step.get("test_time", "-")), + "PMIN": self.labellify(leak_test_1_step.get("test_pressure_qneg", "-")), + "PMIN2": self.labellify(leak_test_2_step.get("test_pressure_qneg", "-")), + "PTEST": self.labellify(leak_test_1_step.get("test_pressure", "-")), + "PTEST2": self.labellify(leak_test_2_step.get("test_pressure", "-")), + "PMAX": self.labellify(leak_test_1_step.get("test_pressure_qpos", "-")), + "TFLUSH": self.labellify(leak_test_1_step.get("flush_time", "-")), + "PFLUSH": self.labellify(leak_test_1_step.get("flush_pressure", "-")), # ACTUAL TESTED VALUES "RESPFILL": self.labellify(leak_test_1_results.get("Running test: filling pressure", "-")), "RESPFILL2": self.labellify(leak_test_2_results.get("Running test: filling pressure", "-")), @@ -750,7 +750,7 @@ class Test(Widget): # RESULT "RESULT": str("CONFORME" if leak_test_1.get("ok", False) else "SCARTO") + str(" FORZATO" if self.data.get("overridden", False) else ""), "RESULT_L1": "ESITO" + str(" FORZATO" if self.data.get("overridden", False) else ""), - "RESULT_L2": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO"), + "RESULT_L2": str("CONFORME" if leak_test_1.get("ok", False) else "SCARTO"), } #TESTING BROTHER label_brother = context.get("RECIPE_TO_PRINT", "-") + context.get("DD","-") + context.get("MO","-") + context.get("YY","-") + context.get("SN5","-")