// ============================================================================ // 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;