85 lines
3.2 KiB
Plaintext
85 lines
3.2 KiB
Plaintext
// ============================================================================
|
||
// KPI CALCULATION Function
|
||
// Purpose: Calculate OEE, Availability, Performance, Quality metrics
|
||
// Triggered by: Timer (every 5 seconds) or on cycle updates
|
||
// ============================================================================
|
||
|
||
// Get current global variables
|
||
const activeOrder = global.get("activeWorkOrder");
|
||
const cycleCount = global.get("cycleCount") || 0;
|
||
const trackingEnabled = global.get("trackingEnabled") || false;
|
||
const operatingTime = global.get("operatingTime") || 0; // seconds
|
||
const downtime = global.get("downtime") || 0; // seconds
|
||
const productionStartTime = global.get("productionStartTime");
|
||
|
||
// If no active order or not tracking, send zeros
|
||
if (!activeOrder || !activeOrder.id || !trackingEnabled || !productionStartTime) {
|
||
msg.payload = {
|
||
oee: 0,
|
||
availability: 0,
|
||
performance: 0,
|
||
quality: 0
|
||
};
|
||
return msg;
|
||
}
|
||
|
||
// Extract work order data
|
||
const targetQty = Number(activeOrder.target) || 0;
|
||
const goodParts = Number(activeOrder.good) || 0;
|
||
const scrapParts = Number(activeOrder.scrap) || 0;
|
||
const totalProduced = goodParts + scrapParts;
|
||
const theoreticalCycleTime = Number(activeOrder.cycleTime || activeOrder.theoreticalCycleTime || 0);
|
||
|
||
// ============================================================================
|
||
// AVAILABILITY = Operating Time / (Operating Time + Downtime)
|
||
// ============================================================================
|
||
let availability = 0;
|
||
const totalTime = operatingTime + downtime;
|
||
|
||
if (totalTime > 0) {
|
||
availability = (operatingTime / totalTime) * 100;
|
||
}
|
||
|
||
// ============================================================================
|
||
// PERFORMANCE = (Actual Production / Theoretical Production) * 100
|
||
// Theoretical Production = Operating Time / Theoretical Cycle Time
|
||
// ============================================================================
|
||
let performance = 0;
|
||
|
||
if (theoreticalCycleTime > 0 && operatingTime > 0) {
|
||
const theoreticalProduction = operatingTime / theoreticalCycleTime;
|
||
if (theoreticalProduction > 0) {
|
||
performance = (cycleCount / theoreticalProduction) * 100;
|
||
}
|
||
}
|
||
|
||
// Cap performance at 100% (can't exceed theoretical max)
|
||
performance = Math.min(performance, 100);
|
||
|
||
// ============================================================================
|
||
// QUALITY = Good Parts / Total Parts Produced
|
||
// ============================================================================
|
||
let quality = 0;
|
||
|
||
if (totalProduced > 0) {
|
||
quality = (goodParts / totalProduced) * 100;
|
||
}
|
||
|
||
// ============================================================================
|
||
// OEE = Availability × Performance × Quality (as decimals)
|
||
// ============================================================================
|
||
const oee = (availability / 100) * (performance / 100) * (quality / 100) * 100;
|
||
|
||
// ============================================================================
|
||
// OUTPUT: Send KPIs to Home template
|
||
// ============================================================================
|
||
msg.topic = "kpiUpdate";
|
||
msg.payload = {
|
||
oee: Math.round(oee),
|
||
availability: Math.round(availability),
|
||
performance: Math.round(performance),
|
||
quality: Math.round(quality)
|
||
};
|
||
|
||
return msg;
|