Merge remote-tracking branch 'origin/master'

This commit is contained in:
neo 2025-02-11 18:19:39 +01:00
commit 311726303c
21 changed files with 883 additions and 290 deletions

View File

@ -0,0 +1,101 @@
codice_ricetta,part_number,tempo_pre_riempimento,pressione_pre_riempimento,tempo_riempimento,tempo_assestamento,percentuale_minima_pressione_assestamento,percentuale_massima_pressione_assestamento,tempo_di_test,pressione_di_test_delta_minimo,pressione_di_test,pressione_di_test_delta_massimo,tempo_svuotamento,pressione_svuotamento,template_di_stampa,campo1,campo2
5803148256,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148256,
5803148257,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148257,
5803148261,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148261,
5803148263,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148263,
5803148264,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148264,
5803148265,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148265,
5803148266,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148266,
5803148267,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148267,
5803148268,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148268,
5803148269,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803148269,
5803166717,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803166717,
5803167128,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5803167128,
5802966801,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5802966801 R.01,
A68507016000,FUEL HOSE PUMP CPL,0,0,0,1,10,10,0,0,7200,0,0.1,0,4,A68507016000,KTM
16LA573CP REV01, HOSE-MCU-TO-MOTOR,0,0,0,0,20,20,2,0,3000,0,0.1,0,2, HOSE-MCU-TO-MO,P16
PIPE-IN-PRE-COOL,16LA372CP,0,0,0,0,20,20,3,0,3500,0,0.1,0,2,16LA372CP REV01,P16
5803083561, TUBO ASPIRAZIONE,0,3000,0,1,20,20,2,0,3000,0,0.1,0,6,5803083561,IVECO
5803083634, TUBO ASPIRAZIONE,0,3000,0,1,20,20,2,0,2000,0,0.1,0,6,5803083634,IVECO
16LA642CP REV01,HOSE-WCACS LINK PIPE,0,0,0,0,20,20,3,0,3500,0,0.1,0,2,HOSE-WCACS LINK ,P16
16LA353CP REV02,HOSE-RH-HT-RADIATOR-TOP,0,2000,1,1,20,20,3,0,3500,0,0.1,0,2,HOSE-RH-HT-RADIA,P16
16LA336CP REV02,16LA336CP,0,0,0,1,20,20,3,0,3500,0,0.1,0,2, HOSE-E-MOTOR,P16
16L0180CP REV04,16L0180CP,0,0,0,1,20,20,3,0,3000,0,0.1,0,2,HOSE LH LTR OUT,P16
HOSE-JNCTN TO W,16L0177CP,0,0,0,1,20,20,3,0,3500,0,0.1,0,2,16L0177CP REV03,P16
HOSE-IPU-OUTLET,16L0170CP,0,0,0,1,20,20,2,0,3000,0,0.1,0,2,16L0170CP REV03,P16
HOSE-TO-MCU,16L0167CP,0,0,0,1,20,20,2,0,3000,0,0.1,0,2,16L0167CP REV02,P16
HOSE-LH-LTR-OUTL,16L0164CP,0,0,0,1,20,20,3,0,3000,0,0.1,0,2,16L0164CP REV02,P16
16L0007CP REV03,16L0007CP,0,0,1,0,20,20,3,0,3000,0,0.1,0,2,HOSE-IPU-JNCTN-T,P16
16FC246CP REV01,16FC246CP,0,0,0,0,20,20,3,0,1000,0,0.1,0,2,ASSY-OIL FILL,P16
HOSE-WCACS-TO,16L0161CP,0,0,0,1,20,20,2,0,3000,0,0.1,0,2,16L0161CP REV04,P16
HOSE-RH-LTR-OUT,16L0154CP,0,0,1,1,20,20,2,0,3000,0,0.1,0,2,16L0154CP REV03,P16
16LA661CP REV01,HOSE-RH-HT-RADIATOR-BOTT,0,2000,1,0,20,20,3,0,3500,0,0.1,0,2,HOSE-RH-HT-RADIA,P16
16L0058CP REV02,16L0058CP,0,0,0,0,20,20,3,0,3500,0,0.1,0,2,HOSE-LT-TUNEL-TO,P16
16FC069CP REV01,ASSY CCV-INTAKE,0,0,0,0,20,20,2,0,1000,0,0.1,0,2,ASSY CCV-INTAKE,P16
16L0145CP REV3,16L0145CP,0,0,0,1,20,20,2,0,3000,0,0.1,0,2,HOSE-HOSE-PUMP-T,P16
16FC056CP REV02,ASSY-MAKE UP AIR,0,0,0,0,20,20,2,0,1000,0,0.1,0,2,ASSY-MAKE UP AIR,P16
HOSE-IPU-OUTLET,16L0151CP,0,0,1,1,20,20,2,0,3000,0,0.1,0,2,16L0151CP REV03,P16
16L0046CP REV03,HOSE-LH-HT-RADIATOR-TOP-,0,2000,1,0,20,20,3,0,3500,0,0.1,0,2,HOSE-LH-HT-RADIA,P16
16L0075CP REV03,16L0075CP,0,0,0,1,20,20,3,0,2500,0,0.1,0,2,HOSE-HEADER-TANK,P16
16FC250CP REV01,16FB640CP,0,0,0,0,20,20,1,0,200,0,0.1,0,2,ASSY CCV - PCV,P16
MY83-6B748-BA,ENGINE OIL ASY-OUTLET,0,0,1,1,10,10,3,0,7000,0,0.0,0,4,MY83-6B748-BA,AST0N MARTIN
6689099A1,ARGO TRACT,0,0,0,1,10,10,2,0,6000,0,0.0,0,4,6689099A1,
6689101A1,ARGO TRACT,0,0,0,1,10,10,2,0,6000,0,0.0,0,4,6689101A1,
6689098A1,ARGO TRACT,0,0,0,1,10,10,2,0,6000,0,0.0,0,4,6689098A1,
5803031876,OIL FILLER PIPE,0,0,1,1,10,10,1,0,500,0,0.0,0,4,5803031876,IVECO
FUGA CALIBRATA,24003,0,7000,0,0,5,5,1,0,7000,0,0.1,0,5,24003 12MBAR,FUGA CALIBRATA
5801384842 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801384842 REV 0,LANCIA BOLZANO
5802729983 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5802729983 REV 0,LANCIA BOLZANO
5802731910 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5802731910 REV 0,LANCIA BOLZANO
5801384841 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801384841 REV0,LANCIA BOLZANO
5802915821,COMPL.MAN,0,0,0,1,15,15,1,0,5000,0,0.1,0,6,5802915821 R.02,
5802915822,COMPL.MAN,0,0,0,1,15,15,1,0,5000,0,0.1,0,6,5802915822 R.02,
504321532 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,504321532 REV 0,LANCIA BOLZANO
5801970063 REV0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801970063 REV0,LANCIA BOLZANO
60192054 REV01,TUBO PER COMBUSTIBILE,0,0,1,1,10,10,1,0,8000,0,0.0,0,4,60192054 REV01,LANCIA BOLZANO
5801862227,TUBO PER COMBUSTIBILE,0,0,1,1,10,10,1,0,8000,0,0.0,0,4,5801862227 REV0,LANCIA BOLZANO
5801970064 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801970064 REV 0,LANCIA BOLZANO
5801970066 REV 1,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801970066 REV01,LANCIA BOLZANO
5801970065 REV0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801970065 REV0,LANCIA BOLZANO
504321531 REV 0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,504321531 REV 0,LANCIA BOLZANO
5801384840 REV0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801384840 REV0,LANCIA BOLZANO
5801384839 REV0,TUBO PER COMBUSTIBILE,0,0,1,1,10,10,1,0,8000,0,0.0,0,4,5801384839 REV0,LANCIA BOLZANO
12970-13-2382,TUBEASSY-CLUTCH COOLING,0,0,0,0,10,10,3,0,7000,0,0.0,0,4,12970-13-2382,MULTIMATIC
12970-13-2384,TUBEASSY-CLUTCH COOLING,0,0,0,0,10,10,3,0,7000,0,0.0,0,4,12970-13-2384,MULTIMATIC
12970-13-2386,TUBEASSY-CLUTCH COOLING,0,0,0,0,10,10,2,0,7000,0,0.0,0,4,12970-13-2386,MULTIMATIC
5801970067 REV0,TUBO PER COMBUSTIBILE,0,0,2,1,10,10,1,0,8000,0,0.0,0,4,5801970067 REV0,LANCIA BOLZANO
61907016000 IN.D,FUEL HOSE PUMP CPL,0,0,0,1,10,10,0,0,7000,0,0.1,0,4,61907016000 IN.D,KTM
5802831451,TUBAZIONE RITORNO,0,0,0,1,10,10,1,0,5000,0,0.1,0,6,5802831451 R.03,
5802831453,TUBAZIONE MANDATA,0,0,0,1,10,10,1,0,5000,0,0.1,0,6,5802831453 R.03,
5802860939,TUBAZIONE TRAVERSA RADI,0,0,0,1,10,10,1,0,5000,0,0.1,0,6,5802860939 R.03,
5802831450,TUBAZIONE INTERMEDIE,0,0,0,1,10,10,1,0,5000,0,0.1,0,6,5802831450 R.03,
5802831452,TUBAZIONE INTERMEDIE,0,0,0,1,10,10,1,0,5000,0,0.1,0,6,5802831452 R.03,
5802860512,TUBAZIONE RITORNO RADIA,0,5000,0,1,10,10,1,0,5000,0,0.1,0,6,5802860512 R.03,
PY83-6B747-BA,ENGINE OIL ASSY-INLET,0,0,1,1,10,10,3,0,7000,0,0.0,0,4,PY83-6B747-BA,AST0N MARTIN
PY83-6B748-BA,ENGINE OIL ASY-OUTLET,0,0,1,1,10,10,3,0,7000,0,0.0,0,4,PY83-6B748-BA,AST0N MARTIN
5802908563,CONNECTION PIPE,0,0,1,2,20,20,1,0,2000,0,0.1,0,5,5802908563,FPT - 13535
5802726236 REV02,OIL FILLER PIPE,0,0,1,1,10,10,1,0,500,0,0.1,0,4,5802726236 REV02,IVECO
5802726232 REV02,OIL FILLER PIPE,0,300,1,1,10,10,1,0,500,0,0.1,0,4,5802726232 REV02,IVECO
TBG-915988,TUBO PLASTICO SX,0,0,0,0,15,15,2,0,3100,0,0.0,0,4,TUBO PLASTICO SX,SAGOM TUBI
TBG-915989,TUBO PLASTICO DX,0,0,0,0,15,15,2,0,3100,0,0.0,0,4,TUBO PLASTICO DX,SAGOM TUBI
TBG-919634,TUBO PLASTICO SX,0,0,1,1,15,15,2,0,3100,0,0.0,0,1,TUBO PLASTICO ,SAGOM TUBI
16EA019SP,,0,0,2,1,10,10,6,0,2000,0,0.0,0,2,P16 MCLAREN,HOSE
91752479,HOSE FUEL,0,0,0,0,10,10,5,0,2000,0,0.0,0,5,91752479 REV.A,CNH - BNJ31
91713309,HOSE FUEL,0,0,0,1,10,10,1,0,2000,0,0.0,0,5,91713309 REV.A,CNH - BNJ31
TBG-919635,TUBO PLASTICO SX,0,0,1,1,15,15,2,0,3100,0,0.1,0,1,TUBO PLASTICO ,SAGOM TUBI
5803030264,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030264 REV.0,IVECO
5803030758,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030758 REV.0,IVECO
5803030799,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030799 REV.0,IVECO
5803030800,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030800 REV.0,IVECO
5803030840,DELIVERY PIPE COMPLETE,0,0,0,1,10,10,1,0,4000,0,0.0,0,4,5803030840 REV.0,IVECO
5803030842,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030842 REV.0,IVECO
5803030878,DELIVERY PIPE COMPLETE,0,0,0,0,10,10,1,0,4000,0,0.0,0,4,5803030878 REV.0,IVECO
5802878056,,0,0,0,1,10,10,1,0,5000,0,0.0,0,6,5802878056 ,
5802831451,,0,0,0,1,10,10,1,0,5000,0,0.0,0,6,5802831451 R.03,
5802967436,,0,0,0,1,10,10,1,0,5000,0,0.0,0,6,5802967436 R.03,
5802860512,,0,0,0,1,10,10,1,0,5000,0,0.0,0,6,5802860512 R.03,
5802989226,FPT,0,0,0,2,10,10,1,0,2000,0,0.0,0,4,5802989226,
5803028303,FPT,0,0,0,1,10,10,2,0,2000,0,0.0,0,4,5803028303,
5802989036,FPT,0,0,0,1,10,10,2,0,2000,0,0.0,0,4,5802989036,
5802269836,FPT,0,0,0,1,10,10,2,0,3000,0,0.0,0,4,5802269836,
000952054,j000952054,0,2200,0,0,5,5,3,0,2200,0,0.0,100,1,000952054,LANCIA BOLZANO
1 codice_ricetta part_number tempo_pre_riempimento pressione_pre_riempimento tempo_riempimento tempo_assestamento percentuale_minima_pressione_assestamento percentuale_massima_pressione_assestamento tempo_di_test pressione_di_test_delta_minimo pressione_di_test pressione_di_test_delta_massimo tempo_svuotamento pressione_svuotamento template_di_stampa campo1 campo2
2 5803148256 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148256
3 5803148257 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148257
4 5803148261 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148261
5 5803148263 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148263
6 5803148264 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148264
7 5803148265 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148265
8 5803148266 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148266
9 5803148267 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148267
10 5803148268 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148268
11 5803148269 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803148269
12 5803166717 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803166717
13 5803167128 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5803167128
14 5802966801 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5802966801 R.01
15 A68507016000 FUEL HOSE PUMP CPL 0 0 0 1 10 10 0 0 7200 0 0.1 0 4 A68507016000 KTM
16 16LA573CP REV01 HOSE-MCU-TO-MOTOR 0 0 0 0 20 20 2 0 3000 0 0.1 0 2 HOSE-MCU-TO-MO P16
17 PIPE-IN-PRE-COOL 16LA372CP 0 0 0 0 20 20 3 0 3500 0 0.1 0 2 16LA372CP REV01 P16
18 5803083561 TUBO ASPIRAZIONE 0 3000 0 1 20 20 2 0 3000 0 0.1 0 6 5803083561 IVECO
19 5803083634 TUBO ASPIRAZIONE 0 3000 0 1 20 20 2 0 2000 0 0.1 0 6 5803083634 IVECO
20 16LA642CP REV01 HOSE-WCACS LINK PIPE 0 0 0 0 20 20 3 0 3500 0 0.1 0 2 HOSE-WCACS LINK P16
21 16LA353CP REV02 HOSE-RH-HT-RADIATOR-TOP 0 2000 1 1 20 20 3 0 3500 0 0.1 0 2 HOSE-RH-HT-RADIA P16
22 16LA336CP REV02 16LA336CP 0 0 0 1 20 20 3 0 3500 0 0.1 0 2 HOSE-E-MOTOR P16
23 16L0180CP REV04 16L0180CP 0 0 0 1 20 20 3 0 3000 0 0.1 0 2 HOSE LH LTR OUT P16
24 HOSE-JNCTN TO W 16L0177CP 0 0 0 1 20 20 3 0 3500 0 0.1 0 2 16L0177CP REV03 P16
25 HOSE-IPU-OUTLET 16L0170CP 0 0 0 1 20 20 2 0 3000 0 0.1 0 2 16L0170CP REV03 P16
26 HOSE-TO-MCU 16L0167CP 0 0 0 1 20 20 2 0 3000 0 0.1 0 2 16L0167CP REV02 P16
27 HOSE-LH-LTR-OUTL 16L0164CP 0 0 0 1 20 20 3 0 3000 0 0.1 0 2 16L0164CP REV02 P16
28 16L0007CP REV03 16L0007CP 0 0 1 0 20 20 3 0 3000 0 0.1 0 2 HOSE-IPU-JNCTN-T P16
29 16FC246CP REV01 16FC246CP 0 0 0 0 20 20 3 0 1000 0 0.1 0 2 ASSY-OIL FILL P16
30 HOSE-WCACS-TO 16L0161CP 0 0 0 1 20 20 2 0 3000 0 0.1 0 2 16L0161CP REV04 P16
31 HOSE-RH-LTR-OUT 16L0154CP 0 0 1 1 20 20 2 0 3000 0 0.1 0 2 16L0154CP REV03 P16
32 16LA661CP REV01 HOSE-RH-HT-RADIATOR-BOTT 0 2000 1 0 20 20 3 0 3500 0 0.1 0 2 HOSE-RH-HT-RADIA P16
33 16L0058CP REV02 16L0058CP 0 0 0 0 20 20 3 0 3500 0 0.1 0 2 HOSE-LT-TUNEL-TO P16
34 16FC069CP REV01 ASSY CCV-INTAKE 0 0 0 0 20 20 2 0 1000 0 0.1 0 2 ASSY CCV-INTAKE P16
35 16L0145CP REV3 16L0145CP 0 0 0 1 20 20 2 0 3000 0 0.1 0 2 HOSE-HOSE-PUMP-T P16
36 16FC056CP REV02 ASSY-MAKE UP AIR 0 0 0 0 20 20 2 0 1000 0 0.1 0 2 ASSY-MAKE UP AIR P16
37 HOSE-IPU-OUTLET 16L0151CP 0 0 1 1 20 20 2 0 3000 0 0.1 0 2 16L0151CP REV03 P16
38 16L0046CP REV03 HOSE-LH-HT-RADIATOR-TOP- 0 2000 1 0 20 20 3 0 3500 0 0.1 0 2 HOSE-LH-HT-RADIA P16
39 16L0075CP REV03 16L0075CP 0 0 0 1 20 20 3 0 2500 0 0.1 0 2 HOSE-HEADER-TANK P16
40 16FC250CP REV01 16FB640CP 0 0 0 0 20 20 1 0 200 0 0.1 0 2 ASSY CCV - PCV P16
41 MY83-6B748-BA ENGINE OIL ASY-OUTLET 0 0 1 1 10 10 3 0 7000 0 0.0 0 4 MY83-6B748-BA AST0N MARTIN
42 6689099A1 ARGO TRACT 0 0 0 1 10 10 2 0 6000 0 0.0 0 4 6689099A1
43 6689101A1 ARGO TRACT 0 0 0 1 10 10 2 0 6000 0 0.0 0 4 6689101A1
44 6689098A1 ARGO TRACT 0 0 0 1 10 10 2 0 6000 0 0.0 0 4 6689098A1
45 5803031876 OIL FILLER PIPE 0 0 1 1 10 10 1 0 500 0 0.0 0 4 5803031876 IVECO
46 FUGA CALIBRATA 24003 0 7000 0 0 5 5 1 0 7000 0 0.1 0 5 24003 12MBAR FUGA CALIBRATA
47 5801384842 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801384842 REV 0 LANCIA BOLZANO
48 5802729983 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5802729983 REV 0 LANCIA BOLZANO
49 5802731910 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5802731910 REV 0 LANCIA BOLZANO
50 5801384841 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801384841 REV0 LANCIA BOLZANO
51 5802915821 COMPL.MAN 0 0 0 1 15 15 1 0 5000 0 0.1 0 6 5802915821 R.02
52 5802915822 COMPL.MAN 0 0 0 1 15 15 1 0 5000 0 0.1 0 6 5802915822 R.02
53 504321532 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 504321532 REV 0 LANCIA BOLZANO
54 5801970063 REV0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801970063 REV0 LANCIA BOLZANO
55 60192054 REV01 TUBO PER COMBUSTIBILE 0 0 1 1 10 10 1 0 8000 0 0.0 0 4 60192054 REV01 LANCIA BOLZANO
56 5801862227 TUBO PER COMBUSTIBILE 0 0 1 1 10 10 1 0 8000 0 0.0 0 4 5801862227 REV0 LANCIA BOLZANO
57 5801970064 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801970064 REV 0 LANCIA BOLZANO
58 5801970066 REV 1 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801970066 REV01 LANCIA BOLZANO
59 5801970065 REV0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801970065 REV0 LANCIA BOLZANO
60 504321531 REV 0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 504321531 REV 0 LANCIA BOLZANO
61 5801384840 REV0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801384840 REV0 LANCIA BOLZANO
62 5801384839 REV0 TUBO PER COMBUSTIBILE 0 0 1 1 10 10 1 0 8000 0 0.0 0 4 5801384839 REV0 LANCIA BOLZANO
63 12970-13-2382 TUBEASSY-CLUTCH COOLING 0 0 0 0 10 10 3 0 7000 0 0.0 0 4 12970-13-2382 MULTIMATIC
64 12970-13-2384 TUBEASSY-CLUTCH COOLING 0 0 0 0 10 10 3 0 7000 0 0.0 0 4 12970-13-2384 MULTIMATIC
65 12970-13-2386 TUBEASSY-CLUTCH COOLING 0 0 0 0 10 10 2 0 7000 0 0.0 0 4 12970-13-2386 MULTIMATIC
66 5801970067 REV0 TUBO PER COMBUSTIBILE 0 0 2 1 10 10 1 0 8000 0 0.0 0 4 5801970067 REV0 LANCIA BOLZANO
67 61907016000 IN.D FUEL HOSE PUMP CPL 0 0 0 1 10 10 0 0 7000 0 0.1 0 4 61907016000 IN.D KTM
68 5802831451 TUBAZIONE RITORNO 0 0 0 1 10 10 1 0 5000 0 0.1 0 6 5802831451 R.03
69 5802831453 TUBAZIONE MANDATA 0 0 0 1 10 10 1 0 5000 0 0.1 0 6 5802831453 R.03
70 5802860939 TUBAZIONE TRAVERSA RADI 0 0 0 1 10 10 1 0 5000 0 0.1 0 6 5802860939 R.03
71 5802831450 TUBAZIONE INTERMEDIE 0 0 0 1 10 10 1 0 5000 0 0.1 0 6 5802831450 R.03
72 5802831452 TUBAZIONE INTERMEDIE 0 0 0 1 10 10 1 0 5000 0 0.1 0 6 5802831452 R.03
73 5802860512 TUBAZIONE RITORNO RADIA 0 5000 0 1 10 10 1 0 5000 0 0.1 0 6 5802860512 R.03
74 PY83-6B747-BA ENGINE OIL ASSY-INLET 0 0 1 1 10 10 3 0 7000 0 0.0 0 4 PY83-6B747-BA AST0N MARTIN
75 PY83-6B748-BA ENGINE OIL ASY-OUTLET 0 0 1 1 10 10 3 0 7000 0 0.0 0 4 PY83-6B748-BA AST0N MARTIN
76 5802908563 CONNECTION PIPE 0 0 1 2 20 20 1 0 2000 0 0.1 0 5 5802908563 FPT - 13535
77 5802726236 REV02 OIL FILLER PIPE 0 0 1 1 10 10 1 0 500 0 0.1 0 4 5802726236 REV02 IVECO
78 5802726232 REV02 OIL FILLER PIPE 0 300 1 1 10 10 1 0 500 0 0.1 0 4 5802726232 REV02 IVECO
79 TBG-915988 TUBO PLASTICO SX 0 0 0 0 15 15 2 0 3100 0 0.0 0 4 TUBO PLASTICO SX SAGOM TUBI
80 TBG-915989 TUBO PLASTICO DX 0 0 0 0 15 15 2 0 3100 0 0.0 0 4 TUBO PLASTICO DX SAGOM TUBI
81 TBG-919634 TUBO PLASTICO SX 0 0 1 1 15 15 2 0 3100 0 0.0 0 1 TUBO PLASTICO SAGOM TUBI
82 16EA019SP 0 0 2 1 10 10 6 0 2000 0 0.0 0 2 P16 MCLAREN HOSE
83 91752479 HOSE FUEL 0 0 0 0 10 10 5 0 2000 0 0.0 0 5 91752479 REV.A CNH - BNJ31
84 91713309 HOSE FUEL 0 0 0 1 10 10 1 0 2000 0 0.0 0 5 91713309 REV.A CNH - BNJ31
85 TBG-919635 TUBO PLASTICO SX 0 0 1 1 15 15 2 0 3100 0 0.1 0 1 TUBO PLASTICO SAGOM TUBI
86 5803030264 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030264 REV.0 IVECO
87 5803030758 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030758 REV.0 IVECO
88 5803030799 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030799 REV.0 IVECO
89 5803030800 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030800 REV.0 IVECO
90 5803030840 DELIVERY PIPE COMPLETE 0 0 0 1 10 10 1 0 4000 0 0.0 0 4 5803030840 REV.0 IVECO
91 5803030842 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030842 REV.0 IVECO
92 5803030878 DELIVERY PIPE COMPLETE 0 0 0 0 10 10 1 0 4000 0 0.0 0 4 5803030878 REV.0 IVECO
93 5802878056 0 0 0 1 10 10 1 0 5000 0 0.0 0 6 5802878056
94 5802831451 0 0 0 1 10 10 1 0 5000 0 0.0 0 6 5802831451 R.03
95 5802967436 0 0 0 1 10 10 1 0 5000 0 0.0 0 6 5802967436 R.03
96 5802860512 0 0 0 1 10 10 1 0 5000 0 0.0 0 6 5802860512 R.03
97 5802989226 FPT 0 0 0 2 10 10 1 0 2000 0 0.0 0 4 5802989226
98 5803028303 FPT 0 0 0 1 10 10 2 0 2000 0 0.0 0 4 5803028303
99 5802989036 FPT 0 0 0 1 10 10 2 0 2000 0 0.0 0 4 5802989036
100 5802269836 FPT 0 0 0 1 10 10 2 0 3000 0 0.0 0 4 5802269836
101 000952054 j000952054 0 2200 0 0 5 5 3 0 2200 0 0.0 100 1 000952054 LANCIA BOLZANO

