126 lines
4.5 KiB
Python
126 lines
4.5 KiB
Python
#!/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")
|