Files
EVOLV/scripts/capture-process-data.js
znetsixe 6a6c04d34b Migrate to new Gitea instance (gitea.wbd-rd.nl)
- Update all submodule URLs from gitea.centraal.wbd-rd.nl to gitea.wbd-rd.nl
- Add settler as proper submodule in .gitmodules
- Add agent skills, function anchors, decisions, and improvements
- Add Docker configuration and scripts
- Add manuals and third_party docs
- Update .gitignore with secrets and build artifacts
- Remove stale .tgz build artifact

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:07:04 +01:00

146 lines
4.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Capture live process data from Node-RED WebSocket debug sidebar.
* Collects samples over a time window and analyzes trends.
*/
const http = require('http');
const NR_URL = 'http://localhost:1880';
const CAPTURE_SECONDS = 30;
// Alternative: poll the Node-RED comms endpoint
// But let's use a simpler approach - inject a temporary catch-all debug and read context
async function fetchJSON(url) {
return new Promise((resolve, reject) => {
http.get(url, res => {
const chunks = [];
res.on('data', c => chunks.push(c));
res.on('end', () => {
try { resolve(JSON.parse(Buffer.concat(chunks))); }
catch (e) { reject(new Error('Parse: ' + e.message)); }
});
}).on('error', reject);
});
}
async function postJSON(url, data) {
return new Promise((resolve, reject) => {
const body = JSON.stringify(data);
const parsed = new URL(url);
const req = http.request({
hostname: parsed.hostname,
port: parsed.port,
path: parsed.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body),
},
}, res => {
const chunks = [];
res.on('data', c => chunks.push(c));
res.on('end', () => {
const text = Buffer.concat(chunks).toString();
try { resolve(JSON.parse(text)); } catch { resolve(text); }
});
});
req.on('error', reject);
req.write(body);
req.end();
});
}
(async () => {
console.log('=== Capturing Process Data (' + CAPTURE_SECONDS + 's) ===\n');
// Use Node-RED inject API to trigger debug output
// Instead, let's read node context which stores the current state
// Get flows to find node IDs
const flows = await fetchJSON(NR_URL + '/flows');
const wwtp = flows.filter(n => n.z === 'demo_tab_wwtp');
// Pumping stations store state in node context
const pss = wwtp.filter(n => n.type === 'pumpingStation');
const pumps = wwtp.filter(n => n.type === 'rotatingMachine');
const samples = [];
const startTime = Date.now();
console.log('Sampling every 3 seconds for ' + CAPTURE_SECONDS + 's...\n');
for (let i = 0; i < Math.ceil(CAPTURE_SECONDS / 3); i++) {
const t = Date.now();
const elapsed = ((t - startTime) / 1000).toFixed(1);
// Read PS context data via Node-RED context API
const sample = { t: elapsed, stations: {} };
for (const ps of pss) {
try {
const ctx = await fetchJSON(NR_URL + '/context/node/' + ps.id + '?store=default');
sample.stations[ps.id] = ctx;
} catch (e) {
sample.stations[ps.id] = { error: e.message };
}
}
for (const pump of pumps) {
try {
const ctx = await fetchJSON(NR_URL + '/context/node/' + pump.id + '?store=default');
sample.stations[pump.id] = ctx;
} catch (e) {
sample.stations[pump.id] = { error: e.message };
}
}
samples.push(sample);
// Print summary for this sample
console.log('--- Sample at t=' + elapsed + 's ---');
for (const ps of pss) {
const ctx = sample.stations[ps.id];
if (ctx && ctx.data) {
console.log(ps.name + ':');
// Print all context keys
Object.entries(ctx.data).forEach(([key, val]) => {
if (typeof val === 'object') {
console.log(' ' + key + ': ' + JSON.stringify(val).substring(0, 200));
} else {
console.log(' ' + key + ': ' + val);
}
});
} else {
console.log(ps.name + ': ' + JSON.stringify(ctx).substring(0, 200));
}
}
for (const pump of pumps) {
const ctx = sample.stations[pump.id];
if (ctx && ctx.data && Object.keys(ctx.data).length > 0) {
console.log(pump.name + ':');
Object.entries(ctx.data).forEach(([key, val]) => {
if (typeof val === 'object') {
console.log(' ' + key + ': ' + JSON.stringify(val).substring(0, 200));
} else {
console.log(' ' + key + ': ' + val);
}
});
}
}
console.log('');
if (i < Math.ceil(CAPTURE_SECONDS / 3) - 1) {
await new Promise(r => setTimeout(r, 3000));
}
}
console.log('\n=== Summary ===');
console.log('Collected ' + samples.length + ' samples over ' + CAPTURE_SECONDS + 's');
})().catch(err => {
console.error('Capture failed:', err);
process.exit(1);
});