View File

@ -0,0 +1,5 @@
verifica_codice_a_barre_abilitata,pressione_di_test_2,cliente,tempo_di_test_2,pressione_pre_riempimento,prova_tenuta_abilitata,modello_etichetta,tempo_di_test,pressione_pre_riempimento_2,prova_tenuta_abilitata_2,stampa_etichetta_abilitata,part_number,tempo_pre_riempimento_2,tempo_pre_riempimento,pressione_di_test,codice_a_barre,codice_ricetta
x,15000,Ferrari,10,1000,x,ferrari_30x16_203.prn,30,1000,x,x,000990684,0,0,2000,,000990684
x,15000,Ferrari,10,1000,x,ferrari_30x16_203.prn,30,1000,x,x,000990685,0,0,2000,,000990685
x,15000,Ferrari,10,1000,x,ferrari_30x16_203.prn,30,1000,x,x,000990686,0,0,2000,,000990686
x,15000,Ferrai,10,1000,x,ferrari_30x16_203.prn,30,1000,x,x,000990708,0,0,5000,,000990708
1 verifica_codice_a_barre_abilitata pressione_di_test_2 cliente tempo_di_test_2 pressione_pre_riempimento prova_tenuta_abilitata modello_etichetta tempo_di_test pressione_pre_riempimento_2 prova_tenuta_abilitata_2 stampa_etichetta_abilitata part_number tempo_pre_riempimento_2 tempo_pre_riempimento pressione_di_test codice_a_barre codice_ricetta
2 x 15000 Ferrari 10 1000 x ferrari_30x16_203.prn 30 1000 x x 000990684 0 0 2000 000990684
3 x 15000 Ferrari 10 1000 x ferrari_30x16_203.prn 30 1000 x x 000990685 0 0 2000 000990685
4 x 15000 Ferrari 10 1000 x ferrari_30x16_203.prn 30 1000 x x 000990686 0 0 2000 000990686
5 x 15000 Ferrai 10 1000 x ferrari_30x16_203.prn 30 1000 x x 000990708 0 0 5000 000990708

