Merge branch 'backup-ricette'

This commit is contained in:
edo-neo 2025-09-15 10:13:09 +02:00
commit ac5eae8241
5 changed files with 376 additions and 145 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 464 KiB

View File

@ -3,6 +3,7 @@ import csv
import locale import locale
from datetime import datetime from datetime import datetime
import shutil import shutil
import socket
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QFileDialog from PyQt5.QtWidgets import QFileDialog
@ -130,7 +131,7 @@ def read_steps(row, config, defaults=None, unsupported_steps=None):
"chan_sel": safe_parse(row.get("canale_di_prova_2", defaults["canale_di_prova_2"])), "chan_sel": safe_parse(row.get("canale_di_prova_2", defaults["canale_di_prova_2"])),
"ext_flush_time": safe_parse(row.get("tempo_svuotamento_esterno_2", defaults["tempo_svuotamento_esterno"])), "ext_flush_time": safe_parse(row.get("tempo_svuotamento_esterno_2", defaults["tempo_svuotamento_esterno"])),
"ext_blow_time": safe_parse(row.get("tempo_soffiaggio_esterno_2", defaults["tempo_soffiaggio_esterno"])), "ext_blow_time": safe_parse(row.get("tempo_soffiaggio_esterno_2", defaults["tempo_soffiaggio_esterno"])),
"pid_pressure_correction": safe_parse(row.get("pid_pressure_correction", defaults["pid_pressure_correction_2"])), "pid_pressure_correction": safe_parse(row.get("pid_pressure_correction_2", defaults["pid_pressure_correction_2"])),
"pid_mod_config": safe_parse(row.get("pid_mod_config", defaults["pid_mod_config"])), "pid_mod_config": safe_parse(row.get("pid_mod_config", defaults["pid_mod_config"])),
}, },
"vision": { "vision": {
@ -287,7 +288,66 @@ def import_recipes(config, csv_path=None, defaults=None, unsupported_steps=None,
logger.error(f"Error importing recipes: {e}") logger.error(f"Error importing recipes: {e}")
raise raise
FIELDNAMES = [
"codice_ricetta",
"cliente",
"part_number",
"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",
"pid_pressure_correction",
"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",
"pid_pressure_correction_2",
"tempo_svuotamento_2",
"pressione_svuotamento_2",
"test_visione_abilitato",
"ricetta_visione",
"stampa_etichetta_abilitata",
"modello_etichetta",
"labeltxt_1",
"labeltxt_2",
"labeltxt_3",
"labeltxt_4",
"labeltxt_5"
]
def export_recipes(config, csv_path=None, logger=None): def export_recipes(config, csv_path=None, logger=None):
# ... (QFileDialog logic remains the same) ...
if csv_path is None: if csv_path is None:
options = QFileDialog.Options() options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog options |= QFileDialog.DontUseNativeDialog
@ -314,31 +374,29 @@ def export_recipes(config, csv_path=None, logger=None):
barcode_serial_field = config.get("recipe", {}).get("barcode_serial_field", "codice_a_barre").strip() barcode_serial_field = config.get("recipe", {}).get("barcode_serial_field", "codice_a_barre").strip()
print_template_field = config.get("recipe", {}).get("label_template_field", "modello_etichetta").strip() print_template_field = config.get("recipe", {}).get("label_template_field", "modello_etichetta").strip()
data = [] data = []
fieldnames = set() # Use a set to avoid duplicates
# Wrap database operations in a transaction for consistency # Wrap database operations in a transaction for consistency
with db.atomic(): with db.atomic():
# Iterate over all recipes in the database
for recipe in Recipes.select(): for recipe in Recipes.select():
try: try:
steps = recipe.get_steps_map() steps = recipe.get_steps_map()
exportable = {
# Base fields # Create a dictionary with default values for all fields
exportable = {field: "" for field in FIELDNAMES}
# Populate the dictionary with recipe data
exportable.update({
recipe_name_field: recipe.name, recipe_name_field: recipe.name,
"cliente": recipe.client, "cliente": recipe.client,
"part_number": recipe.part_number, "part_number": recipe.part_number,
} })
# Add base fields to the fieldnames # Conditionally update the dictionary for each step
fieldnames.update([recipe_name_field, "cliente", "part_number"])
# Check and add steps conditionally
if "connector" in steps: if "connector" in steps:
exportable.update({ exportable.update({
"verifica_connettore_abilitata": "x", "verifica_connettore_abilitata": "x",
"connettore": steps["connector"].spec["connector"] "connettore": steps["connector"].spec["connector"]
}) })
fieldnames.update(["verifica_connettore_abilitata", "connettore"])
if "resistance" in steps: if "resistance" in steps:
exportable.update({ exportable.update({
@ -348,22 +406,18 @@ def export_recipes(config, csv_path=None, logger=None):
"tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"], "tolleranza_resistenza_pos": steps["resistance"].spec["tolerance_pos"],
"tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"], "tolleranza_resistenza_neg": steps["resistance"].spec["tolerance_neg"],
}) })
fieldnames.update(["verifica_resistenza_connettore_abilitata", "scala_resistenza", "r nominale",
"tolleranza_resistenza_pos", "tolleranza_resistenza_neg"])
if "barcodes" in steps: if "barcodes" in steps:
exportable.update({ exportable.update({
barcode_enable_field: "x", barcode_enable_field: "x",
barcode_serial_field: steps["barcodes"].spec["serial"] barcode_serial_field: steps["barcodes"].spec["serial"]
}) })
fieldnames.update([barcode_enable_field, barcode_serial_field])
if "screws" in steps: if "screws" in steps:
exportable.update({ exportable.update({
"avvitatura_abilitata": "x", "avvitatura_abilitata": "x",
"viti": steps["screws"].spec["quantity"] "viti": steps["screws"].spec["quantity"]
}) })
fieldnames.update(["avvitatura_abilitata", "viti"])
if "leak_1" in steps: if "leak_1" in steps:
exportable.update({ exportable.update({
@ -374,8 +428,6 @@ def export_recipes(config, csv_path=None, logger=None):
"pressione_di_test": steps["leak_1"].spec["test_pressure"], "pressione_di_test": steps["leak_1"].spec["test_pressure"],
"pid_pressure_correction": steps["leak_1"].spec["pid_pressure_correction"], "pid_pressure_correction": steps["leak_1"].spec["pid_pressure_correction"],
}) })
fieldnames.update(["prova_tenuta_abilitata", "tempo_pre_riempimento", "pressione_pre_riempimento",
"tempo_di_test", "pressione_di_test"])
if "leak_2" in steps: if "leak_2" in steps:
exportable.update({ exportable.update({
@ -386,29 +438,30 @@ def export_recipes(config, csv_path=None, logger=None):
"pressione_di_test_2": steps["leak_2"].spec["test_pressure"], "pressione_di_test_2": steps["leak_2"].spec["test_pressure"],
"pid_pressure_correction": steps["leak_1"].spec["pid_pressure_correction"], "pid_pressure_correction": steps["leak_1"].spec["pid_pressure_correction"],
}) })
fieldnames.update(["prova_tenuta_abilitata_2", "tempo_pre_riempimento_2", "pressione_pre_riempimento_2",
"tempo_di_test_2", "pressione_di_test_2"])
if "vision" in steps: if "vision" in steps:
exportable.update({ exportable.update({
"test_visione_abilitato": steps["vision"].spec.get("enabled", ""), "test_visione_abilitato": steps["vision"].spec.get("enabled", ""),
"ricetta_visione": steps["vision"].spec["recipe"] "ricetta_visione": steps["vision"].spec["recipe"]
}) })
fieldnames.update(["test_visione_abilitato", "ricetta_visione"])
if "print" in steps: if "print" in steps:
exportable.update({ exportable.update({
"stampa_etichetta_abilitata": "x", "stampa_etichetta_abilitata": "x",
print_template_field: steps["print"].spec["template"], print_template_field: steps["print"].spec.get("template", ""),
# Add the labeltxt fields here
"labeltxt_1": steps["print"].spec.get("labeltxt_1", ""),
"labeltxt_2": steps["print"].spec.get("labeltxt_2", ""),
"labeltxt_3": steps["print"].spec.get("labeltxt_3", ""),
"labeltxt_4": steps["print"].spec.get("labeltxt_4", ""),
"labeltxt_5": steps["print"].spec.get("labeltxt_5", ""),
}) })
fieldnames.update(["stampa_etichetta_abilitata", print_template_field])
# Append the exportable row to the data # Append the exportable row to the data
data.append(exportable) data.append(exportable)
except Exception as e: except Exception as e:
if logger: if logger:
logger.error(f"Error processing recipe {recipe.name}: {e}") logger.error(f"Error processing recipe {recipe.name}: {e}")
# Continue with next recipe instead of failing the entire export
continue continue
except Exception as e: except Exception as e:
if logger: if logger:
@ -419,8 +472,8 @@ def export_recipes(config, csv_path=None, logger=None):
if len(data): if len(data):
if logger: if logger:
logger.info(f"Exporting recipes to {csv_path}") logger.info(f"Exporting recipes to {csv_path}")
with open(csv_path, "w", newline="") as f: with open(csv_path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=list(fieldnames)) writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
writer.writeheader() writer.writeheader()
writer.writerows(data) writer.writerows(data)
if logger: if logger:
@ -429,18 +482,38 @@ def export_recipes(config, csv_path=None, logger=None):
def backup_current_recipes(config, logger=None): def backup_current_recipes(config, logger=None):
""" """
Back up current recipes to a timestamped CSV file in the predefined backup directory. Back up current recipes to a CSV file in a single common folder. The file name equals the
[machine]/description from the active machine config (sanitized). Saving overwrites any
previous backup with the same machine description.
""" """
# Define the backup directory and file name # Get machine description from config; fall back to hostname if missing
machine_desc = None
try:
machine_desc = (config.get("machine", {}) or {}).get("description")
except Exception:
machine_desc = None
if not machine_desc:
machine_desc = socket.gethostname()
# Sanitize description to be safe as a file name
safe_name = str(machine_desc).strip()
# Replace path separators and common forbidden characters on Windows/Unix
for ch in ['\\', '/', ':', '*', '?', '"', '<', '>', '|']:
safe_name = safe_name.replace(ch, '_')
# Also collapse consecutive spaces
safe_name = ' '.join(safe_name.split())
# Ensure .csv extension
if not safe_name.lower().endswith('.csv'):
safe_name = f"{safe_name}.csv"
# Define the single backup directory and file path
backup_dir = os.path.join('config', 'csv_import', 'backup_csv') backup_dir = os.path.join('config', 'csv_import', 'backup_csv')
timestamp = datetime.now().strftime("%d%m%y%H%M%S") backup_path = os.path.join(backup_dir, safe_name)
backup_file = f"backup_{timestamp}.csv"
backup_path = os.path.join(backup_dir, backup_file)
# Ensure the backup directory exists # Ensure the backup directory exists
os.makedirs(backup_dir, exist_ok=True) os.makedirs(backup_dir, exist_ok=True)
# Export current recipes to the backup path # Export current recipes to the backup path (export_recipes overwrites the file)
export_recipes(config=config, csv_path=backup_path, logger=logger) export_recipes(config=config, csv_path=backup_path, logger=logger)
if logger: if logger:

View File

@ -3,6 +3,9 @@ import argparse
import faulthandler import faulthandler
import logging import logging
import os import os
from src.lib.helpers.recipe_manager import backup_current_recipes
os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION']="python" os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION']="python"
import platform import platform
import signal import signal
@ -77,7 +80,7 @@ try:
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMessageBox, QInputDialog, QLineEdit from PyQt5.QtWidgets import QApplication, QMessageBox, QInputDialog, QLineEdit
import sip import sip
from ui import About, Archive, Login, Main_Window, Test, Users_Management,Logs_Management ,Recipe_Selection, \ from ui import About, Archive, Login, Main_Window, Test, Users_Management, Logs_Management, Recipes_Management , Recipe_Selection, \
Barcode_Recipe_Selection, LastCommit Barcode_Recipe_Selection, LastCommit
if "--vision" in sys.argv: if "--vision" in sys.argv:
@ -215,6 +218,7 @@ try:
self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode) self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode)
self.main_window.ristampa_etichetta_a.triggered.connect(self.reprint_label) self.main_window.ristampa_etichetta_a.triggered.connect(self.reprint_label)
self.main_window.tag_a.triggered.connect(self.tag_write) self.main_window.tag_a.triggered.connect(self.tag_write)
self.main_window.recipes_export_a.triggered.connect(self.trigger_recipe_backup)
if "pipe_cutter" in self.components.keys(): if "pipe_cutter" in self.components.keys():
self.main_window.cut_a.setVisible(True) self.main_window.cut_a.setVisible(True)
self.main_window.cut_a.triggered.connect(self.cut_tube) self.main_window.cut_a.triggered.connect(self.cut_tube)
@ -496,6 +500,26 @@ try:
def load_recipe_from_rfid(self, data): def load_recipe_from_rfid(self, data):
self.tag_loaded_recipe = data self.tag_loaded_recipe = data
def trigger_recipe_backup(self):
"""
This method acts as a bridge to call the imported backup function.
"""
try:
# Use the imported function and pass the required objects
backup_current_recipes(config=self.config, logger=logging)
QMessageBox.information(
self.main_window,
"Esportazione Riuscita",
"Backup delle ricette creato con successo."
)
except Exception as e:
logging.exception("Error during recipe backup")
QMessageBox.critical(
self.main_window,
"Errore di Esportazione",
f"Si è verificato un errore durante il salvataggio: {e}"
)
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)

