examples/ (new — was empty except standalone-demo.js):
01-Basic.json 14 nodes, inject + dashboard, no parent
02-Integration.json 32 nodes, 2 tabs, measurement + MGC + 2 pumps,
link-out/link-in channels per node-red-flow-layout.md
03-Dashboard.json 63 nodes, 3 tabs (process + UI + setup),
FlowFuse charts + sliders, trend-split pattern
README.md load instructions
tools/build-examples.js regenerator
All canonical topic names only (set.*, cmd.*, data.*, child.*). No
legacy aliases. Every ui-* widget has x/y. Every chart has the full
mandatory key set from node-red-flow-layout.md §4.
wiki/Home.md (new) — pilot page for the 14-section visual-first template.
Sections 5 (topic-contract) + 9 (data-model) are auto-generated via the
new npm run wiki:* scripts; everything else hand-written following
.claude/refactor/WIKI_TEMPLATE.md.
package.json — added wiki:contract / wiki:datamodel / wiki:all scripts
wired to ../generalFunctions/scripts/wikiGen.js.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1326 lines
27 KiB
JSON
1326 lines
27 KiB
JSON
[
|
|
{
|
|
"id": "ps_dash_proc",
|
|
"type": "tab",
|
|
"label": "Process Plant",
|
|
"disabled": false,
|
|
"info": "Tier 3: full station with measurement + MGC + 2 pumps, formatted for live dashboard."
|
|
},
|
|
{
|
|
"id": "ps_dash_ui",
|
|
"type": "tab",
|
|
"label": "Dashboard UI",
|
|
"disabled": false,
|
|
"info": "FlowFuse dashboard 2.0: 3 charts (flow / level / volumePercent), text widgets and 2 sliders."
|
|
},
|
|
{
|
|
"id": "ps_dash_setup",
|
|
"type": "tab",
|
|
"label": "Setup",
|
|
"disabled": false,
|
|
"info": "Once-true injects: initial mode + initial inflow seed."
|
|
},
|
|
{
|
|
"id": "ps_dash_base",
|
|
"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": "ps_dash_theme",
|
|
"type": "ui-theme",
|
|
"name": "EVOLV Theme",
|
|
"colors": {
|
|
"surface": "#ffffff",
|
|
"primary": "#0c99d9",
|
|
"bgPage": "#eeeeee",
|
|
"groupBg": "#ffffff",
|
|
"groupOutline": "#cccccc"
|
|
},
|
|
"sizes": {
|
|
"density": "default",
|
|
"pagePadding": "14px",
|
|
"groupGap": "14px",
|
|
"groupBorderRadius": "6px",
|
|
"widgetGap": "12px"
|
|
}
|
|
},
|
|
{
|
|
"id": "ps_dash_page",
|
|
"type": "ui-page",
|
|
"name": "PumpingStation Demo",
|
|
"ui": "ps_dash_base",
|
|
"path": "/pumping-station",
|
|
"icon": "water",
|
|
"layout": "grid",
|
|
"theme": "ps_dash_theme",
|
|
"breakpoints": [
|
|
{
|
|
"name": "Default",
|
|
"px": "0",
|
|
"cols": "12"
|
|
}
|
|
],
|
|
"order": 1,
|
|
"className": ""
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_ctrl",
|
|
"type": "ui-group",
|
|
"name": "Controls",
|
|
"page": "ps_dash_page",
|
|
"width": 6,
|
|
"height": 1,
|
|
"order": 1,
|
|
"showTitle": true,
|
|
"className": ""
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_status",
|
|
"type": "ui-group",
|
|
"name": "Operator Status",
|
|
"page": "ps_dash_page",
|
|
"width": 6,
|
|
"height": 1,
|
|
"order": 2,
|
|
"showTitle": true,
|
|
"className": ""
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_trend",
|
|
"type": "ui-group",
|
|
"name": "Live Trends",
|
|
"page": "ps_dash_page",
|
|
"width": 12,
|
|
"height": 1,
|
|
"order": 3,
|
|
"showTitle": true,
|
|
"className": ""
|
|
},
|
|
{
|
|
"id": "ps_dash_proc_title",
|
|
"type": "comment",
|
|
"z": "ps_dash_proc",
|
|
"name": "Process Plant\n━━━━━━━━━━━━━━━━━\nFull station with parent (MGC) and 2 pump children.\nEvents go to Dashboard UI through evt:ps; commands come back through cmd:ps-mode and cmd:ps-demand.",
|
|
"info": "",
|
|
"x": 600,
|
|
"y": 40,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lin_proc_mode",
|
|
"type": "link in",
|
|
"z": "ps_dash_proc",
|
|
"name": "cmd:ps-mode",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 480,
|
|
"wires": [
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_proc_demand",
|
|
"type": "link in",
|
|
"z": "ps_dash_proc",
|
|
"name": "cmd:ps-demand",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 540,
|
|
"wires": [
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_proc_setupmode",
|
|
"type": "link in",
|
|
"z": "ps_dash_proc",
|
|
"name": "setup:to-ps-mode",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 420,
|
|
"wires": [
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_proc_setupinflow",
|
|
"type": "link in",
|
|
"z": "ps_dash_proc",
|
|
"name": "setup:to-ps-inflow",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 600,
|
|
"wires": [
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_meas_level",
|
|
"type": "measurement",
|
|
"z": "ps_dash_proc",
|
|
"name": "Basin level sensor",
|
|
"mode": "analog",
|
|
"channels": "[]",
|
|
"scaling": false,
|
|
"i_min": 0,
|
|
"i_max": 0,
|
|
"i_offset": 0,
|
|
"o_min": 0,
|
|
"o_max": 1,
|
|
"simulator": true,
|
|
"smooth_method": "mean",
|
|
"count": 5,
|
|
"processOutputFormat": "process",
|
|
"dbaseOutputFormat": "influxdb",
|
|
"uuid": "example-level-001",
|
|
"supplier": "vega",
|
|
"category": "sensor",
|
|
"assetType": "level",
|
|
"model": "VEGAPULS-31",
|
|
"unit": "m",
|
|
"assetTagNumber": "LT-001",
|
|
"enableLog": false,
|
|
"logLevel": "error",
|
|
"positionVsParent": "atEquipment",
|
|
"positionIcon": "",
|
|
"hasDistance": false,
|
|
"distance": 0,
|
|
"distanceUnit": "m",
|
|
"distanceDescription": "",
|
|
"x": 600,
|
|
"y": 700,
|
|
"wires": [
|
|
[],
|
|
[],
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_inj_level",
|
|
"type": "inject",
|
|
"z": "ps_dash_proc",
|
|
"name": "sim level 1.6 m",
|
|
"props": [
|
|
{
|
|
"p": "topic",
|
|
"vt": "str"
|
|
},
|
|
{
|
|
"p": "payload",
|
|
"v": "1.6",
|
|
"vt": "num"
|
|
}
|
|
],
|
|
"topic": "measurement",
|
|
"repeat": "",
|
|
"crontab": "",
|
|
"once": false,
|
|
"onceDelay": "",
|
|
"x": 120,
|
|
"y": 700,
|
|
"wires": [
|
|
[
|
|
"ps_dash_meas_level"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_pump_a",
|
|
"type": "rotatingMachine",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump A",
|
|
"speed": "1",
|
|
"startup": "2",
|
|
"warmup": "1",
|
|
"shutdown": "2",
|
|
"cooldown": "1",
|
|
"movementMode": "staticspeed",
|
|
"machineCurve": "",
|
|
"uuid": "example-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": "error",
|
|
"positionVsParent": "atEquipment",
|
|
"positionIcon": "",
|
|
"hasDistance": false,
|
|
"distance": "",
|
|
"distanceUnit": "m",
|
|
"distanceDescription": "",
|
|
"x": 840,
|
|
"y": 320,
|
|
"wires": [
|
|
[],
|
|
[],
|
|
[
|
|
"ps_dash_mgc"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_pump_b",
|
|
"type": "rotatingMachine",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump B",
|
|
"speed": "1",
|
|
"startup": "2",
|
|
"warmup": "1",
|
|
"shutdown": "2",
|
|
"cooldown": "1",
|
|
"movementMode": "staticspeed",
|
|
"machineCurve": "",
|
|
"uuid": "example-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": "error",
|
|
"positionVsParent": "atEquipment",
|
|
"positionIcon": "",
|
|
"hasDistance": false,
|
|
"distance": "",
|
|
"distanceUnit": "m",
|
|
"distanceDescription": "",
|
|
"x": 840,
|
|
"y": 400,
|
|
"wires": [
|
|
[],
|
|
[],
|
|
[
|
|
"ps_dash_mgc"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_mgc",
|
|
"type": "machineGroupControl",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump Group",
|
|
"enableLog": true,
|
|
"logLevel": "info",
|
|
"positionVsParent": "atEquipment",
|
|
"positionIcon": "",
|
|
"hasDistance": false,
|
|
"distance": "",
|
|
"distanceUnit": "m",
|
|
"x": 1080,
|
|
"y": 360,
|
|
"wires": [
|
|
[],
|
|
[],
|
|
[
|
|
"ps_dash_station"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_station",
|
|
"type": "pumpingStation",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pumping Station",
|
|
"simulator": false,
|
|
"basinVolume": 50,
|
|
"basinHeight": 3.5,
|
|
"inflowLevel": 3,
|
|
"outflowLevel": 0.2,
|
|
"overflowLevel": 3.2,
|
|
"defaultFluid": "wastewater",
|
|
"inletPipeDiameter": 0.3,
|
|
"outletPipeDiameter": 0.3,
|
|
"pipelineLength": 80,
|
|
"maxDischargeHead": 24,
|
|
"staticHead": 12,
|
|
"maxInflowRate": 200,
|
|
"temperatureReferenceDegC": 15,
|
|
"timeleftToFullOrEmptyThresholdSeconds": 0,
|
|
"enableDryRunProtection": true,
|
|
"enableOverfillProtection": true,
|
|
"dryRunThresholdPercent": 2,
|
|
"overfillThresholdPercent": 98,
|
|
"minHeightBasedOn": "outlet",
|
|
"processOutputFormat": "process",
|
|
"dbaseOutputFormat": "influxdb",
|
|
"refHeight": "NAP",
|
|
"basinBottomRef": 1,
|
|
"uuid": "example-ps-001",
|
|
"supplier": "WBD-RD",
|
|
"category": "station",
|
|
"assetType": "pumpingstation",
|
|
"model": "demo-50m3",
|
|
"unit": "m3/h",
|
|
"enableLog": true,
|
|
"logLevel": "info",
|
|
"positionVsParent": "atEquipment",
|
|
"positionIcon": "",
|
|
"hasDistance": false,
|
|
"distance": "",
|
|
"distanceUnit": "m",
|
|
"distanceDescription": "",
|
|
"controlMode": "levelbased",
|
|
"startLevel": 1.2,
|
|
"minLevel": 0.4,
|
|
"maxLevel": 2.8,
|
|
"flowSetpoint": null,
|
|
"flowDeadband": null,
|
|
"x": 1320,
|
|
"y": 520,
|
|
"wires": [
|
|
[
|
|
"ps_dash_trend_split"
|
|
],
|
|
[],
|
|
[]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_trend_split",
|
|
"type": "function",
|
|
"z": "ps_dash_proc",
|
|
"name": "Trend split + status",
|
|
"func": "const p = (msg && msg.payload && typeof msg.payload === 'object') ? msg.payload : {};\nconst cache = context.get('c') || {}; Object.assign(cache, p); context.set('c', cache);\nfunction pick(prefix){ for (const k of Object.keys(cache)) if (k===prefix||k.indexOf(prefix+'.')===0){ const v=Number(cache[k]); if(Number.isFinite(v)) return v;} return null; }\nconst flowIn = pick('flow.predicted.in');\nconst flowOut = pick('flow.predicted.out');\nconst level = pick('level.predicted.atequipment');\nconst volPct = Number(cache.volumePercent);\nconst ts = Date.now();\nconst flowMsgs = [];\nif (flowIn != null) flowMsgs.push({ topic: 'Inflow', payload: flowIn * 3600, timestamp: ts });\nif (flowOut != null) flowMsgs.push({ topic: 'Outflow', payload: flowOut * 3600, timestamp: ts });\nconst flowOut1 = flowMsgs.length ? flowMsgs : null;\nconst levelOut = level != null ? { topic: 'Level', payload: level, timestamp: ts } : null;\nconst volOut = Number.isFinite(volPct) ? { topic: 'Volume%', payload: volPct, timestamp: ts } : null;\nconst stateStr = `state=${cache.state||'?'} | mode=${cache.controlMode||cache.mode||'?'}`;\nconst percStr = cache.percControl != null ? Number(cache.percControl).toFixed(1) + ' %' : 'n/a';\nconst dirStr = cache.direction || 'n/a';\nconst tEmpty = cache.timeToEmpty != null ? Number(cache.timeToEmpty).toFixed(0) + ' s' : 'n/a';\nreturn [\n flowOut1,\n levelOut,\n volOut,\n { payload: stateStr },\n { payload: percStr },\n { payload: dirStr },\n { payload: tEmpty }\n];",
|
|
"outputs": 7,
|
|
"noerr": 0,
|
|
"initialize": "",
|
|
"finalize": "",
|
|
"libs": [],
|
|
"x": 1560,
|
|
"y": 520,
|
|
"wires": [
|
|
[
|
|
"lout_evt_flow"
|
|
],
|
|
[
|
|
"lout_evt_level"
|
|
],
|
|
[
|
|
"lout_evt_volpct"
|
|
],
|
|
[
|
|
"lout_evt_state"
|
|
],
|
|
[
|
|
"lout_evt_perc"
|
|
],
|
|
[
|
|
"lout_evt_dir"
|
|
],
|
|
[
|
|
"lout_evt_tempty"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lout_evt_flow",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:flow",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_flow"
|
|
],
|
|
"x": 1800,
|
|
"y": 420,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_level",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:level",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_level"
|
|
],
|
|
"x": 1800,
|
|
"y": 460,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_volpct",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:volpct",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_volpct"
|
|
],
|
|
"x": 1800,
|
|
"y": 500,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_state",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:state",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_state"
|
|
],
|
|
"x": 1800,
|
|
"y": 540,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_perc",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:perc",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_perc"
|
|
],
|
|
"x": 1800,
|
|
"y": 580,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_dir",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:dir",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_dir"
|
|
],
|
|
"x": 1800,
|
|
"y": 620,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_evt_tempty",
|
|
"type": "link out",
|
|
"z": "ps_dash_proc",
|
|
"name": "evt:tempty",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_ui_tempty"
|
|
],
|
|
"x": 1800,
|
|
"y": 660,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_station",
|
|
"type": "group",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pumping Station (PC)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#0c99d9",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_station",
|
|
"ps_dash_trend_split",
|
|
"lin_proc_mode",
|
|
"lin_proc_demand",
|
|
"lin_proc_setupmode",
|
|
"lin_proc_setupinflow",
|
|
"lout_evt_flow",
|
|
"lout_evt_level",
|
|
"lout_evt_volpct",
|
|
"lout_evt_state",
|
|
"lout_evt_perc",
|
|
"lout_evt_dir",
|
|
"lout_evt_tempty"
|
|
],
|
|
"x": 95,
|
|
"y": 375,
|
|
"w": 1930,
|
|
"h": 350
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_pa",
|
|
"type": "group",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump A (EM)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#86bbdd",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_pump_a"
|
|
],
|
|
"x": 815,
|
|
"y": 275,
|
|
"w": 250,
|
|
"h": 110
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_pb",
|
|
"type": "group",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump B (EM)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#86bbdd",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_pump_b"
|
|
],
|
|
"x": 815,
|
|
"y": 355,
|
|
"w": 250,
|
|
"h": 110
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_mgc",
|
|
"type": "group",
|
|
"z": "ps_dash_proc",
|
|
"name": "Pump Group MGC (UN)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#50a8d9",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_mgc"
|
|
],
|
|
"x": 1055,
|
|
"y": 315,
|
|
"w": 250,
|
|
"h": 110
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_level",
|
|
"type": "group",
|
|
"z": "ps_dash_proc",
|
|
"name": "Level Sensor (CM)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#a9daee",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_meas_level",
|
|
"ps_dash_inj_level"
|
|
],
|
|
"x": 95,
|
|
"y": 655,
|
|
"w": 730,
|
|
"h": 110
|
|
},
|
|
{
|
|
"id": "ps_dash_ui_title",
|
|
"type": "comment",
|
|
"z": "ps_dash_ui",
|
|
"name": "Dashboard UI\n━━━━━━━━━━━━━━━\nLink-ins on L0 receive evt:* from Process Plant.\nSliders on L2 emit cmd:* back to Process Plant.\nCharts use the trend-split pattern: one chart per metric, series labelled by msg.topic.",
|
|
"info": "",
|
|
"x": 600,
|
|
"y": 40,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lin_ui_flow",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:flow",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 220,
|
|
"wires": [
|
|
[
|
|
"ui_chart_flow"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_level",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:level",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 320,
|
|
"wires": [
|
|
[
|
|
"ui_chart_level"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_volpct",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:volpct",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 420,
|
|
"wires": [
|
|
[
|
|
"ui_chart_volpct"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_state",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:state",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 520,
|
|
"wires": [
|
|
[
|
|
"ui_text_state"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_perc",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:perc",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 560,
|
|
"wires": [
|
|
[
|
|
"ui_text_perc"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_dir",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:dir",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 600,
|
|
"wires": [
|
|
[
|
|
"ui_text_dir"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lin_ui_tempty",
|
|
"type": "link in",
|
|
"z": "ps_dash_ui",
|
|
"name": "evt:tempty",
|
|
"links": [],
|
|
"x": 120,
|
|
"y": 640,
|
|
"wires": [
|
|
[
|
|
"ui_text_tempty"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ui_chart_flow",
|
|
"type": "ui-chart",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_trend",
|
|
"name": "Flow trend",
|
|
"label": "Flow (m³/h)",
|
|
"order": 1,
|
|
"width": 12,
|
|
"height": 6,
|
|
"chartType": "line",
|
|
"category": "topic",
|
|
"categoryType": "msg",
|
|
"xAxisLabel": "time",
|
|
"xAxisType": "time",
|
|
"xAxisProperty": "",
|
|
"xAxisPropertyType": "timestamp",
|
|
"xAxisFormat": "",
|
|
"xAxisFormatType": "auto",
|
|
"yAxisLabel": "m³/h",
|
|
"yAxisProperty": "payload",
|
|
"yAxisPropertyType": "msg",
|
|
"xmin": "",
|
|
"xmax": "",
|
|
"ymin": "",
|
|
"ymax": "",
|
|
"bins": 10,
|
|
"action": "append",
|
|
"stackSeries": false,
|
|
"pointShape": "circle",
|
|
"pointRadius": 4,
|
|
"interpolation": "linear",
|
|
"showLegend": true,
|
|
"className": "",
|
|
"removeOlder": "15",
|
|
"removeOlderUnit": "60",
|
|
"removeOlderPoints": "200",
|
|
"colors": [
|
|
"#0095FF",
|
|
"#FF0000",
|
|
"#FF7F0E",
|
|
"#2CA02C",
|
|
"#A347E1",
|
|
"#D62728",
|
|
"#FF9896",
|
|
"#9467BD",
|
|
"#C5B0D5"
|
|
],
|
|
"textColor": [
|
|
"#666666"
|
|
],
|
|
"textColorDefault": true,
|
|
"gridColor": [
|
|
"#e5e5e5"
|
|
],
|
|
"gridColorDefault": true,
|
|
"x": 1080,
|
|
"y": 220,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_chart_level",
|
|
"type": "ui-chart",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_trend",
|
|
"name": "Level trend",
|
|
"label": "Level (m)",
|
|
"order": 2,
|
|
"width": 12,
|
|
"height": 6,
|
|
"chartType": "line",
|
|
"category": "topic",
|
|
"categoryType": "msg",
|
|
"xAxisLabel": "time",
|
|
"xAxisType": "time",
|
|
"xAxisProperty": "",
|
|
"xAxisPropertyType": "timestamp",
|
|
"xAxisFormat": "",
|
|
"xAxisFormatType": "auto",
|
|
"yAxisLabel": "m",
|
|
"yAxisProperty": "payload",
|
|
"yAxisPropertyType": "msg",
|
|
"xmin": "",
|
|
"xmax": "",
|
|
"ymin": "",
|
|
"ymax": "",
|
|
"bins": 10,
|
|
"action": "append",
|
|
"stackSeries": false,
|
|
"pointShape": "circle",
|
|
"pointRadius": 4,
|
|
"interpolation": "linear",
|
|
"showLegend": true,
|
|
"className": "",
|
|
"removeOlder": "15",
|
|
"removeOlderUnit": "60",
|
|
"removeOlderPoints": "200",
|
|
"colors": [
|
|
"#0095FF",
|
|
"#FF0000",
|
|
"#FF7F0E",
|
|
"#2CA02C",
|
|
"#A347E1",
|
|
"#D62728",
|
|
"#FF9896",
|
|
"#9467BD",
|
|
"#C5B0D5"
|
|
],
|
|
"textColor": [
|
|
"#666666"
|
|
],
|
|
"textColorDefault": true,
|
|
"gridColor": [
|
|
"#e5e5e5"
|
|
],
|
|
"gridColorDefault": true,
|
|
"x": 1080,
|
|
"y": 320,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_chart_volpct",
|
|
"type": "ui-chart",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_trend",
|
|
"name": "Volume %",
|
|
"label": "Volume (%)",
|
|
"order": 3,
|
|
"width": 12,
|
|
"height": 6,
|
|
"chartType": "line",
|
|
"category": "topic",
|
|
"categoryType": "msg",
|
|
"xAxisLabel": "time",
|
|
"xAxisType": "time",
|
|
"xAxisProperty": "",
|
|
"xAxisPropertyType": "timestamp",
|
|
"xAxisFormat": "",
|
|
"xAxisFormatType": "auto",
|
|
"yAxisLabel": "%",
|
|
"yAxisProperty": "payload",
|
|
"yAxisPropertyType": "msg",
|
|
"xmin": "",
|
|
"xmax": "",
|
|
"ymin": "",
|
|
"ymax": "",
|
|
"bins": 10,
|
|
"action": "append",
|
|
"stackSeries": false,
|
|
"pointShape": "circle",
|
|
"pointRadius": 4,
|
|
"interpolation": "linear",
|
|
"showLegend": true,
|
|
"className": "",
|
|
"removeOlder": "15",
|
|
"removeOlderUnit": "60",
|
|
"removeOlderPoints": "200",
|
|
"colors": [
|
|
"#0095FF",
|
|
"#FF0000",
|
|
"#FF7F0E",
|
|
"#2CA02C",
|
|
"#A347E1",
|
|
"#D62728",
|
|
"#FF9896",
|
|
"#9467BD",
|
|
"#C5B0D5"
|
|
],
|
|
"textColor": [
|
|
"#666666"
|
|
],
|
|
"textColorDefault": true,
|
|
"gridColor": [
|
|
"#e5e5e5"
|
|
],
|
|
"gridColorDefault": true,
|
|
"x": 1080,
|
|
"y": 420,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_text_state",
|
|
"type": "ui-text",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_status",
|
|
"name": "State",
|
|
"label": "Station state",
|
|
"order": 1,
|
|
"width": 4,
|
|
"height": 1,
|
|
"format": "{{msg.payload}}",
|
|
"layout": "row-spread",
|
|
"x": 1080,
|
|
"y": 520,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_text_perc",
|
|
"type": "ui-text",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_status",
|
|
"name": "percControl",
|
|
"label": "Control %",
|
|
"order": 2,
|
|
"width": 4,
|
|
"height": 1,
|
|
"format": "{{msg.payload}}",
|
|
"layout": "row-spread",
|
|
"x": 1080,
|
|
"y": 560,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_text_dir",
|
|
"type": "ui-text",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_status",
|
|
"name": "direction",
|
|
"label": "Direction",
|
|
"order": 3,
|
|
"width": 4,
|
|
"height": 1,
|
|
"format": "{{msg.payload}}",
|
|
"layout": "row-spread",
|
|
"x": 1080,
|
|
"y": 600,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_text_tempty",
|
|
"type": "ui-text",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_status",
|
|
"name": "timeToEmpty",
|
|
"label": "Time to empty",
|
|
"order": 4,
|
|
"width": 4,
|
|
"height": 1,
|
|
"format": "{{msg.payload}}",
|
|
"layout": "row-spread",
|
|
"x": 1080,
|
|
"y": 640,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ui_dd_mode",
|
|
"type": "ui-dropdown",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_ctrl",
|
|
"name": "Mode",
|
|
"label": "Control mode",
|
|
"order": 1,
|
|
"width": 6,
|
|
"height": 1,
|
|
"passthru": true,
|
|
"multiple": false,
|
|
"options": [
|
|
{
|
|
"label": "manual",
|
|
"value": "manual",
|
|
"type": "str"
|
|
},
|
|
{
|
|
"label": "levelbased",
|
|
"value": "levelbased",
|
|
"type": "str"
|
|
},
|
|
{
|
|
"label": "flowbased",
|
|
"value": "flowbased",
|
|
"type": "str"
|
|
},
|
|
{
|
|
"label": "none",
|
|
"value": "none",
|
|
"type": "str"
|
|
}
|
|
],
|
|
"payload": "",
|
|
"topic": "set.mode",
|
|
"topicType": "str",
|
|
"x": 600,
|
|
"y": 160,
|
|
"wires": [
|
|
[
|
|
"ui_wrap_mode"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ui_sl_demand",
|
|
"type": "ui-slider",
|
|
"z": "ps_dash_ui",
|
|
"group": "ps_dash_grp_ctrl",
|
|
"name": "Demand",
|
|
"label": "Manual demand (m³/h)",
|
|
"order": 2,
|
|
"width": 6,
|
|
"height": 1,
|
|
"passthru": true,
|
|
"outs": "end",
|
|
"topic": "set.demand",
|
|
"topicType": "str",
|
|
"min": 0,
|
|
"max": 200,
|
|
"step": 5,
|
|
"icon": "",
|
|
"thumbLabel": "always",
|
|
"showValue": true,
|
|
"className": "",
|
|
"x": 600,
|
|
"y": 220,
|
|
"wires": [
|
|
[
|
|
"ui_wrap_demand"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ui_wrap_mode",
|
|
"type": "function",
|
|
"z": "ps_dash_ui",
|
|
"name": "topic=set.mode",
|
|
"func": "msg.topic = 'set.mode';\nmsg.payload = String(msg.payload || 'manual');\nreturn msg;",
|
|
"outputs": 1,
|
|
"noerr": 0,
|
|
"initialize": "",
|
|
"finalize": "",
|
|
"libs": [],
|
|
"x": 1080,
|
|
"y": 160,
|
|
"wires": [
|
|
[
|
|
"lout_cmd_mode"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ui_wrap_demand",
|
|
"type": "function",
|
|
"z": "ps_dash_ui",
|
|
"name": "topic=set.demand",
|
|
"func": "msg.topic = 'set.demand';\nmsg.payload = Number(msg.payload);\nreturn Number.isFinite(msg.payload) ? msg : null;",
|
|
"outputs": 1,
|
|
"noerr": 0,
|
|
"initialize": "",
|
|
"finalize": "",
|
|
"libs": [],
|
|
"x": 1080,
|
|
"y": 220,
|
|
"wires": [
|
|
[
|
|
"lout_cmd_demand"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "lout_cmd_mode",
|
|
"type": "link out",
|
|
"z": "ps_dash_ui",
|
|
"name": "cmd:ps-mode",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_proc_mode"
|
|
],
|
|
"x": 1800,
|
|
"y": 160,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "lout_cmd_demand",
|
|
"type": "link out",
|
|
"z": "ps_dash_ui",
|
|
"name": "cmd:ps-demand",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_proc_demand"
|
|
],
|
|
"x": 1800,
|
|
"y": 220,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "grp_ui_ctrl",
|
|
"type": "group",
|
|
"z": "ps_dash_ui",
|
|
"name": "Controls (PC)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#0c99d9",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ui_dd_mode",
|
|
"ui_sl_demand",
|
|
"ui_wrap_mode",
|
|
"ui_wrap_demand",
|
|
"lout_cmd_mode",
|
|
"lout_cmd_demand"
|
|
],
|
|
"x": 575,
|
|
"y": 115,
|
|
"w": 1450,
|
|
"h": 170
|
|
},
|
|
{
|
|
"id": "grp_ui_status",
|
|
"type": "group",
|
|
"z": "ps_dash_ui",
|
|
"name": "Operator status (PC)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#0c99d9",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ui_text_state",
|
|
"ui_text_perc",
|
|
"ui_text_dir",
|
|
"ui_text_tempty",
|
|
"lin_ui_state",
|
|
"lin_ui_perc",
|
|
"lin_ui_dir",
|
|
"lin_ui_tempty"
|
|
],
|
|
"x": 95,
|
|
"y": 475,
|
|
"w": 1210,
|
|
"h": 230
|
|
},
|
|
{
|
|
"id": "grp_ui_trend",
|
|
"type": "group",
|
|
"z": "ps_dash_ui",
|
|
"name": "Live trends (PC)",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#0c99d9",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ui_chart_flow",
|
|
"ui_chart_level",
|
|
"ui_chart_volpct",
|
|
"lin_ui_flow",
|
|
"lin_ui_level",
|
|
"lin_ui_volpct"
|
|
],
|
|
"x": 95,
|
|
"y": 175,
|
|
"w": 1210,
|
|
"h": 310
|
|
},
|
|
{
|
|
"id": "ps_dash_setup_title",
|
|
"type": "comment",
|
|
"z": "ps_dash_setup",
|
|
"name": "Deploy-time setup\n━━━━━━━━━━━━━━━━━━━\nInitialises set.mode = levelbased and seeds an inflow at deploy time.",
|
|
"info": "",
|
|
"x": 600,
|
|
"y": 40,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ps_dash_setup_mode",
|
|
"type": "inject",
|
|
"z": "ps_dash_setup",
|
|
"name": "set.mode = levelbased",
|
|
"props": [
|
|
{
|
|
"p": "topic",
|
|
"vt": "str"
|
|
},
|
|
{
|
|
"p": "payload",
|
|
"v": "levelbased",
|
|
"vt": "str"
|
|
}
|
|
],
|
|
"topic": "set.mode",
|
|
"repeat": "",
|
|
"crontab": "",
|
|
"once": true,
|
|
"onceDelay": "0.5",
|
|
"x": 120,
|
|
"y": 160,
|
|
"wires": [
|
|
[
|
|
"ps_dash_lout_setup_mode"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_setup_inflow",
|
|
"type": "inject",
|
|
"z": "ps_dash_setup",
|
|
"name": "seed inflow 60 m3/h",
|
|
"props": [
|
|
{
|
|
"p": "topic",
|
|
"vt": "str"
|
|
},
|
|
{
|
|
"p": "payload",
|
|
"v": "60",
|
|
"vt": "num"
|
|
}
|
|
],
|
|
"topic": "set.inflow",
|
|
"repeat": "",
|
|
"crontab": "",
|
|
"once": true,
|
|
"onceDelay": "1.0",
|
|
"x": 120,
|
|
"y": 220,
|
|
"wires": [
|
|
[
|
|
"ps_dash_lout_setup_inflow"
|
|
]
|
|
]
|
|
},
|
|
{
|
|
"id": "ps_dash_lout_setup_mode",
|
|
"type": "link out",
|
|
"z": "ps_dash_setup",
|
|
"name": "setup:to-ps-mode",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_proc_setupmode"
|
|
],
|
|
"x": 1800,
|
|
"y": 160,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ps_dash_lout_setup_inflow",
|
|
"type": "link out",
|
|
"z": "ps_dash_setup",
|
|
"name": "setup:to-ps-inflow",
|
|
"mode": "link",
|
|
"links": [
|
|
"lin_proc_setupinflow"
|
|
],
|
|
"x": 1800,
|
|
"y": 220,
|
|
"wires": []
|
|
},
|
|
{
|
|
"id": "ps_dash_grp_setup",
|
|
"type": "group",
|
|
"z": "ps_dash_setup",
|
|
"name": "Deploy-time setup",
|
|
"style": {
|
|
"label": true,
|
|
"stroke": "#000000",
|
|
"fill": "#dddddd",
|
|
"fill-opacity": "0.10"
|
|
},
|
|
"nodes": [
|
|
"ps_dash_setup_mode",
|
|
"ps_dash_setup_inflow",
|
|
"ps_dash_lout_setup_mode",
|
|
"ps_dash_lout_setup_inflow"
|
|
],
|
|
"x": 95,
|
|
"y": 115,
|
|
"w": 1930,
|
|
"h": 170
|
|
}
|
|
]
|