View File

@ -1,5 +1,5 @@
[machine]
description = ST-TEN-12 AUTOMATICO
description = ST-TEN-12 M2 C04
instruction_folder = st-ten-12
image_for_warning= st-ten-12

View File

@ -13,7 +13,7 @@ neo_pixels: absent
remote_api: absent
tecna_t3: present
vision_saver: absent
vision: absent
vision: present
screwdriver: absent
fixture_id: present
barcode_recipe_selection: present
@ -26,11 +26,11 @@ poll_time: 10
hold_time: 10
[tecna_t3]
port: /dev/ttyUSB1
model: t3p
port: /dev/ttyUSB0
model: t3l
[fixture_rfid]
port: USB0
port: USB1
[digital_io]
# OUTPUT MAP FOR VALVE CONTROL UNITS
@ -54,7 +54,6 @@ cliente: IVECO
part_number: specificare part number
canale_di_prova: 0
warning_img:
pid_pressure_correction: 105
dimensione_lotto_abilitata:
n_componenti:1
istruzione_abilitata: x
@ -89,6 +88,8 @@ pressione_di_test_2: 1000
pressione_di_test_delta_massimo_2: 200
tempo_svuotamento_2: 1
pressione_svuotamento_2: 100
pid_pressure_correction: 105
pid_pressure_correction_2: 105
stampa_etichetta_abilitata: x
modello_etichetta: ETA30x16_203dpi.prn

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Define the temporary file name for the .desktop file
SCRIPT="/tmp/shortcut-$(date +%s).desktop"
# Create the .desktop file with the required content
echo "[Desktop Entry]" >> $SCRIPT
echo "Version=1.0" >> $SCRIPT
echo "Name=AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT
echo "Comment=Shortcut to AVVIO PROGRAMMA COLLAUDO" >> $SCRIPT
echo "Exec=$HOME/PycharmProjects/st-ten-1/runmetest.sh" >> $SCRIPT
echo "Icon=$HOME/PycharmProjects/st-ten-1/src/ui/imgs/neo_red.ico" >> $SCRIPT
echo "Terminal=false" >> $SCRIPT
echo "Type=Application" >> $SCRIPT
echo "Categories=Utility;" >> $SCRIPT
# Prompt for sudo password and copy the .desktop file to the user's Desktop
sudo cp $SCRIPT "$HOME/Desktop/AVVIO PROGRAMMA TEST.desktop"
# Make the .desktop file executable
sudo chmod +x "$HOME/Desktop/AVVIO PROGRAMMA TEST.desktop"
# Remove the temporary .desktop file
rm $SCRIPT
echo "Shortcut created on Desktop"

4
runmetest.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash -e
cd "$(dirname "$0")"
source "./venv/bin/activate" || source "./venv/Scripts/activate" || :
python -O "./src/main.py" --no-edgetpu --no-tflite --no-autotest --sim-archiver --sim-printer --system-id=test-linux --no-autotest --no-lock --sim-io --dev-portal --auto-login-admin $*

View File

@ -273,7 +273,7 @@ class ArchiveSynchronizer(Component):
self.log.error(f"id {record.id}: {path_in}: file not found.")
return False
except Forbidden as e:
if re.match("^Object '.*?' is subject to bucket's retention policy and cannot be deleted, overwritten or archived until .*?$", e._response.json()["error"]["message"]) is not None:
if re.match("^Object '.*?' is subject .*?$", e._response.json()["error"]["message"]) is not None:
self.log.info(f"id {record.id}: {path_in}: already stored.")
else:
self.log.warning(f"id: {record.id}: failed to store remotely: {str(e)}: {e._response.json()}")

View File

@ -174,7 +174,7 @@ class Component(QObject):
self._lock.release()
return running
def wait_completion(self, timeout=5):
def wait_completion(self, timeout=10):
"""
waits until the requested action has been completed by the component
this will return immediately if threaded=False was passed at component initialization

View File

@ -14,11 +14,14 @@ from .hikrobot_dll import *
class HikrobotSmartCamera(Component):
def __init__(self, config=None, name=None, period=0.5, lazy=True, paused=False, threaded=True):
def __init__(self, config=None, name=None, period=0.2, lazy=True, paused=False, threaded=True):
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
self.simulate = "--sim-camera" in sys.argv
self.num_cameras=1
self.connected = False
self.ok_memory = True
self.ok_frames = []
self.ok_results =[]
def config_changed(self):
self.connected = False
@ -99,39 +102,53 @@ class HikrobotSmartCamera(Component):
for cam_idx in range(self.num_cameras):
cam = self.cam_list[cam_idx]
self.log.info(f"GET FRAME CAMERA # {cam_idx}")
# Trigger acquisition & test execution
nRet = mv_lib.MV_VS_SetCommandValue(cam["handle"], b"AcquisitionStart")
if nRet != MV_VS_OK:
self.log.error(f"CAM{cam_idx} AcquisitionStart failed! [{nRet&0xFFFFFFFF:#x}]")
self.connected = False
# get frame
frame_res = MV_VS_GetFrame(cam["handle"])
if frame_res is not None:
res = frame_res["res"]["ScDeviceSolutionRunningResult"]
frame = frame_res["frame"]
# rotate frame
if rot[cam_idx] == "1":
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
if rot[cam_idx] == "2":
frame = cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
if rot[cam_idx] == "3":
frame = cv2.rotate(frame, cv2.ROTATE_180)
if concat_frame is None:
concat_frame = copy.deepcopy(frame)
else:
concat_frame = cv2.hconcat([concat_frame, frame])
concat_results.append(not res)
if self.ok_results[cam_idx]:
# keep last good result
frame = self.ok_frames[cam_idx]
res = False
else:
self.connected = False
super()._get([concat_frame, concat_results])
# Trigger acquisition & test execution
nRet = mv_lib.MV_VS_SetCommandValue(cam["handle"], b"AcquisitionStart")
if nRet != MV_VS_OK:
self.log.error(f"CAM{cam_idx} AcquisitionStart failed! [{nRet&0xFFFFFFFF:#x}]")
self.connected = False
frame_res = None
else:
# get frame
frame_res = MV_VS_GetFrame(cam["handle"])
if frame_res is not None:
res = frame_res["res"]["ScDeviceSolutionRunningResult"]
frame = frame_res["frame"]
# rotate frame
if rot[cam_idx] == "1":
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
if rot[cam_idx] == "2":
frame = cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
if rot[cam_idx] == "3":
frame = cv2.rotate(frame, cv2.ROTATE_180)
else:
self.connected = False
if concat_frame is None:
concat_frame = copy.deepcopy(frame)
else:
concat_frame = cv2.hconcat([concat_frame, frame])
concat_results.append(not res)
if not res:
self.ok_results[cam_idx] = True
self.ok_frames[cam_idx] = copy.deepcopy(frame)
super()._get([concat_frame, self.ok_results])
def resume(self):
self.log.info(f"RESUMING")
if not self.connected:
self.config_changed()
if self.connected:
# init OK result memory
self.ok_frames = [None for n in range(self.num_cameras)]
self.ok_results = [False for n in range(self.num_cameras)]
if len(self.cam_list) == self.num_cameras:
# Dummy acquisition for each camera to avoid reading past images
for cam_idx in range(self.num_cameras):

View File

@ -2,6 +2,7 @@ import sys
import traceback
import warnings
import pymodbus
from PyQt5.QtWidgets import QMessageBox
if "--sim-serial" in sys.argv:
@ -18,113 +19,190 @@ if "--sim-modbus" not in sys.argv:
else:
from components.dummies.pymodbus import ModbusClient
from PyQt5.QtCore import QMutex
from PyQt5.QtCore import QMutex, pyqtSignal
from .component import Component
class ModbusComponent(Component):
modbus_error_signal = pyqtSignal(str)
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True, registers=None):
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
self.registers = registers if registers is not None else {}
self.lock = QMutex()
def config_changed(self):
self.method = self.config[self.name].get("method", "rtu").lower()
self.port = self.config[self.name]["port"]
self.baudrate = int(self.config[self.name]["baudrate"])
self.stopbits = getattr(serial, self.config[self.name].get("stopbits", "stopbits_one").upper())
self.parity = getattr(serial, self.config[self.name].get("parity", "parity_none").upper())
self.bytesize = getattr(serial, self.config[self.name].get("bytesize", "eightbits").upper())
self.byteorder = getattr(Endian, self.config[self.name].get("byteorder", "Big").upper())
self.wordorder = getattr(Endian, self.config[self.name].get("wordorder", "Little").upper())
self.timeout = int(self.config[self.name].get("timeout", 1))
# Read configuration values
self.method = self.config[self.name].get("method", "rtu").lower()
self.port = self.config[self.name]["port"]
self.baudrate = int(self.config[self.name]["baudrate"])
self.stopbits = getattr(serial, self.config[self.name].get("stopbits", "stopbits_one").upper())
self.parity = getattr(serial, self.config[self.name].get("parity", "parity_none").upper())
self.bytesize = getattr(serial, self.config[self.name].get("bytesize", "eightbits").upper())
self.byteorder = getattr(Endian, self.config[self.name].get("byteorder", "Big").upper())
self.wordorder = getattr(Endian, self.config[self.name].get("wordorder", "Little").upper())
self.timeout = int(self.config[self.name].get("timeout", 1))
# Lock the interaction to ensure thread safety
self.lock.lock()
try:
# Initialize the Modbus client
self.client = ModbusClient(
method=self.method,
port=self.port,
stopbits=self.stopbits,
bytesize=self.bytesize,
parity=self.parity,
baudrate=self.baudrate,
timeout=self.timeout,
strict=False,
)
if not self.client.connect():
raise ConnectionError(f"Cannot connect to Modbus on port {self.port}")
if not self.client.is_socket_open():
raise ConnectionError(f"Connection socket not open on port {self.port}")
except FileNotFoundError as e:
error_message = f"Serial port error: {self.port} not found. Check your configuration."
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
except Exception as e:
error_message = f"Configuration error: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
finally:
self.lock.unlock()
def _read(self, register, count=1, **kwargs):
"""Read holding registers with error handling."""
self.lock.lock()
self.client = ModbusClient(
method=self.method,
port=self.port,
stopbits=self.stopbits,
bytesize=self.bytesize,
parity=self.parity,
baudrate=self.baudrate,
timeout=self.timeout,
strict=False,
)
if not self.client.connect():
QMessageBox.critical(None, "ERRORE", f"ERRORE MODBUS - VERIFICARE CONNESSIONE USB")
exit(-1)
#raise ConnectionError("device not reachable (could not connect): {} ({})".format(self.name, self.port))
if not self.client.is_socket_open():
raise ConnectionError("device not reachable (socket not open): {} ({})".format(self.name, self.port))
self.lock.unlock()
def _read(self, register, count=1,**kwargs):
while True:
self.lock.lock()
read = self.client.read_holding_registers(register, count=count,**kwargs)
self.lock.unlock()
try:
read = self.client.read_holding_registers(register, count=count, **kwargs)
if read.isError():
self.log.exception(traceback.format_exception(type(read), read, read.__traceback__))
# raise read
else:
break
return read
def _write(self, register, value,**kwargs):
while True:
self.lock.lock()
wrote = self.client.write_registers(register, value, skip_encode=True,**kwargs)
error_message = f"Modbus read failed: Could not read Modbus register {register}"
self.modbus_error_signal.emit(error_message)
raise ValueError(f"Modbus read error at register {register}")
return read
except pymodbus.exceptions.ConnectionException:
error_message = f"Modbus read failed: Connection error at port {self.port}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
return None # Return None to signal failure
except Exception as e:
error_message = f"Error reading Modbus register {register}: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
return None
finally:
self.lock.unlock()
def _write(self, register, value, **kwargs):
"""Write to holding registers with error handling."""
self.lock.lock()
try:
wrote = self.client.write_registers(register, value, skip_encode=True, **kwargs)
# Check if the response indicates an error
if wrote.isError():
self.log.exception(traceback.format_exception(type(wrote), wrote, wrote.__traceback__))
# raise wrote
else:
break
raise ValueError(f"Modbus write error at register {register}")
return wrote
except pymodbus.exceptions.ConnectionException as ce:
error_message = f"Modbus write failed: Connection error at port {self.port}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
except Exception as e:
error_message = f"Error writing Modbus register {register} with value {value}: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
finally:
self.lock.unlock()
def _decode(self, read, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
decoder = BinaryPayloadDecoder.fromRegisters(read.registers, byteorder=self.byteorder, wordorder=self.wordorder)
data = getattr(decoder, f"decode_{data_type}")(*args, **kwargs)
data = (data - offset) / gain
if data_type.endswith("uint"):
data = int(abs(data))
elif data_type.endswith("int"):
data = int(data)
else:
raise NotImplementedError(f"data_type {data_type!r} is not supported")
return data
"""Decode data safely."""
if read is None:
error_message = "Error decoding Modbus data: No data to decode (read returned None)"
#self.log.error(error_message)
self.modbus_error_signal.emit(error_message)
return None
try:
decoder = BinaryPayloadDecoder.fromRegisters(
read.registers, byteorder=self.byteorder, wordorder=self.wordorder
)
data = getattr(decoder, f"decode_{data_type}")(*args, **kwargs)
data = (data - offset) / gain
return int(abs(data)) if "uint" in data_type else int(data)
except AttributeError:
error_message = "Modbus read returned invalid data (NoneType encountered)"
#self.log.error(error_message)
self.modbus_error_signal.emit(error_message)
except Exception as e:
error_message = f"Error decoding Modbus data: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
return None
def _encode(self, data, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
builder = BinaryPayloadBuilder(byteorder=self.byteorder, wordorder=self.wordorder)
data = data * gain + offset
if data_type.endswith("uint"):
data = int(abs(data))
elif data_type.endswith("int"):
data = int(data)
else:
raise NotImplementedError(f"data_type {data_type!r} is not supported")
getattr(builder, f"add_{data_type}")(data, *args, **kwargs)
return builder.build()
"""Encode data for Modbus write with error handling."""
try:
builder = BinaryPayloadBuilder(byteorder=self.byteorder, wordorder=self.wordorder)
data = data * gain + offset
if data_type.endswith("uint"):
data = int(abs(data))
elif data_type.endswith("int"):
data = int(data)
else:
raise NotImplementedError(f"Data type {data_type!r} is not supported")
getattr(builder, f"add_{data_type}")(data, *args, **kwargs)
return builder.build()
except Exception as e:
error_message = f"Error encoding Modbus data: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
return None
def read(self, register, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
if data_type.startswith("16bit_"):
count = 1
elif data_type.startswith("32bit_"):
count = 2
else:
raise NotImplementedError(f"data_type {data_type!r} is not supported")
return self._decode(self._read(register, count=count, **kwargs), *args, data_type=data_type, gain=gain,offset=offset)
"""Read and decode Modbus register data with error handling."""
try:
if data_type.startswith("16bit_"):
count = 1
elif data_type.startswith("32bit_"):
count = 2
else:
raise NotImplementedError(f"Data type {data_type!r} is not supported")
return self._decode(
self._read(register, count=count, **kwargs),
*args,
data_type=data_type,
gain=gain,
offset=offset,
)
except Exception as e:
error_message = f"Error inside Modbus read: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
return None
def write(self, register, data, *args, data_type="16bit_uint", gain=1, offset=0, **kwargs):
self._write(register, self._encode(data, *args, data_type=data_type, gain=gain, offset=offset),**kwargs)
# def _get(self, data):
# # print("MODBUS", str(int(QThread.currentThreadId())), flush=True)
# super()._get(data)
"""Encode and write data to Modbus registers with error handling."""
try:
encoded_data = self._encode(data, *args, data_type=data_type, gain=gain, offset=offset)
if encoded_data is not None:
self._write(register, encoded_data, **kwargs)
except Exception as e:
error_message = f"Error inside Modbus write: {str(e)}"
#self.log.error(error_message, exc_info=True)
self.modbus_error_signal.emit(error_message)
def __del__(self, event=None):
self.lock.lock()
if self.client.is_socket_open():
self.client.close()
self.lock.unlock()
try:
self.lock.lock()
if self.client.is_socket_open():
self.client.close()
except Exception as e:
error_message = f"Error during Modbus cleanup: {str(e)}"
#self.log.error(error_message, exc_info=True)
finally:
self.lock.unlock()

View File

@ -85,5 +85,39 @@ class RFID_PN532(Component):
self.rfid_error_signal.emit(False)
self.mutex.unlock()
def write_tag(self,data):
self.data_to_write=copy.deepcopy(data)
def write_tag(self, data):
self.data_to_write = copy.deepcopy(data)
if not self.simulate:
if not self.connected:
self.open_device()
if not self.connected:
self.log.error("Failed to connect to device")
return
if self.mutex.tryLock():
try:
target = self.clf.sense(RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F'))
if target is not None:
tag = src.lib.nfc.tag.activate(self.clf, target)
if tag is not None and tag.ndef is not None:
self.log.info("Detected NFC tag, writing data...")
ndef_record = ndef.TextRecord(self.data_to_write)
# IMPORTANT: DON'T CLOSE DEVICE BEFORE WRITING
tag.ndef.records = [ndef_record] # Write the record to the tag
self.log.info(f"Data '{self.data_to_write}' written successfully to tag.")
else:
self.log.error("Tag is not NDEF-compatible or invalid")
else:
self.log.debug("No tag present for writing")
except Exception as e:
self.log.error(f"Error during tag writing: {e}")
finally:
# Move closing outside the try block
self.mutex.unlock() # Unlock mutex always
# Close AFTER writing and mutex release
if self.connected:
self.close_device() # close_device can raise exception

View File

@ -1,5 +1,7 @@
import time
from lib.db import Recipes, db
from PyQt5.QtCore import QSemaphore, pyqtSignal
from PyQt5.QtCore import QSemaphore, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QMessageBox
from .component import Component
@ -11,9 +13,11 @@ from .tecna_marposs_provaset_t3p_registers import registers as t3p_registers
class TecnaMarpossProvasetT3(ModbusComponent):
_store_recipes_signal = pyqtSignal(object)
_store_recipes_lock = QSemaphore(0)
tecna_error_signal = pyqtSignal(bool, str) # Emits (True, error_message) if error exists, else (False, "")
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, registers=None)
self.modbus_error_signal.connect(self.handle_modbus_error)
def config_changed(self):
super().config_changed()
@ -26,13 +30,17 @@ class TecnaMarpossProvasetT3(ModbusComponent):
else:
raise NotImplementedError(f"tecna t3 model {self.model!r} not implemented.")
self.set_measure_units()
self.units = self.get_measure_units()
self.max_program_number = self.read("Max number of programs")
self.saver_label_count = min(abs(int(self.config[self.name].get("saver_label_count", 1))), 0b1111)
self.saver_print_on_fail = 1 if self.config[self.name].get("saver_print_on_fail", "no").lower() in {"yes", "y", "on", "true", "1", "x"} else 0
self.saver_label_template = min(abs(int(self.config[self.name].get("saver_label_template", 1))), 0b11111111)
self.model = self.config[self.name]["model"].lower()
self.log.info(f"units: {self.units}")
try:
self.units = self.get_measure_units()
self.max_program_number = self.read("Max number of programs")
self.saver_label_count = min(abs(int(self.config[self.name].get("saver_label_count", 1))), 0b1111)
self.saver_print_on_fail = 1 if self.config[self.name].get("saver_print_on_fail", "no").lower() in {"yes", "y", "on", "true", "1", "x"} else 0
self.saver_label_template = min(abs(int(self.config[self.name].get("saver_label_template", 1))), 0b11111111)
self.model = self.config[self.name]["model"].lower()
self.log.info(f"units: {self.units}")
except Exception as e:
error_message = f"Error during config_changed operation: {str(e)}"
self.tecna_error_signal.emit(True, error_message)
_pressure_units = {"mH2O": 0, "mbar": 1, "kPa": 2, "mmHg": 3, "inH2O": 4, "psi": 5, "mmH2O": 6, } # (se fondoscala <=6 bar)
_leak_units = {"mmH2O": 0, "mbar": 1, "Pa": 2, "mmHg": 3, "inH2O": 4, "psi": 5, }
@ -125,111 +133,133 @@ class TecnaMarpossProvasetT3(ModbusComponent):
return data
@Component.reconfig_on_error
def read(self, register, *args, data_type=None, gain=None, offset=None, formatting=None, decoding_map=None, **kwargs):
if type(register) is str:
register, s = self.registers[register]
def read(self, register, *args, data_type=None, gain=None, offset=None, formatting=None, decoding_map=None,
**kwargs):
try:
if type(register) is str:
register, s = self.registers[register]
if data_type is None:
data_type = s.get("dt", None)
if gain is None:
gain = s.get("g", None)
if offset is None:
offset = s.get("o", None)
if formatting is None:
formatting = s.get("f", None)
if decoding_map is None:
decoding_map = s.get("decoding", None)
if not len(args):
args = s.get("a", [])
if not len(kwargs):
kwargs = s.get("k", {})
if data_type is None:
data_type = s.get("dt", None)
data_type = "16bit_uint"
if gain is None:
gain = s.get("g", None)
gain = 1
if offset is None:
offset = s.get("o", None)
if formatting is None:
formatting = s.get("f", None)
if decoding_map is None:
decoding_map = s.get("decoding", None)
if not len(args):
args = s.get("a", [])
if not len(kwargs):
kwargs = s.get("k", {})
if data_type is None:
data_type = "16bit_uint"
if gain is None:
gain = 1
if offset is None:
offset = 0
return self._convert_from_format(
super().read(
offset = 0
return self._convert_from_format(
super().read(
register,
*args,
data_type=data_type,
gain=gain,
offset=offset,
**kwargs,
),
formatting=formatting,
decoding_map=decoding_map,
)
except Exception as e:
error_message = f"Error during read operation on register {register}: {str(e)}"
self.log.error(error_message, exc_info=True)
self.tecna_error_signal.emit(True, error_message)
raise # Re-raise the exception for further upstream handling if needed
@Component.reconfig_on_error
@Component.reconfig_on_error
def write(self, register, data, *args, data_type=None, gain=None, offset=None, formatting=None, encoding_map=None,
**kwargs):
try:
if type(register) is str:
register, s = self.registers[register]
if data_type is None:
data_type = s.get("dt", None)
if gain is None:
gain = s.get("g", None)
if offset is None:
offset = s.get("o", None)
if formatting is None:
formatting = s.get("f", None)
if encoding_map is None:
encoding_map = s.get("encoding", None)
if not len(args):
args = s.get("a", [])
if not len(kwargs):
kwargs = s.get("k", {})
if data_type is None:
data_type = "16bit_uint"
if gain is None:
gain = 1
if offset is None:
offset = 0
return super().write(
register,
self._convert_to_format(
data,
formatting=formatting,
encoding_map=encoding_map,
),
*args,
data_type=data_type,
gain=gain,
offset=offset,
**kwargs,
),
formatting=formatting,
decoding_map=decoding_map,
)
@Component.reconfig_on_error
def write(self, register, data, *args, data_type=None, gain=None, offset=None, formatting=None, encoding_map=None, **kwargs):
if type(register) is str:
register, s = self.registers[register]
if data_type is None:
data_type = s.get("dt", None)
if gain is None:
gain = s.get("g", None)
if offset is None:
offset = s.get("o", None)
if formatting is None:
formatting = s.get("f", None)
if encoding_map is None:
encoding_map = s.get("encoding", None)
if not len(args):
args = s.get("a", [])
if not len(kwargs):
kwargs = s.get("k", {})
if data_type is None:
data_type = "16bit_uint"
if gain is None:
gain = 1
if offset is None:
offset = 0
return super().write(
register,
self._convert_to_format(
data,
formatting=formatting,
encoding_map=encoding_map,
),
*args,
data_type=data_type,
gain=gain,
offset=offset,
**kwargs,
)
)
except Exception as e:
error_message = f"Error during write operation on register {register} with data {data}: {str(e)}"
self.log.error(error_message, exc_info=True)
self.tecna_error_signal.emit(True, error_message)
raise # Re-raise the exception for further upstream handling if needed
@Component.reconfig_on_error
def _get(self):
# print("TECNA", str(int(QThread.currentThreadId())), flush=True)
# 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",
"Running test: active phase",
"Running test: test type",
"Running test: sequence index",
"Digital inputs status (mask)",
# "Digital outputs status (mask)",
]}
if self.model == "t3p":
pass
elif self.model == "t3l":
info.update({r: self.read(r) for r in [
"Active not severe alarm flags",
]})
else:
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])
try:
# 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",
"Running test: active phase",
"Running test: test type",
"Running test: sequence index",
"Digital inputs status (mask)",
# "Digital outputs status (mask)",
]}
if self.model == "t3p":
pass
elif self.model == "t3l":
info.update({r: self.read(r) for r in [
"Active not severe alarm flags",
]})
else:
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])
except Exception as e:
error_message = f"Error during _get operation: {str(e)}"
self.log.error(error_message, exc_info=True)
self.tecna_error_signal.emit(True, error_message)
raise # Re-raise the exception for further upstream handling
@Component.reconfig_on_error
def _set(self, val=None):
@ -299,7 +329,7 @@ class TecnaMarpossProvasetT3(ModbusComponent):
"FSL - Discharge limit": step.spec["flush_pressure"],
"PSQ - Next sequence program PSOUT mode": 0,
"RAMPS: T1 configuration": pid_ramps,
"PID: pressure correction": step.spec["pid_pressure_correction"],
"PID: pressure correction": step.spec.get("pid_pressure_correction",0),
"Various flags": 0b0000000000010000 if self.config["recipes_defaults"]["tester_discharge_enable"] == "yes" else 0b0000000000000000
}
@ -402,6 +432,7 @@ class TecnaMarpossProvasetT3(ModbusComponent):
# READ ALL PARAMETERS
for register_name, field_name in spec.items():
recipe_data[field_name] = self.read(register_name)
time.sleep(0.01)
recipe_name=self.int_array_to_str([recipe_data[f"R{wn}"] for wn in range(8)])
recipe_code=self.int_array_to_str([recipe_data[f"C{wn}"] for wn in range(12)])
recipe_f1=self.int_array_to_str([recipe_data[f"F1_{wn}"] for wn in range(8)])
@ -446,3 +477,19 @@ class TecnaMarpossProvasetT3(ModbusComponent):
break
result+=char2
return result
@pyqtSlot(str)
def handle_modbus_error(self, error_message):
"""
Handle errors received from the ModbusComponent and send
appropriate error signals for Tecna Marposs.
"""
if error_message:
# Emit the Tecna-specific error signal with True and the error message
self.tecna_error_signal.emit(True, error_message)
self.log.error(f"Modbus error encountered: {error_message}")
return True, error_message
else:
# Emit no error (False)
self.tecna_error_signal.emit(False, "")
return False, None

View File

@ -125,11 +125,21 @@ try:
def read_recipes(self):
self.recipes = {}
max_num_recipes=self.components["tecna_t3"].max_program_number
max_num_recipes=300
#max_num_recipes=100
logging.info(f"NUMBER OF RECIPES TO BE READ: {max_num_recipes}")
for recipe_num in range(1, max_num_recipes+1):
logging.info(f"READING RECIPE #{recipe_num}")
self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num)
recipe_ok=False
for retry in range(3):
logging.info(f"READING RECIPE #{recipe_num}")
try:
self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num)
recipe_ok=True
break
except Exception as e:
logging.info(f"ERROR - RETRYING RECIPE #{recipe_num}")
if not recipe_ok:
self.recipes[recipe_num] = {"recipe_name":"READ_ERROR"}
def export_recipes(self, csv_path=None):
if csv_path is None:

View File

@ -6,14 +6,52 @@ 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 PyQt5.QtWidgets import QShortcut, QApplication, QDialog, QVBoxLayout, QLabel, QPushButton, QPlainTextEdit, \
QHBoxLayout, QMessageBox
from ui.test_test import Test_Test
from ui.widget import Widget
from lib import db
from lib.db.models import Recipes
from lib.db.models import Recipes , Users
test_scan="xxx\nyyy\nzzz"
class TagWindow(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Scrittura NFC")
self.setFixedSize(400, 300)
layout = QVBoxLayout(self)
self.text_edit = QPlainTextEdit(self)
self.text_edit.setPlaceholderText("Scanerizza il QRcode della Dima")
self.text_edit.setFixedHeight(100)
layout.addWidget(self.text_edit)
button_layout = QHBoxLayout()
self.ok_button = QPushButton("Conferma Tag", self)
self.ok_button.clicked.connect(self.on_ok_clicked)
# Create the Close button
self.close_button = QPushButton("Chiudi", self)
self.close_button.clicked.connect(self.close)
button_layout.addWidget(self.ok_button)
button_layout.addWidget(self.close_button)
layout.addLayout(button_layout)
def on_ok_clicked(self):
entered_text = self.text_edit.toPlainText()
print(f"Text Entered: {entered_text}")
self.accept()
class Barcode_Recipe_Selection(Test_Test):
def __init__(self, parent):
super().__init__()
@ -34,6 +72,8 @@ class Barcode_Recipe_Selection(Test_Test):
self.status_palettes["warning"].setColor(QPalette.Base, QColor(255, 165, 0))
self.status_palettes[""].setColor(QPalette.Base, QColor(255, 255, 0))
self.tag_b.clicked.connect(self.open_tag_window)
self.recipe_selection_b.clicked.connect(self.parent.set_recipe_mode_table)
self.barcode_input_l.setFocus()
@ -49,6 +89,12 @@ class Barcode_Recipe_Selection(Test_Test):
self.ok_timer.setSingleShot(True)
self.ok_timer.timeout.connect(self.set_recipe)
session= Users.get_session()
if session.is_admin:
self.tag_b.setVisible(True)
else:
self.tag_b.setVisible(False)
def start(self, recipe=None, step=None, pieces=None):
@ -113,4 +159,35 @@ class Barcode_Recipe_Selection(Test_Test):
self.parent_assembly_widget().set_text("SCANSIONARE BARCODE SELEZIONE RICETTA")
def open_tag_window(self):
# Open the tag writing window
self.tag_window = TagWindow(self)
result = self.tag_window.exec_() # Get the result of the dialog (OK or Cancel)
if result != QDialog.Accepted:
return # If canceled, return
entered_text = self.tag_window.text_edit.toPlainText().strip()
if not entered_text:
QMessageBox.warning(
self,
"Warning",
"The text is empty. Please enter text to write to the tag.",
)
return
# Check if the tag is empty
if self.parent.components["fixture_id"].current_data:
# Tag already contains data, ask for confirmation to overwrite
confirmation_result = QMessageBox.question(
self,
"Tag Already Written",
"The tag already contains data. Do you want to overwrite it?",
QMessageBox.Yes | QMessageBox.No,
)
if confirmation_result == QMessageBox.No:
return # User does not want to overwrite, so return without writing
# Write the entered text to the tag
self.parent.components["fixture_id"].write_tag(entered_text)
QMessageBox.information(self, "Success", "The tag has been successfully written.")

View File

@ -13,54 +13,146 @@
<property name="windowTitle">
<string>Test Connector</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0" alignment="Qt::AlignHCenter">
<widget class="QPlainTextEdit" name="barcode_input_l">
<property name="minimumSize">
<size>
<width>600</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<height>200</height>
</size>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="plainText">
<string/>
</property>
</widget>
</item>
<item row="3" column="0" alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="recipe_selection_b">
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="text">
<string>TORNA ALLA TABELLA RICETTE</string>
</property>
</widget>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>308</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1" colspan="2">
<widget class="QPushButton" name="recipe_selection_b">
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="text">
<string>TORNA ALLA TABELLA RICETTE</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2" colspan="2">
<widget class="QPlainTextEdit" name="barcode_input_l">
<property name="minimumSize">
<size>
<width>600</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<height>200</height>
</size>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="plainText">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>78</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>378</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>78</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>168</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="tag_b">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>SCRIVI TAG NFC</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>28</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -28,7 +28,6 @@ from ui.test_vision import Test_Vision
from ui.test_warning_img import Test_Warning_Img
from ui.widget import Widget
from components import ArchiveSynchronizer
from src.components.rfid_pn532 import RFID_PN532
class Test(Widget):
@ -58,17 +57,28 @@ class Test(Widget):
else:
self.flag_label.setVisible(False)
self.active_errors = [] # List to hold current errors (type: tuples of (message, is_error))
self.current_error_index = 0 # Keeps track of the current error index during alternation
# Timer for alternating errors
self.error_timer = QTimer()
self.error_timer.setInterval(2000) # Fire every 2 seconds
self.error_timer.timeout.connect(self.display_current_error) # Connect the timer to the display logic
# SHOW AND UPDATE TIME CLOCK
self.refresh_time(init=True)
# INIT RECIPE
self.recipe = None
self.auto_import = Recipe_Selection
self.archive_synch = ArchiveSynchronizer(config=config)
self.rfid = RFID_PN532(config=config)
if "fixture_id" in self.components:
self.rfid = self.components["fixture_id"]
self.rfid.rfid_error_signal.connect(self.handle_rfid_error)
if "tecna_t3" in self.components:
self.tecna = self.components["tecna_t3"]
self.tecna.tecna_error_signal.connect(self.handle_modbus_error)
self.error_label.setText("")
self.error_label.setStyleSheet("QLabel { color: red; }")
self.rfid.rfid_error_signal.connect(self.handle_rfid_error)
if self.config["hardware_config"]["barcode_recipe_selection"] == "present":
self.recipe_selection_mode = "barcode"
@ -78,6 +88,7 @@ class Test(Widget):
self.tester_component = None
if self.config["hardware_config"]["tecna_t3"] == "present":
self.tester_component = "tecna_t3"
self.components["tecna_t3"].tecna_error_signal.connect(self.handle_modbus_error)
elif self.config["hardware_config"]["furness_controls"] == "present":
self.tester_component = "furness_control"
@ -828,13 +839,89 @@ class Test(Widget):
self.fail_cycle()
self.change_recipe()
def add_error(self, message, is_error):
"""
Add a new error message to the list of active errors.
Args:
message (str): The error message to add.
is_error (bool): True if it's an error that should show in red, False for non-errors.
"""
# Avoid duplicates
if (message, is_error) not in self.active_errors:
self.active_errors.append((message, is_error))
# Start the timer if it's not already active
if not self.error_timer.isActive():
self.error_timer.start()
def remove_error(self, message):
"""
Remove an error message from the list of active errors.
Args:
message (str): The error message to remove.
"""
self.active_errors = [err for err in self.active_errors if err[0] != message]
# Reset the error index if necessary
if self.current_error_index >= len(self.active_errors):
self.current_error_index = 0
# Stop the timer if there are no more errors
if not self.active_errors:
self.error_label.setText("")
self.error_label.setStyleSheet("")
self.error_timer.stop()
def display_current_error(self):
"""
Display the current error from the active errors list. If there are multiple errors,
it alternates between them every time this function is called.
"""
if self.active_errors:
# Get the current error message and update the label
message, is_error = self.active_errors[self.current_error_index]
self.error_label.setText(message)
if is_error:
self.error_label.setStyleSheet("color: red;")
else:
self.error_label.setStyleSheet("color: green;")
# Move to the next error for the next call to this method
self.current_error_index = (self.current_error_index + 1) % len(self.active_errors)
else:
# Clear the label if there are no errors
self.error_label.setText("")
self.error_label.setStyleSheet("")
@pyqtSlot(bool)
def handle_rfid_error(self, connected):
"""
Handle errors related to the RFID system.
Args:
connected (bool): True if connected, False if not.
"""
if connected:
self.error_label.setText("") # Update the GUI label
self.remove_error("Errore RFID.") # Remove the RFID error
else:
self.error_label.setText("Errore RFID.") # Update the GUI label
self.error_label.setStyleSheet("color: red;")
self.add_error("Errore RFID.", True) # Add the RFID error
@pyqtSlot(bool, str)
def handle_modbus_error(self, has_error, error_message):
"""
Handle Tecna/Modbus errors and manage the error list.
Args:
has_error (bool): True if there is an error, False otherwise.
error_message (str): The error message to add.
"""
#print(f"DEBUG: Modbus error handler called - has_error={has_error}, error_message={error_message}") # Debugging
if has_error:
self.add_error(f"Errore Tecna", True) # Add the Modbus error
else:
self.remove_error(f"Errore Tecna") # Remove the Modbus error
def update_label_with_args(self, extra_info=None):
"""

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1192</width>
<height>114</height>
<height>120</height>
</rect>
</property>
<property name="windowTitle">
@ -412,7 +412,7 @@ CONTATORE</string>
</property>
</widget>
</item>
<item row="0" column="0">
<item row="0" column="9">
<widget class="QLabel" name="flag_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">

View File

@ -4,7 +4,7 @@ import weakref
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QMessageBox, QDialog, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtCore import Qt, pyqtSlot
from ui import Dialog
from ui.test_instructions_reminder import Test_Instructions_Reminder
from ui.test_test import Test_Test
@ -26,6 +26,8 @@ class Test_Leak(Test_Test):
self.show_instruction_b.setVisible("show_instructions" in self.parent.config["hardware_config"].keys())
self.show_instruction_b.clicked.connect(self.show_instruction)
self.components[self.tester_component].tecna_error_signal.connect(self.handle_modbus_error)
def show_instruction(self):
dialog=Dialog()
dialog.setCentralWidget(Test_Instructions_Reminder(recipe=self.parent.recipe,bench_name=self.parent.config.machine_id))
@ -312,3 +314,15 @@ class Test_Leak(Test_Test):
def save_last(self):
if self.last is None:
return
@pyqtSlot(bool, str)
def handle_modbus_error(self, error, error_message):
"""
Handle errors received from the Modbus component and stop the test gracefully.
"""
if error:
self.display_text(
text=f"ERRORE TECNA TEST INTERROTTO.",
bg_color="red", text_color="white"
)
self.stop_test()

View File

@ -15,7 +15,7 @@ class Test_Vision(Test_Test):
def __init__(self, components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=True):
super().__init__(components=components, recipe=recipe, step=step, pieces=pieces, run_once=run_once, reset_on_start=reset_on_start, enable_override=enable_override)
if "--sim-camera" not in sys.argv:
self.ok_counter_limit = 2
self.ok_counter_limit = 3
else:
self.ok_counter_limit = 1
# DETECTIONS TABLE