La plupart des ingénieurs de test commencent avec la sortie du terminal. Cela fonctionne pendant le développement, mais les opérateurs de production ont besoin d'un écran dédié avec des indicateurs pass/fail, des invites et des champs de saisie. Ce guide montre comment créer une interface opérateur avec OpenHTF et TofuPilot sans écrire de code frontend.
Ce que voit l'opérateur
L'interface opérateur terminée fonctionne dans un navigateur et affiche :
- La saisie du numéro de série (lecteur de code-barres ou saisie manuelle)
- La progression des phases en temps réel pendant le test
- Les invites opérateur avec champs de saisie (texte, nombres, listes déroulantes, choix par image)
- Le résultat pass/fail avec un affichage en couleur
- Les valeurs de mesure avec l'état des limites
L'opérateur ne voit jamais de terminal, de navigateur de fichiers ni de code Python.
Prérequis
- Python 3.10+
- OpenHTF installé (
pip install openhtf) - SDK Python TofuPilot 1.11.0+ installé (
pip install tofupilot)
Étape 1 : Créer des phases de test avec des invites
Utilisez le plug user_input d'OpenHTF pour ajouter des interactions opérateur. Chaque invite met le test en pause jusqu'à ce que l'opérateur réponde.
operator_ui_test.py25 lines
import openhtf as htffrom openhtf.plugs import user_inputfrom openhtf.util import units@htf.plug(prompts=user_input.UserInput)def phase_load_dut(test, prompts): """Attendre que l'opérateur charge le DUT dans le montage.""" prompts.prompt( "Placez la carte dans le montage de test et fermez la bride. " "Appuyez sur Entrée quand vous êtes prêt." )@htf.plug(prompts=user_input.UserInput)@htf.measures( htf.Measurement("label_present").with_args(docstring="Résultat de l'inspection de l'étiquette"),)def phase_visual_check(test, prompts): """Demander à l'opérateur de vérifier que l'étiquette est présente et correcte.""" result = prompts.prompt( "L'étiquette du produit est-elle présente et correctement alignée ?", text_input=True, ) test.measurements.label_present = resultÉtape 2 : Ajouter des mesures automatisées
Mélangez les invites opérateur avec les mesures automatisées des instruments. L'opérateur voit les deux types de phases dans la même interface.
operator_ui_test.py22 lines
@htf.measures( htf.Measurement("supply_voltage_V") .in_range(minimum=4.9, maximum=5.1) .with_units(units.VOLT), htf.Measurement("boot_time_ms") .in_range(maximum=2000) .with_units(units.MILLISECOND),)def phase_power_and_boot(test): """Automatisé : mesurer la tension d'alimentation et le temps de démarrage.""" test.measurements.supply_voltage_V = 5.02 test.measurements.boot_time_ms = 1340@htf.measures( htf.Measurement("wifi_rssi_dBm") .in_range(minimum=-70, maximum=-20) .with_units(units.DBM),)def phase_wireless_check(test): """Automatisé : vérifier la puissance du signal WiFi.""" test.measurements.wifi_rssi_dBm = -42Étape 3 : Ajouter une étape opérateur finale
Une fois les tests automatisés terminés, demandez à l'opérateur de retirer le DUT et d'apposer une étiquette pass/fail.
@htf.plug(prompts=user_input.UserInput)def phase_unload(test, prompts): """Demander à l'opérateur de retirer le DUT et d'apposer l'étiquette.""" prompts.prompt( "Retirez la carte du montage. " "Apposez une étiquette PASS si le test a réussi. " "Appuyez sur Entrée quand c'est fait." )Étape 4 : Connecter à TofuPilot et exécuter
Reliez toutes les phases ensemble et connectez-vous à TofuPilot. L'interface opérateur est diffusée automatiquement vers une URL dans le navigateur.
from tofupilot.openhtf import uploadtest = htf.Test( phase_load_dut, phase_visual_check, phase_power_and_boot, phase_wireless_check, phase_unload,)test.add_output_callbacks(upload())test.execute(test_start=lambda: input("Scan serial: "))Lorsque vous exécutez ce script, TofuPilot affiche une URL dans la console. Ouvrez-la dans un navigateur sur la station de l'opérateur. L'opérateur voit chaque phase dans l'ordre, répond aux invites et obtient un résultat pass/fail clair.
Étape 5 : Configurer la station pour la production
| Paramètre | Comment |
|---|---|
| Mode kiosque | Lancer Chrome avec --kiosk --app=<streaming-url> |
| Démarrage automatique | Ajouter la commande au script de démarrage du système |
| Lecteur de code-barres | Le configurer en clavier USB HID (le scan arrive dans le champ de saisie actif) |
| Texte agrandi | Régler le zoom du navigateur à 150 % |
| Écran tactile | Les invites TofuPilot fonctionnent au toucher, sans souris |
| Stations multiples | Chaque station a sa propre URL de streaming |
Types de saisie disponibles
L'interface opérateur de TofuPilot prend en charge des types de saisie structurés au-delà du simple texte :
| Type de saisie | Cas d'usage |
|---|---|
| Texte | Numéros de série, notes de l'opérateur |
| Nombre | Mesures manuelles, comptages |
| Curseur | Réglages analogiques, appréciations subjectives |
| Boutons radio | Choisir une option dans une liste |
| Case à cocher | Confirmer plusieurs éléments (checklist) |
| Liste déroulante | Choisir dans une longue liste d'options |
| Choix par image | Choisir parmi des photos (orientation d'un composant, type de défaut) |
| Interrupteur | Décisions oui/non |
Ces saisies s'affichent automatiquement dans le navigateur. L'opérateur les remplit et les valeurs remontent au script de test sous forme de données de mesure.
Schémas courants
Arrêt immédiat avec notification de l'opérateur
from openhtf import PhaseResult@htf.measures( htf.Measurement("power_good").equals("PASS"),)def phase_power_check(test): """Arrêter tôt si la mise sous tension échoue. Inutile de tester une carte morte.""" result = "PASS" test.measurements.power_good = result if result != "PASS": return PhaseResult.STOPLorsque cette phase échoue, l'opérateur voit immédiatement l'échec dans le navigateur, avec la mesure fautive mise en évidence. Il n'attend pas l'expiration des phases restantes.
Étapes opérateur conditionnelles
@htf.plug(prompts=user_input.UserInput)@htf.measures( htf.Measurement("rework_action").with_args(docstring="Reprise effectuée"),)def phase_rework_prompt(test, prompts): """Si une phase précédente a signalé un problème, demander une reprise à l'opérateur.""" action = prompts.prompt( "L'inspection de soudure a signalé le pad U3. " "Reprenez le joint et appuyez sur Entrée quand c'est fait.", text_input=True, ) test.measurements.rework_action = action