Files
plast-track/README.md
2026-06-15 13:35:22 +01:00

332 lines
8.0 KiB
Markdown

# Plast Track MVP
Lightweight MES/IoT MVP for supervising multi-brand injection molding machines using passive signal acquisition, MQTT event ingestion, operator input, and real-time web dashboards.
## Objective
This MVP supervises production without Euromap dependency and without sending any command back to the press. It focuses on:
- machine status visualization
- automatic cycle counting
- real cycle time capture
- current production order tracking
- produced quantity and scrap quantity
- automatic downtime detection
- operator downtime qualification
- scrap declaration
- daily OEE/TRS
- workshop dashboard in real time
## Architecture
```text
Passive machine signal / external sensor
-> isolated relay / optocoupler / industrial DI module
-> IoT gateway or edge service
-> MQTT topic
-> FastAPI backend
-> PostgreSQL
-> WebSocket / REST API
-> React frontend dashboard
```
Services:
- `database`: PostgreSQL with schema and seed data
- `mqtt`: Mosquitto broker
- `backend`: FastAPI API, MQTT consumer, downtime logic, OEE computation, WebSocket notifications
- `edge-simulator`: publishes simulated machine events on MQTT
- `frontend`: React + TypeScript operator/dashboard interface
## Repository Layout
```text
/backend
/frontend
/edge-simulator
/database/init.sql
/database/seed.sql
/mqtt/mosquitto.conf
/docker-compose.yml
```
## Run Locally
Prerequisites:
- Docker Desktop or Docker Engine with Compose
Start the full MVP:
```bash
docker compose up --build
```
Exposed services:
- frontend: `http://localhost:5173`
- backend API: `http://localhost:8000`
- backend health: `http://localhost:8000/health`
- PostgreSQL: `localhost:5432`
- MQTT: `localhost:1883`
## Demo Data
Seeded machines:
- `INJ-01` - Haitian Mars II
- `INJ-02` - Engel e-victory
- `INJ-03` - Arburg Allrounder
Seeded production orders:
- `OF-1001` running on `INJ-01`
- `OF-1002` planned on `INJ-02`
The edge simulator continuously publishes cycles and stop events for the demo machines.
## MQTT Topics And Payloads
Topic pattern:
```text
plasttrack/machines/{machine_code}/events
```
Raw signal event example:
```json
{
"machine_id": "INJ-01",
"event_type": "digital_input_changed",
"timestamp": "2026-06-14T10:32:15Z",
"input_name": "cycle_signal",
"input_value": true,
"cycle_time_sec": 18.7,
"source": "digital_input"
}
```
The backend derives valid cycles from the configured signal edge and timing rules. It still stores normalized `cycle_completed` events if upstream integrations publish them directly.
Automatic stop event example:
```json
{
"machine_id": "INJ-01",
"event_type": "machine_stopped",
"timestamp": "2026-06-14T10:35:20Z",
"auto_detected": true
}
```
## REST API
Machines:
- `GET /api/dashboard`
- `GET /api/machines`
- `GET /api/machines/{machine_id}`
- `GET /api/machines/{machine_id}/config`
- `PATCH /api/machines/{machine_id}/config`
- `GET /api/machines/{machine_id}/status`
- `GET /api/machines/{machine_id}/events`
- `GET /api/machines/{machine_id}/cycles`
- `GET /api/machines/{machine_id}/downtimes`
Production orders:
- `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`
Downtimes:
- `GET /api/downtimes/open`
- `POST /api/downtimes/{id}/qualify`
Scrap:
- `GET /api/scraps`
- `POST /api/scraps`
OEE:
- `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`
Reference data:
- `GET /api/reference-data`
WebSocket:
- `ws://localhost:8000/ws/dashboard`
## Manual API Checks
List machines:
```bash
curl http://localhost:8000/api/machines
```
Create a production order:
```bash
curl -X POST http://localhost:8000/api/production-orders \
-H "Content-Type: application/json" \
-d '{
"order_number": "OF-2001",
"machine_id": 2,
"article_ref": "ART-2001",
"article_name": "Bac Technique",
"mold_ref": "M-2001",
"material_ref": "PP-BLACK",
"planned_qty": 1200,
"cavities": 2,
"theoretical_cycle_time_sec": 21.5
}'
```
Qualify a downtime:
```bash
curl -X POST http://localhost:8000/api/downtimes/1/qualify \
-H "Content-Type: application/json" \
-d '{
"reason_code": "attente_matiere",
"comment": "Material not available at the machine",
"qualified_by": "operateur_1"
}'
```
Declare scrap:
```bash
curl -X POST http://localhost:8000/api/scraps \
-H "Content-Type: application/json" \
-d '{
"machine_id": "INJ-01",
"production_order_id": 1,
"quantity": 12,
"reason_code": "bavure",
"comment": "Flash on parting line",
"operator_name": "operateur_1"
}'
```
## OEE Logic
Formula:
```text
OEE = Availability x Performance x Quality
```
Implemented rules:
- planned time: overlap of started production orders with the query window
- downtime: overlap of machine downtimes with the query window
- operating time: `planned time - downtime`
- performance: `theoretical cycle contribution / operating time`, capped at `100%`
- quality: `good quantity / total produced quantity`
## How The Simulator Works
The simulator publishes:
- `digital_input_changed` for `machine_power_on`
- `digital_input_changed` for `cycle_signal`
- `digital_input_changed` for `general_alarm`
Each machine gets a nominal cycle time, a pulse width, and a random stop probability. The backend consumes these MQTT events, detects the configured cycle edge, and updates production data in PostgreSQL.
## Connecting A Real Passive Gateway Later
To replace the simulator with a real gateway:
1. Read passive, electrically isolated machine signals only.
2. Publish normalized JSON events to the same MQTT topic pattern.
3. Keep event timestamps in UTC ISO-8601 format.
4. Map per-machine debounce, min/max cycle time, and stop detection delay in the database or future admin UI.
Expected minimum signals:
- `machine_power_on`
- `cycle_signal`
Optional signals:
- `auto_mode`
- `mold_open`
- `ejector_forward`
- `general_alarm`
- `pump_running`
## Industrial Safety
- Never wire the IoT gateway directly to PLC outputs or machine circuits.
- Use interface relays, optocouplers, or isolated industrial input modules.
- Validate every wiring decision with a qualified automation or industrial electrical technician.
- Keep acquisition passive and non-intrusive.
- Do not modify the machine PLC logic for this MVP.
- This MVP must never command or pilot the press.
## Tests
Backend tests included:
- OEE calculation unit test
- MQTT event parsing test
Run locally:
```bash
cd backend
pytest
```
Frontend build check:
```bash
cd frontend
npm install
npm run build
```
## Current Limits
- No authentication or role management
- No production scheduling calendar
- No historian-grade buffering on the edge side
- No historical reporting endpoints beyond daily OEE/TRS
- No real passive gateway adapter package yet; the simulator publishes normalized MQTT payloads
- WebSocket currently pushes refresh notifications, then the UI refetches data
- The simulator models passive-signal-derived events, not actual electrical IO reads
## Current UI Modules
The frontend is organized into module tabs rather than one long dashboard page:
- `Atelier`: machine cards, status filtering, sorting, quick actions, fullscreen workshop mode
- `Machine`: selected machine detail, cycle trend, recent events, downtime history
- `TRS`: daily OEE/TRS summary and per-machine OEE
- `OF`: production order creation and status management
- `Arrets`: open downtime qualification
- `Rebuts`: scrap declaration and scrap log
- `Config`: persistent passive signal and timing configuration per machine
Operator forms include inline validation, inline API error feedback, and success toasts.
## Industrial Readiness Backlog
Next hardening steps before a real shop-floor pilot:
- define a real passive gateway adapter spec with exact input mapping and MQTT payload examples
- add edge-side buffering for MQTT/backend outage periods
- expand tests for downtime transitions, order status transitions, and signal debounce edge cases
- add historical reporting endpoints for OEE, downtime, and scrap trends