127 lines
3.5 KiB
Python
127 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
|
|
with open('/home/mdares/.node-red/flows.json', 'r') as f:
|
|
flows = json.load(f)
|
|
|
|
# New Format Graph Data function that handles KPI history data
|
|
new_format_func = '''// Format Graph Data for KPI charts
|
|
|
|
// Check if we have KPI history data (from global context)
|
|
if (msg.topic === "kpiHistory" && msg.payload) {
|
|
const kpiData = msg.payload;
|
|
|
|
// Extract arrays
|
|
const oeeHist = kpiData.oee || [];
|
|
const availHist = kpiData.availability || [];
|
|
const perfHist = kpiData.performance || [];
|
|
const qualHist = kpiData.quality || [];
|
|
|
|
// Build labels and data arrays
|
|
const labels = [];
|
|
const oeeData = [];
|
|
const availData = [];
|
|
const perfData = [];
|
|
const qualData = [];
|
|
|
|
// Use OEE timestamps as primary (they should all be the same length)
|
|
oeeHist.forEach((point, index) => {
|
|
const timestamp = new Date(point.timestamp);
|
|
labels.push(timestamp.toLocaleString());
|
|
|
|
oeeData.push(point.value || 0);
|
|
availData.push(availHist[index]?.value || 0);
|
|
perfData.push(perfHist[index]?.value || 0);
|
|
qualData.push(qualHist[index]?.value || 0);
|
|
});
|
|
|
|
msg.graphData = {
|
|
labels: labels,
|
|
datasets: [
|
|
{ label: 'OEE %', data: oeeData },
|
|
{ label: 'Availability %', data: availData },
|
|
{ label: 'Performance %', data: perfData },
|
|
{ label: 'Quality %', data: qualData }
|
|
]
|
|
};
|
|
|
|
node.warn(`[GRAPH DATA] Formatted ${labels.length} KPI history points`);
|
|
|
|
delete msg.topic;
|
|
delete msg.payload;
|
|
return msg;
|
|
}
|
|
|
|
// Legacy support: work_orders query data (if needed)
|
|
const rows = msg.payload || [];
|
|
|
|
if (!Array.isArray(rows) || rows.length === 0) {
|
|
msg.graphData = {
|
|
labels: [],
|
|
datasets: [
|
|
{ label: 'OEE %', data: [] },
|
|
{ label: 'Availability %', data: [] },
|
|
{ label: 'Performance %', data: [] },
|
|
{ label: 'Quality %', data: [] }
|
|
]
|
|
};
|
|
delete msg.topic;
|
|
delete msg.payload;
|
|
return msg;
|
|
}
|
|
|
|
// If we have work_orders data, format it (though we won't use this path anymore)
|
|
const labels = [];
|
|
const goodData = [];
|
|
const scrapData = [];
|
|
const efficiencyData = [];
|
|
const qualityData = [];
|
|
|
|
rows.forEach(row => {
|
|
const timestamp = new Date(row.updated_at);
|
|
labels.push(timestamp.toLocaleString());
|
|
|
|
const good = Number(row.good_parts) || 0;
|
|
const scrap = Number(row.scrap_parts) || 0;
|
|
const target = Number(row.target_quantity) || 0;
|
|
|
|
goodData.push(good);
|
|
scrapData.push(scrap);
|
|
|
|
let eff = (row.progress_percent != null)
|
|
? Number(row.progress_percent)
|
|
: (target > 0 ? (good / target) * 100 : 0);
|
|
efficiencyData.push(Math.min(eff, 100));
|
|
|
|
const total = good + scrap;
|
|
const quality = total > 0 ? (good / total) * 100 : 100;
|
|
qualityData.push(quality);
|
|
});
|
|
|
|
msg.graphData = {
|
|
labels: labels,
|
|
datasets: [
|
|
{ label: 'OEE %', data: efficiencyData }, // Use efficiency as fallback
|
|
{ label: 'Availability %', data: [] },
|
|
{ label: 'Performance %', data: [] },
|
|
{ label: 'Quality %', data: qualityData }
|
|
]
|
|
};
|
|
|
|
delete msg.topic;
|
|
delete msg.payload;
|
|
|
|
return msg;'''
|
|
|
|
# Update Format Graph Data function
|
|
for node in flows:
|
|
if node.get('id') == 'format_graph_data_node_id':
|
|
node['func'] = new_format_func
|
|
print("✓ Updated Format Graph Data function to handle KPI data")
|
|
break
|
|
|
|
with open('/home/mdares/.node-red/flows.json', 'w') as f:
|
|
json.dump(flows, f, indent=4)
|
|
|
|
print("✓ flows.json updated")
|