View File

@ -25,7 +25,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>843</width> <width>843</width>
<height>27</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuAbout"> <widget class="QMenu" name="menuAbout">
@ -55,6 +55,7 @@
<addaction name="save_tecna_recipes_a"/> <addaction name="save_tecna_recipes_a"/>
<addaction name="diagnostics_a"/> <addaction name="diagnostics_a"/>
<addaction name="admin_enable_a"/> <addaction name="admin_enable_a"/>
<addaction name="recipes_export_a"/>
</widget> </widget>
<widget class="QMenu" name="menuStrumenti"> <widget class="QMenu" name="menuStrumenti">
<property name="font"> <property name="font">
@ -170,6 +171,11 @@
<string>Ultima Versione Software</string> <string>Ultima Versione Software</string>
</property> </property>
</action> </action>
<action name="recipes_export_a">
<property name="text">
<string>Backup ricette</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -184,15 +184,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active> </active>
<inactive> <inactive>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -330,15 +321,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive> </inactive>
<disabled> <disabled>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -476,21 +458,13 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled> </disabled>
</palette> </palette>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -654,15 +628,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active> </active>
<inactive> <inactive>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -800,15 +765,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive> </inactive>
<disabled> <disabled>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -946,21 +902,13 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled> </disabled>
</palette> </palette>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -1130,15 +1078,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active> </active>
<inactive> <inactive>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -1276,15 +1215,6 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive> </inactive>
<disabled> <disabled>
<colorrole role="WindowText"> <colorrole role="WindowText">
@ -1422,21 +1352,13 @@
</color> </color>
</brush> </brush>
</colorrole> </colorrole>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="128">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled> </disabled>
</palette> </palette>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -1468,6 +1390,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -1487,6 +1410,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -1534,6 +1458,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -1546,6 +1471,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1559,6 +1485,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1575,6 +1502,7 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1599,6 +1527,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1623,6 +1552,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1641,6 +1571,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1659,6 +1590,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1672,6 +1604,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1688,6 +1621,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1701,6 +1635,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1714,6 +1649,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1730,6 +1666,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1752,6 +1689,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1776,6 +1714,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1800,6 +1739,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1818,6 +1758,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1837,6 +1778,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1872,6 +1814,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1885,6 +1828,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1901,6 +1845,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1923,6 +1868,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1947,6 +1893,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1965,6 +1912,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1983,6 +1931,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2017,6 +1966,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>48</pointsize> <pointsize>48</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2038,6 +1988,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2054,6 +2005,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2083,6 +2035,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2096,6 +2049,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2109,6 +2063,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2131,6 +2086,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2149,6 +2105,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2171,6 +2128,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2189,6 +2147,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2205,6 +2164,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2218,6 +2178,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2242,6 +2203,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2258,6 +2220,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -2271,37 +2234,7 @@ border: 1px solid black;
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<bold>false</bold> <weight>50</weight>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);
border: 1px solid black;
</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item row="9" column="4" alignment="Qt::AlignRight">
<widget class="QLabel" name="valore_PID">
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Valore PID</string>
</property>
</widget>
</item>
<item row="9" column="7">
<widget class="QLabel" name="valore_PID_l">
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>