7.6 KiB
Health-check pont-bascule branché sur l'écran de pesée
Date: 2026-05-21 Ticket: FER-19 Statut: Spec validée
Contexte
Aujourd'hui, à l'arrivée sur l'écran de pesée (réception ou expédition), l'UI affiche un texte hardcodé « Pont-bascule connecté » et un loader. C'est du faux : l'état réel du pont-bascule n'est jamais vérifié.
Le pont-bascule (Raspberry sur le réseau, ex. http://100.122.43.54:8000) expose deux routes :
POST /send/dsd— déclenche une pesée et renvoie le poids + le DSD. Déjà utilisée viaGET /receptions/weighetGET /shipments/weigh(state providers →PontBasculeService::fetch()).GET /health— health-check, non branchée aujourd'hui.
Réponse type de /health :
{
"ok": true,
"mode": "serial",
"busy": false,
"hostname": "liot-rasp-ferme-01",
"timestamp": 1779357080.6277,
"port": "/dev/ttyUSB0",
"baudrate": 9600,
"port_connected": true,
"port_error": null
}
Un bypass existe déjà côté backend (PONT_BASCULE_BYPASS=true) : il court-circuite l'appel
HTTP et renvoie un payload de test. Il est actif partout aujourd'hui (.env.local, .env.prod).
Objectif
- Brancher le vrai health-check du pont-bascule à l'arrivée sur l'écran de pesée.
- Afficher le véritable état (connecté / non connecté) à la place du texte hardcodé.
- Désactiver le bouton « peser » tant que le pont n'est pas valide.
- Conserver le bypass : en bypass, l'état est « sain » pour ne pas casser le dev.
- Ne pas dupliquer la configuration d'URL (une seule variable d'env de base).
Décisions de design
- Endpoint générique
GET /pont_bascule/health(ressource API Platform autonome). Le health-check est agnostique de l'entité pesée — un seul endpoint partagé, pas un par entité. - Check unique au montage de l'écran de pesée (pas de polling). Si le pont est down à l'arrivée, le bouton reste désactivé jusqu'au rechargement de la page. Conforme à la demande.
- Critère de validité :
healthy = ok === true && port_connected === true && port_error === null && busy === false. (busybloquant car une pesée déjà en cours metbusyàtrue.) - Bypass :
PONT_BASCULE_BYPASS=true→ health renvoiehealthy: truesans appel réseau. - Pont injoignable = état normal : le backend renvoie
200 { healthy: false }(jamais 500), pour ne pas déclencher de toast d'erreur côtéuseApi./weighgarde son comportement 500 actuel.
Configuration env (suppression de la duplication)
- Remplacer
PONT_BASCULE_URL(URL complète.../send/dsd) parPONT_BASCULE_BASE_URL(URL de base sans chemin, ex.http://100.122.43.54:8000). - Le service construit lui-même
{base}/send/dsdet{base}/health. - Fichiers à mettre à jour :
.env(valeur vide),.env.local,.env.prod, etconfig/services.yaml(argument$baseUrlau lieu de$endpoint). PONT_BASCULE_BYPASSinchangé.
Backend
PontBasculeService (src/Service/PontBasculeService.php)
- Renommer la dépendance
$endpoint→$baseUrl. fetch(): POST sur{baseUrl}/send/dsd(comportement inchangé sinon).- Nouvelle méthode
checkHealth(): PontBasculeHealth:- si
$bypass→ renvoie unPontBasculeHealthsain (healthy = true) sans appel réseau ; - sinon →
GET {baseUrl}/health, parse le JSON, calculehealthy = ok === true && port_connected === true && port_error === null && busy === false; - si l'appel transport échoue ou le JSON est invalide / incomplet → renvoie
PontBasculeHealthavechealthy = false(aucune exception levée).
- si
DTO PontBasculeHealth (src/Dto/PontBasculeHealth.php)
Groupe de sérialisation pont_bascule:health:read. Champs :
healthy: bool— le seul champ consommé par le front.- Champs informatifs (debug / affichage futur) :
ok: bool,busy: bool,portConnected: bool,portError: ?string,hostname: ?string.
Ressource API PontBasculeHealthCheck (src/ApiResource/PontBasculeHealthCheck.php)
- Classe carrier fine (vide) hébergeant l'opération
GET /pont_bascule/health, sans état persistant,output=PontBasculeHealth::class(le DTO),provider=PontBasculeHealthProvider. Même montage que/receptions/weigh(host déclare l'opération,output= DTO, provider renvoie le DTO). - Nommée
PontBasculeHealthCheckpour éviter la collision de nom court avec le DTODto\PontBasculeHealth. - Route conservée
/pont_bascule/health(pont_basculeinvariable).
PontBasculeHealthProvider (src/State/PontBasculeHealthProvider.php)
- Appelle
PontBasculeService::checkHealth()et renvoie le DTOPontBasculeHealth. - Toujours
200, même pont down (pas deHttpException).
Frontend
Couche service
- Nouveau composable
usePontBascule(composables/usePontBascule.ts) exposantcheckHealth()→api.get('pont_bascule/health'), renvoie{ healthy: boolean, ... }. Le health-check étant agnostique de l'entité, il vit dans son propre composable (et non dansworkflow-service.tsqui est un factory par entité) — une seule implémentation, pas de duplication réception/expédition.
useWeighingStep.ts (composables/steps/)
- Ajout d'un état réactif
pontBasculeStatus: 'checking' | 'connected' | 'disconnected'(initialisé à'checking'). - Au
onMounted: appel du health-check →connectedsihealthy === true, sinondisconnected. - Exposer
pontBasculeStatusau composant.
workflow-weight.vue (components/workflow/)
- Le texte hardcodé ligne 5 (
Pont-bascule connecté) devient dynamique selonpontBasculeStatus:checking→ « Vérification du pont-bascule… »connected→ « Pont-bascule connecté » (vert, style actuel)disconnected→ « Pont-bascule non connecté » (rouge)
- Le bouton « peser » reçoit
disabledtant quepontBasculeStatus !== 'connected'(état grisé). Les boutons « Valider la pesée » et « Générer le bon » restent inchangés.
Textes d'état (codés en dur)
Convention du projet : les textes d'UI dans les composants/pages sont codés en dur en
français (le « Pont-bascule connecté » actuel l'est déjà). fr.json n'est consommé que
par useApi pour les toasts. On reste cohérent : les trois libellés sont écrits directement
dans workflow-weight.vue, pas dans fr.json.
checking→ « Vérification du pont-bascule… » (couleur primary)connected→ « Pont-bascule connecté » (vert)disconnected→ « Pont-bascule non connecté » (rouge)
Error handling
/weigh: comportement inchangé (500 +PontBasculeException)./pont_bascule/health: ne lève jamais d'erreur réseau vers le front. Pont injoignable ou payload invalide =200 { healthy: false }→ pas de toast d'erreuruseApi.
Tests
Backend (PHPUnit, MockHttpClient)
Couvrir PontBasculeService::checkHealth() :
- bypass actif →
healthy = true, aucun appel réseau ; - payload sain (
ok,port_connected,port_error: null,busy: false) →healthy = true; port_errornon null →healthy = false;port_connected: false→healthy = false;busy: true→healthy = false;- transport KO / JSON invalide →
healthy = false(pas d'exception).
Frontend
Pas de test auto existant pour ce flux. Validation manuelle :
- bypass on → bouton « peser » actif, texte « connecté » ;
- simuler un fail (
healthy: false) → bouton grisé, texte « non connecté ».
Hors périmètre
- Polling / rafraîchissement automatique de l'état (check unique au montage retenu).
- Bouton « réessayer » manuel.
- Traductions autres que
fr.