Test Station Setup

Interface opérateur avec OpenHTF

Construisez l'interface opérateur d'un test OpenHTF sur une station TofuPilot : invites texte, boutons de confirmation, saisie texte et images.

CCharlotte Evequoz
intermediate5 min de lecture17 juin 2026

Interface opérateur avec OpenHTF

OpenHTF peut mettre un test en pause pour interagir avec l'opérateur via son plug user_input. Quand le test s'exécute sur une station TofuPilot, ces invites s'affichent dans le kiosque de la station : une image optionnelle, votre message, et soit un bouton de confirmation soit un champ de saisie. Ce guide couvre toute cette surface avec des exemples, et se termine par le rendu sur la station.

Ce que voit l'opérateur

Une invite apparaît sur un écran avec :

  • Une image optionnelle, au-dessus du message
  • Le texte du message
  • Un bouton Continuer, ou un champ de saisie, selon l'appel

L'opérateur n'ouvre jamais de terminal ni de visionneuse séparée.

Prérequis

  • Python 3.10+
  • OpenHTF installé (pip install openhtf)

Le plug UserInput

Un seul appel pilote l'invite. Attachez le plug UserInput à une phase et appelez prompt().

signature.py
from openhtf.plugs import user_inputprompts.prompt(    message,            # texte affiché à l'opérateur    text_input=False,   # False = bouton de confirmation, True = champ de saisie    timeout_s=None,     # optionnel, lève PromptUnansweredError au timeout    image_url=None,     # image optionnelle affichée dans l'invite)

Il retourne le texte de l'opérateur (une chaîne vide quand text_input=False).

Message et bouton Continuer

power_cycle.py
import openhtf as htffrom openhtf.plugs import user_input@htf.plug(prompts=user_input.UserInput)def power_cycle(test, prompts):    prompts.prompt("Faites un cycle d'alimentation, attendez la LED, puis cliquez sur Continuer.")

Saisie texte

scan_serial.py
@htf.plug(prompts=user_input.UserInput)def scan_serial(test, prompts):    serial = prompts.prompt("Scannez le numéro de série :", text_input=True)    test.dut_id = serial

Décisions Oui / Non

OpenHTF n'a pas de widget à deux boutons Oui/Non. Le schéma est toujours le même : demander une réponse tapée, puis brancher dessus, en général en renvoyant PhaseResult.CONTINUE pour continuer ou PhaseResult.STOP pour arrêter le test. L'exemple ci-dessous conditionne le test à un contrôle LED.

led_check.py
@htf.plug(prompts=user_input.UserInput)def led_check(test, prompts):    answer = prompts.prompt("La LED clignote-t-elle en vert ? Tapez y ou n :", text_input=True)    return htf.PhaseResult.CONTINUE if answer.strip().lower() == "y" \        else htf.PhaseResult.STOP

Le même schéma couvre beaucoup de décisions opérateur, par exemple : confirmer qu'un connecteur est bien enfoncé avant la mise sous tension, juger un pass/fail visuel sur une finition ou une étiquette, ou décider si une unité part en reprise après une inspection.

Afficher une image dans l'invite

Passez image_url et l'image s'affiche, au-dessus du message, en direct pendant le run. Cela fonctionne avec un bouton de confirmation et avec un champ de saisie. L'URL est tout ce qu'accepte une balise image HTML.

Image hébergée

connector_check.py
@htf.plug(prompts=user_input.UserInput)def connector_check(test, prompts):    prompts.prompt(        "Branchez le câble comme indiqué, puis cliquez sur Continuer.",        image_url="http://localhost:8080/reference/connector.png",    )

Image locale en data URI (sans serveur)

Sur une station, c'est en général le plus simple : lisez un fichier local et intégrez-le en data URI base64, sans rien à héberger.

visual_inspection.py
import base64def data_uri(path, mime="image/png"):    with open(path, "rb") as f:        return f"data:{mime};base64," + base64.b64encode(f.read()).decode("ascii")@htf.plug(prompts=user_input.UserInput)def visual_inspection(test, prompts):    reference = data_uri("/opt/station/reference/board_top.jpg", "image/jpeg")    answer = prompts.prompt(        "La carte correspond-elle à la référence ? Tapez y ou n :",        text_input=True,        image_url=reference,    )    return htf.PhaseResult.CONTINUE if answer.strip().lower() == "y" \        else htf.PhaseResult.STOP

Image capturée pendant le test

confirm_capture.py
@htf.plug(prompts=user_input.UserInput)def confirm_capture(test, prompts):    path = "/tmp/capture.png"    camera.grab_frame(path)  # votre code de capture    prompts.prompt(        "L'image capturée est-elle nette et centrée ?",        text_input=True,        image_url=data_uri(path, "image/png"),    )

Remarques : utilisez image/png ou image/jpeg ; l'URL doit se charger depuis le navigateur qui exécute le kiosque, donc un data URI est le plus sûr sur une station. image_url affiche l'image en direct ; pour la garder aussi dans l'enregistrement du run, attachez-la avec test.attach_from_file(path).

Texte de statut en direct

OpenHTF n'a pas de ligne de console qui se met à jour toute seule pour l'opérateur. Pour faire remonter la progression pendant une phase, utilisez test.logger : chaque appel émet un enregistrement de log en direct, diffusé vers l'UI opérateur qui affiche le run (l'UI web d'OpenHTF, ou le kiosque TofuPilot) et conservé dans l'enregistrement du test. Utilisez-le pour la progression, puis une courte invite une fois l'étape terminée.

discharge.py
@htf.plug(prompts=user_input.UserInput)def discharge(test, prompts):    test.logger.info("En attente de la décharge du condensateur...")  # entrée de log en direct    wait_for_discharge()  # votre code    prompts.prompt("Condensateur déchargé. Cliquez sur Continuer.")

Ce que voit l'opérateur dans TofuPilot

Ces invites s'affichent dans le kiosque de la station TofuPilot, l'UI opérateur que la CLI sert localement et ouvre dans un navigateur. Activez le kiosque sur la station, ou forcez-le pour un run avec tofupilot run --kiosk. Quand une phase appelle prompt(), le kiosque affiche l'image, le message et le bouton Continuer ou le champ de saisie sur un écran ; l'opérateur répond et le run continue. Pour suivre depuis le dashboard, ouvrez la vue opérateur de la station sur <votre-url-tofupilot>/<org>/operator/<station-id>.

Si vous avez besoin de saisies plus riches que ces invites OpenHTF, comme des listes, checklists, curseurs, interrupteurs ou une barre de progression en direct, vous pouvez les ajouter avec une procédure du framework TofuPilot qui déclare des composants UI.

Plus de guides

Mettez ce guide en pratique