Synchronisation hors ligne des données de test avec TofuPilot
Toutes les stations de test n'ont pas une connexion internet. Salles blanches, déploiements terrain, installations sécurisées et ateliers de production avec un WiFi instable ont tous besoin de capturer les données de test de manière fiable. Le client Python de TofuPilot gère les scénarios hors ligne en vous permettant de stocker les résultats localement et de les synchroniser lorsque la connectivité est rétablie.
Quand le test hors ligne est nécessaire
| Scénario | Pourquoi c'est hors ligne |
|---|---|
| Installation air-gap | Les exigences de sécurité interdisent l'accès internet |
| Test terrain | Lieu distant sans connectivité |
| Salle blanche | Pas d'accès réseau à l'intérieur de l'environnement contrôlé |
| Atelier de production | WiFi peu fiable, impossible de s'y fier pour chaque test |
| Station de test mobile | Déplacements entre sites |
Dans tous ces cas, le test doit s'exécuter et enregistrer les données indépendamment de l'état du réseau. On ne peut pas dire à une ligne de production de s'arrêter parce que le WiFi est en panne.
Architecture pour le test hors ligne en priorité
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Station de │────▶│ Stockage │────▶│ TofuPilot │
│ test │ │ local │ │ (cloud) │
│ (exécute) │ │ (fichiers │ │ │
│ │ │ JSON) │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
Hors ligne Quand connecté
La station de test écrit les résultats dans un stockage local. Un processus de synchronisation les envoie à TofuPilot lorsqu'une connexion est disponible.
Étape 1 : Stocker les résultats localement
Écrire les résultats de test dans des fichiers JSON sur la machine locale. Chaque fichier représente une exécution de test.
import json
import os
from datetime import datetime
OFFLINE_DIR = "/data/test-results/pending"
os.makedirs(OFFLINE_DIR, exist_ok=True)
def run_test(serial_number):
"""Exécuter le test et stocker les résultats localement."""
# Exécuter vos mesures de test réelles
vcc = measure_voltage(channel=1)
current = measure_current()
result = {
"procedure_id": "BOARD-FUNCTIONAL-V3",
"unit_under_test": {"serial_number": serial_number},
"run_passed": 3.25 <= vcc <= 3.35 and 30 <= current <= 60,
"tested_at": datetime.utcnow().isoformat(),
"steps": [{
"name": "Power Rail Check",
"step_type": "measurement",
"status": 3.25 <= vcc <= 3.35,
"measurements": [{
"name": "vcc_3v3",
"value": vcc,
"unit": "V",
"limit_low": 3.25,
"limit_high": 3.35,
}],
}, {
"name": "Current Draw",
"step_type": "measurement",
"status": 30 <= current <= 60,
"measurements": [{
"name": "idle_current_ma",
"value": current,
"unit": "mA",
"limit_low": 30,
"limit_high": 60,
}],
}],
}
filename = f"{serial_number}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.json"
filepath = os.path.join(OFFLINE_DIR, filename)
with open(filepath, "w") as f:
json.dump(result, f, indent=2)
print(f"Résultat sauvegardé localement : {filepath}")
return result
# Exécuter les tests quel que soit l'état du réseau
run_test("UNIT-5501")
run_test("UNIT-5502")Étape 2 : Synchroniser une fois connecté
Un script de synchronisation séparé envoie les résultats en attente à TofuPilot et les déplace dans un répertoire « synchronisé ».
import json
import os
import shutil
from tofupilot import TofuPilotClient
PENDING_DIR = "/data/test-results/pending"
SYNCED_DIR = "/data/test-results/synced"
os.makedirs(SYNCED_DIR, exist_ok=True)
def sync_pending_results():
"""Envoyer tous les résultats en attente à TofuPilot."""
client = TofuPilotClient()
pending_files = sorted(os.listdir(PENDING_DIR))
if not pending_files:
print("Aucun résultat en attente à synchroniser.")
return
print(f"Synchronisation de {len(pending_files)} résultats en attente...")
for filename in pending_files:
filepath = os.path.join(PENDING_DIR, filename)
with open(filepath) as f:
result = json.load(f)
try:
client.create_run(
procedure_id=result["procedure_id"],
unit_under_test=result["unit_under_test"],
run_passed=result["run_passed"],
steps=result["steps"],
)
# Déplacer dans le répertoire synchronisé
shutil.move(filepath, os.path.join(SYNCED_DIR, filename))
print(f"Synchronisé : {filename}")
except Exception as e:
print(f"Échec de synchronisation de {filename} : {e}")
# Laisser dans le répertoire en attente pour réessai
remaining = len(os.listdir(PENDING_DIR))
print(f"Synchronisation terminée. {remaining} fichiers encore en attente.")
sync_pending_results()Étape 3 : Automatiser la synchronisation
Exécuter le script de synchronisation automatiquement lorsque la connectivité est disponible.
Option A : Tâche cron
# Essayer de synchroniser toutes les 15 minutes
*/15 * * * * /usr/bin/python3 /opt/test-station/sync_results.py >> /var/log/test-sync.log 2>&1Option B : Déclenchement sur événement réseau
import subprocess
import time
def has_internet():
try:
subprocess.check_call(
["curl", "-s", "--max-time", "5", "https://app.tofupilot.com/api/health"],
stdout=subprocess.DEVNULL,
)
return True
except subprocess.CalledProcessError:
return False
while True:
if has_internet():
subprocess.run(["python3", "sync_results.py"])
time.sleep(300) # Vérifier toutes les 5 minutesIntégrité des données
La synchronisation hors ligne introduit un risque : que se passe-t-il si un fichier est corrompu ou si une synchronisation échoue partiellement ?
| Risque | Atténuation |
|---|---|
| Corruption de fichier | Écrire dans un fichier temporaire d'abord, puis renommer (écriture atomique) |
| Envoi en double | TofuPilot déduplique par procédure + numéro de série + horodatage |
| Échec partiel de synchronisation | Les fichiers restent en attente jusqu'à leur envoi réussi |
| Décalage d'horloge sur les machines hors ligne | Utiliser des horodatages monotones pour l'ordonnancement, UTC pour le temps absolu |
Quand utiliser ce pattern
Utilisez le test hors ligne en priorité quand :
- Votre station de test ne peut pas garantir la connectivité réseau
- La latence réseau ralentirait le temps de cycle du test
- Vous avez besoin que les tests s'exécutent même pendant les pannes réseau
- Les exigences de sécurité interdisent l'accès cloud direct depuis l'atelier de test
Pour les stations avec une connectivité fiable, envoyez les résultats directement à TofuPilot depuis le script de test. Le pattern hors ligne ajoute de la complexité qui n'est justifiée que lorsque la connectivité est peu fiable.