644 lines
13 KiB
Markdown
644 lines
13 KiB
Markdown
# Prompt Codex — Développer un MVP MES/IoT pour superviser des presses à injecter multi-marques par acquisition passive de signaux
|
||
|
||
## Rôle attendu de l'AI coder
|
||
|
||
Tu es un développeur senior full-stack + IoT industriel. Tu dois concevoir et développer un MVP de supervision de production pour des presses à injecter utilisées en plasturgie/injection plastique, quelle que soit leur marque.
|
||
|
||
Contrainte importante : le parc machine peut inclure plusieurs marques et modèles, sans garantie d'interface Euromap 63, Euromap 77, OPC UA ou autre protocole standard. Le MVP ne doit donc dépendre d'aucun protocole constructeur spécifique. L'acquisition doit se faire principalement par lecture passive de signaux électriques machine isolés, capteurs externes et saisie opérateur.
|
||
|
||
## Objectif du MVP
|
||
|
||
Développer une application web MES légère permettant de superviser les machines en temps réel et de calculer les indicateurs de production de base.
|
||
|
||
Le MVP doit permettre de suivre :
|
||
|
||
- état machine : production, arrêt, réglage, hors planning ;
|
||
- compteur cycles automatique ;
|
||
- temps de cycle réel ;
|
||
- OF en cours ;
|
||
- quantité produite ;
|
||
- quantité bonne ;
|
||
- quantité rebutée ;
|
||
- arrêts machine automatiques ;
|
||
- qualification des causes d'arrêt par opérateur ;
|
||
- saisie des rebuts ;
|
||
- calcul TRS/OEE ;
|
||
- dashboard atelier temps réel.
|
||
|
||
## Périmètre machine
|
||
|
||
Machines cibles : presses à injecter toutes marques.
|
||
|
||
Hypothèse technique :
|
||
|
||
- pas d'Euromap 63 garanti ;
|
||
- pas d'Euromap 77 garanti ;
|
||
- pas d'OPC UA machine garanti ;
|
||
- pas d'accès direct aux paramètres process avancés au démarrage ;
|
||
- acquisition basée sur signaux électriques isolés et/ou capteurs externes ;
|
||
- approche compatible avec différentes marques via une configuration par machine, sans dépendance à un automate ou protocole propriétaire.
|
||
|
||
## Acquisition machine par signaux passifs
|
||
|
||
### Option A — Lecture signaux électriques machine
|
||
|
||
Le MVP doit gérer une acquisition basée sur des entrées digitales issues de la machine, via relais d'interface ou optocoupleurs.
|
||
|
||
Ne jamais connecter directement la gateway IoT aux sorties automate ou aux circuits machine. Toute connexion doit être isolée électriquement. L'acquisition doit rester strictement passive et non intrusive.
|
||
|
||
Chaîne recommandée :
|
||
|
||
```text
|
||
Sortie machine / contact sec / relais auxiliaire
|
||
→ relais d'interface ou optocoupleur
|
||
→ entrée digitale gateway IoT
|
||
→ service edge
|
||
→ MQTT
|
||
→ backend MES
|
||
```
|
||
|
||
### Signaux machine minimum à supporter
|
||
|
||
Le système doit pouvoir configurer les signaux suivants par machine :
|
||
|
||
| Signal | Type | Utilisation |
|
||
|---|---|---|
|
||
| machine_power_on | digital input | machine sous tension |
|
||
| auto_mode | digital input | machine en mode automatique |
|
||
| cycle_signal | digital input | détection cycle ou fin de cycle |
|
||
| mold_open | digital input optionnel | validation fin de cycle |
|
||
| ejector_forward | digital input optionnel | comptage cycle fiable |
|
||
| general_alarm | digital input optionnel | détection arrêt ou alarme |
|
||
| pump_running | digital input optionnel | machine active |
|
||
|
||
Le MVP doit fonctionner avec seulement 2 signaux minimum :
|
||
|
||
1. machine_power_on ;
|
||
2. cycle_signal.
|
||
|
||
Les autres signaux doivent être optionnels.
|
||
|
||
## Logique de détection cycle
|
||
|
||
Le signal principal est `cycle_signal`.
|
||
|
||
Règles :
|
||
|
||
- détecter un cycle uniquement sur front montant ou front descendant configurable ;
|
||
- appliquer un anti-rebond logiciel ;
|
||
- ignorer les impulsions trop proches ;
|
||
- calculer `cycle_time_sec` entre deux cycles valides ;
|
||
- publier un événement `cycle_completed` à chaque cycle valide.
|
||
|
||
Paramètres configurables par machine :
|
||
|
||
```json
|
||
{
|
||
"machine_id": "INJ-01",
|
||
"cycle_signal_edge": "rising",
|
||
"debounce_ms": 300,
|
||
"min_cycle_time_sec": 5,
|
||
"max_cycle_time_sec": 300,
|
||
"stop_detection_delay_sec": 180
|
||
}
|
||
```
|
||
|
||
### Exemple événement cycle
|
||
|
||
```json
|
||
{
|
||
"machine_id": "INJ-01",
|
||
"event_type": "cycle_completed",
|
||
"timestamp": "2026-06-14T10:32:15Z",
|
||
"cycle_time_sec": 18.7,
|
||
"source": "digital_input",
|
||
"input_name": "cycle_signal"
|
||
}
|
||
```
|
||
|
||
## Logique de détection arrêt
|
||
|
||
Un arrêt est détecté automatiquement si aucun cycle valide n'est reçu pendant une durée configurable.
|
||
|
||
Règle par défaut :
|
||
|
||
```text
|
||
Si aucun cycle depuis 180 secondes alors créer un arrêt machine automatique.
|
||
```
|
||
|
||
L'arrêt reste ouvert jusqu'au prochain cycle valide ou jusqu'à action opérateur.
|
||
|
||
À la reprise :
|
||
|
||
- fermer l'arrêt automatiquement ;
|
||
- calculer la durée ;
|
||
- laisser la cause vide si non qualifiée ;
|
||
- demander à l'opérateur de qualifier l'arrêt.
|
||
|
||
### Exemple événement arrêt
|
||
|
||
```json
|
||
{
|
||
"machine_id": "INJ-01",
|
||
"event_type": "machine_stopped",
|
||
"timestamp": "2026-06-14T10:35:20Z",
|
||
"reason_code": null,
|
||
"auto_detected": true
|
||
}
|
||
```
|
||
|
||
### Causes d'arrêt initiales
|
||
|
||
Créer les causes suivantes :
|
||
|
||
- changement_moule ;
|
||
- reglage ;
|
||
- attente_matiere ;
|
||
- attente_operateur ;
|
||
- panne_machine ;
|
||
- panne_moule ;
|
||
- attente_qualite ;
|
||
- nettoyage ;
|
||
- pause ;
|
||
- micro_arret ;
|
||
- autre.
|
||
|
||
## Stack technique souhaitée
|
||
|
||
Développer une application simple, robuste et industrialisable.
|
||
|
||
Stack recommandée :
|
||
|
||
- Backend : Python FastAPI ;
|
||
- Frontend : React + TypeScript ;
|
||
- Base de données : PostgreSQL ;
|
||
- Temps réel : WebSocket ;
|
||
- Messaging IoT : MQTT ;
|
||
- Broker MQTT : Mosquitto ;
|
||
- Edge simulator : service Python simulant les entrées digitales ;
|
||
- Déploiement local : Docker Compose.
|
||
|
||
Le MVP doit être exécutable localement avec :
|
||
|
||
```bash
|
||
docker compose up --build
|
||
```
|
||
|
||
## Services à créer
|
||
|
||
Créer les services suivants :
|
||
|
||
```text
|
||
/plast-track-mvp
|
||
/backend
|
||
/frontend
|
||
/edge-simulator
|
||
/mqtt
|
||
/database
|
||
docker-compose.yml
|
||
README.md
|
||
```
|
||
|
||
### backend
|
||
|
||
API FastAPI.
|
||
|
||
Responsabilités :
|
||
|
||
- recevoir les événements MQTT ;
|
||
- historiser les cycles ;
|
||
- historiser les états machine ;
|
||
- détecter ou clôturer les arrêts ;
|
||
- gérer les OF ;
|
||
- gérer les rebuts ;
|
||
- calculer TRS/OEE ;
|
||
- exposer API REST ;
|
||
- exposer WebSocket pour dashboard temps réel.
|
||
|
||
### frontend
|
||
|
||
Application React.
|
||
|
||
Écrans minimum :
|
||
|
||
1. Dashboard atelier ;
|
||
2. Détail machine ;
|
||
3. Lancement OF ;
|
||
4. Qualification arrêt ;
|
||
5. Saisie rebut ;
|
||
6. Vue TRS journalier.
|
||
|
||
### edge-simulator
|
||
|
||
Service Python permettant de simuler une ou plusieurs presses à injecter de marques différentes.
|
||
|
||
Fonctions :
|
||
|
||
- publier `machine_power_on` ;
|
||
- publier `cycle_completed` ;
|
||
- simuler temps de cycle variable ;
|
||
- simuler arrêt machine ;
|
||
- simuler reprise ;
|
||
- simuler alarme générale optionnelle.
|
||
|
||
Le simulateur doit publier sur MQTT.
|
||
|
||
Exemple topic :
|
||
|
||
```text
|
||
plasttrack/machines/INJ-01/events
|
||
```
|
||
|
||
Payload :
|
||
|
||
```json
|
||
{
|
||
"machine_id": "INJ-01",
|
||
"event_type": "cycle_completed",
|
||
"timestamp": "2026-06-14T10:32:15Z",
|
||
"cycle_time_sec": 18.7
|
||
}
|
||
```
|
||
|
||
## Modèle de données PostgreSQL
|
||
|
||
Créer au minimum les tables suivantes.
|
||
|
||
### machines
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- code ;
|
||
- name ;
|
||
- brand ;
|
||
- model ;
|
||
- status ;
|
||
- is_active ;
|
||
- created_at ;
|
||
- updated_at.
|
||
|
||
Exemples :
|
||
|
||
```text
|
||
code = INJ-01
|
||
brand = Haitian
|
||
model = Mars II
|
||
|
||
Les champs `brand` et `model` doivent rester totalement configurables pour supporter n'importe quelle machine du parc.
|
||
```
|
||
|
||
### production_orders
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- order_number ;
|
||
- machine_id ;
|
||
- article_ref ;
|
||
- article_name ;
|
||
- mold_ref ;
|
||
- material_ref ;
|
||
- planned_qty ;
|
||
- cavities ;
|
||
- theoretical_cycle_time_sec ;
|
||
- status ;
|
||
- started_at ;
|
||
- ended_at ;
|
||
- created_at ;
|
||
- updated_at.
|
||
|
||
### machine_events
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- machine_id ;
|
||
- event_type ;
|
||
- timestamp ;
|
||
- payload JSONB ;
|
||
- created_at.
|
||
|
||
### cycles
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- machine_id ;
|
||
- production_order_id ;
|
||
- timestamp ;
|
||
- cycle_time_sec ;
|
||
- cavities ;
|
||
- produced_qty ;
|
||
- is_valid ;
|
||
- created_at.
|
||
|
||
### downtimes
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- machine_id ;
|
||
- production_order_id ;
|
||
- start_time ;
|
||
- end_time ;
|
||
- duration_sec ;
|
||
- reason_code ;
|
||
- comment ;
|
||
- auto_detected ;
|
||
- qualified_by ;
|
||
- created_at ;
|
||
- updated_at.
|
||
|
||
### scraps
|
||
|
||
Champs :
|
||
|
||
- id ;
|
||
- machine_id ;
|
||
- production_order_id ;
|
||
- quantity ;
|
||
- reason_code ;
|
||
- comment ;
|
||
- operator_name ;
|
||
- timestamp ;
|
||
- created_at.
|
||
|
||
### reference tables
|
||
|
||
Créer aussi :
|
||
|
||
- downtime_reasons ;
|
||
- scrap_reasons ;
|
||
- operators optionnel.
|
||
|
||
## API REST minimum
|
||
|
||
Créer les endpoints suivants.
|
||
|
||
### Machines
|
||
|
||
```http
|
||
GET /api/machines
|
||
GET /api/machines/{machine_id}
|
||
GET /api/machines/{machine_id}/status
|
||
GET /api/machines/{machine_id}/events
|
||
GET /api/machines/{machine_id}/cycles
|
||
GET /api/machines/{machine_id}/downtimes
|
||
```
|
||
|
||
### OF
|
||
|
||
```http
|
||
GET /api/production-orders
|
||
POST /api/production-orders
|
||
POST /api/production-orders/{id}/start
|
||
POST /api/production-orders/{id}/pause
|
||
POST /api/production-orders/{id}/close
|
||
```
|
||
|
||
### Arrêts
|
||
|
||
```http
|
||
GET /api/downtimes/open
|
||
POST /api/downtimes/{id}/qualify
|
||
```
|
||
|
||
Payload qualification :
|
||
|
||
```json
|
||
{
|
||
"reason_code": "attente_matiere",
|
||
"comment": "Matière non disponible au poste",
|
||
"qualified_by": "operateur_1"
|
||
}
|
||
```
|
||
|
||
### Rebuts
|
||
|
||
```http
|
||
POST /api/scraps
|
||
GET /api/scraps
|
||
```
|
||
|
||
Payload rebut :
|
||
|
||
```json
|
||
{
|
||
"machine_id": "INJ-01",
|
||
"production_order_id": 1,
|
||
"quantity": 12,
|
||
"reason_code": "bavure",
|
||
"comment": "Bavure côté plan de joint",
|
||
"operator_name": "operateur_1"
|
||
}
|
||
```
|
||
|
||
### TRS/OEE
|
||
|
||
```http
|
||
GET /api/oee/daily?date=2026-06-14
|
||
GET /api/oee/machines/{machine_id}?from=2026-06-14T00:00:00Z&to=2026-06-14T23:59:59Z
|
||
```
|
||
|
||
## Calcul TRS/OEE
|
||
|
||
Formule :
|
||
|
||
```text
|
||
TRS = Disponibilité × Performance × Qualité
|
||
```
|
||
|
||
### Disponibilité
|
||
|
||
```text
|
||
Disponibilité = Temps de marche / Temps planifié
|
||
```
|
||
|
||
Pour le MVP :
|
||
|
||
- temps planifié = durée entre démarrage OF et fin OF, ou journée de production configurée ;
|
||
- temps arrêt = somme des downtimes ;
|
||
- temps marche = temps planifié - temps arrêt.
|
||
|
||
### Performance
|
||
|
||
```text
|
||
Performance = (Cycle théorique × Nombre de cycles valides) / Temps de marche
|
||
```
|
||
|
||
Limiter la performance à 100% par défaut pour éviter les valeurs aberrantes.
|
||
|
||
### Qualité
|
||
|
||
```text
|
||
Qualité = Quantité bonne / Quantité produite totale
|
||
```
|
||
|
||
Avec :
|
||
|
||
```text
|
||
Quantité produite totale = cycles valides × nombre empreintes
|
||
Quantité bonne = quantité produite totale - rebuts
|
||
```
|
||
|
||
## Frontend attendu
|
||
|
||
### Dashboard atelier
|
||
|
||
Afficher des cartes machines.
|
||
|
||
Chaque carte doit montrer :
|
||
|
||
- code machine ;
|
||
- état courant ;
|
||
- couleur d'état ;
|
||
- OF en cours ;
|
||
- article ;
|
||
- moule ;
|
||
- cycle réel moyen ;
|
||
- cycle théorique ;
|
||
- quantité produite ;
|
||
- quantité rebutée ;
|
||
- avancement OF ;
|
||
- TRS du jour ;
|
||
- dernier arrêt.
|
||
|
||
Codes couleur :
|
||
|
||
| État | Couleur UI |
|
||
|---|---|
|
||
| production | vert |
|
||
| arret_non_qualifie | orange |
|
||
| arret_qualifie | rouge |
|
||
| reglage | bleu |
|
||
| hors_planning | gris |
|
||
|
||
### Détail machine
|
||
|
||
Afficher :
|
||
|
||
- état temps réel ;
|
||
- courbe des cycles récents ;
|
||
- historique des arrêts ;
|
||
- bouton qualifier arrêt ;
|
||
- bouton déclarer rebut ;
|
||
- OF en cours.
|
||
|
||
### Interface opérateur
|
||
|
||
L'interface doit être simple, utilisable sur tablette industrielle.
|
||
|
||
Boutons grands :
|
||
|
||
- Lancer OF ;
|
||
- Déclarer rebut ;
|
||
- Qualifier arrêt ;
|
||
- Appel maintenance optionnel ;
|
||
- Fin OF.
|
||
|
||
## Données de démonstration
|
||
|
||
Créer un seed avec :
|
||
|
||
Machines :
|
||
|
||
```text
|
||
INJ-01 — Haitian Mars II
|
||
INJ-02 — Engel e-victory
|
||
INJ-03 — Arburg Allrounder
|
||
```
|
||
|
||
Causes rebut :
|
||
|
||
- bavure ;
|
||
- manque_matiere ;
|
||
- brulure ;
|
||
- retassure ;
|
||
- deformation ;
|
||
- point_noir ;
|
||
- humidite ;
|
||
- couleur_non_conforme ;
|
||
- collage_moule ;
|
||
- casse_piece ;
|
||
- defaut_dimensionnel ;
|
||
- autre.
|
||
|
||
Créer au moins deux OF de démonstration.
|
||
|
||
## Exigences qualité
|
||
|
||
Le code doit être :
|
||
|
||
- clair ;
|
||
- typé autant que possible ;
|
||
- documenté ;
|
||
- modulaire ;
|
||
- prêt pour extension vers vraies gateways IoT ;
|
||
- sans dépendance à Euromap ni à un protocole propriétaire constructeur.
|
||
|
||
Ajouter :
|
||
|
||
- tests unitaires backend pour calcul OEE ;
|
||
- test de parsing événement MQTT ;
|
||
- README d'installation ;
|
||
- exemple de payload MQTT ;
|
||
- script seed database.
|
||
|
||
## Sécurité industrielle
|
||
|
||
Ajouter dans le README une section sécurité :
|
||
|
||
- ne jamais raccorder directement une sortie automate à une gateway ;
|
||
- utiliser relais d'interface, optocoupleurs ou modules d'entrées industrielles isolées ;
|
||
- valider tout câblage avec automaticien ou électricien industriel ;
|
||
- ne jamais modifier la logique automate machine pour le MVP ;
|
||
- l'acquisition doit rester passive et non intrusive ;
|
||
- le système MES ne doit jamais piloter la presse dans cette première version.
|
||
|
||
## Livrables attendus
|
||
|
||
Produire un repository complet avec :
|
||
|
||
```text
|
||
README.md
|
||
CONTRIBUTING.md optionnel
|
||
docker-compose.yml
|
||
/backend
|
||
/frontend
|
||
/edge-simulator
|
||
/database/init.sql
|
||
/database/seed.sql
|
||
```
|
||
|
||
Le README doit expliquer :
|
||
|
||
1. l'objectif du MVP ;
|
||
2. l'architecture ;
|
||
3. comment lancer le projet ;
|
||
4. comment simuler les machines ;
|
||
5. comment tester les endpoints ;
|
||
6. comment brancher plus tard une vraie gateway IoT ;
|
||
7. les limites du MVP.
|
||
|
||
## Critères d'acceptation
|
||
|
||
Le MVP est considéré terminé si :
|
||
|
||
- `docker compose up --build` lance tous les services ;
|
||
- le simulateur publie des cycles MQTT ;
|
||
- le backend reçoit et historise les cycles ;
|
||
- le dashboard affiche au moins 3 machines ;
|
||
- les cycles incrémentent la quantité produite ;
|
||
- un arrêt est créé automatiquement si absence de cycle ;
|
||
- un opérateur peut qualifier un arrêt ;
|
||
- un opérateur peut saisir un rebut ;
|
||
- le TRS/OEE journalier est calculé ;
|
||
- aucun composant ne dépend d'Euromap 63, 77 ou d'un protocole propriétaire constructeur.
|
||
|
||
## Important
|
||
|
||
Commencer par une version simple mais fonctionnelle. Ne pas développer de fonctionnalités avancées de pilotage machine. Le MVP doit uniquement superviser, historiser, calculer et afficher.
|
||
|
||
Ne pas implémenter de commande vers la presse. Le système est en lecture passive + saisie opérateur.
|