[ { "id": "tab_mgc_basic", "type": "tab", "label": "MGC - Basic", "disabled": false, "info": "Tier 1: one machineGroupControl (MGC) coordinating three rotatingMachine pumps. Setup once-fires virtualControl + cmd.startup on all three pumps; then operator demand drives the MGC, which dispatches per-pump flow setpoints." }, { "id": "grp_mgc_unit", "type": "group", "z": "tab_mgc_basic", "name": "Machine Group (Unit)", "style": { "label": true, "stroke": "#000000", "fill": "#50a8d9", "fill-opacity": "0.10" }, "nodes": [ "mgc_basic_node" ], "x": 974, "y": 359, "w": 152, "h": 122 }, { "id": "grp_pump_a", "type": "group", "z": "tab_mgc_basic", "name": "Pump A (Equipment)", "style": { "label": true, "stroke": "#000000", "fill": "#86bbdd", "fill-opacity": "0.10" }, "nodes": [ "rm_basic_pump_a" ], "x": 694, "y": 199, "w": 142, "h": 82 }, { "id": "grp_pump_b", "type": "group", "z": "tab_mgc_basic", "name": "Pump B (Equipment)", "style": { "label": true, "stroke": "#000000", "fill": "#86bbdd", "fill-opacity": "0.10" }, "nodes": [ "rm_basic_pump_b" ], "x": 694, "y": 379, "w": 142, "h": 82 }, { "id": "grp_pump_c", "type": "group", "z": "tab_mgc_basic", "name": "Pump C (Equipment)", "style": { "label": true, "stroke": "#000000", "fill": "#86bbdd", "fill-opacity": "0.10" }, "nodes": [ "rm_basic_pump_c" ], "x": 694, "y": 559, "w": 142, "h": 82 }, { "id": "grp_drv_mode", "type": "group", "z": "tab_mgc_basic", "name": "1. Control mode", "style": { "stroke": "#666666", "fill": "#ffdf7f", "fill-opacity": "0.15", "label": true, "color": "#333333" }, "nodes": [ "inj_mode_optimal", "inj_mode_priority" ], "x": 94, "y": 99, "w": 312, "h": 122 }, { "id": "grp_drv_scaling", "type": "group", "z": "tab_mgc_basic", "name": "2. Scaling", "style": { "stroke": "#666666", "fill": "#ffdf7f", "fill-opacity": "0.15", "label": true, "color": "#333333" }, "nodes": [ "inj_scaling_norm", "inj_scaling_abs" ], "x": 94, "y": 259, "w": 312, "h": 122 }, { "id": "grp_drv_demand", "type": "group", "z": "tab_mgc_basic", "name": "3. Operator demand (% of group capacity)", "style": { "stroke": "#666666", "fill": "#ffdf7f", "fill-opacity": "0.15", "label": true, "color": "#333333" }, "nodes": [ "inj_demand_25", "inj_demand_50", "inj_demand_75", "inj_demand_100", "inj_demand_0" ], "x": 94, "y": 419, "w": 312, "h": 222 }, { "id": "grp_setup", "type": "group", "z": "tab_mgc_basic", "name": "Setup — once on deploy", "style": { "stroke": "#666666", "fill": "#dddddd", "fill-opacity": "0.20", "label": true, "color": "#333333" }, "nodes": [ "inj_setup_start", "fn_setup_fanout" ], "x": 94, "y": 679, "w": 532, "h": 82 }, { "id": "grp_dbg", "type": "group", "z": "tab_mgc_basic", "name": "Debug outputs (sidebar)", "style": { "stroke": "#666666", "fill": "#d1d1d1", "fill-opacity": "0.2", "label": true, "color": "#333333" }, "nodes": [ "dbg_port0", "dbg_port1", "dbg_port2" ], "x": 1234, "y": 339, "w": 232, "h": 202 }, { "id": "cmt_title", "type": "comment", "z": "tab_mgc_basic", "name": "MGC — Basic (Tier 1)", "info": "One machineGroupControl coordinating three rotatingMachine pumps.\n\nDefaults: mode=optimalControl, scaling=normalized.\n\nSETUP — fires once on deploy\n- Switches all 3 pumps to virtualControl mode\n- Sends cmd.startup to all 3 pumps\nPumps register with the MGC automatically via Port 2 (child.register).\n\nHOW TO USE\n1. Deploy — the Setup group auto-runs after ~1.5 s, putting pumps in virtual + started.\n2. Click any \"set.demand = N %\" — MGC dispatches per-pump flow setpoints by BEP-gravitation (default) or priority list, depending on the mode.\n3. Switch scaling to `absolute` to interpret set.demand as m³/h instead of %.\n4. Switch mode to `priorityControl` for sequential equal-flow control; `optimalControl` (default) picks the best combination automatically.\n5. Send `set.demand = 0` to drain the group (turnOffAllMachines).\n\nPORTS (MGC)\n- Port 0: process output (mode, scaling, totals, dist-from-peak)\n- Port 1: InfluxDB-shaped payload\n- Port 2: parent-registration handshake (when wired into a pumpingStation)", "x": 1100, "y": 280, "wires": [] }, { "id": "inj_mode_optimal", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_mode", "name": "set.mode = optimalControl", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "optimalControl", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.mode", "x": 260, "y": 140, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_mode_priority", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_mode", "name": "set.mode = priorityControl", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "priorityControl", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.mode", "x": 260, "y": 180, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_scaling_norm", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_scaling", "name": "set.scaling = normalized", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "normalized", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.scaling", "x": 260, "y": 300, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_scaling_abs", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_scaling", "name": "set.scaling = absolute", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "absolute", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.scaling", "x": 260, "y": 340, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_demand_0", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_demand", "name": "set.demand = 0 (stop)", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "0", "vt": "num" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.demand", "x": 260, "y": 460, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_demand_25", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_demand", "name": "set.demand = 25 %", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "25", "vt": "num" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.demand", "x": 260, "y": 500, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_demand_50", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_demand", "name": "set.demand = 50 %", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "50", "vt": "num" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.demand", "x": 260, "y": 540, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_demand_75", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_demand", "name": "set.demand = 75 %", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "75", "vt": "num" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.demand", "x": 260, "y": 580, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_demand_100", "type": "inject", "z": "tab_mgc_basic", "g": "grp_drv_demand", "name": "set.demand = 100 %", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload", "v": "100", "vt": "num" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": "", "topic": "set.demand", "x": 260, "y": 620, "wires": [ [ "mgc_basic_node" ] ] }, { "id": "inj_setup_start", "type": "inject", "z": "tab_mgc_basic", "g": "grp_setup", "name": "Auto-start pumps", "props": [ { "p": "payload", "v": "go", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": "1.5", "topic": "", "x": 220, "y": 720, "wires": [ [ "fn_setup_fanout" ] ] }, { "id": "fn_setup_fanout", "type": "function", "z": "tab_mgc_basic", "g": "grp_setup", "name": "fan-out: virtualControl + startup → A/B/C", "func": "// Fire two messages per pump: set.mode = virtualControl, then cmd.startup.\n// Each output is a message array — Node-RED dispatches them sequentially.\nconst setMode = { topic: 'set.mode', payload: 'virtualControl' };\nconst startup = { topic: 'cmd.startup', payload: {} };\nreturn [\n [setMode, startup], // → Pump A\n [setMode, startup], // → Pump B\n [setMode, startup], // → Pump C\n];\n", "outputs": 3, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 480, "y": 720, "wires": [ [ "rm_basic_pump_a" ], [ "rm_basic_pump_b" ], [ "rm_basic_pump_c" ] ] }, { "id": "rm_basic_pump_a", "type": "rotatingMachine", "z": "tab_mgc_basic", "g": "grp_pump_a", "name": "Pump A", "speed": "1", "startup": "2", "warmup": "1", "shutdown": "2", "cooldown": "1", "movementMode": "staticspeed", "machineCurve": "", "uuid": "mgc-basic-pump-a", "supplier": "hidrostal", "category": "pump", "assetType": "pump-centrifugal", "model": "hidrostal-H05K-S03R", "unit": "m3/h", "curvePressureUnit": "mbar", "curveFlowUnit": "m3/h", "curvePowerUnit": "kW", "curveControlUnit": "%", "enableLog": false, "logLevel": "info", "positionVsParent": "atEquipment", "positionIcon": "", "hasDistance": false, "distance": "", "distanceUnit": "m", "distanceDescription": "", "x": 760, "y": 240, "wires": [ [], [], [ "mgc_basic_node" ] ] }, { "id": "rm_basic_pump_b", "type": "rotatingMachine", "z": "tab_mgc_basic", "g": "grp_pump_b", "name": "Pump B", "speed": "1", "startup": "2", "warmup": "1", "shutdown": "2", "cooldown": "1", "movementMode": "staticspeed", "machineCurve": "", "uuid": "mgc-basic-pump-b", "supplier": "hidrostal", "category": "pump", "assetType": "pump-centrifugal", "model": "hidrostal-H05K-S03R", "unit": "m3/h", "curvePressureUnit": "mbar", "curveFlowUnit": "m3/h", "curvePowerUnit": "kW", "curveControlUnit": "%", "enableLog": false, "logLevel": "info", "positionVsParent": "atEquipment", "positionIcon": "", "hasDistance": false, "distance": "", "distanceUnit": "m", "distanceDescription": "", "x": 760, "y": 420, "wires": [ [], [], [ "mgc_basic_node" ] ] }, { "id": "rm_basic_pump_c", "type": "rotatingMachine", "z": "tab_mgc_basic", "g": "grp_pump_c", "name": "Pump C", "speed": "1", "startup": "2", "warmup": "1", "shutdown": "2", "cooldown": "1", "movementMode": "staticspeed", "machineCurve": "", "uuid": "mgc-basic-pump-c", "supplier": "hidrostal", "category": "pump", "assetType": "pump-centrifugal", "model": "hidrostal-H05K-S03R", "unit": "m3/h", "curvePressureUnit": "mbar", "curveFlowUnit": "m3/h", "curvePowerUnit": "kW", "curveControlUnit": "%", "enableLog": false, "logLevel": "info", "positionVsParent": "atEquipment", "positionIcon": "", "hasDistance": false, "distance": "", "distanceUnit": "m", "distanceDescription": "", "x": 760, "y": 600, "wires": [ [], [], [ "mgc_basic_node" ] ] }, { "id": "mgc_basic_node", "type": "machineGroupControl", "z": "tab_mgc_basic", "g": "grp_mgc_unit", "name": "Machine Group", "processOutputFormat": "process", "dbaseOutputFormat": "influxdb", "mode": "optimalControl", "scaling": "normalized", "uuid": "", "supplier": "", "category": "", "assetType": "", "model": "", "unit": "", "enableLog": false, "logLevel": "info", "positionVsParent": "atEquipment", "positionIcon": "", "hasDistance": false, "distance": "", "distanceUnit": "m", "distanceDescription": "", "x": 1050, "y": 420, "wires": [ [ "dbg_port0" ], [ "dbg_port1" ], [ "dbg_port2" ] ] }, { "id": "dbg_port0", "type": "debug", "z": "tab_mgc_basic", "g": "grp_dbg", "name": "Port 0: Process", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 1340, "y": 380, "wires": [] }, { "id": "dbg_port1", "type": "debug", "z": "tab_mgc_basic", "g": "grp_dbg", "name": "Port 1: InfluxDB", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 1340, "y": 440, "wires": [] }, { "id": "dbg_port2", "type": "debug", "z": "tab_mgc_basic", "g": "grp_dbg", "name": "Port 2: Parent reg", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 1350, "y": 500, "wires": [] }, { "id": "mgc_global_cfg", "type": "global-config", "env": [], "modules": { "EVOLV": "1.0.29" } } ]