Comment créer une interface opérateur de test en Python
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 :
- Saisie du numéro de série (lecteur de code-barres ou saisie manuelle)
- Progression des phases en temps réel pendant le test
- Invites opérateur avec champs de saisie (texte, nombres, listes déroulantes, choix basés sur des images)
- Résultat pass/fail avec affichage coloré
- Valeurs de mesure avec statut 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.
import openhtf as htf
from openhtf.plugs import user_input
from 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 la fixture."""
prompts.prompt(
"Placez la carte dans la fixture de test et fermez le clamp. "
"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.
@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
Après les tests automatisés, demandez à l'opérateur de retirer le DUT et d'appliquer 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'appliquer l'étiquette."""
prompts.prompt(
"Retirez la carte de la fixture. "
"Appliquez 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 automatiquement diffusée vers une URL dans le navigateur.
from tofupilot.openhtf import TofuPilot
test = htf.Test(
phase_load_dut,
phase_visual_check,
phase_power_and_boot,
phase_wireless_check,
phase_unload,
)
with TofuPilot(test):
test.execute(test_start=lambda: input("Scanner le numéro de série : "))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 | Configurer comme clavier USB HID (le scan va dans le champ de saisie actif) |
| Gros texte | Régler le zoom du navigateur à 150 % |
| Écran tactile | Les invites TofuPilot fonctionnent avec la saisie tactile, pas besoin de souris |
| Stations multiples | Chaque station a sa propre URL de streaming |
Types de saisie disponibles
L'interface opérateur TofuPilot prend en charge des types de saisie structurés au-delà du simple texte :
| Type de saisie | Cas d'utilisation |
|---|---|
| Texte | Numéros de série, notes de l'opérateur |
| Nombre | Mesures manuelles, comptages |
| Curseur | Ajustements analogiques, évaluations subjectives |
| Boutons radio | Choisir une option dans une liste |
| Case à cocher | Confirmer plusieurs éléments (checklist) |
| Liste déroulante | Sélectionner dans une longue liste d'options |
| Choix par image | Choisir parmi des photos (orientation de 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 en tant que données de mesure.
Cas d'utilisation courants
Échec rapide avec notification 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 défaillante mise en évidence. Il n'attend pas que les phases restantes expirent.
É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 à l'opérateur de reprendre."""
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