Initial Plast Track MVP
This commit is contained in:
331
README.md
Normal file
331
README.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user