#!/usr/bin/env python3 import json with open('/home/mdares/.node-red/flows.json', 'r') as f: flows = json.load(f) # Find Work Order buttons node work_order_buttons_node = None for node in flows: if node.get('id') == '9bbd4fade968036d': work_order_buttons_node = node break if not work_order_buttons_node: print("✗ Could not find Work Order buttons node") exit(1) # Get the current function code func_code = work_order_buttons_node.get('func', '') # Find the complete-work-order case and add high scrap detection # Look for the end of the complete-work-order case (before the "return" statement) # Add the high scrap detection code before the final database insert high_scrap_code = ''' // ============================================================ // HIGH SCRAP DETECTION // ============================================================ const targetQty = Number(order.target) || 0; const scrapCount = Number(order.scrap) || 0; const scrapPercent = targetQty > 0 ? (scrapCount / targetQty) * 100 : 0; // Trigger: Scrap > 10% of target quantity if (scrapPercent > 10 && targetQty > 0) { const severity = scrapPercent > 25 ? 'critical' : 'warning'; const highScrapAnomaly = { anomaly_type: 'high-scrap', severity: severity, title: `High Waste Detected`, description: `Work order completed with ${scrapCount} scrap parts (${scrapPercent.toFixed(1)}% of target ${targetQty}). Why is there so much waste?`, data: { scrap_count: scrapCount, target_quantity: targetQty, scrap_percent: Math.round(scrapPercent * 10) / 10, good_parts: Number(order.good) || 0, total_cycles: global.get("cycleCount") || 0 }, kpi_snapshot: { oee: (msg.kpis && msg.kpis.oee) || 0, availability: (msg.kpis && msg.kpis.availability) || 0, performance: (msg.kpis && msg.kpis.performance) || 0, quality: (msg.kpis && msg.kpis.quality) || 0 }, work_order_id: order.id, cycle_count: global.get("cycleCount") || 0, timestamp: Date.now(), status: 'active' }; node.warn(`[HIGH SCRAP] Detected ${scrapPercent.toFixed(1)}% scrap on work order ${order.id}`); // Send to Event Logger (output 5) const anomalyMsg = { topic: "anomaly-detected", payload: [highScrapAnomaly] }; // Return with anomaly message on output 5 return [dbMsg, null, null, null, anomalyMsg]; } ''' # Find the complete-work-order case and inject the code # Look for the section where dbMsg is created and before the return statement search_pattern = 'case "complete-work-order":' if search_pattern in func_code: # Find the return statement in this case # We want to add the code before "return [dbMsg, null, null, null];" # Split by the case parts = func_code.split(search_pattern) before_case = parts[0] after_case = parts[1] # Find the return statement within this case # Look for "return [dbMsg," return_pattern = 'return [dbMsg, null, null, null];' if return_pattern in after_case: # Split at the return statement case_parts = after_case.split(return_pattern, 1) case_code = case_parts[0] after_return = case_parts[1] # Inject the high scrap detection code before the return new_case_code = case_code + high_scrap_code + '\\n ' + return_pattern # Reconstruct the function code func_code = before_case + search_pattern + new_case_code + after_return work_order_buttons_node['func'] = func_code print("✓ Added high scrap detection to complete-work-order handler") else: print("⚠ Could not find return statement pattern") else: print("✗ Could not find complete-work-order case") exit(1) # Increase outputs count to 5 work_order_buttons_node['outputs'] = 5 # Add the 5th output wire to Event Logger current_wires = work_order_buttons_node['wires'] current_wires.append(['event_logger_node_id']) # Add 5th output to Event Logger work_order_buttons_node['wires'] = current_wires print("✓ Added 5th output to Work Order buttons node") print("✓ Wired to Event Logger") # Save flows.json with open('/home/mdares/.node-red/flows.json', 'w') as f: json.dump(flows, f, indent=4) print("✓ flows.json updated")