De nombreuses équipes hardware construisent des bases de données personnalisées pour les résultats de test. PostgreSQL, SQLite, Microsoft Access. Elles fonctionnent bien au début. Puis quelqu'un demande les tendances de FPY entre les stations, ou vous avez besoin d'un accès multi-sites, ou un auditeur veut l'historique complet des révisions, et la charge de maintenance dépasse la simplicité initiale.
TofuPilot remplace cette infrastructure personnalisée par une plateforme gérée qui prend en charge le stockage, l'analytique et la traçabilité nativement.
Schémas courants de bases de données personnalisées
La plupart des bases de données de test développées en interne suivent l'un des schémas suivants. Voici un exemple typique :
-- Le schéma vers lequel la plupart des équipes convergent
CREATE TABLE test_runs (
id SERIAL PRIMARY KEY,
serial_number VARCHAR(50),
test_name VARCHAR(100),
result VARCHAR(10), -- 'PASS' ou 'FAIL'
operator VARCHAR(50),
station VARCHAR(50),
started_at TIMESTAMP,
duration_seconds FLOAT
);
CREATE TABLE measurements (
id SERIAL PRIMARY KEY,
run_id INTEGER REFERENCES test_runs(id),
name VARCHAR(100),
value FLOAT,
unit VARCHAR(20),
lower_limit FLOAT,
upper_limit FLOAT,
passed BOOLEAN
);Cette structure capture les éléments de base. Mais elle ne couvre pas ce qui compte à grande échelle :
- Pas d'analytique intégrée. Le FPY, le Cpk et les cartes de contrôle nécessitent des requêtes personnalisées et du code de visualisation que quelqu'un doit maintenir.
- Pas de piste d'audit. Si quelqu'un modifie une ligne, la valeur originale est perdue, sauf si vous avez construit des tables d'historique basées sur des triggers.
- Pas d'accès multi-sites. Un fichier PostgreSQL ou SQLite local ne peut pas servir des équipes sur plusieurs sites sans travail d'infrastructure.
- Dérive du schéma. Chaque station de test peut insérer des données légèrement différentes selon qui a écrit l'instruction INSERT.
Utilisateurs de bases de données TestStand
Si vous utilisez le logger de base de données intégré de NI TestStand, vous avez une variante de ce problème. TestStand écrit vers SQL Server, Oracle ou Access en utilisant un schéma fixe avec UUT_RESULT, STEP_RESULT, PROP_RESULT et des tables spécifiques aux types (PROP_NUMERICLIMIT, PROP_NUMERIC, PROP_STRINGVALUE). L'interrogation nécessite 5 à 6 JOINs de tables, et l'ajout de métadonnées personnalisées implique de modifier le mapping de base de données du Process Model.
Le même schéma de migration s'applique : remplacez l'INSERT en base de données (ou le logger de base de données de TestStand) par des mesures OpenHTF et laissez TofuPilot gérer le stockage. Si vous migrez spécifiquement depuis TestStand, consultez le guide dédié sur la migration de NI TestStand vers Python.
Remplacer les insertions personnalisées par OpenHTF
Si votre workflow actuel ressemble à « exécuter le script de test, INSERT les résultats dans la base de données », voici l'équivalent OpenHTF + TofuPilot. Au lieu de gérer la base de données, vous définissez les mesures dans le test et laissez TofuPilot gérer le stockage.
Une insertion typique dans une base de données personnalisée ressemble à ceci :
# Ce que vous remplacez : des insertions manuelles en BDD après chaque test
import psycopg2
conn = psycopg2.connect("dbname=testdata user=testeng")
cur = conn.cursor()
cur.execute(
"INSERT INTO test_runs (serial_number, test_name, result, station) "
"VALUES (%s, %s, %s, %s) RETURNING id",
("SN-5001", "thermal_cycle", "PASS", "STATION-3"),
)
run_id = cur.fetchone()[0]
cur.execute(
"INSERT INTO measurements (run_id, name, value, unit, lower_limit, upper_limit, passed) "
"VALUES (%s, %s, %s, %s, %s, %s, %s)",
(run_id, "peak_temp", 84.2, "C", 70.0, 90.0, True),
)
conn.commit()
conn.close()Voici le même test en OpenHTF avec TofuPilot :
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot
@htf.measures(
htf.Measurement("peak_temp")
.with_units(units.DEGREE_CELSIUS)
.in_range(70.0, 90.0),
htf.Measurement("settling_time")
.with_units(units.SECOND)
.in_range(maximum=30.0),
htf.Measurement("thermal_resistance")
.in_range(0.5, 2.0),
)
def thermal_cycle(test):
test.measurements.peak_temp = 84.2
test.measurements.settling_time = 18.7
test.measurements.thermal_resistance = 1.1
def main():
test = htf.Test(thermal_cycle)
with TofuPilot(test):
test.execute(test_start=lambda: "SN-5001")
if __name__ == "__main__":
main()Pas de code de connexion à la base de données. Pas de SQL. Pas de maintenance de schéma. Les mesures sont définies avec leurs limites dans le test lui-même, ce qui garantit que chaque exécution est validée et structurée de manière identique.
Migration des données historiques
Vous avez des années de données de test dans votre base de données personnalisée. L'API REST de TofuPilot vous permet de les importer avec préservation complète des horodatages.
import psycopg2
from tofupilot import TofuPilotClient
client = TofuPilotClient()
conn = psycopg2.connect("dbname=testdata user=testeng")
cur = conn.cursor()
# Récupérer les exécutions avec leurs mesures
cur.execute("""
SELECT r.serial_number, r.test_name, r.result, r.started_at, r.duration_seconds,
m.name, m.value, m.unit, m.lower_limit, m.upper_limit
FROM test_runs r
JOIN measurements m ON m.run_id = r.id
ORDER BY r.id
""")
current_run = None
steps = []
for row in cur:
serial, test_name, result, started_at, duration, m_name, m_val, m_unit, m_low, m_high = row
if current_run and current_run != (serial, started_at):
# Envoyer l'exécution précédente
prev_serial, prev_started = current_run
client.create_run(
procedure_id=test_name,
unit_under_test={"serial_number": prev_serial},
run_passed=result == "PASS",
started_at=prev_started,
duration=duration,
steps=steps,
)
steps = []
current_run = (serial, started_at)
# Trouver ou créer l'étape
step = next((s for s in steps if s["name"] == test_name), None)
if not step:
step = {"name": test_name, "step_passed": result == "PASS", "measurements": []}
steps.append(step)
step["measurements"].append({
"name": m_name,
"measured_value": m_val,
"unit": m_unit,
"lower_limit": m_low,
"upper_limit": m_high,
})
conn.close()Adaptez la requête à votre schéma. L'essentiel est de faire correspondre vos tables à la structure de TofuPilot : chaque ligne de test_runs devient une exécution, chaque ligne de measurements devient une mesure au sein d'une étape.
Ce qui remplace vos requêtes personnalisées
Si vous avez construit des requêtes SQL ou des scripts Python personnalisés pour l'analytique, le tableau de bord de TofuPilot les remplace.
| Votre requête / script personnalisé | Fonctionnalité intégrée de TofuPilot |
|---|---|
SELECT COUNT(*) ... GROUP BY result pour le rendement | Tendances FPY, mises à jour en temps réel |
| Scripts de contrôle statistique des procédés | Cpk et cartes de contrôle par mesure |
WHERE result = 'FAIL' GROUP BY measurement | Pareto des défaillances avec analyse détaillée |
GROUP BY station pour le débit | Tableau de bord de débit par station |
WHERE serial_number = 'X' pour la traçabilité | Recherche par numéro de série avec historique complet |
| Scripts de reporting personnalisés | Rapports exportables et API REST |
TofuPilot suit tout cela automatiquement. Ouvrez l'onglet Analytique pour voir le FPY, le Cpk et l'analyse des défaillances pour n'importe quelle procédure.
Exécuter les deux systèmes pendant la transition
Vous pouvez faire fonctionner votre base de données personnalisée et TofuPilot en parallèle pour valider la migration :
- Ajoutez TofuPilot à une station de test tout en gardant vos insertions de base de données existantes actives. Les deux systèmes reçoivent les mêmes résultats.
- Comparez les données pendant une semaine. Vérifiez que les valeurs de mesure, les comptages pass/fail et les horodatages correspondent entre votre base de données et TofuPilot.
- Supprimez les insertions de la base de données personnalisée de cette station une fois que vous êtes confiant. Passez à la station suivante.
- Conservez votre ancienne base de données en lecture seule comme archive. Vous pouvez toujours l'interroger pour une vérification historique.
La base de données personnalisée n'a pas besoin de disparaître immédiatement. Elle cesse simplement d'être le système de référence une fois que TofuPilot prend le relais.