diff --git a/config/label_designs/STANDARD/EtichettaR5.nlbl b/config/label_designs/STANDARD/EtichettaR5.nlbl index 0769605..5af1648 100644 Binary files a/config/label_designs/STANDARD/EtichettaR5.nlbl and b/config/label_designs/STANDARD/EtichettaR5.nlbl differ diff --git a/config/label_designs/STANDARD/EtichettaR5_Pitesti.nlbl b/config/label_designs/STANDARD/EtichettaR5_Pitesti.nlbl new file mode 100644 index 0000000..6474ee4 Binary files /dev/null and b/config/label_designs/STANDARD/EtichettaR5_Pitesti.nlbl differ diff --git a/config/label_templates/ETACL-40_130.prn b/config/label_templates/ETACL-40_130.prn index 3d374dc..e445358 100644 --- a/config/label_templates/ETACL-40_130.prn +++ b/config/label_templates/ETACL-40_130.prn @@ -1,4 +1,4 @@ -SIZE 37.5 mm, 130 mm +SIZE 27.5 mm, 50 mm GAP 3 mm, 0 mm SPEED 2 DENSITY 7 @@ -10,10 +10,9 @@ SET CUTTER OFF SET PARTIAL_CUTTER OFF SET TEAR ON CLS -DMATRIX 116,270,184,184,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" +DMATRIX 82,230,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" CODEPAGE 1252 -TEXT 261,377,"ROMAN.TTF",180,1,7,"{RECIPE}-{DD}{MO}{YY}{SN5}" -DMATRIX 116,175,184,184,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" -DMATRIX 116,78,184,184,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" -BOX 13,16,287,401,3 +TEXT 212,357,"ROMAN.TTF",180,1,7,"{RECIPE}-{DD}{MO}{YY}{SN5}" +DMATRIX 82,129,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" +DMATRIX 82,28,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" PRINT 1,1 diff --git a/config/label_templates/ETACL.prn b/config/label_templates/ETACL.prn index c610911..e445358 100644 --- a/config/label_templates/ETACL.prn +++ b/config/label_templates/ETACL.prn @@ -12,7 +12,7 @@ SET TEAR ON CLS DMATRIX 82,230,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" CODEPAGE 1252 -TEXT 212,357,"ROMAN.TTF",180,1,7,"{RECIPE}-{DD}{MO}{YY}" +TEXT 212,357,"ROMAN.TTF",180,1,7,"{RECIPE}-{DD}{MO}{YY}{SN5}" DMATRIX 82,129,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" DMATRIX 82,28,138,138,x3,22,22,"{RECIPE}-{DD}{MO}{YY}{SN5}" PRINT 1,1 diff --git a/config/label_templates/EtichettaR5.prn b/config/label_templates/EtichettaR5.prn index cf1999f..fd3080f 100644 --- a/config/label_templates/EtichettaR5.prn +++ b/config/label_templates/EtichettaR5.prn @@ -18,25 +18,25 @@ ^XZ ^XA ^MMT -^PW320 -^LL1119 +^PW496 +^LL1559 ^LS0 -^FT33,86^A0N,45,46^FH\^CI28^FDERRECINQUE^FS^CI27 -^BY2,3,56^FT44,310^BCN,,N,N +^FT61,119^A0N,67,68^FH\^CI28^FDERRECINQUE^FS^CI27 +^BY2,3,83^FT77,430^BCN,,N,N ^FH\^FD>:{PART}^FS -^FT15,347^A0N,31,30^FH\^CI28^FDPart number:^FS^CI27 -^FT15,427^A0N,31,30^FH\^CI28^FD{PART}^FS^CI27 -^FT17,136^A0N,17,18^FH\^CI28^FDVia Meucci 31/A - 10079 Mappano(TO)^FS^CI27 -^FT53,193^A0N,39,38^FH\^CI28^FDFPT^FS^CI27 -^FT53,235^A0N,39,38^FH\^CI28^FDLEAK TEST^FS^CI27 -^FT15,387^A0N,31,30^FH\^CI28^FD{DESCRIPTION}^FS^CI27 -^FT15,740^A0N,31,30^FH\^CI28^FDSequential number:^FS^CI27 -^FT15,779^A0N,31,30^FH\^CI28^FD{SN5}^FS^CI27 -^FT15,856^A0N,17,18^FH\^CI28^FD{DD}/{MM}/{YY}^FS^CI27 -^FT161,856^A0N,17,18^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 -^FT17,1081^A0N,31,30^FH\^CI28^FDESITO:^FS^CI27 -^FT143,1081^A0N,31,30^FH\^CI28^FDCONFORME^FS^CI27 -^FT15,934^A0N,25,25^FH\^CI28^FDOperatore^FS^CI27 -^FT15,967^A0N,25,25^FH\^CI28^FD{OPERATOR}^FS^CI27 +^FT34,482^A0N,46,46^FH\^CI28^FDPart number:^FS^CI27 +^FT34,595^A0N,46,46^FH\^CI28^FD{PART}^FS^CI27 +^FT37,172^A0N,25,25^FH\^CI28^FDVia Meucci 31/A - 10079 Mappano(TO)^FS^CI27 +^FT91,256^A0N,58,56^FH\^CI28^FDFPT^FS^CI27 +^FT91,312^A0N,58,56^FH\^CI28^FDLEAK TEST^FS^CI27 +^FT34,530^A0N,46,46^FH\^CI28^FD{DESCRIPTION}^FS^CI27 +^FT34,1243^A0N,46,46^FH\^CI28^FDSequential number:^FS^CI27 +^FT34,1291^A0N,46,46^FH\^CI28^FD{SN5}^FS^CI27 +^FT34,1361^A0N,33,33^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT250,1361^A0N,33,33^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 +^FT37,1487^A0N,46,46^FH\^CI28^FDCHECK:^FS^CI27 +^FT223,1487^A0N,46,46^FH\^CI28^FDCONFORME^FS^CI27 +^FT34,1427^A0N,38,38^FH\^CI28^FDOperatore^FS^CI27 +^FT223,1427^A0N,38,38^FH\^CI28^FD{OPERATOR}^FS^CI27 ^PQ1,0,1,Y ^XZ diff --git a/config/label_templates/EtichettaR5_Pitesti.prn b/config/label_templates/EtichettaR5_Pitesti.prn new file mode 100644 index 0000000..7d4787a --- /dev/null +++ b/config/label_templates/EtichettaR5_Pitesti.prn @@ -0,0 +1,45 @@ +CT~~CD,~CC^~CT~ +^XA +~TA000 +~JSN +^LT0 +^MNW +^MTT +^PON +^PMN +^LH0,0 +^JMA +^PR2,2 +~SD22 +^JUS +^LRN +^CI27 +^PA0,1,1,0 +^XZ +^XA +^MMT +^PW320 +^LL1119 +^LS0 +^FT57,105^A0N,39,38^FH\^CI28^FDERRECINQUE^FS^CI27 +^FT58,148^A0N,20,20^FH\^CI28^FDVia Meucci 31/A^FS^CI27 +^FT58,173^A0N,20,20^FH\^CI28^FD10079 Mappano(TO)^FS^CI27 +^FT18,758^A0N,23,20^FH\^CI28^FD{DD}/{MO}/{YY}^FS^CI27 +^FT183,758^A0N,23,20^FH\^CI28^FD{HH}:{MI}:{SS}^FS^CI27 +^FT18,981^A0N,31,30^FH\^CI28^FDESITO:^FS^CI27 +^FT144,981^A0N,31,30^FH\^CI28^FDCONFORME^FS^CI27 +^FT24,471^A0N,25,25^FH\^CI28^FDPart number:^FS^CI27 +^FT24,513^A0N,23,23^FH\^CI28^FD{PART}^FS^CI27 +^FT24,555^A0N,25,25^FH\^CI28^FDSequential number:^FS^CI27 +^FT24,598^A0N,23,23^FH\^CI28^FD{SN4}^FS^CI27 +^FT18,833^A0N,23,23^FH\^CI28^FDOperatore:^FS^CI27 +^FT157,674^A0N,23,23^FH\^CI28^FD{RESLEAK} mbar^FS^CI27 +^FT18,674^A0N,23,23^FH\^CI28^FD{TTEST} s^FS^CI27 +^FT18,724^A0N,23,23^FH\^CI28^FD{PTEST} mbar^FS^CI27 +^BY1,3,64^FT58,384^BCN,,N,N +^FH\^FD>:{PART}^FS +^FT58,241^A0N,25,25^FH\^CI28^FD{DESCRIPTION}^FS^CI27 +^FT58,292^A0N,45,46^FH\^CI28^FDLEAK TEST^FS^CI27 +^FT165,833^A0N,23,23^FH\^CI28^FD{BADGE_NUM}^FS^CI27 +^PQ1,0,1,Y +^XZ diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index 23ac1bd..22004bd 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -162,9 +162,9 @@ settling_time: 5 settling_pressure_min_percent: 5 settling_pressure_max_percent: 5 test_time: 10 -test_pressure_min_delta: 5 +test_pressure_qneg: 5 test_pressure: 9000 -test_pressure_max_delta: 5 +test_pressure_qpos: 5 flush_time: 1 flush_pressure: 100 diff --git a/config/machine_settings/hostnames.ini b/config/machine_settings/hostnames.ini index 664d451..819d1f9 100644 --- a/config/machine_settings/hostnames.ini +++ b/config/machine_settings/hostnames.ini @@ -2,6 +2,8 @@ ST-TEN-1: st-ten-1 ST-TEN-2: st-ten-2 stten3: st-ten-3 -stten4: st-ten-4 +ST-TEN-4: st-ten-4 st-ten-5: st-ten-5 st-ten-6: st-ten-6 +st-ten-7: st-ten-7 +st-ten-8: st-ten-8 diff --git a/config/machine_settings/st-ten-1.ini b/config/machine_settings/st-ten-1.ini index 5a60b38..0a022fa 100644 --- a/config/machine_settings/st-ten-1.ini +++ b/config/machine_settings/st-ten-1.ini @@ -10,7 +10,7 @@ neo_pixels: present remote_api: absent tecna_t3: present vision_saver: present -vision: absent +vision: present screwdriver: present [tecna_t3] @@ -29,3 +29,67 @@ description_field: descrizione [label_printer] platform: windows printer: zd420 + +[recipes_defaults] + + +codice_ricetta: specificare ricetta +cliente: IVECO +part_number: specificare part number +config_elettrovalvole: 0 +warning_img: + +dimensione_lotto_abilitata: + +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: 15 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_time: 10 +test_pressure_qneg: 10 +test_pressure: 7000 +test_pressure_qpos: 5 +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/config/machine_settings/st-ten-2.ini b/config/machine_settings/st-ten-2.ini index 41cc687..621a3ef 100644 --- a/config/machine_settings/st-ten-2.ini +++ b/config/machine_settings/st-ten-2.ini @@ -39,3 +39,19 @@ pressione_di_test_delta_massimo: 30 tempo_svuotamento: 1 pressione_svuotamento: 100 config_elettrovalvole: 0 + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 5 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_time: 10 +test_pressure_qneg: 5 +test_pressure: 9000 +test_pressure_qpos: 5 +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/config/machine_settings/st-ten-5.ini b/config/machine_settings/st-ten-5.ini index 58b56e5..228f784 100644 --- a/config/machine_settings/st-ten-5.ini +++ b/config/machine_settings/st-ten-5.ini @@ -10,6 +10,7 @@ remote_api: absent tecna_t3: present digital_io: present barcode_recipe_selection: present +show_instructions: yes [tecna_t3] port: COM4 @@ -90,9 +91,9 @@ settling_time: 10 settling_pressure_min_percent: 5 settling_pressure_max_percent: 5 test_time: 10 -test_pressure_min_delta: 10 +test_pressure_qneg: 10 test_pressure: 5000 -test_pressure_max_delta: 5 +test_pressure_qpos: 5 flush_time: 1 flush_pressure: 100 relay_config: 1 \ No newline at end of file diff --git a/config/machine_settings/st-ten-6.ini b/config/machine_settings/st-ten-6.ini index 6fd8e6b..46555b6 100644 --- a/config/machine_settings/st-ten-6.ini +++ b/config/machine_settings/st-ten-6.ini @@ -3,8 +3,7 @@ description = ST-TEN-6 DOPPIA PROVA PRESSIONE 6/20 BAR [hardware_config] archive_synchronizer: present -; galaxy_camera: present -uvc_camera: present +uvc_camera: absent label_printer: present neo_pixels: present remote_api: absent @@ -28,6 +27,7 @@ printer: zd421 [digital_io] id: USB-5860,BID#0 + [recipe] recipe_name_field: codice_ricetta part_number_field: codice_prodotto @@ -38,8 +38,8 @@ description_field: descrizione dimensione_lotto_abilitata: tempo_pre_riempimento: 0 pressione_pre_riempimento: 1000 -tempo_riempimento: 15 -tempo_assestamento: 15 +tempo_riempimento: 10 +tempo_assestamento: 10 tempo_di_test: 10 percentuale_minima_pressione_assestamento: 5 percentuale_massima_pressione_assestamento: 5 @@ -52,8 +52,8 @@ config_elettrovalvole: 1 prova_tenuta_abilitata_2: tempo_pre_riempimento_2: 0 pressione_pre_riempimento_2: 1000 -tempo_riempimento_2: 20 -tempo_assestamento_2: 20 +tempo_riempimento_2: 10 +tempo_assestamento_2: 10 tempo_di_test_2: 10 percentuale_minima_pressione_assestamento_2: 5 percentuale_massima_pressione_assestamento_2: 5 @@ -69,14 +69,16 @@ modello_etichetta: EtichettaR5_Montaggio_1prova.prn enabled: true pre_filling_time: 0 pre_filling_pressure: 1000 -filling_time: 15 +filling_time: 10 settling_time: 10 settling_pressure_min_percent: 5 settling_pressure_max_percent: 5 +test_pressure: 7000 test_time: 10 -test_pressure_min_delta: 35 -test_pressure: 15000 -test_pressure_max_delta: 5 +test_pressure_qpos: 5 #Q+ Upper test leak limit +test_pressure_qneg: 15 #Q- Lower test leak limit +test_pressure_tt_qpos: 0 # 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/st-ten-7.ini b/config/machine_settings/st-ten-7.ini new file mode 100644 index 0000000..3b3e1f8 --- /dev/null +++ b/config/machine_settings/st-ten-7.ini @@ -0,0 +1,82 @@ +[machine] +description = ST-TEN-7 SECONDO BANCO IVECO DAILY ELETTRICO + +[hardware_config] +archive_synchronizer: present +uvc_camera: absent +label_printer: present +neo_pixels: present +remote_api: absent +tecna_t3: present +vision_saver: absent +vision: absent +screwdriver: absent +digital_io: present +second_leak_test: present + +[tecna_t3] +port: COM4 +model: t3l + +[neo_pixels] +port: COM5 + +[label_printer] +platform: windows +printer: zd421 + +[digital_io] +id: USB-5860,BID#0 + +[recipe] +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[recipes_defaults] +dimensione_lotto_abilitata: +tempo_pre_riempimento: 0 +pressione_pre_riempimento: 1000 +tempo_riempimento: 15 +tempo_assestamento: 15 +tempo_di_test: 10 +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: 1 +pressione_svuotamento: 100 +config_elettrovalvole: 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: 1 +pressione_svuotamento_2: 100 +config_elettrovalvole_2: 2 +modello_etichetta: EtichettaR5_Montaggio_1prova.prn + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 15 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_time: 10 +test_pressure_qneg: 35 +test_pressure: 15000 +test_pressure_qpos: 5 +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/config/machine_settings/st-ten-8.ini b/config/machine_settings/st-ten-8.ini new file mode 100644 index 0000000..f9d764b --- /dev/null +++ b/config/machine_settings/st-ten-8.ini @@ -0,0 +1,85 @@ +[machine] +description = ST-TEN-8 DAILY AUTOMATICO + +[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: present +second_leak_test: absent +fixture_id: present +discard_box: present + +[tecna_t3] +port: COM4 +model: t3l + +[label_printer] +platform: windows +printer: zd421 + +[digital_io] +id: USB-5860,BID#0 +discard_idx:15 # BIT NUMBER OF THE I/0 MODULE USED FOR DISCARD SENSING + +[fixture_rfid] +port: COM5 + +[recipe] +recipe_name_field: codice_ricetta +part_number_field: codice_prodotto +label_template_field: modello_etichetta +description_field: descrizione + +[recipes_defaults] +dimensione_lotto_abilitata: +tempo_pre_riempimento: 0 +pressione_pre_riempimento: 1000 +tempo_riempimento: 15 +tempo_assestamento: 15 +tempo_di_test: 10 +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: 1 +pressione_svuotamento: 100 +config_elettrovalvole: 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: 1 +pressione_svuotamento_2: 100 +config_elettrovalvole_2: 2 +modello_etichetta: EtichettaR5_Montaggio_1prova.prn + +[autotest_leak] +enabled: true +pre_filling_time: 0 +pre_filling_pressure: 1000 +filling_time: 15 +settling_time: 10 +settling_pressure_min_percent: 5 +settling_pressure_max_percent: 5 +test_time: 10 +test_pressure_qneg: 35 +test_pressure: 15000 +test_pressure_qpos: 5 +flush_time: 1 +flush_pressure: 100 +relay_config: 1 \ No newline at end of file diff --git a/config/vision/labels/000952054.pbtxt b/config/vision/labels/000952054.pbtxt new file mode 100644 index 0000000..12fa2ca --- /dev/null +++ b/config/vision/labels/000952054.pbtxt @@ -0,0 +1,10 @@ +item { + id: 1 + name: 'ok' + color: '0x55AA55' +} +item { + id: 2 + name: 'ko' + color: '0xff0000' +} diff --git a/config/vision/labels/labels.pbtxt b/config/vision/labels/labels.pbtxt index 4ab5798..12fa2ca 100644 --- a/config/vision/labels/labels.pbtxt +++ b/config/vision/labels/labels.pbtxt @@ -1,10 +1,10 @@ item { id: 1 - name: 'hs-ok' + name: 'ok' color: '0x55AA55' } item { id: 2 - name: 'hs-ko' + name: 'ko' color: '0xff0000' } diff --git a/config/vision/labels/termorestringente_923578.pbtxt b/config/vision/labels/termorestringente_923578.pbtxt new file mode 100644 index 0000000..4ab5798 --- /dev/null +++ b/config/vision/labels/termorestringente_923578.pbtxt @@ -0,0 +1,10 @@ +item { + id: 1 + name: 'hs-ok' + color: '0x55AA55' +} +item { + id: 2 + name: 'hs-ko' + color: '0xff0000' +} diff --git a/config/vision/recipes/000952054.ini b/config/vision/recipes/000952054.ini new file mode 100644 index 0000000..95003a3 --- /dev/null +++ b/config/vision/recipes/000952054.ini @@ -0,0 +1,33 @@ +# O-RING PRESENCE DETECTOR +# FOR FERRARI 000952054 + +[general] +name: ORING +instruction: CONTROLLARE PRESENZA N. 2 O-RING SU RACCORDI +neural_network: od1-50000 +type: targeted + +# POINTS FORMAT: +# point_name: point_center point_size fill_color border_color border_thickness shape +# EXAMPLE: +# name: X,Y W,H 0xAARRGGBB 0xAARRGGBB T SHAPE CLASS +# ZONES FORMAT: +# region_name: region_center region_margin class +# margin can be a box (XM*2,YM*2) or a radius (R) +# EXAMPLES: +# name: X,Y XM,YM T SHAPE CLASS +# name: X,Y R T SHAPE CLASS +# LABELS FORMAT: +# label_name: label_start_location font_size fill_color border_color border_thickness text +# EXAMPLE: +# name: X,Y S 0xAARRGGBB 0xAARRGGBB T TEXT + +[markers] + +[zones] +p1: 430,1140 520,260 ok +p2: 2900,1140 520,260 ok + +[labels] +p1: 180,900 120 0xffffffff 0xff000000 4 O-RING 1 +p2: 2600,900 120 0xffffffff 0xff000000 4 O-RING 2 diff --git a/config/vision/recipes/termorestringente_923578.ini b/config/vision/recipes/termorestringente_923578.ini index 861193a..4a05850 100644 --- a/config/vision/recipes/termorestringente_923578.ini +++ b/config/vision/recipes/termorestringente_923578.ini @@ -3,6 +3,8 @@ [general] name: TERMORESTRINGENTE instruction: CONTROLLARE PRESENZA TERMORESTRINGENTE +neural_network: hs5-20000 +type: global # POINTS FORMAT: # point_name: point_center point_size fill_color border_color border_thickness shape diff --git a/config/warning_images/generic/Img-07.png b/config/warning_images/generic/Img-07.png index f76247f..dcccb1d 100644 Binary files a/config/warning_images/generic/Img-07.png and b/config/warning_images/generic/Img-07.png differ diff --git a/config/warning_images/generic/Img-10.png b/config/warning_images/generic/Img-10.png new file mode 100644 index 0000000..a8a3ffd Binary files /dev/null and b/config/warning_images/generic/Img-10.png differ diff --git a/config/warning_images/generic/Img-11.png b/config/warning_images/generic/Img-11.png new file mode 100644 index 0000000..0109a3d Binary files /dev/null and b/config/warning_images/generic/Img-11.png differ diff --git a/init_win.bat b/init_win.bat index c7208b9..b266984 100644 --- a/init_win.bat +++ b/init_win.bat @@ -2,7 +2,13 @@ :: RUN FROM POWERSHELL W/ADMIN RIGHTS: :: Set-ExecutionPolicy Unrestricted -Scope CurrentUser +pip install -r src/requirements.txt + +mkdir tmp cd tmp +:: Advantech XNAVI +Invoke-WebRequest -uri "https://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-2BZC0F1" -usebasicparsing -outfile xnavi.zip + :: GXIPY -Invoke-WebRequest -uri "https://dahengimaging.com/downloads/Galaxy_Windows_EN_32bits%2064bits_1.18.2208.9301.zip" -OutFile Galaxy_Windows_EN_32bits_64bits_1.18.2208.9301.zip \ No newline at end of file +Invoke-WebRequest -uri "https://dahengimaging.com/downloads/Galaxy_Windows_EN_32bits%2064bits_1.18.2208.9301.zip" -usebasicparsing -OutFile Galaxy_Windows_EN_32bits_64bits_1.18.2208.9301.zip \ No newline at end of file diff --git a/runme_custom.sh b/runme_custom.sh deleted file mode 100755 index ce0f29a..0000000 --- a/runme_custom.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -e -cd "$(dirname "$0")" -source "./venv/bin/activate" || source "./venv/Scripts/activate" || : -python -O "./src/main.py" --auto-accept-test-admin-permission --auto-login-admin --no-edgetpu --no-gpu --panel --system-id=st-ten-5 --no-autotest --sim-camera --sim-modbus --sim-os-label-printer --sim-serial --style windows $* diff --git a/runme_noautotest.bat b/runme_noautotest.bat new file mode 100644 index 0000000..0e1d578 --- /dev/null +++ b/runme_noautotest.bat @@ -0,0 +1,4 @@ +echo on +SET mypath=%~dp0 +cd %mypath% +.\venv\Scripts\activate.bat && python -O "./src/main.py" --no-edgetpu --no-tflite --no-autotest diff --git a/src/components/rfid.py b/src/components/rfid.py new file mode 100644 index 0000000..69af776 --- /dev/null +++ b/src/components/rfid.py @@ -0,0 +1,42 @@ +import ctypes +import sys +import platform +from PyQt5.QtCore import QMutex, Qt, QTimer, pyqtSlot, pyqtSignal +from .component import Component +import nfc +from nfc.clf import RemoteTarget + + + +is_win = platform.system() == "Windows" + +class RFID(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.mutex = QMutex() + self.simulate="--sim-rfid" in sys.argv + self.clf = nfc.ContactlessFrontend() + + def open_device(self): + self.clf.open('tty:USB0:pn532') + + def close_device(self): + pass + + @pyqtSlot() + def start(self): + # ACQUISITION TIMER + self.timer = QTimer() + self.timer.setTimerType(Qt.PreciseTimer) + self.timer.setInterval(int(1000 / 20)) + self.timer.timeout.connect(self.get) + self.timer.start() + super().start() + + @pyqtSlot() + def get(self): + data=None + if data is not None: + super()._get([data]) + + diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 6276e20..93c45f2 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -205,15 +205,16 @@ class TecnaMarpossProvasetT3(ModbusComponent): # READ INFO info = {r: self.read(r) for r in [ "Real time test pressure output", - "Real time differential pressure output", "Real time pressure line regulator", - "Active alarm flags", - "Active test program number", + #"Real time differential pressure output", + #"Active alarm flags", + #"Active test program number", "Running test: active phase", "Running test: test type", + "Running test: measured leak", "Running test: sequence index", "Digital inputs status (mask)", - # "Digital outputs status (mask)", + "Digital outputs status (mask)", ]} if self.model == "t3p": pass @@ -222,9 +223,12 @@ class TecnaMarpossProvasetT3(ModbusComponent): "Active not severe alarm flags", ]}) else: - raise NotImplementedError(f"techna t3 model {self.model!r} not implemented.") + raise NotImplementedError(f"Tecna t3 model {self.model!r} not implemented.") if info["Running test: active phase"] == "FINE TEST": # "END TEST, WAITING THE START OF A NEW TEST": info.update(self.get_test_results()) + for round_me in ["measured leak"]: + if round_me in info.keys(): + info.update({round_me:float(f"{info[round_me]:.2f}")}) self.log.debug(str(info)) super()._get([info]) @@ -251,13 +255,13 @@ class TecnaMarpossProvasetT3(ModbusComponent): def get_test_results(self): self.log.info("getting test results") return {r: self.read(r) for r in [ - "Running test: phase backwards time", + #"Running test: phase backwards time", "Running test: filling pressure", "Running test: pressure at the end of settling", - "Running test: burst pressure", + #"Running test: burst pressure", "Running test: measured leak", - "Running test: calculated leak flow rate", - "Running test: calculate RVP%", + #"Running test: calculated leak flow rate", + #"Running test: calculate RVP%", "Running test: result", ]} @@ -277,7 +281,8 @@ class TecnaMarpossProvasetT3(ModbusComponent): # **{769 - 1 + i: (recipe_name[i * 2 + 1] << 8) + recipe_name[i * 2] for i in range(8)}, # print field 2 "Print options": 0b0000000000000000 | self.saver_label_count << 12 | self.saver_print_on_fail << 8 | self.saver_label_template, "Test type": "Leak Test", - "Test flags": 0b0110000001011100 if step.spec.get("autotest", False) is not True else 0b0110000001010100, + # "Test flags": 0b0110000001011100 if step.spec.get("autotest", False) is not True else 0b0110000001010100, + "Test flags": 0b0110100001010100 if step.spec.get("autotest", False) in ("ok_check","ko_check") else 0b0110000001010100, "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"], @@ -285,9 +290,9 @@ class TecnaMarpossProvasetT3(ModbusComponent): "PR- - Min pressure tolerance %": step.spec["settling_pressure_min_percent"], "PR+ - Max pressure tolerance % (P+)": step.spec["settling_pressure_max_percent"], "T3 - Measure time": step.spec["test_time"], - "Q- Lower test leak limit": step.spec["test_pressure_min_delta"], + "Q- Lower test leak limit": step.spec["test_pressure_qneg"], "PREL - Nominal test pressure": step.spec["test_pressure"], - "Q+ Upper test leak limit": step.spec["test_pressure_max_delta"], + "Q+ Upper test leak limit": step.spec["test_pressure_qpos"], "FST - Discharge time": step.spec["flush_time"], "FSL - Discharge limit": step.spec["flush_pressure"], } diff --git a/src/components/tecna_marposs_provaset_t3l_registers.py b/src/components/tecna_marposs_provaset_t3l_registers.py index cf0bb3f..3b28ab0 100644 --- a/src/components/tecna_marposs_provaset_t3l_registers.py +++ b/src/components/tecna_marposs_provaset_t3l_registers.py @@ -80,7 +80,7 @@ registers = { "Running test: calculated leak flow rate": [42 - 1, {"dt": "32bit_int", "f": 1507, }], "Running test: calculate RVP%": [44 - 1, {"dt": "32bit_int", }], "Running test: result": [46 - 1, {"dt": "16bit_uint", "decoding": { - 1: "LEAK TEST PASSED (also used in Volume+Leak tests)", + 1: "LEAK TEST PASSED", 2: "BURST TEST PASSED WITH BURST", 3: "BURST TEST PASSED WITHOUT BURST", 4: "APERTURE TEST PASSED", diff --git a/src/components/tecna_marposs_provaset_t3p_registers.py b/src/components/tecna_marposs_provaset_t3p_registers.py index 62a2535..750e8bb 100644 --- a/src/components/tecna_marposs_provaset_t3p_registers.py +++ b/src/components/tecna_marposs_provaset_t3p_registers.py @@ -59,7 +59,7 @@ registers = { "Running test: calculated leak flow rate": [42 - 1, {"dt": "32bit_int", "f": 24, }], "Running test: calculate RVP%": [44 - 1, {"dt": "32bit_int", }], "Running test: result": [46 - 1, {"dt": "16bit_uint", "decoding": { - 1: "LEAK TEST PASSED (also used in Volume+Leak tests)", + 1: "LEAK TEST PASSED", 2: "BURST TEST PASSED WITH BURST", 3: "BURST TEST PASSED WITHOUT BURST", 4: "APERTURE TEST PASSED", diff --git a/src/components/vision.py b/src/components/vision.py index 5f0bc65..bd4a9cb 100644 --- a/src/components/vision.py +++ b/src/components/vision.py @@ -57,7 +57,7 @@ else: class Vision(Component): - """everything is expected the have shape with height (y) first then width (x)""" + """everything is expected to have shape with height (y) first then width (x)""" status_signal = pyqtSignal(object) loading_model_signal = pyqtSignal(object) @@ -66,6 +66,7 @@ class Vision(Component): super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded) self.lock = QMutex() self.simulate = "--sim-vision" in sys.argv + self.vision_config = None def start(self): self.model = None @@ -96,7 +97,7 @@ class Vision(Component): self.render_consumer.out.connect(self.process_render_consumed) super().start() - def config_changed(self): + def config_changed(self,vision_recipe=None): # OBJECT DETECTION self.detection_threshold = float(self.config[self.name].get("detection_threshold", 0.5)) # recipe @@ -104,7 +105,8 @@ class Vision(Component): self.labels = None # LOAD RECIPE self.recipes_dir = Path(self.config[self.name].get("recipes_dir", "./config/vision/recipes")) - self.set_recipe(None) + self.set_recipe(vision_recipe) + self.vision_recipe=vision_recipe self.recipe_watcher = QFileSystemWatcher([]) self.recipe_watcher.fileChanged.connect(self._set_recipe) # LOAD MODEL @@ -119,9 +121,11 @@ class Vision(Component): if "--no-tflite" in sys.argv: self.allowed_modes.pop("edgetpu", None) self.allowed_modes.pop("tflite", None) - self.load_model(self.config[self.name].get("neural_network", None)) + if self.vision_config is not None: + self.load_model(self.vision_config["neural_network"]) # LOAD LABELS - label_map = label_map_util.load_labelmap("./config/vision/labels/labels.pbtxt") + label_file="labels" if vision_recipe is None else vision_recipe + label_map = label_map_util.load_labelmap(f"./config/vision/labels/{label_file}.pbtxt") self.num_classes = len(label_map.item) categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=self.num_classes, use_display_name=True) self.category_index = label_map_util.create_category_index(categories) @@ -148,7 +152,7 @@ class Vision(Component): return pow((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2, 1 / 2) def clear_recipe(self): - self.recipe = None + self.recipe_name = None self.markers = {} self.zones = {} self.labels = {} @@ -170,6 +174,7 @@ class Vision(Component): if len(read) != 1 or self.recipe_path not in read: raise AssertionError("Recipe could not be read.") os.path.splitext(os.path.basename(read[0]))[0] + self.vision_config = config._sections.get("general", None) self.markers = self.parse_markers(config._sections.get("markers", None)) self.zones = self.parse_zones(config._sections.get("zones", None)) self.labels = self.parse_labels(config._sections.get("labels", None)) @@ -179,7 +184,7 @@ class Vision(Component): self.log.exception(f"Error reading {self.recipe_path!r}:") self.clear_recipe() self.status_signal.emit({ - "recipe": self.recipe, + "recipe": self.recipe_name, "markers": self.markers, "zones": self.zones, "labels": self.labels, @@ -189,8 +194,8 @@ class Vision(Component): if recipe is None: self.clear_recipe() else: - self.recipe = recipe - self._set_recipe(self.recipes_dir / str(recipe)) + self.recipe_name = recipe.split(".")[0] + self._set_recipe(self.recipes_dir / f"{self.recipe_name}.ini") def parse_markers(self, config=None): if config is None: @@ -434,11 +439,104 @@ class Vision(Component): parsed_detections.append(detection) return parsed_detections + def check_features_targeted(self, frame, lock=True): + parsed_detections = [] + for zone_name,zone in self.zones.items(): + y1,x1,y2,x2=int(zone["box"][0]),int(zone["box"][1]),int(zone["box"][2]),int(zone["box"][3]) + crop = frame[y1:y2,x1:x2] + + if self.interpreter is not None and frame.shape != self.interpreter.get_input_details()[0]["shape"][1:3]: + tensor = np.expand_dims(cv2.resize(crop, self.interpreter.get_input_details()[0]["shape"][1:3], interpolation=cv2.INTER_LINEAR), axis=0) + else: + frame_resized = cv2.resize(crop, (256, 256), interpolation=cv2.INTER_LINEAR) + tensor = tf.convert_to_tensor(np.asarray(frame_resized)) + tensor = tensor[tf.newaxis, ...] + # tensor = np.expand_dims(frame, axis=0) + # Run inference + if lock: + self.lock.lock() + if self.simulate or self.tf_mode == "simulation": + detections = { + "detection_scores": [[1.0]], + "detection_boxes": [[[0.2, 0.2, 0.8, 0.8]]], + "detection_classes": [[1]], + } + if lock: + self.lock.unlock() + elif self.tf_mode in {"edgetpu", "tflite"}: + i_d = self.interpreter.get_input_details() + # print(i_d) + o_d = self.interpreter.get_output_details() + # print(o_d) + self.interpreter.set_tensor(i_d[0]["index"], tensor) + self.interpreter.invoke() + # PARSE TFLITE DETECTIONS + # signature_list = self.interpreter._get_full_signature_list() + # if signature_list: + # if len(signature_list) > 1: + # raise ValueError("Only support model with one signature.") + # signature = signature_list[next(iter(signature_list))] + # # count = int(self.interpreter.get_tensor(signature["outputs"]["output_0"])[0]) + # scores = self.interpreter.get_tensor(signature["outputs"]["output_1"])[0] + # class_ids = self.interpreter.get_tensor(signature["outputs"]["output_2"])[0] + # boxes = self.interpreter.get_tensor(signature["outputs"]["output_3"])[0] + if self.interpreter.get_tensor(o_d[3]["index"]).size == 1: + boxes = self.interpreter.get_tensor(o_d[0]["index"])[0] + class_ids = self.interpreter.get_tensor(o_d[1]["index"])[0] + scores = self.interpreter.get_tensor(o_d[2]["index"])[0] + # count = int(self.interpreter.get_tensor(o_d[3]["index"])[0]) + else: + scores = self.interpreter.get_tensor(o_d[0]["index"])[0] + boxes = self.interpreter.get_tensor(o_d[1]["index"])[0] + # count = int(self.interpreter.get_tensor(o_d[2]["index"])[0]) + class_ids = self.interpreter.get_tensor(o_d[3]["index"])[0] + if lock: + self.lock.unlock() + detections = { + "detection_scores": [scores], + "detection_boxes": [boxes], + "detection_classes": [map(lambda class_id: class_id + 1, class_ids)], + } + else: + detections = self.model(tensor) + if lock: + self.lock.unlock() + detections = { + "detection_scores": detections["detection_scores"].numpy().tolist(), + "detection_boxes": detections["detection_boxes"].numpy().tolist(), + "detection_classes": detections["detection_classes"], + } + # WARNING: results other than the ones related to tensor[-1] will be discarded + for d_score, d_box, d_class in zip( # , d_mask in zip( + detections["detection_scores"][-1], + detections["detection_boxes"][-1], + detections["detection_classes"][-1], + # detections["detection_masks"][-1], + ): + if d_score < self.detection_threshold: + continue + box = list(d_box) + box = [i * s for i, s in zip(box, crop.shape[:2] * 2)] # rescale detection to frame size + box_real=[box[0]+y1,box[1]+x1,box[2]+y1,box[3]+x1] + detection = { + "score": d_score, + "box": box_real, + "class": self.category_index[int(d_class)], + # "mask": d_mask, + "center": self.get_center(box), + "size": self.get_size(box), + } + + parsed_detections.append(detection) + break # keep only first detection + + return parsed_detections + def detections_to_items(self, detections): # DRAW DETECTIONS if detections is not None and len(detections): style = { - "border_thickness": 25, + "border_thickness": 5, "fill_color": QColor("#00000000"), "shape": "rect", "convert_negative_placement": False, @@ -460,7 +558,7 @@ class Vision(Component): # MATCH DETECTIONS WITH RECIPE results = dict.fromkeys(self.zones) for detection in detections: - # find closest zone center to the detection + # find the closest zone center to the detection # filtering out those that do not contain the detection min_distance = sys.maxsize closest_zone = None @@ -586,7 +684,7 @@ class Vision(Component): **style, "border_color": Qt.green if item["ok"] else Qt.red, } - return items + return items else: return {} @@ -744,7 +842,11 @@ class Vision(Component): # VISION_CONSUMER TASK if consumable is None: return - detections = self.check_features(consumable["frame"]) + if self.vision_config["type"]=="targeted": + detections = self.check_features_targeted(consumable["frame"]) + else: + detections = self.check_features(consumable["frame"]) + results = self.process_detections(detections) return {"detections": detections, "results": results} diff --git a/src/lib/db/__init__.py b/src/lib/db/__init__.py index fcf7ce0..fb0510d 100644 --- a/src/lib/db/__init__.py +++ b/src/lib/db/__init__.py @@ -60,8 +60,8 @@ def init_db(): # "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_min_delta": 100, "test_pressure": 1000, "test_pressure_max_delta": 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_min_delta": 100, "test_pressure": 1000, "test_pressure_max_delta": 100, "flush_time": 1, "flush_pressure": 100}, + # "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(): diff --git a/src/lib/db/models/archive.py b/src/lib/db/models/archive.py index 32e1e7d..1aae510 100644 --- a/src/lib/db/models/archive.py +++ b/src/lib/db/models/archive.py @@ -10,7 +10,7 @@ from .users import Users class Archive(BaseModel): id = AutoField(primary_key=True, unique=True, null=False) - time = DateTimeField(unique=True, null=False, default=datetime.now) + time = DateTimeField(unique=True, null=False, default=datetime.now()) user = ForeignKeyField(Users, Users.username, null=False) result = BooleanField(null=False) overridden = BooleanField(null=False) @@ -22,7 +22,11 @@ class Archive(BaseModel): @classmethod @db.atomic() def archive(cls, test_data, result, overridden): + time=datetime.now() + test_data["time"]=time.strftime("%d/%m/%Y %H:%M:%S") + test_data["user"]=Users.get_session().username return cls.create( + time=time, user=Users.get_session().user, result=result, overridden=overridden, diff --git a/src/lib/db/models/users.py b/src/lib/db/models/users.py index 2eae003..ad3423d 100755 --- a/src/lib/db/models/users.py +++ b/src/lib/db/models/users.py @@ -136,11 +136,9 @@ class Users(BaseModel): def delete_by_username(cls, username): cls.update(password="").where(cls.username == username).execute() - @classmethod - def delete(cls, *args, **kwargs): - # OVERRIDE DELETION - # so that deleting a user will only disable it - return cls.update(password="") +# @classmethod +# def delete(cls, *args, **kwargs): +# return cls.delete() @property def is_admin(self): diff --git a/src/lib/helpers/config_reader.py b/src/lib/helpers/config_reader.py index f248296..61d39ad 100644 --- a/src/lib/helpers/config_reader.py +++ b/src/lib/helpers/config_reader.py @@ -48,7 +48,7 @@ class ConfigReader(QObject): def read_config_file(self, config_path): config_path = str(config_path) - config = ConfigParser(*self._args, **self._kwargs) + config = ConfigParser(*self._args, **self._kwargs, allow_no_value=True,comment_prefixes="#",inline_comment_prefixes="#") read = config.read(config_path) if len(read) != 1 or config_path != read[0]: raise AssertionError(f"Config file {config_path} could not be read.") diff --git a/src/lib/helpers/timing.py b/src/lib/helpers/timing.py index cae4c92..742b766 100644 --- a/src/lib/helpers/timing.py +++ b/src/lib/helpers/timing.py @@ -1,7 +1,7 @@ from time import perf_counter, time ref = time() - perf_counter() - +pass def timing(): global ref diff --git a/src/main.py b/src/main.py index 1030df4..d779608 100644 --- a/src/main.py +++ b/src/main.py @@ -68,7 +68,7 @@ try: from lib.helpers import ConfigReader from PyQt5.QtCore import QObject, QThread, pyqtSignal from PyQt5.QtWidgets import QApplication, QMessageBox - from ui import About, Archive, Login, Main_Window, Test, Users_Management + from ui import About, Archive, Login, Main_Window, Test, Users_Management, Recipe_Selection if "--vision" in sys.argv: from components import GalaxyCamera, NeoPixels, UVCCamera, Vision, VisionSaver @@ -166,23 +166,22 @@ try: Archive(hide_cloud_image="vision_saver" not in self().components))) if "--archive" in sys.argv: self.main_window.archive_a.trigger() - self.main_window.about_a.triggered.connect( - lambda checked, self=weakref.ref(self): self().main_window.open_dialog(About())) if "--about" in sys.argv: self.main_window.about_a.trigger() - self.main_window.admin_m.menuAction().setVisible( - False) # admin menu should not be visible before an admin logs in + + # admin menu should not be visible before an admin logs in + self.main_window.admin_m.menuAction().setVisible(False) + + self.main_window.about_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(About())) self.main_window.quit_a.triggered.connect(quit_app) - self.main_window.users_management_a.triggered.connect( - lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Users_Management())) + self.main_window.users_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Users_Management())) + self.main_window.table_selection_a.triggered.connect(self.set_recipe_mode_table) + self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode) + if "--users-management" in sys.argv: self.main_window.users_management_a.trigger() - # self.main_window.recipes_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Recipes_Management())) - # if "--recipes-management" in sys.argv: - # self.main_window.recipes_management_a.trigger() - # self.main_window.steps_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Steps_Management())) - # if "--steps-management" in sys.argv: - # self.main_window.steps_management_a.trigger() + + # CONFIG-SPECIFIC MENU ENTRY ACTIVATION if "tecna_t3" in self.components and ( "--enable-saving-tecna-recipes" in sys.argv or self.config.get("tecna_t3", {}).get("saver", None) == "present"): @@ -192,9 +191,8 @@ try: self.main_window.save_tecna_recipes_a.trigger() else: self.main_window.save_tecna_recipes_a.setVisible(False) + self.main_window.barcode_selection_a.setVisible(self.config["hardware_config"]["barcode_recipe_selection"] == "present") - self.main_window.table_selection_a.triggered.connect(self.set_recipe_mode_table) - self.main_window.barcode_selection_a.triggered.connect(self.set_recipe_mode_barcode) # OPEN LOGIN TAB self.open_login() # SHOW MAIN WINDOW @@ -220,16 +218,23 @@ try: else: self.main_window.admin_m.menuAction().setVisible(False) # open test - self.main_window.open_tab(Test(self.config, self.components)) + self.main_window.open_tab(Test(self.config, self.components,self)) else: self.main_window.admin_m.menuAction().setVisible(False) def logout(self): - if type(self.main_window.centralWidget) is Test: - self.main_window.centralWidget.change_recipe() Users.logout() self.main_window.admin_m.menuAction().setVisible(False) - self.open_login() + if type(self.main_window.centralWidget().centralWidget.widget) is Recipe_Selection: + # LOGOUT IMMEDIATELY IF NOT TESTING + self.open_login() + else: + if not self.main_window.centralWidget().autotesting: + self.main_window.centralWidget().change_recipe() # STOP CURRENT TEST + self.main_window.centralWidget().request_autotest("logout") + else: + # LOGOUT IMMEDIATELY IF AUTOTESTING + self.open_login() def set_recipe_mode_table(self): self.main_window.centralWidget().set_recipe_mode_table() diff --git a/src/scripts/csv_extract_LEAK.py b/src/scripts/csv_extract_LEAK.py new file mode 100644 index 0000000..30d7a8d --- /dev/null +++ b/src/scripts/csv_extract_LEAK.py @@ -0,0 +1,35 @@ +import csv +import json + +file="STTEN5" +with open(f"tmp/{file}.csv",) as csv_file: + csv_reader = csv.reader(csv_file, delimiter=',') + + with open(f'tmp/{file}_out.csv', 'w') as csv_out: + + # create the csv writer + writer = csv.writer(csv_out, lineterminator="\n") + + line_count = 0 + for row in csv_reader: + if line_count == 0: + print(f'Column names are {", ".join(row)}') + row.append("caduta") + row.append("pressione") + row.pop(1) # remove data column + line_count += 1 + writer.writerow(row) + else: + data=json.loads(row[1]) + if "leak_1" in data.keys(): + leak=data["leak_1"]["0"]["results"]["data"]["""Running test: measured leak"""] + press=data["leak_1"]["0"]["results"]["data"]["""Running test: filling pressure"""] + leakstr=f'{leak:.3f}' + pressstr = f'{press:.3f}' + line_count += 1 + row.append(leakstr) + row.append(pressstr) + row.pop(1) # remove data column + writer.writerow(row) + + print(f'Processed {line_count} lines.') \ No newline at end of file diff --git a/src/test/csv_import/Tabella_e_daily_p3.csv b/src/test/csv_import/Tabella_e_daily_p3.csv new file mode 100644 index 0000000..186549c --- /dev/null +++ b/src/test/csv_import/Tabella_e_daily_p3.csv @@ -0,0 +1,40 @@ +codice_ricetta,Priorita ,descrizione,etichette_supplementari,Numero nastri (N),Numero sensori anello (SA),Numero sensori presenza (SP) +5803223729,3,priorita  3,,,, +5803223730,3,priorita  3,,,, +5803223731,3,priorita  3,,,, +5803223732,3,priorita  3,,,, +5803223733,3,priorita  3,,,, +5803223734,3,priorita  3,,,, +5803223735,3,priorita  3,,,, +5803223736,3,priorita  3,,,, +5803223737,3,priorita  3,,,, +5803223738,3,priorita  3,,,, +5803223739,3,priorita  3,,,, +5803223740,3,priorita  3,,,, +5803223741,3,priorita  3,,,, +5803223742,3,priorita  3,,,, +5803223743,3,priorita  3,,,, +5803223744,3,priorita  3,,,, +5803223745,3,priorita  3,,,, +5803223746,3,priorita  3,,,, +5803223747,3,priorita  3,,,, +5803223748,3,priorita  3,,,, +5803223749,3,priorita  3,,,, +5803223750,3,priorita  3,,,, +5803223751,3,priorita  3,,,, +5803223752,3,priorita  3,,,, +5803223753,3,priorita  3,,,, +5803120372,3,priorita  3,,,, +5803120373,3,priorita  3,,,, +5803120374,3,priorita  3,,,, +5803120375,3,priorita  3,,,, +5803101543,3,priorita  3,,,, +5803101544,3,priorita  3,,,, +5803101545,3,priorita  3,,,, +5803101546,3,priorita  3,,,, +5803101547,3,priorita  3,,,, +5803223754,3,priorita  3,,,, +5803223755,3,priorita  3,,,, +5803120371,3,priorita  3,,,, +5803228584,3,priorita  3,,,, +5803228585,3,priorita  3,,,, diff --git a/src/test/rfid.py b/src/test/rfid.py new file mode 100644 index 0000000..74fa362 --- /dev/null +++ b/src/test/rfid.py @@ -0,0 +1,46 @@ +import time +import ndef +import nfc +from nfc.clf import RemoteTarget + +clf = nfc.ContactlessFrontend() +connected=False +while True: + try: + if not connected: + connected=clf.open('tty:USB0:pn532') + if connected: + target = clf.sense(RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F')) + if target is not None: + tag = nfc.tag.activate(clf, target) + if tag is not None: + print(tag) + if tag.ndef is not None: + if not len(tag.ndef.records): + print("EMPTY TAG - WRITING...") + if not tag.ndef.is_writeable: + print("This Tag is not writeable.") + break + else: + tag.format() + #tag.ndef.records = [ndef.TextRecord("Errecinque"),ndef.TextRecord("5812345678")] + record=ndef.TextRecord("Errecinque,fixture,5812345678") + tag.ndef.records = [record] + if tag.ndef.has_changed: + print("WRITE ERROR") + else: + print("WRITE OK") + + for record in tag.ndef.records: + print(record) + else: + print("ERROR NOT NDEF") + else: + print("NO TARGET") + except Exception as e: + print(f"EXCEPTION {e}") + connected=False + time.sleep(0.3) + +print("EXITING") +clf.close() \ No newline at end of file diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 79605ac..6eb3e3d 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -6,7 +6,7 @@ from datetime import datetime from lib.db import Crud_DB from peewee import TextField -from PyQt5.QtCore import Qt, QTimer, pyqtSignal +from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QSize from PyQt5.QtWidgets import (QAbstractItemView, QComboBox, QDialog, QGridLayout, QHeaderView, QLineEdit, QMessageBox, QPlainTextEdit, QPushButton) @@ -148,6 +148,7 @@ class Combo_Box_Cell_Widget(QComboBox, Cell): class External_Dialog_Cell_Widget(QPushButton, Cell): def __init__(self, action=None, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None): self.dialog = QDialog() + self.dialog.resize(QSize(800,800)) self.editor = QPlainTextEdit() self.dialog.setLayout(QGridLayout()) self.dialog.layout().setSpacing(0) diff --git a/src/ui/leak_step_editor/leak_step_editor.py b/src/ui/leak_step_editor/leak_step_editor.py index 2d5203f..e157ef2 100644 --- a/src/ui/leak_step_editor/leak_step_editor.py +++ b/src/ui/leak_step_editor/leak_step_editor.py @@ -15,9 +15,9 @@ class Leak_Step_Editor(Editor): "settling_pressure_max_percent": self.settling_pressure_max_percent_sb, # test "test_time": self.test_time_sb, - "test_pressure_min_delta": self.test_pressure_min_delta_sb, + "test_pressure_qneg": self.test_pressure_qneg_sb, "test_pressure": self.test_pressure_sb, - "test_pressure_max_delta": self.test_pressure_max_delta_sb, + "test_pressure_qpos": self.test_pressure_qpos_sb, # flush "flush_time": self.flush_time_sb, "flush_pressure": self.flush_pressure_sb, diff --git a/src/ui/leak_step_editor/leak_step_editor.ui b/src/ui/leak_step_editor/leak_step_editor.ui index 7b1356b..1bf8742 100644 --- a/src/ui/leak_step_editor/leak_step_editor.ui +++ b/src/ui/leak_step_editor/leak_step_editor.ui @@ -221,7 +221,7 @@ - + 0 @@ -238,7 +238,7 @@ - + 9999 diff --git a/src/ui/main_window/main_window.ui b/src/ui/main_window/main_window.ui index f404bef..0ec3684 100644 --- a/src/ui/main_window/main_window.ui +++ b/src/ui/main_window/main_window.ui @@ -25,7 +25,7 @@ 0 0 843 - 28 + 31 @@ -35,7 +35,7 @@ - About + Informazioni @@ -72,7 +72,7 @@ - Powered by + Contatti diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 7cba138..06ec26b 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -128,8 +128,8 @@ class Recipe_Selection(Widget): self.export_b.setVisible(False) self.delete_all_b.setVisible(False) # TESTING - if "--auto-select" in sys.argv or "--test" in sys.argv: - recipe = "5802850925" + if "--auto-select" in sys.argv: + recipe = "000952054" cn = self.crud.select_index["name"] self.crud.db_tw.clearSelection() for rn in range(1, self.crud.db_tw.rowCount()): @@ -214,9 +214,9 @@ class Recipe_Selection(Widget): "settling_pressure_min_percent": int(row.get("percentuale_minima_pressione_assestamento", defaults["percentuale_minima_pressione_assestamento"])), "settling_pressure_max_percent": int(row.get("percentuale_massima_pressione_assestamento", defaults["percentuale_massima_pressione_assestamento"])), "test_time": int(row.get("tempo_di_test", defaults["tempo_di_test"])), - "test_pressure_min_delta": int(row.get("pressione_di_test_delta_minimo", defaults["pressione_di_test_delta_minimo"])), + "test_pressure_qneg": int(row.get("pressione_di_test_delta_minimo", defaults["pressione_di_test_delta_minimo"])), "test_pressure": int(row.get("pressione_di_test", defaults["pressione_di_test"])), - "test_pressure_max_delta": int(row.get("pressione_di_test_delta_massimo", defaults["pressione_di_test_delta_massimo"])), + "test_pressure_qpos": int(row.get("pressione_di_test_delta_massimo", defaults["pressione_di_test_delta_massimo"])), "flush_time": int(row.get("tempo_svuotamento", defaults["tempo_svuotamento"])), "flush_pressure": int(row.get("pressione_svuotamento", defaults["pressione_svuotamento"])), "relay_config": int(row.get("config_elettrovalvole", defaults["config_elettrovalvole"])) @@ -229,9 +229,9 @@ class Recipe_Selection(Widget): "settling_pressure_min_percent": int(row.get("percentuale_minima_pressione_assestamento_2", defaults["percentuale_minima_pressione_assestamento_2"])), "settling_pressure_max_percent": int(row.get("percentuale_massima_pressione_assestamento_2", defaults["percentuale_massima_pressione_assestamento_2"])), "test_time": int(row.get("tempo_di_test_2", defaults["tempo_di_test_2"])), - "test_pressure_min_delta": int(row.get("pressione_di_test_delta_minimo_2", defaults["pressione_di_test_delta_minimo_2"])), + "test_pressure_qneg": int(row.get("pressione_di_test_delta_minimo_2", defaults["pressione_di_test_delta_minimo_2"])), "test_pressure": int(row.get("pressione_di_test_2", defaults["pressione_di_test_2"])), - "test_pressure_max_delta": int(row.get("pressione_di_test_delta_massimo_2", defaults["pressione_di_test_delta_massimo_2"])), + "test_pressure_qpos": int(row.get("pressione_di_test_delta_massimo_2", defaults["pressione_di_test_delta_massimo_2"])), "flush_time": int(row.get("tempo_svuotamento_2", defaults["tempo_svuotamento_2"])), "flush_pressure": int(row.get("pressione_svuotamento_2", defaults["pressione_svuotamento_2"])), "relay_config": int(row.get("config_elettrovalvole_2", defaults["config_elettrovalvole_2"])) @@ -434,9 +434,9 @@ class Recipe_Selection(Widget): "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_min_delta"], + "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_max_delta"], + "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 "", @@ -447,9 +447,9 @@ class Recipe_Selection(Widget): "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_min_delta"], + "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_max_delta"], + "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"], diff --git a/src/ui/rfid_recipe_selection/__init__.py b/src/ui/rfid_recipe_selection/__init__.py new file mode 100644 index 0000000..b3a3f30 --- /dev/null +++ b/src/ui/rfid_recipe_selection/__init__.py @@ -0,0 +1 @@ +from .rfid_recipe_selection import RFID_Recipe_Selection diff --git a/src/ui/rfid_recipe_selection/rfid_recipe_selection.py b/src/ui/rfid_recipe_selection/rfid_recipe_selection.py new file mode 100644 index 0000000..9b2ee0b --- /dev/null +++ b/src/ui/rfid_recipe_selection/rfid_recipe_selection.py @@ -0,0 +1,85 @@ +import sys + +import peewee +from PyQt5 import Qt + +from lib.helpers import timing +from PyQt5.QtCore import Qt, QTimer, QThread +from PyQt5.QtGui import QKeySequence, QPixmap, QPalette, QColor +from PyQt5.QtWidgets import QShortcut, QApplication +from ui.widget import Widget +from lib import db +from lib.db.models import Recipes + +class RFID(Widget): + def __init__(self, parent): + super().__init__() + self.parent=parent + self.recipe_db_model=Recipes + self.status_palettes = { + True: QPalette(), + "": QPalette(), + "warning": QPalette(), + False: QPalette(), + None: QPalette(), + } + self.status_palettes[True].setColor(QPalette.Base, Qt.green) + self.status_palettes[False].setColor(QPalette.Base, Qt.red) + self.status_palettes["warning"].setColor(QPalette.Base, QColor(255, 165, 0)) + self.status_palettes[""].setColor(QPalette.Base, QColor(255, 255, 0)) + + self.delay_timer = QTimer() + self.delay_timer.setSingleShot(True) + self.delay_timer.timeout.connect(self.reset_display) + + self.ok_timer = QTimer() + self.ok_timer.setSingleShot(True) + self.ok_timer.timeout.connect(self.set_recipe) + + def start(self, recipe=None, step=None, pieces=None): + + self.rfid_input_l.setPalette(self.status_palettes[None]) + self.rfid_input_l.setPlainText("") + + def get(self, data=None, override=False): + if not len(data): + data = None + if data is None: + return + else: + lines = data + if lines[0]=="ERRECINQUE RFID": + # RECIPE CODE FOUND + self.recipe=lines[1] + self.rfid_input_l.setPalette(self.status_palettes[True]) + self.ok_timer.start(2000) + + else: + # RECIPE CODE NOT FOUND + self.rfid_input_l.setPalette(self.status_palettes[False]) + self.instruction_text("FORMATO RFID DIMA NON VALIDO", "red") + self.delay_timer.start(3000) + + # LOOKUP RECIPE + + def set_recipe(self): + try: + recipe = self.recipe_db_model.get_by_id(self.recipe) + self.parent.set_recipe(recipe) + except peewee.DoesNotExist: + self.rfid_input_l.setPalette(self.status_palettes[False]) + self.instruction_text("RICETTA NON TROVATA","red") + self.delay_timer.start(3000) + + + def reset_display(self): + self.rfid_input_l.setFocus() + self.rfid_input_l.setPlainText("") + self.rfid_input_l.setPalette(self.status_palettes[""]) + self.instruction_text("SCANSIONARE BARCODE SELEZIONE RICETTA") + + def instruction_text(self,text,color=None): + if getattr(self.parent.centralWidget, "set_text"): + self.parent.centralWidget.set_text(text, color=color) + + diff --git a/src/ui/rfid_recipe_selection/rfid_recipe_selection.ui b/src/ui/rfid_recipe_selection/rfid_recipe_selection.ui new file mode 100644 index 0000000..2805d48 --- /dev/null +++ b/src/ui/rfid_recipe_selection/rfid_recipe_selection.ui @@ -0,0 +1,95 @@ + + + Test_Connector + + + + 0 + 0 + 1445 + 793 + + + + Test Connector + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + 12 + + + + + + + + + + + + 600 + 0 + + + + + 600 + 200 + + + + + 20 + + + + 123 +456 +abc + + + + + + + + 20 + + + + TORNA ALLA TABELLA RICETTE + + + + + + + + diff --git a/src/ui/test/test.py b/src/ui/test/test.py index e3cded2..bf2faf7 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -29,16 +29,15 @@ from ui.widget import Widget class Test(Widget): - def __init__(self, config, components=None): + def __init__(self, config, components=None,main_window=None): super().__init__() + self.main_window=main_window self.config = config self.components = components # GET LOGGER self.log = logging.getLogger("Test") # SHOW MACHINE DESCRIPTION self.machine_description_l.setText(self.config.get("machine", {}).get("description", "N/A")) - # SHOW USERNAME - # SHOW USERNAME session = Users.get_session() self.user_l.setText(session.username) @@ -91,9 +90,9 @@ class Test(Widget): "count_end": Test_Assembly(img_path=None, text=u"LOTTO TERMINATO, PREMERE CONTINUA PERCOMINCIARNE UNO NUOVO", widget=Test_Count_End(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), "done": Test_Assembly(img_path=self.select_step_img("success"), text=u"COLLAUDO COMPLETATO", widget=None), "emergency": Test_Assembly(img_path=self.select_step_img("reset_emergency"), text=u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\"", widget=None), - "fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO, PREMERE CONTINUA PER COMINCIARE UN NUOVO CICLO", widget=Test_Fail()), + "fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO, PREMERE CONTINUA PER COMINCIARE UN NUOVO CICLO", widget=Test_Fail(parent=self)), "leak_1": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces,parent=self)), - "leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), + "leak_2": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces,parent=self)), "instruction": Test_Assembly(img_path=None, text=u"ESEGUIRE LE OPERAZIONI DI MONTAGGIO INDICATE IN FIGURA", widget=Test_Instructions(components=self.components, recipe=self.recipe,bench_name=self.config.machine_id, step=self.step)), "print": Test_Assembly(img_path=self.select_step_img("print"), text=u"STAMPA ETICHETTA IN CORSO", widget=None), "resistance": Test_Assembly(img_path=None, text=u"COLLEGARE CONNETTORE ELETTRICO PER EFFETTUARE PROVA RESISTENZA", widget=Test_Resistance(components=self.components, recipe=self.recipe, step=self.step, pieces=self.pieces)), @@ -113,7 +112,8 @@ class Test(Widget): self.autotesting_reason = None self.autotest_cycle_steps = None if "--no-autotest" not in sys.argv: - self.autotest_period = 12 * 60 * 60 * 1000 + self.autotest_period = 8.5 * 60 * 60 * 1000 # 8.5 HOURS + # self.autotest_period = 12 * 60 * 60 * 1000 # 12 HOURS if not self.config["autotest_done"]: self.request_autotest("init") else: @@ -314,6 +314,8 @@ class Test(Widget): for i, step in enumerate(steps): if i in skip: continue + if step.type == "vision": + self.components["vision"].config_changed(vision_recipe=self.recipe.name) if step.type == "count": count_found = True if "warning_img" in step.spec: @@ -349,6 +351,7 @@ class Test(Widget): self.cycle_steps = steps self.check_steps_dependencies(self.cycle_steps) leak_autotest_steps=[] + # CONFIGURE LEAK AUTOTEST PARAMETERS if self.config["autotest_leak"]["enabled"]=="true": l_at_1=copy.deepcopy(self.config["autotest_leak"]) l_at_1.pop("enabled") @@ -357,6 +360,8 @@ class Test(Widget): l_at_2=copy.deepcopy(self.config["autotest_leak"]) l_at_2.pop("enabled") l_at_2={a: float(x) for a, x in l_at_2.items()} + 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)] @@ -452,13 +457,32 @@ class Test(Widget): self.data[step_name] = {} if data is not None: data["step"] = model_to_dict(self.step) - self.data[step_name][str(len(self.data[step_name]))] = data + data["step"].pop("name",None) + + # MAKE ARRAY ONLY IF MORE THAN ONE TEST OF SAME TYPE + if len(self.data[step_name])>1: + self.data[step_name][str(len(self.data[step_name]))] = data + else: + self.data[step_name] = data + self.data["overridden"] = self.data["overridden"] or data.get("overridden", False) self.data["ok"] = self.data["ok"] and data.get("ok", False) self.next() def done(self, ok=True): - self.log.info("cycle done") + self.log.info("cycle done, saving data...") + + #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(): + self.data[leak]["results"]={k:self.data[leak]["results"]["tecna_t3"][k] for k in ["Running test: filling pressure", + "Running test: measured leak", + "Running test: pressure at the end of settling", + "Running test: result"] + + } if "vision" in self.data: vision_test_1 = self.data.get("vision", {}).get("0", {}) out_paths = self.components["vision_saver"].save( @@ -471,6 +495,9 @@ class Test(Widget): for vision in self.data.get("vision", {}).values(): vision.pop("frame", None) vision.pop("render", None) + vision.pop("detections", None) + if "results" in vision.keys(): + vision["results"].pop("results", None) if self.autotesting: self.data["autotest"] = True self.data["autotest_reason"] = self.autotesting_reason @@ -483,6 +510,11 @@ class Test(Widget): self.pieces["ok"] += 1 else: self.pieces["ko"] += 1 + else: + if self.autotesting_reason == "logout": + if ok: + self.main_window.show_login() + return archived @staticmethod @@ -503,21 +535,19 @@ class Test(Widget): self.log.info("cycle printed already compiled label") # LABEL PRINT recipe = archived.test_data.get("recipe", {}) - leak_test_1 = archived.test_data.get("leak_1", {}).get("0", {}) + leak_test_1 = archived.test_data.get("leak_1", {}) leak_test_1_step = leak_test_1.get("step", {}) leak_test_1_step_spec = leak_test_1_step.get("spec", {}) leak_test_1_results = leak_test_1.get("results", {}) - leak_test_1_results_data = leak_test_1_results.get("data", {}) - leak_test_2 = archived.test_data.get("leak_2", {}).get("0", {}) + leak_test_2 = archived.test_data.get("leak_2", {}) leak_test_2_step = leak_test_2.get("step", {}) leak_test_2_step_spec = leak_test_2_step.get("spec", {}) leak_test_2_results = leak_test_2.get("results", {}) - leak_test_2_results_data = leak_test_2_results.get("data", {}) - psetminp_a = leak_test_1_step_spec.get("test_pressure", 0) * (100+leak_test_1_step_spec.get("test_pressure_min_delta", 0)/100) - psetmaxp_a = leak_test_1_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_1_step_spec.get("test_pressure_max_delta", 0)/100) - psetminp2_a = leak_test_2_step_spec.get("settling_pressure_min_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_min_delta", 0)/100) - psetmaxp2_a = leak_test_2_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_max_delta", 0)/100) + psetminp_a = leak_test_1_step_spec.get("test_pressure", 0) * (100+leak_test_1_step_spec.get("test_pressure_qneg", 0)/100) + psetmaxp_a = leak_test_1_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_1_step_spec.get("test_pressure_qpos", 0)/100) + psetminp2_a = leak_test_2_step_spec.get("settling_pressure_min_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_qneg", 0)/100) + psetmaxp2_a = leak_test_2_step_spec.get("settling_pressure_max_percent", 0) * (100+leak_test_2_step_spec.get("test_pressure_qpos", 0)/100) printer_fields = self.step.spec context = { @@ -525,6 +555,7 @@ class Test(Widget): "RECIPE": self.labellify(recipe.get("name", "-")), "CLIENT": self.labellify(recipe.get("client", "-")), "PART": self.labellify(recipe.get("part_number", "-")), + "DESCRIPTION": self.labellify(recipe.get("description", "-")), # 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", "-")), @@ -544,24 +575,22 @@ class Test(Widget): "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_min_delta", "-")), - "PMIN2": self.labellify(leak_test_2_step_spec.get("test_pressure_min_delta", "-")), + "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_max_delta", "-")), + "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", "-")), # ACTUAL TESTED VALUES - "RESTPB": self.labellify(leak_test_1_results_data.get("Running test: phase backwards time", "-")), - "RESPFILL": self.labellify(leak_test_1_results_data.get("Running test: filling pressure", "-")), - "RESPSET": self.labellify(leak_test_1_results_data.get("Running test: pressure at the end of settling", "-")), - "RESPSET2": self.labellify(leak_test_2_results_data.get("Running test: pressure at the end of settling", "-")), - "RESPB": self.labellify(leak_test_1_results_data.get("Running test: burst pressure", "-")), - "RESLEAK": self.labellify(leak_test_1_results_data.get("Running test: measured leak", "-")), - "RESLEAK2": self.labellify(leak_test_2_results_data.get("Running test: measured leak", "-")), - "RESFLOW": self.labellify(leak_test_1_results_data.get("Running test: calculated leak flow rate", "-")), - "RESRVP": self.labellify(leak_test_1_results_data.get("Running test: calculate RVP%", "-")), - "RESRES": self.labellify(leak_test_1_results_data.get("Running test: result", "-")), + "RESPFILL": self.labellify(leak_test_1_results.get("Running test: filling pressure", "-")), + "RESPFILL2": self.labellify(leak_test_2_results.get("Running test: filling pressure", "-")), + "RESPSET": self.labellify(leak_test_1_results.get("Running test: pressure at the end of settling", "-")), + "RESPSET2": self.labellify(leak_test_2_results.get("Running test: pressure at the end of settling", "-")), + "RESLEAK": self.labellify(leak_test_1_results.get("Running test: measured leak", "-")), + "RESLEAK2": self.labellify(leak_test_2_results.get("Running test: measured leak", "-")), + "RESRES": self.labellify(leak_test_1_results.get("Running test: result", "-")), + "RESRES2": self.labellify(leak_test_2_results.get("Running test: result", "-")), # SERIAL DEFINITION "SN": str(archived.id), "SN4": f"{archived.id:0>4}", @@ -597,6 +626,13 @@ class Test(Widget): # PRINT MAIN PRODUCT LABEL compiled_label = self.components["label_printer"].print_label(label, context=context) + # if recipe.get("part_number", "-") == "5802814210 R.3": + # num_labels=2 + # else: + # num_labels=1 + # + # for i in range(num_labels): + # compiled_label = self.components["label_printer"].print_label(label, context=context) self.log.info(f"Main label printed: {context!r}") return compiled_label diff --git a/src/ui/test/test.ui b/src/ui/test/test.ui index 9bdf1aa..ac9e4b9 100755 --- a/src/ui/test/test.ui +++ b/src/ui/test/test.ui @@ -6,8 +6,8 @@ 0 0 - 842 - 118 + 1252 + 146 @@ -52,52 +52,7 @@ 3 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 200 - 40 - - - - - 12 - 75 - true - - - - CAMBIA DISEGNO - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + Qt::Horizontal @@ -110,71 +65,6 @@ - - - - - 12 - 75 - true - - - - 12345 - - - Qt::AlignCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 12 - 75 - true - - - - PEZZI FATTI - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - 12345 -567 - - - Qt::AlignCenter - - - @@ -201,14 +91,38 @@ - - - - - 0 - 0 - + + + + Qt::Horizontal + + + 40 + 20 + + + + + + + + + 16 + 75 + true + + + + - + + + Qt::AlignCenter + + + + + 12 @@ -217,25 +131,14 @@ - N. DISEGNO: + 12345 + + + Qt::AlignCenter - - - - - 12 - 75 - true - - - - OPERATORE: - - - - + @@ -268,7 +171,7 @@ - + 12 @@ -277,11 +180,66 @@ - - + OPERATORE: - + + + + + 12 + 75 + true + + + + 12345 +567 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + N. DISEGNO: + + + + + + + + 12 + 75 + true + + + + PEZZI FATTI + + + Qt::AlignCenter + + + + Qt::Horizontal @@ -297,11 +255,24 @@ - - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - 16 + 12 75 true @@ -309,6 +280,69 @@ - + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 200 + 40 + + + + + 12 + 75 + true + + + + CAMBIA DISEGNO + + + + + + + + 12 + 75 + true + + + + ULTIMO AUTOTEST: + + + Qt::AlignCenter + + + + + + + + 12 + 75 + true + + + + DD/MM/YY HH:MM + Qt::AlignCenter diff --git a/src/ui/test_connector/test_connector.py b/src/ui/test_connector/test_connector.py index 69a6eaa..af8f0a5 100644 --- a/src/ui/test_connector/test_connector.py +++ b/src/ui/test_connector/test_connector.py @@ -90,4 +90,4 @@ class Test_Connector(Test_Test): return barcode is not None and len(barcode) def set_focus(self): - self.barcodes_le.setFocus() + self.connector_le.setFocus() diff --git a/src/ui/test_fail/test_fail.py b/src/ui/test_fail/test_fail.py index f01da20..ffcc5d2 100644 --- a/src/ui/test_fail/test_fail.py +++ b/src/ui/test_fail/test_fail.py @@ -10,14 +10,24 @@ from ui.test_test import Test_Test class Test_Fail(Test_Test): - def __init__(self, components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False): + def __init__(self, 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.continue_b.clicked.connect(lambda checked, self=weakref.ref(self): self().ok.emit(None)) + self.parent=parent + self.discard_timer=QTimer() + self.discard_timer.timeout.connect(self.wait_discard) def start(self, recipe=None, step=None, pieces=None): show = super().start(recipe=recipe, step=step, pieces=pieces) if show is False: return show + if "discard_box" in self.parent.config["hardware_config"].keys(): + if self.parent_assembly_widget is not None : + self.continue_b.setVisible(False) + self.discard_timer.start(100) + self.parent_assembly_widget().set_text(text="TEST KO - INSERIRE IL PEZZO COLLAUDATO NEL CONTENITORE DI SEGREGAZIONE SCARTI") + self.io_connection=self.components["digital_io"].out.connect(self.wait_discard) + self.visualize() # TESTING if "--test" in sys.argv: @@ -25,11 +35,21 @@ class Test_Fail(Test_Test): self.test_timer.setSingleShot(True) self.test_timer.timeout.connect(self.continue_b.click) self.test_timer.start(500) - # /TESTING return show - # def stop(self): - # super().stop() + def stop(self): + if "discard_box" in self.parent.config["hardware_config"].keys(): + self.disconnect(self.io_connection) + super().stop() + + def wait_discard(self,data=None): + if data is not None: + if len(data[0]["digital_io"]) == 0: + return + else: + sensor_index = int(self.parent.config["digital_io"]["discard_idx"]) + byte_idx = int(sensor_index / 8) + bit_idx = sensor_index % 8 + if data[0]["digital_io"][byte_idx][bit_idx]: + self.ok.emit(None) - # def reset(self): - # super().reset() diff --git a/src/ui/test_leak/test_leak.py b/src/ui/test_leak/test_leak.py index 4fe6330..70d4669 100644 --- a/src/ui/test_leak/test_leak.py +++ b/src/ui/test_leak/test_leak.py @@ -2,24 +2,33 @@ import sys import time import weakref -from PyQt5.QtWidgets import QMessageBox +from PyQt5.QtWidgets import QMessageBox, QDialog +from ui import Dialog from ui.test_test import Test_Test from components.Automation.BDaq import ErrorCode 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): 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.parent=parent self.step=step self.start_b.clicked.connect(self.start_test) self.stop_b.clicked.connect(lambda checked, self=weakref.ref(self): self().components["tecna_t3"].stop_test()) - self.parent=parent + self.show_instruction_b.setVisible("show_instructions" in self.parent.config["hardware_config"].keys()) + self.show_instruction_b.clicked.connect(self.show_instruction) + + def show_instruction(self): + dialog=Dialog() + dialog.setCentralWidget(self.parent.cycle_available_steps["instruction"]) + dialog.show() def start_test(self): # print extra labels if self.step.type == "leak_1": self.parent.print_extra_labels() - self.components["tecna_t3"].start_test() + + self.components["tecna_t3"].start_test() def start(self, recipe=None, step=None, pieces=None): # TESTING @@ -32,6 +41,17 @@ 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": + self.test_num_l.setText("1/2") + else: + self.test_num_l.setText("2/2") + else: + self.test_num_l.setText("1/1") + + self.recipe_pressure_l.setText(f"{self.step.spec['test_pressure']}") + self.leak_min_l.setText(f"{self.step.spec['test_pressure_qneg']}") + self.leak_max_l.setText(f"{self.step.spec['test_pressure_qpos']}") # setup test loop self.components["tecna_t3"].write_recipe(self.recipe, self.step) self.get_connection = self.components["tecna_t3"].out.connect(self.get) @@ -102,7 +122,7 @@ class Test_Leak(Test_Test): if step == "ok_check": ok = type(result) is str and "passed" in result.lower() # AUTOTEST - NO LEAK elif step == "ko_check": - ok = type(result) is str and "failed" in result.lower() # AUTOTEST - LEAK + ok = type(result) is str and "passed" in result.lower() # AUTOTEST - LEAK else: ok = type(result) is str and "passed" in result.lower() # NORMAL TEST @@ -112,25 +132,30 @@ class Test_Leak(Test_Test): ret = self.components["digital_io"].set_bit_verify(0, 1, 0) else: - result = None + #result = None ok = None + + results={"ok":ok} + results.update(data) super().get([{ "time": data.get("time", None), - "results": { - "ok": ok, - "result": result, - "data": data["tecna_t3"], - }, + "results": results + #"results": { + #"ok": ok, + #"result": result, + #"data": data["tecna_t3"], + #}, }], override=override, fail=ok is False) def visualize(self, data=None): if data is None: data = {} - d = data.get("results", {}).get("data", {}) + d = data.get("results", {}).get("tecna_t3", {}) for k, l in { "Running test: active phase": self.test_phase_l, "Real time test pressure output": self.circuit_pressure_l, - "Real time differential pressure output": self.leak_l, + #"Real time differential pressure output": self.leak_l, + "Running test: measured leak": self.leak_l, "Real time pressure line regulator": self.regulated_pressure_l, # "Active alarm flags": self._l, "Running test: test type": self.test_type_l, @@ -156,6 +181,9 @@ class Test_Leak(Test_Test): if self.parent_assembly_widget is not None: self.parent_assembly_widget().set_text(text="COLLEGARE GLI ATTACCHI PNEUMATICI E PREMERE START PER INIZIARE LA PROVA TENUTA") self.start_b.setEnabled(True) + self.start_b.setDefault(True) + self.start_b.setFocus() + self.stop_b.setEnabled(False) else: if self.step is not None: diff --git a/src/ui/test_leak/test_leak.ui b/src/ui/test_leak/test_leak.ui index 90ef48e..a9844d9 100644 --- a/src/ui/test_leak/test_leak.ui +++ b/src/ui/test_leak/test_leak.ui @@ -6,8 +6,8 @@ 0 0 - 370 - 491 + 1611 + 894 @@ -26,313 +26,8 @@ 0 - - - - - 12 - 75 - true - - - - PROVA TENUTA - - - - - - - 16 - 50 - false - - - - Tipo di test - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16 - 50 - false - - - - Pressione del circuito - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16 - 50 - false - - - - Fase del test - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16 - 50 - false - - - - Pressione regolatore - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 130 - 16777215 - - - - - 20 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - 130 - 16777215 - - - - - 20 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - 16 - 50 - false - - - - Perdita - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - - - - - - 130 - 16777215 - - - - - 20 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - 16 - 50 - false - - - - Indice di sequenza del test - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16 - 50 - false - - - - mbar - - - - - - - - 16 - 50 - false - - - - mbar - - - - - - - - 16 - 50 - false - - - - mbar - - - - - - - - 16 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - 16 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - 16 - 50 - false - - - - background-color: rgb(255, 255, 255); -border: 1px solid black; - - - - - - - - - - - - - + + 0 @@ -345,529 +40,10 @@ border: 1px solid black; 100 - - - - - - - 0 - 0 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 127 - 255 - 127 - - - - - - - 63 - 255 - 63 - - - - - - - 0 - 127 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 85 - 255 - 127 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 255 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 127 - 255 - 127 - - - - - - - 63 - 255 - 63 - - - - - - - 0 - 127 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 85 - 255 - 127 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 255 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 127 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 127 - 255 - 127 - - - - - - - 63 - 255 - 63 - - - - - - - 0 - 127 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 127 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 127 - 0 - - - - - - - 85 - 255 - 127 - - - - - - - 85 - 255 - 127 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - - - 20 - 75 - true - - - - background-color:rgb(85, 255, 127); - - - START - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Risultato - - - - - - - 0 - 0 - - - - %v / %m - - - - - - - - 0 - 0 - - - - - 32 - 32 - - - - - - - - - - - - - - - - 0 - 0 - - - + - 0 - 100 + 16777215 + 16777215 @@ -1327,7 +503,1018 @@ border: 1px solid black; - + + + + + 0 + 0 + + + + + 0 + 100 + + + + + + + + + 0 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 112 + 112 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 112 + 112 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 127 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 0 + 0 + + + + + + + 112 + 112 + 255 + + + + + + + 112 + 112 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 20 + 75 + true + + + + background-color:rgb(112, 112, 255); + + + MOSTRA ISTRUZIONE + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Risultato + + + + + + + 0 + 0 + + + + %v / %m + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + - + + + + + + + + + + + 0 + 0 + + + + + 0 + 100 + + + + + 16777215 + 16777215 + + + + + + + + + 0 + 0 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 127 + 255 + 127 + + + + + + + 63 + 255 + 63 + + + + + + + 0 + 127 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 85 + 255 + 127 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 255 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 127 + 255 + 127 + + + + + + + 63 + 255 + 63 + + + + + + + 0 + 127 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 85 + 255 + 127 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 255 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 127 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 127 + 255 + 127 + + + + + + + 63 + 255 + 63 + + + + + + + 0 + 127 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 127 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 127 + 0 + + + + + + + 85 + 255 + 127 + + + + + + + 85 + 255 + 127 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + 20 + 75 + true + + + + background-color:rgb(85, 255, 127); + + + START + + + false + + + false + + + false + + + + @@ -1347,6 +1534,558 @@ border: 1px solid black; + + + + + 12 + 75 + true + + + + PROVA TENUTA + + + + + + + 16 + 50 + false + + + + Caduta massima ammessa + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + Indice di sequenza del test + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + Pressione regolatore + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + Tipo di test + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + + 48 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + 1/1 + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 16 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + Pressione del circuito + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 16 + 50 + false + + + + Fase del test + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + Caduta di pressione misurata + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + Pressione di test da ricetta + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + Caduta minima ammessa + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16 + 50 + false + + + + mbar + + + + + + + + 130 + 16777215 + + + + + 20 + 50 + false + + + + background-color: rgb(255, 255, 255); +border: 1px solid black; + + + + - + + + + + + + + 16 + 50 + false + + + + 0 + + + NUMERO TEST + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + - + + + Qt::AlignCenter + + + + + + diff --git a/src/ui/test_test/test_test.py b/src/ui/test_test/test_test.py index 34413bd..d14f358 100644 --- a/src/ui/test_test/test_test.py +++ b/src/ui/test_test/test_test.py @@ -1,5 +1,7 @@ import sys +import time import weakref +from datetime import datetime from lib.helpers import timing from PyQt5.QtCore import Qt, QTimer, pyqtSignal @@ -119,6 +121,7 @@ class Test_Test(Widget): self.last = None def get(self, data=None, override=False, fail=False, preserve_counter=False, skip_delay=False): + cur_timing = timing() if self.done: # avoid proccessing if completed return if data is None: @@ -129,18 +132,19 @@ class Test_Test(Widget): data = self.last if self.last is not None else {} else: data = data[-data_usable.index(True) - 1] - if data.get("time", None) is None: - data["time"] = timing() + data["time"] = datetime.now().strftime("%H:%M:%S") if fail: result_ok = False elif override: result_ok = True else: result_ok = data.get("results", {}).get("ok", None) + duration=cur_timing - self.start_time + data.pop("step",None) self.last = { **data, "overridden": override, - "duration": timing() - self.start_time, + "duration": float(f"{duration:.2f}"), "ok": result_ok, } if fail: