Si vous avez déjà des scripts de test OpenHTF en production, la première chose à savoir est que vous n'avez pas à les réécrire. La CLI TofuPilot exécute OpenHTF nativement : phases, mesures, logs, pièces jointes et invites opérateur sont transmis au dashboard sans aucune modification de code. Ce guide couvre ce chemin, puis la question distincte de savoir quand un portage vers le TofuPilot Framework vaut l'effort.
Étape 1 : exécuter votre script existant sur la CLI
Installez la CLI :
curl -fsSL https://www.tofupilot.app/install | shPointez-la vers votre point d'entrée OpenHTF existant :
tofupilot run ./main.pyC'est toute la migration pour la plupart des scripts. La CLI détecte le test OpenHTF, l'exécute et diffuse le run. Vous obtenez le streaming temps réel, l'interface opérateur, la mise en file d'attente hors ligne et le déploiement au push sans toucher au code de test.
Étape 2 : choisir comment les résultats arrivent au dashboard
Il existe deux chemins pris en charge, et ils ne sont pas exclusifs.
Par la CLI. Exécutez avec --upload sur une procédure liée. Rien ne change dans le script.
tofupilot logintofupilot linktofupilot run ./main.py --uploadPar le callback Python. Si vous gérez votre propre distribution et ne voulez pas la CLI dans la boucle, le paquet tofupilot fournit un callback de sortie OpenHTF :
pip install "tofupilot[openhtf]"main.py20 lines
import openhtf as htffrom tofupilot.openhtf import uploaddef phase_one(test): return htf.PhaseResult.CONTINUEdef main(): test = htf.Test( phase_one, procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", part_number="PCB01", ) test.add_output_callbacks(upload()) test.execute(lambda: "SN-0001")if __name__ == "__main__": main()upload() lit TOFUPILOT_API_KEY depuis l'environnement. add_output_callbacks est le point d'extension propre à OpenHTF, donc le callback se compose avec ceux que vous utilisez déjà, comme json_factory.
Pour une instance auto-hébergée avec une autorité de certification privée :
test.add_output_callbacks(upload( url="https://tofupilot.yourcompany.com", verify="/path/to/ca-certificate.pem",))Étape 3 : abandonner le gestionnaire de contexte déprécié
Si vos scripts utilisent with TofuPilot(test):, ce wrapper est déprécié. Sur tofupilot>=2.16.0 il fonctionne encore comme une fine enveloppe autour du même callback et émet un FutureWarning. Les versions 2.15.0 à 2.15.2 ne l'incluent pas du tout et lèvent une ImportError.
Remplacez-le par la forme callback en deux lignes :
from tofupilot import TofuPilotwith TofuPilot(test): test.execute(test_start=lambda: input("Serial: "))from tofupilot.openhtf import uploadtest.add_output_callbacks(upload())test.execute(test_start=lambda: input("Serial: "))Trois détails à connaître lors de ce changement :
OpenHTF est un extra depuis 2.15.0. Installez tofupilot[openhtf], et non tofupilot seul, pour qu'une station qui n'utilise que le client API ne tire pas un framework de test qu'elle n'importe jamais.
Le streaming MQTT a disparu. stream=True est accepté mais ignoré avec un avertissement dans les logs ; passez stream=False pour le faire taire. L'interface opérateur en direct est fournie par la CLI, donc exécutez avec tofupilot run si vous en dépendiez.
Ctrl-C se comporte différemment. Le wrapper supprimait KeyboardInterrupt, donc Ctrl-C sortait silencieusement. Le callback simple le laisse remonter. Si vos scripts de banc dépendaient de cette sortie silencieuse, entourez test.execute(...) d'un try/except KeyboardInterrupt.
Étape 4 : déployer sur les stations
Une fois le script exécuté sous la CLI, le déploiement est un push Git. La station récupère la nouvelle version, avec des artefacts de build immuables et un retour arrière instantané en cas de problème. Les runs sont mis en file d'attente localement quand le réseau tombe et se synchronisent à son retour.
Rien de tout cela n'exige le TofuPilot Framework. Les procédures OpenHTF se déploient de la même façon.
Quand porter vers le TofuPilot Framework
Le portage est optionnel. Il vaut la peine pour des raisons précises, pas par principe.
| Raison de porter | Pourquoi OpenHTF ne peut pas le faire |
|---|---|
| La ligne est limitée par le débit | Les phases OpenHTF s'exécutent séquentiellement ; le Framework exécute les phases indépendantes en parallèle |
| Plusieurs cartes sur un même montage | Exécution multi-slot, chaque slot ayant son propre run et son propre verdict |
| Les opérateurs ont besoin de workflows guidés riches | Formulaires et affichages déclaratifs, aucun travail frontend |
| Validation de la forme d'une courbe ou d'un balayage | Agrégations et validateurs par axe |
| Vous voulez des limites relisibles comme des données | Les limites vivent en YAML, versionnées séparément de la logique |
| Raison de ne pas porter | |
|---|---|
| Ça fonctionne et la ligne n'est pas limitée par le débit | Le coût de migration n'achète rien |
| Un paradigme Python pur est une préférence d'équipe | La couche YAML est un vrai concept à apprendre |
| Apache 2.0 compte pour votre revue juridique | La concession de brevet d'OpenHTF |
Le portage, concrètement
Si vous portez, la correspondance est mécanique.
| OpenHTF | TofuPilot Framework |
|---|---|
Fonction de phase avec @htf.measures | Fonction simple ; mesures déclarées en YAML |
.in_range(3.2, 3.4) | validators avec >= et <= |
.equals("2.1.0") | validators avec operator: "==" |
Sous-classe de BasePlug | Classe Python simple |
setUp / tearDown | __init__ / close |
@htf.plug(dut=DutPlug) | Plug injecté par nom de paramètre |
test.measurements.x = v | measurements.x = v |
htf.Test(phase1, phase2) | Liste main: dans la procédure |
@htf.PhaseOptions(timeout_s=10) | timeout sur la phase |
Ordre des phases dans htf.Test(...) | depends_on |
Avant :
openhtf_version.py26 lines
import openhtf as htffrom openhtf.plugs import BasePlugfrom openhtf.util import unitsclass DutPlug(BasePlug): def setUp(self): self.connected = True def read_voltage(self) -> float: return 3.31 def tearDown(self): self.connected = False@htf.measures( htf.Measurement("rail_3v3").in_range(3.2, 3.4).with_units(units.VOLT),)@htf.plug(dut=DutPlug)def test_power(test, dut): test.measurements.rail_3v3 = dut.read_voltage()test = htf.Test(test_power, part_number="PCBA-100")test.execute(test_start=lambda: input("Serial: "))Après :
class Dut: def __init__(self): self.connected = True def read_voltage(self) -> float: return 3.31 def close(self): self.connected = Falsedef power(measurements, dut): measurements.rail_3v3 = dut.read_voltage()procedure.yaml24 lines
name: PCBA Functional Testversion: 1.0.0unit: serial_number: default_value: "PCBA000001" part_number: default_value: "PCBA-100"plugs: - name: dut python: plugs.dut:Dutmain: - name: Power python: phases.power measurements: - name: Rail 3V3 unit: V validators: - operator: ">=" expected_value: 3.2 - operator: "<=" expected_value: 3.4Valider avant de basculer
Quel que soit le chemin choisi, exécutez l'ancienne et la nouvelle version sur les mêmes unités, y compris des unités connues comme mauvaises, et comparez mesure par mesure. Une limite mal transcrite pendant un portage est le mode de défaillance qui laisse partir de mauvaises cartes, et il est peu coûteux de l'attraper ainsi.
Gardez des noms de mesures identiques de part et d'autre du portage. Renommer rail_3v3 scinde l'historique et vous perdez la tendance que vous cherchiez à préserver.
Mélanger les deux
Vous n'avez pas à choisir un seul modèle pour toute l'usine. Gardez OpenHTF là où il tourne déjà, et utilisez le Framework sur les nouvelles stations qui ont besoin de slots parallèles ou de workflows opérateur plus riches. Les deux tournent sur la même CLI et remontent vers le même dashboard, donc le rendement et la traçabilité restent cohérents dans ce mélange.
Voir TofuPilot Framework contre OpenHTF pour la comparaison complète.
Erreurs fréquentes
| Erreur | Conséquence | Correction |
|---|---|---|
Installer tofupilot seul pour un script OpenHTF | ImportError sur tofupilot.openhtf | Installer tofupilot[openhtf] |
Conserver with TofuPilot(test): | FutureWarning, et ImportError sur 2.15.x | Passer à add_output_callbacks(upload()) |
Attendre que stream=True fasse quelque chose | Silencieusement ignoré | Utiliser tofupilot run pour l'interface en direct |
| Renommer des mesures pendant un portage | L'historique de tendance se scinde en deux | Garder les noms strictement identiques |
| Porter sans validation en parallèle | Une erreur de transcription atteint la production | Exécuter les deux sur les mêmes unités d'abord |
| Porter parce que c'est plus récent | Un coût sans bénéfice | Porter pour le parallélisme, l'interface ou les courbes |
