[ { "id": "f1e8a6c8b2a4477f", "type": "tab", "label": "RotatingMachine Basic", "disabled": false, "info": "Basic manual control and visualization for rotatingMachine" }, { "id": "ui_base_rm_basic", "type": "ui-base", "name": "EVOLV Demo", "path": "/dashboard", "appIcon": "", "includeClientData": true, "acceptsClientConfig": [ "ui-notification", "ui-control" ], "showPathInSidebar": false, "headerContent": "page", "navigationStyle": "default", "titleBarStyle": "default" }, { "id": "ui_theme_rm_basic", "type": "ui-theme", "name": "EVOLV Basic Theme", "colors": { "surface": "#ffffff", "primary": "#0094ce", "bgPage": "#eeeeee", "groupBg": "#ffffff", "groupOutline": "#cccccc" }, "sizes": { "density": "default", "pagePadding": "12px", "groupGap": "12px", "groupBorderRadius": "4px", "widgetGap": "12px" } }, { "id": "ui_page_rm_basic", "type": "ui-page", "name": "RotatingMachine Basic", "ui": "ui_base_rm_basic", "path": "/rotating-machine-basic", "icon": "settings_input_component", "layout": "grid", "theme": "ui_theme_rm_basic", "breakpoints": [ { "name": "Default", "px": "0", "cols": "12" } ], "order": 1, "className": "" }, { "id": "ui_group_rm_ctrl", "type": "ui-group", "name": "Machine Controls", "page": "ui_page_rm_basic", "width": "6", "height": "1", "order": 1, "showTitle": true, "className": "" }, { "id": "ui_group_rm_sim", "type": "ui-group", "name": "Simulation Inputs", "page": "ui_page_rm_basic", "width": "6", "height": "1", "order": 2, "showTitle": true, "className": "" }, { "id": "ui_group_rm_obs", "type": "ui-group", "name": "Observed Output", "page": "ui_page_rm_basic", "width": "12", "height": "24", "order": 3, "showTitle": true, "className": "" }, { "id": "rm_node_basic", "type": "rotatingMachine", "z": "f1e8a6c8b2a4477f", "name": "RM Basic", "speed": "1", "startup": "3", "warmup": "3", "shutdown": "3", "cooldown": "3", "movementMode": "staticspeed", "machineCurve": "", "uuid": "", "supplier": "hidrostal", "category": "machine", "assetType": "pump-centrifugal", "model": "hidrostal-H05K-S03R", "unit": "m3/h", "enableLog": false, "logLevel": "error", "positionVsParent": "atEquipment", "positionIcon": "", "hasDistance": false, "distance": "", "distanceUnit": "m", "distanceDescription": "", "x": 1060, "y": 420, "wires": [ [ "rm_parse_output" ], [ "rm_debug_influx" ], [ "rm_debug_parent" ] ] }, { "id": "rm_mode_dropdown", "type": "ui-dropdown", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_ctrl", "name": "Mode", "label": "Mode", "order": 1, "width": "6", "height": "1", "passthru": true, "multiple": false, "options": [ { "label": "auto", "value": "auto", "type": "str" }, { "label": "virtualControl", "value": "virtualControl", "type": "str" }, { "label": "fysicalControl", "value": "fysicalControl", "type": "str" } ], "payload": "", "topic": "setMode", "x": 210, "y": 160, "wires": [ [ "rm_set_mode" ] ] }, { "id": "rm_set_mode", "type": "change", "z": "f1e8a6c8b2a4477f", "name": "topic=setMode", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "setMode", "tot": "str" } ], "x": 440, "y": 160, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_startup_btn", "type": "ui-button", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_ctrl", "name": "Startup", "label": "Startup", "order": 2, "width": "3", "height": "1", "emulateClick": false, "tooltip": "Run startup sequence", "color": "", "bgcolor": "", "icon": "play_arrow", "payload": "startup", "payloadType": "str", "topic": "", "x": 200, "y": 220, "wires": [ [ "rm_exec_sequence_builder" ] ] }, { "id": "rm_shutdown_btn", "type": "ui-button", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_ctrl", "name": "Shutdown", "label": "Shutdown", "order": 3, "width": "3", "height": "1", "emulateClick": false, "tooltip": "Run shutdown sequence", "icon": "stop", "payload": "shutdown", "payloadType": "str", "topic": "", "x": 200, "y": 260, "wires": [ [ "rm_exec_sequence_builder" ] ] }, { "id": "rm_emergency_btn", "type": "ui-button", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_ctrl", "name": "Emergency Stop", "label": "Emergency Stop", "order": 4, "width": "6", "height": "1", "emulateClick": false, "tooltip": "Emergency stop", "color": "#ffffff", "bgcolor": "#cc0000", "icon": "warning", "payload": "{\"source\":\"GUI\",\"action\":\"emergencystop\"}", "payloadType": "json", "topic": "emergencystop", "x": 240, "y": 300, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_exec_sequence_builder", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "Build execSequence", "func": "msg.topic = 'execSequence';\nmsg.payload = {\n source: 'GUI',\n action: 'execSequence',\n parameter: msg.payload\n};\nreturn msg;", "outputs": 1, "noerr": 0, "x": 470, "y": 240, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_setpoint_input", "type": "ui-number-input", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_ctrl", "name": "Setpoint", "label": "Setpoint %", "order": 5, "width": "6", "height": "1", "passthru": true, "topic": "", "min": 0, "max": 100, "step": 1, "x": 200, "y": 360, "wires": [ [ "rm_exec_movement_builder", "rm_ctrl_setpoint_for_chart" ] ] }, { "id": "rm_exec_movement_builder", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "Build execMovement", "func": "msg.topic = 'execMovement';\nmsg.payload = {\n source: 'GUI',\n action: 'execMovement',\n setpoint: Number(msg.payload)\n};\nreturn msg;", "outputs": 1, "noerr": 0, "x": 480, "y": 360, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_pressure_down_input", "type": "ui-number-input", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_sim", "name": "Downstream Pressure", "label": "Downstream pressure (mbar)", "order": 1, "width": "6", "height": "1", "passthru": true, "topic": "", "min": 0, "max": 3000, "step": 10, "x": 230, "y": 460, "wires": [ [ "rm_sim_pressure_down_builder" ] ] }, { "id": "rm_pressure_up_input", "type": "ui-number-input", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_sim", "name": "Upstream Pressure", "label": "Upstream pressure (mbar)", "order": 2, "width": "6", "height": "1", "passthru": true, "topic": "", "min": 0, "max": 3000, "step": 10, "x": 220, "y": 500, "wires": [ [ "rm_sim_pressure_up_builder" ] ] }, { "id": "rm_sim_pressure_down_builder", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "simulate downstream pressure", "func": "msg.topic = 'simulateMeasurement';\nmsg.payload = {\n type: 'pressure',\n position: 'downstream',\n value: Number(msg.payload),\n unit: 'mbar'\n};\nreturn msg;", "outputs": 1, "noerr": 0, "x": 510, "y": 460, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_sim_pressure_up_builder", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "simulate upstream pressure", "func": "msg.topic = 'simulateMeasurement';\nmsg.payload = {\n type: 'pressure',\n position: 'upstream',\n value: Number(msg.payload),\n unit: 'mbar'\n};\nreturn msg;", "outputs": 1, "noerr": 0, "x": 500, "y": 500, "wires": [ [ "rm_node_basic" ] ] }, { "id": "rm_parse_output", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "Parse RM process output", "func": "const incoming = (msg && msg.payload && typeof msg.payload === 'object') ? msg.payload : {};\nconst lastPayload = context.get('lastPayload') || {};\nconst merged = { ...lastPayload, ...incoming };\ncontext.set('lastPayload', merged);\n\nconst cache = context.get('metricCache') || {\n flow: 0,\n power: 0,\n ctrl: 0,\n nCog: 0,\n stateCode: 0,\n state: 'idle',\n mode: 'auto',\n runtime: 0,\n moveTimeleft: 0,\n maintenanceTime: 0\n};\n\nconst pickNumber = (...keys) => {\n for (const key of keys) {\n const value = Number(merged[key]);\n if (Number.isFinite(value)) return value;\n }\n return null;\n};\n\nconst pickString = (key, fallback = null) => {\n const value = merged[key];\n if (value === undefined || value === null || value === '') return fallback;\n return String(value);\n};\n\nconst flow = pickNumber('flow.predicted.downstream.default', 'flow.predicted.downstream');\nconst power = pickNumber('power.predicted.atequipment.default', 'power.predicted.atequipment', 'power.predicted.atEquipment.default', 'power.predicted.atEquipment');\nconst ctrl = pickNumber('ctrl', 'ctrl.predicted.atequipment.default', 'ctrl.predicted.atequipment', 'ctrl.predicted.atEquipment.default', 'ctrl.predicted.atEquipment');\nconst nCog = pickNumber('NCogPercent', 'NCog');\nconst runtime = pickNumber('runtime');\nconst moveTimeleft = pickNumber('moveTimeleft');\nconst maintenanceTime = pickNumber('maintenanceTime');\nconst state = pickString('state', cache.state);\nconst mode = pickString('mode', cache.mode);\n\nconst stateCodeMap = { off: 0, idle: 1, starting: 2, warmingup: 3, operational: 4, accelerating: 5, decelerating: 6, stopping: 7, coolingdown: 8, maintenance: 9 };\nconst stateCode = stateCodeMap[state] ?? cache.stateCode;\n\nif (flow !== null) cache.flow = flow;\nif (power !== null) cache.power = power;\nif (ctrl !== null) cache.ctrl = ctrl;\nif (nCog !== null) cache.nCog = nCog;\nif (runtime !== null) cache.runtime = runtime;\nif (moveTimeleft !== null) cache.moveTimeleft = moveTimeleft;\nif (maintenanceTime !== null) cache.maintenanceTime = maintenanceTime;\ncache.state = state;\ncache.mode = mode;\ncache.stateCode = stateCode;\ncontext.set('metricCache', cache);\n\nreturn [\n { topic: 'actual_flow', payload: cache.flow },\n { topic: 'predicted_power', payload: cache.power },\n { topic: 'actual_ctrl', payload: cache.ctrl },\n { topic: 'nCog', payload: cache.nCog },\n { topic: 'stateCode', payload: cache.stateCode },\n { payload: 'state=' + cache.state + ', mode=' + cache.mode + ', ctrl=' + cache.ctrl.toFixed(2) + '%' },\n { payload: 'runtime=' + cache.runtime.toFixed(3) + ' h | moveTimeLeft=' + cache.moveTimeleft.toFixed(0) + ' s | maintenance=' + cache.maintenanceTime.toFixed(3) + ' h' },\n { payload: JSON.stringify(merged) }\n];", "outputs": 8, "noerr": 0, "x": 1310, "y": 420, "wires": [ [ "rm_chart_flow" ], [ "rm_chart_power" ], [ "rm_chart_ctrl" ], [ "rm_chart_ncog" ], [ "rm_chart_statecode" ], [ "rm_text_state" ], [ "rm_text_timing" ], [ "rm_text_snapshot" ] ] }, { "id": "rm_chart_flow", "type": "ui-chart", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Predicted Flow", "label": "Flow (m3/h)", "order": 1, "width": 12, "height": 4, "chartType": "line", "category": "", "xAxisLabel": "time", "xAxisType": "time", "yAxisLabel": "m3/h", "removeOlder": "1", "removeOlderUnit": "3600", "removeOlderPoints": "", "x": 1560, "y": 340, "wires": [], "showLegend": true }, { "id": "rm_chart_power", "type": "ui-chart", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Predicted Power", "label": "Power (kW)", "order": 2, "width": 12, "height": 4, "chartType": "line", "xAxisType": "time", "yAxisLabel": "kW", "removeOlder": "1", "removeOlderUnit": "3600", "x": 1560, "y": 400, "wires": [], "showLegend": true }, { "id": "rm_chart_ctrl", "type": "ui-chart", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Control Position", "label": "Ctrl (%)", "order": 3, "width": 12, "height": 4, "chartType": "line", "xAxisType": "time", "yAxisLabel": "%", "removeOlder": "1", "removeOlderUnit": "3600", "x": 1560, "y": 460, "wires": [], "showLegend": true }, { "id": "rm_text_state", "type": "ui-text", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "State/Mode", "label": "Current State", "order": 6, "width": 12, "height": 1, "format": "{{msg.payload}}", "layout": "row-spread", "x": 1560, "y": 520, "wires": [] }, { "id": "rm_debug_influx", "type": "debug", "z": "f1e8a6c8b2a4477f", "name": "Influx output", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 1290, "y": 560, "wires": [] }, { "id": "rm_debug_parent", "type": "debug", "z": "f1e8a6c8b2a4477f", "name": "Parent output", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 1280, "y": 600, "wires": [] }, { "id": "rm_chart_ncog", "type": "ui-chart", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "NCog", "label": "NCog (%)", "order": 4, "width": 12, "height": 4, "chartType": "line", "xAxisType": "time", "yAxisLabel": "%", "removeOlder": "1", "removeOlderUnit": "3600", "x": 1560, "y": 520, "wires": [], "showLegend": true }, { "id": "rm_chart_statecode", "type": "ui-chart", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Machine State Code", "label": "State Code (off=0 .. maint=9)", "order": 5, "width": 12, "height": 4, "chartType": "line", "xAxisType": "time", "yAxisLabel": "state", "removeOlder": "1", "removeOlderUnit": "3600", "x": 1560, "y": 580, "wires": [], "showLegend": true }, { "id": "rm_text_timing", "type": "ui-text", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Timing", "label": "Timing", "order": 7, "width": 12, "height": 1, "format": "{{msg.payload}}", "layout": "row-spread", "x": 1560, "y": 700, "wires": [] }, { "id": "rm_text_snapshot", "type": "ui-text", "z": "f1e8a6c8b2a4477f", "group": "ui_group_rm_obs", "name": "Latest Payload", "label": "Latest Payload", "order": 8, "width": 12, "height": 1, "format": "{{msg.payload}}", "layout": "row-spread", "x": 1560, "y": 740, "wires": [] }, { "id": "rm_ctrl_setpoint_for_chart", "type": "function", "z": "f1e8a6c8b2a4477f", "name": "ctrl setpoint series", "func": "msg.topic = 'setpoint_ctrl';\nmsg.payload = Number(msg.payload);\nreturn Number.isFinite(msg.payload) ? msg : null;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 610, "y": 280, "wires": [ [ "rm_chart_ctrl" ] ] } ]