- 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>
185 lines
7.4 KiB
JavaScript
185 lines
7.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Patch demo-flow.json:
|
|
* 1. Fix NH4 chart — remove demo_link_meas_dash from new NH4 nodes
|
|
* 2. Update parse function — use "NH4 @ Xm" label format
|
|
* 3. Reorganize entire treatment tab — logical left-to-right layout
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const flowPath = path.join(__dirname, '..', 'docker', 'demo-flow.json');
|
|
const flow = JSON.parse(fs.readFileSync(flowPath, 'utf8'));
|
|
|
|
const find = (id) => flow.find(n => n.id === id);
|
|
|
|
// ============================================================
|
|
// 1. FIX NH4 CHART WIRING
|
|
// Remove demo_link_meas_dash from the 4 new NH4 nodes.
|
|
// They should only go to process link + NH4 profile link.
|
|
// ============================================================
|
|
|
|
const newNh4Ids = ['demo_meas_nh4_in', 'demo_meas_nh4_a', 'demo_meas_nh4_b', 'demo_meas_nh4_c'];
|
|
for (const id of newNh4Ids) {
|
|
const n = find(id);
|
|
if (n) {
|
|
n.wires[0] = n.wires[0].filter(w => w !== 'demo_link_meas_dash');
|
|
console.log(` ${id} Port 0 wires: ${JSON.stringify(n.wires[0])}`);
|
|
}
|
|
}
|
|
console.log('1. Fixed: removed demo_link_meas_dash from new NH4 nodes');
|
|
|
|
// ============================================================
|
|
// 2. UPDATE PARSE FUNCTION — "NH4 @ Xm" format
|
|
// Also make it generic: read distance from payload metadata
|
|
// if available, fall back to topic matching.
|
|
// ============================================================
|
|
|
|
const parseFn = find('demo_fn_nh4_profile_parse');
|
|
if (parseFn) {
|
|
parseFn.func = `const p = msg.payload || {};
|
|
const topic = msg.topic || '';
|
|
const now = Date.now();
|
|
const val = Number(p.mAbs);
|
|
if (!Number.isFinite(val)) return null;
|
|
|
|
// Build label from distance metadata if available, else match by tag
|
|
const dist = p.distance;
|
|
const tag = p.assetTagNumber || topic;
|
|
let label;
|
|
if (dist !== undefined && dist !== null) {
|
|
label = 'NH4 @ ' + dist + 'm';
|
|
} else if (tag.includes('NH4-IN')) label = 'NH4 @ 0m';
|
|
else if (tag.includes('NH4-A')) label = 'NH4 @ 10m';
|
|
else if (tag.includes('NH4-B')) label = 'NH4 @ 25m';
|
|
else if (tag.includes('NH4-001')) label = 'NH4 @ 35m';
|
|
else if (tag.includes('NH4-C')) label = 'NH4 @ 45m';
|
|
else label = 'NH4 @ ?m';
|
|
|
|
return { topic: label, payload: Math.round(val * 100) / 100, timestamp: now };`;
|
|
console.log('2. Updated NH4 profile parse function to "NH4 @ Xm" format');
|
|
}
|
|
|
|
// ============================================================
|
|
// 3. REORGANIZE TREATMENT TAB LAYOUT
|
|
//
|
|
// Logical left-to-right process flow:
|
|
//
|
|
// Col 1 (x=80): Comments / section headers
|
|
// Col 2 (x=200): Injects (reactor tick, monster flow)
|
|
// Col 3 (x=420): Inlet measurements (flow, DO, NH4 profile)
|
|
// Col 4 (x=640): Link outs (meas dash, NH4 profile dash)
|
|
// Col 5 (x=820): Reactor
|
|
// Col 6 (x=1060): Settler
|
|
// Col 7 (x=1280): Effluent measurements
|
|
// Col 8 (x=1500): Effluent link outs
|
|
//
|
|
// Row zones (y):
|
|
// Row A (y=40): Section comment
|
|
// Row B (y=100-440): Main process: reactor measurements → reactor → settler
|
|
// Row C (y=500-700): Effluent measurements (downstream of settler)
|
|
// Row D (y=760-900): RAS recycle loop (below main flow)
|
|
// Row E (y=960-1120): Merge collection / influent composition
|
|
//
|
|
// ============================================================
|
|
|
|
const layout = {
|
|
// ── SECTION COMMENT ──
|
|
'demo_comment_treatment': { x: 80, y: 40 },
|
|
|
|
// ── INJECTS ──
|
|
'demo_inj_reactor_tick': { x: 200, y: 120 },
|
|
'demo_inj_monster_flow': { x: 200, y: 560 },
|
|
|
|
// ── INLET MEASUREMENTS (column, spaced 60px) ──
|
|
'demo_meas_flow': { x: 420, y: 100 }, // FT-001 flow
|
|
'demo_meas_do': { x: 420, y: 160 }, // DO-001
|
|
'demo_meas_nh4_in': { x: 420, y: 220 }, // NH4-IN 0m
|
|
'demo_meas_nh4_a': { x: 420, y: 280 }, // NH4-A 10m
|
|
'demo_meas_nh4': { x: 420, y: 340 }, // NH4-001 35m (existing, keep between A & B for distance order — wait, 25m < 35m)
|
|
'demo_meas_nh4_b': { x: 420, y: 400 }, // NH4-B 25m
|
|
'demo_meas_nh4_c': { x: 420, y: 460 }, // NH4-C 45m
|
|
|
|
// ── LINK OUTS (from measurements) ──
|
|
'demo_link_meas_dash': { x: 640, y: 130 },
|
|
'demo_link_nh4_profile_dash': { x: 640, y: 340 },
|
|
|
|
// ── REACTOR ──
|
|
'demo_reactor': { x: 820, y: 220 },
|
|
|
|
// ── REACTOR LINK OUTS ──
|
|
'demo_link_reactor_dash': { x: 1020, y: 180 },
|
|
'demo_link_overview_reactor_out': { x: 1020, y: 220 },
|
|
|
|
// ── SETTLER ──
|
|
'demo_settler': { x: 1060, y: 320 },
|
|
|
|
// ── SHARED LINK OUTS (process + influx) ──
|
|
'demo_link_influx_out_treatment': { x: 1020, y: 260 },
|
|
'demo_link_process_out_treatment': { x: 1020, y: 300 },
|
|
|
|
// ── EFFLUENT SECTION ──
|
|
'demo_comment_effluent_meas': { x: 80, y: 520 },
|
|
'demo_meas_eff_flow': { x: 1280, y: 320 },
|
|
'demo_meas_eff_do': { x: 1280, y: 380 },
|
|
'demo_meas_eff_nh4': { x: 1280, y: 440 },
|
|
'demo_meas_eff_no3': { x: 1280, y: 500 },
|
|
'demo_meas_eff_tss': { x: 1280, y: 560 },
|
|
'demo_link_eff_meas_dash': { x: 1500, y: 440 },
|
|
'demo_link_overview_eff_out': { x: 1500, y: 500 },
|
|
|
|
// ── MONSTER (downstream of settler, parallel to effluent meas) ──
|
|
'demo_monster': { x: 1060, y: 440 },
|
|
'demo_fn_monster_flow': { x: 400, y: 560 },
|
|
|
|
// ── RAS RECYCLE LOOP (below main process) ──
|
|
'demo_fn_ras_filter': { x: 1060, y: 760 },
|
|
'demo_pump_ras': { x: 1280, y: 760 },
|
|
'demo_meas_ft_ras': { x: 1500, y: 760 },
|
|
'demo_inj_ras_mode': { x: 1280, y: 820 },
|
|
'demo_inj_ras_speed': { x: 1280, y: 880 },
|
|
'demo_comment_pressure': { x: 80, y: 740 },
|
|
|
|
// ── MERGE COLLECTION (bottom section) ──
|
|
'demo_comment_merge': { x: 80, y: 960 },
|
|
'demo_link_merge_west_in': { x: 100, y: 1000 },
|
|
'demo_link_merge_north_in': { x: 100, y: 1060 },
|
|
'demo_link_merge_south_in': { x: 100, y: 1120 },
|
|
'demo_fn_tag_west': { x: 300, y: 1000 },
|
|
'demo_fn_tag_north': { x: 300, y: 1060 },
|
|
'demo_fn_tag_south': { x: 300, y: 1120 },
|
|
'demo_fn_merge_collect': { x: 520, y: 1060 },
|
|
'demo_link_merge_dash': { x: 720, y: 1020 },
|
|
'demo_fn_influent_compose': { x: 720, y: 1100 },
|
|
};
|
|
|
|
// Sort NH4 measurements by distance for visual order
|
|
// NH4-IN=0m, NH4-A=10m, NH4-B=25m, NH4-001=35m, NH4-C=45m
|
|
// Adjust y to be in distance order:
|
|
layout['demo_meas_nh4_in'] = { x: 420, y: 220 }; // 0m
|
|
layout['demo_meas_nh4_a'] = { x: 420, y: 280 }; // 10m
|
|
layout['demo_meas_nh4_b'] = { x: 420, y: 340 }; // 25m
|
|
layout['demo_meas_nh4'] = { x: 420, y: 400 }; // 35m
|
|
layout['demo_meas_nh4_c'] = { x: 420, y: 460 }; // 45m
|
|
|
|
let moved = 0;
|
|
for (const [id, pos] of Object.entries(layout)) {
|
|
const n = find(id);
|
|
if (n) {
|
|
n.x = pos.x;
|
|
n.y = pos.y;
|
|
moved++;
|
|
} else {
|
|
console.warn(` WARN: node ${id} not found`);
|
|
}
|
|
}
|
|
console.log(`3. Repositioned ${moved} nodes on treatment tab`);
|
|
|
|
// ============================================================
|
|
// WRITE OUTPUT
|
|
// ============================================================
|
|
|
|
fs.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + '\n', 'utf8');
|
|
console.log(`\nDone. Wrote ${flow.length} nodes to ${flowPath}`);
|