Propagate threshold rename; point platform manual at pumpingStation wiki
Some checks failed
CI / lint-and-test (push) Has been cancelled

Follows pumpingStation@a218945 + generalFunctions@4252292 rename:

- Bump pumpingStation and generalFunctions submodule pointers.
- Update examples/pumpingstation-3pumps-dashboard/ (build_flow.py,
  flow.json, README.md) to use the new threshold names. Collapsed
  minFlowLevel into startLevel; reshuffled order to match the basin
  bottom-to-top: minLevel, startLevel, maxLevel.
- wiki/manuals/README.md: drop the stale pumpingStation.md line and
  point readers at pumpingStation/wiki instead (docs have moved into
  the node's own repo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
znetsixe
2026-04-22 16:15:36 +02:00
parent 4a9521154b
commit b885f291d4
6 changed files with 98 additions and 117 deletions

View File

@@ -91,7 +91,7 @@ The Emergency Stop button always works regardless of mode and uses the new inter
## Notable design choices
- **PS is in `manual` control mode** (`controlMode: "manual"`). The default `levelbased` mode would auto-shut all pumps as soon as basin level dips below `stopLevel` (1 m default), which masks the demo. Manual = observation only.
- **PS is in `manual` control mode** (`controlMode: "manual"`). The default `levelbased` mode would auto-shut all pumps as soon as basin level dips below `minLevel` (1 m default), which masks the demo. Manual = observation only.
- **PS safety guards (dry-run / overfill) disabled.** With no real inflow the basin will frequently look "empty" — that's expected for a demo, not a fault. In production you'd configure a real `q_in` source and leave safeties on.
- **MGC scaling = `absolute`, mode = `optimalcontrol`.** Set via inject at deploy. Demand in m³/h, BEP-driven distribution.
- **demand_router gates Qd ≤ 0.** A demand of 0 would shut every running pump (via MGC.turnOffAllMachines). Use the explicit Stop All button to actually take pumps down.

View File

@@ -52,6 +52,13 @@ LANE_X = [120, 380, 640, 900, 1160, 1420]
ROW = 80 # standard inter-row pitch
SECTION_GAP = 200 # additional shift between major sections
# Position icon map — must match generalFunctions/src/menu/physicalPosition.js
POSITION_ICON = {
"upstream": "\u2192", # →
"downstream": "\u2190", # ←
"atEquipment": "\u22a5", # ⊥
}
# ---------------------------------------------------------------------------
# Cross-tab link channel names (the wiring contract)
@@ -356,9 +363,14 @@ def build_process_tab():
))
# Two measurement sensors (upstream + downstream)
# Static pressures: upstream ~100 mbar (basin hydrostatic),
# downstream ~1300 mbar (discharge head ≈ 12 m).
# Differential = 1200 mbar = 120 kPa — mid-range on the
# hidrostal curve (7003900 mbar). Simulator OFF so the
# value is stable and predictable.
for j, pos in enumerate(("upstream", "downstream")):
mid = f"meas_{pump}_{pos[0]}"
absmin, absmax = (50, 400) if pos == "upstream" else (800, 2200)
static_val = 100 if pos == "upstream" else 1300
mid_label = f"PT-{label.split()[1]}-{'Up' if pos == 'upstream' else 'Dn'}"
nodes.append({
"id": mid, "type": "measurement", "z": TAB_PROCESS,
@@ -366,7 +378,7 @@ def build_process_tab():
"mode": "analog", "channels": "[]",
"scaling": False,
"i_min": 0, "i_max": 1, "i_offset": 0,
"o_min": absmin, "o_max": absmax,
"o_min": static_val, "o_max": static_val,
"simulator": True,
"smooth_method": "mean", "count": "5",
"processOutputFormat": "process", "dbaseOutputFormat": "influxdb",
@@ -375,7 +387,7 @@ def build_process_tab():
"assetType": "pressure", "model": "vega-pressure-10",
"unit": "mbar", "assetTagNumber": f"PT-{i+1}-{pos[0].upper()}",
"enableLog": False, "logLevel": "warn",
"positionVsParent": pos, "positionIcon": "",
"positionVsParent": pos, "positionIcon": POSITION_ICON.get(pos, ""),
"hasDistance": False, "distance": 0, "distanceUnit": "m",
"distanceDescription": "",
"x": LANE_X[1], "y": y_section + 40 + j * 50,
@@ -424,7 +436,7 @@ def build_process_tab():
"curvePressureUnit": "mbar", "curveFlowUnit": "m3/h",
"curvePowerUnit": "kW", "curveControlUnit": "%",
"enableLog": False, "logLevel": "warn",
"positionVsParent": "atEquipment", "positionIcon": "",
"positionVsParent": "atEquipment", "positionIcon": POSITION_ICON["atEquipment"],
"hasDistance": False, "distance": 0, "distanceUnit": "m",
"distanceDescription": "",
"x": LANE_X[3], "y": y_section + 80,
@@ -493,7 +505,7 @@ def build_process_tab():
"assetType": "machinegroupcontrol",
"model": "default", "unit": "m3/h", "supplier": "evolv",
"enableLog": False, "logLevel": "warn",
"positionVsParent": "atEquipment", "positionIcon": "",
"positionVsParent": "atEquipment", "positionIcon": POSITION_ICON["atEquipment"],
"hasDistance": False, "distance": 0, "distanceUnit": "m",
"distanceDescription": "",
"processOutputFormat": "process", "dbaseOutputFormat": "influxdb",
@@ -572,7 +584,7 @@ def build_process_tab():
"category": "station", "assetType": "pumpingstation",
"model": "default", "unit": "m3/s", "supplier": "evolv",
"enableLog": False, "logLevel": "warn",
"positionVsParent": "atEquipment", "positionIcon": "",
"positionVsParent": "atEquipment", "positionIcon": POSITION_ICON["atEquipment"],
"hasDistance": False, "distance": 0, "distanceUnit": "m",
"distanceDescription": "",
"processOutputFormat": "process", "dbaseOutputFormat": "influxdb",
@@ -586,19 +598,18 @@ def build_process_tab():
"controlMode": "levelbased",
"basinVolume": 30,
"basinHeight": 4,
"heightInlet": 3.5,
"heightOutlet": 0.3,
"heightOverflow": 3.8,
"inflowLevel": 3.5,
"outflowLevel": 0.3,
"overflowLevel": 3.8,
"inletPipeDiameter": 0.3,
"outletPipeDiameter": 0.3,
# Level-based control thresholds
"startLevel": 2.0, # pumps ON above 2.0 m (50% of height)
"stopLevel": 1.0, # pumps OFF below 1.0 m (25% of height)
"minFlowLevel": 2.0, # 0% pump demand at startLevel (must match startLevel!)
"maxFlowLevel": 3.5, # 100% pump demand at this level
"minLevel": 1.0, # pumps OFF below 1.0 m (25% of height)
"startLevel": 2.0, # 0% pump demand — ramp begins here
"maxLevel": 3.5, # 100% pump demand at this level
# Hydraulics
"refHeight": "NAP",
"minHeightBasedOn": "inlet",
"minHeightBasedOn": "outlet", # basin drains to outlet pipe (0.3 m), not inlet
"basinBottomRef": 0,
"staticHead": 12,
"maxDischargeHead": 24,
@@ -631,15 +642,16 @@ def build_process_tab():
"}\n"
"const lvl = find('level.predicted.');\n"
"const vol = find('volume.predicted.');\n"
"const qIn = find('flow.measured.upstream.') || find('flow.measured.in.');\n"
"const qOut = find('flow.measured.downstream.') || find('flow.measured.out.');\n"
"const qIn = find('flow.predicted.in.');\n"
"const qOut = find('flow.predicted.out.');\n"
"const netFlowRate = find('netFlowRate.predicted.');\n"
"// Compute derived metrics\n"
"// Basin capacity = basinVolume (config). Don't hardcode — read it once.\n"
"if (!context.get('maxVol')) context.set('maxVol', 30.0); // basinVolume from PS config\n"
"const maxVol = context.get('maxVol');\n"
"const fillPct = vol != null ? Math.min(100, Math.max(0, Math.round(Number(vol) / maxVol * 100))) : null;\n"
"const netM3h = (c.netFlow != null) ? Number(c.netFlow) * 3600 : null;\n"
"const seconds = (c.seconds != null && Number.isFinite(Number(c.seconds))) ? Number(c.seconds) : null;\n"
"const netM3h = netFlowRate != null ? Number(netFlowRate) * 3600 : null;\n"
"const seconds = (c.timeleft != null && Number.isFinite(Number(c.timeleft))) ? Number(c.timeleft) : null;\n"
"const timeStr = seconds != null ? (seconds > 60 ? Math.round(seconds/60) + ' min' : Math.round(seconds) + ' s') : 'n/a';\n"
"msg.payload = {\n"
" direction: c.direction || 'steady',\n"
@@ -655,6 +667,9 @@ def build_process_tab():
" volumeNum: vol != null ? Number(vol) : null,\n"
" fillPctNum: fillPct,\n"
" netFlowNum: netM3h,\n"
" percControl: c.percControl != null ? Number(c.percControl) : null,\n"
" qInNum: qIn != null ? Number(qIn) * 3600 : null,\n"
" qOutNum: qOut != null ? Number(qOut) * 3600 : null,\n"
"};\n"
"return msg;",
outputs=1, wires=[["lout_evt_ps"]],
@@ -921,8 +936,11 @@ def build_ui_tab():
" p.fillPctNum != null ? {topic: 'Basin fill', payload: p.fillPctNum, timestamp: ts} : null,\n"
" p.levelNum != null ? {topic: 'Basin level', payload: p.levelNum, timestamp: ts} : null,\n"
" p.netFlowNum != null ? {topic: 'Net flow', payload: p.netFlowNum,timestamp: ts} : null,\n"
" p.percControl != null ? {topic: 'PS demand', payload: p.percControl, timestamp: ts} : null,\n"
" p.qInNum != null ? {topic: 'Inflow', payload: p.qInNum, timestamp: ts} : null,\n"
" p.qOutNum != null ? {topic: 'Outflow', payload: p.qOutNum, timestamp: ts} : null,\n"
"];",
outputs=10,
outputs=13,
wires=[
["ui_ps_direction"],
["ui_ps_level"],
@@ -934,7 +952,10 @@ def build_ui_tab():
# Trend + gauge outputs — split level and fill to separate charts
["trend_short_fill", "trend_long_fill", "gauge_ps_fill", "gauge_ps_fill_long"], # fill % → fill chart + gauges
["trend_short_level", "trend_long_level", "gauge_ps_level", "gauge_ps_level_long"], # level → level chart + gauges
["trend_short_level", "trend_long_level"], # net flow → level chart (shared axis)
["trend_short_flow", "trend_long_flow"], # net flow → flow charts
["trend_short_fill", "trend_long_fill"], # percControl (%) → fill charts (same y-axis)
["trend_short_flow", "trend_long_flow"], # inflow m3/h → flow charts
["trend_short_flow", "trend_long_flow"], # outflow m3/h → flow charts
],
))
@@ -1118,11 +1139,11 @@ def build_ui_tab():
# ===== Basin charts + gauges (fill %, level, net flow) =====
# Gauge segment definitions (reused for both pages)
TANK_SEGMENTS = [
{"color": "#f44336", "from": 0}, # red: below stopLevel (1.0 m)
{"color": "#f44336", "from": 0}, # red: below minLevel (1.0 m)
{"color": "#ff9800", "from": 1.0}, # orange: between stop and start
{"color": "#2196f3", "from": 2.0}, # blue: normal operating (startLevel)
{"color": "#ff9800", "from": 3.5}, # orange: approaching overflow
{"color": "#f44336", "from": 3.8}, # red: overflow zone (heightOverflow)
{"color": "#f44336", "from": 3.8}, # red: overflow zone (overflowLevel)
]
FILL_SEGMENTS = [
{"color": "#f44336", "from": 0},
@@ -1314,19 +1335,8 @@ def build_setup_tab():
CH_MODE, target_in_ids=["lin_mode"]
))
y = 350
nodes.append(inject(
"setup_pumps_startup", TAB_SETUP, LANE_X[0], y,
"auto-startup all pumps",
topic="execSequence",
payload='{"source":"GUI","action":"execSequence","parameter":"startup"}',
payload_type="json", once=True, once_delay="4",
wires=["lout_setup_station_start"]
))
nodes.append(link_out(
"lout_setup_station_start", TAB_SETUP, LANE_X[1], y,
CH_STATION_START, target_in_ids=["lin_station_start"]
))
# Auto-startup removed: the MGC starts pumps on demand from the PS.
# Starting pumps before the PS requests them causes flow below startLevel.
# (Random demand removed — sinus inflow drives the demo automatically.
# No explicit "random on" inject needed.)

View File

@@ -37,8 +37,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 50,
"o_max": 400,
"o_min": 100,
"o_max": 100,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -54,7 +54,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "upstream",
"positionIcon": "",
"positionIcon": "\u2192",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -80,8 +80,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 800,
"o_max": 2200,
"o_min": 1300,
"o_max": 1300,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -97,7 +97,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "downstream",
"positionIcon": "",
"positionIcon": "\u2190",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -188,7 +188,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "atEquipment",
"positionIcon": "",
"positionIcon": "\u22a5",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -258,8 +258,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 50,
"o_max": 400,
"o_min": 100,
"o_max": 100,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -275,7 +275,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "upstream",
"positionIcon": "",
"positionIcon": "\u2192",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -301,8 +301,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 800,
"o_max": 2200,
"o_min": 1300,
"o_max": 1300,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -318,7 +318,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "downstream",
"positionIcon": "",
"positionIcon": "\u2190",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -409,7 +409,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "atEquipment",
"positionIcon": "",
"positionIcon": "\u22a5",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -479,8 +479,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 50,
"o_max": 400,
"o_min": 100,
"o_max": 100,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -496,7 +496,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "upstream",
"positionIcon": "",
"positionIcon": "\u2192",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -522,8 +522,8 @@
"i_min": 0,
"i_max": 1,
"i_offset": 0,
"o_min": 800,
"o_max": 2200,
"o_min": 1300,
"o_max": 1300,
"simulator": true,
"smooth_method": "mean",
"count": "5",
@@ -539,7 +539,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "downstream",
"positionIcon": "",
"positionIcon": "\u2190",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -630,7 +630,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "atEquipment",
"positionIcon": "",
"positionIcon": "\u22a5",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -703,7 +703,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "atEquipment",
"positionIcon": "",
"positionIcon": "\u22a5",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -845,7 +845,7 @@
"enableLog": false,
"logLevel": "warn",
"positionVsParent": "atEquipment",
"positionIcon": "",
"positionIcon": "\u22a5",
"hasDistance": false,
"distance": 0,
"distanceUnit": "m",
@@ -855,17 +855,16 @@
"controlMode": "levelbased",
"basinVolume": 30,
"basinHeight": 4,
"heightInlet": 3.5,
"heightOutlet": 0.3,
"heightOverflow": 3.8,
"inflowLevel": 3.5,
"outflowLevel": 0.3,
"overflowLevel": 3.8,
"inletPipeDiameter": 0.3,
"outletPipeDiameter": 0.3,
"minLevel": 1.0,
"startLevel": 2.0,
"stopLevel": 1.0,
"minFlowLevel": 2.0,
"maxFlowLevel": 3.5,
"maxLevel": 3.5,
"refHeight": "NAP",
"minHeightBasedOn": "inlet",
"minHeightBasedOn": "outlet",
"basinBottomRef": 0,
"staticHead": 12,
"maxDischargeHead": 24,
@@ -892,7 +891,7 @@
"type": "function",
"z": "tab_process",
"name": "format PS port 0",
"func": "const p = msg.payload || {};\nconst c = context.get('c') || {};\nObject.assign(c, p);\ncontext.set('c', c);\nfunction find(prefix) {\n for (const k in c) { if (k.indexOf(prefix) === 0) return c[k]; }\n return null;\n}\nconst lvl = find('level.predicted.');\nconst vol = find('volume.predicted.');\nconst qIn = find('flow.measured.upstream.') || find('flow.measured.in.');\nconst qOut = find('flow.measured.downstream.') || find('flow.measured.out.');\n// Compute derived metrics\n// Basin capacity = basinVolume (config). Don't hardcode \u2014 read it once.\nif (!context.get('maxVol')) context.set('maxVol', 30.0); // basinVolume from PS config\nconst maxVol = context.get('maxVol');\nconst fillPct = vol != null ? Math.min(100, Math.max(0, Math.round(Number(vol) / maxVol * 100))) : null;\nconst netM3h = (c.netFlow != null) ? Number(c.netFlow) * 3600 : null;\nconst seconds = (c.seconds != null && Number.isFinite(Number(c.seconds))) ? Number(c.seconds) : null;\nconst timeStr = seconds != null ? (seconds > 60 ? Math.round(seconds/60) + ' min' : Math.round(seconds) + ' s') : 'n/a';\nmsg.payload = {\n direction: c.direction || 'steady',\n level: lvl != null ? Number(lvl).toFixed(2) + ' m' : 'n/a',\n volume: vol != null ? Number(vol).toFixed(1) + ' m\u00b3' : 'n/a',\n fillPct: fillPct != null ? fillPct + '%' : 'n/a',\n netFlow: netM3h != null ? netM3h.toFixed(0) + ' m\u00b3/h' : 'n/a',\n timeLeft: timeStr,\n qIn: qIn != null ? (Number(qIn) * 3600).toFixed(0) + ' m\u00b3/h' : 'n/a',\n qOut: qOut != null ? (Number(qOut) * 3600).toFixed(0) + ' m\u00b3/h' : 'n/a',\n // Numerics for trends\n levelNum: lvl != null ? Number(lvl) : null,\n volumeNum: vol != null ? Number(vol) : null,\n fillPctNum: fillPct,\n netFlowNum: netM3h,\n};\nreturn msg;",
"func": "const p = msg.payload || {};\nconst c = context.get('c') || {};\nObject.assign(c, p);\ncontext.set('c', c);\nfunction find(prefix) {\n for (const k in c) { if (k.indexOf(prefix) === 0) return c[k]; }\n return null;\n}\nconst lvl = find('level.predicted.');\nconst vol = find('volume.predicted.');\nconst qIn = find('flow.predicted.in.');\nconst qOut = find('flow.predicted.out.');\nconst netFlowRate = find('netFlowRate.predicted.');\n// Compute derived metrics\n// Basin capacity = basinVolume (config). Don't hardcode \u2014 read it once.\nif (!context.get('maxVol')) context.set('maxVol', 30.0); // basinVolume from PS config\nconst maxVol = context.get('maxVol');\nconst fillPct = vol != null ? Math.min(100, Math.max(0, Math.round(Number(vol) / maxVol * 100))) : null;\nconst netM3h = netFlowRate != null ? Number(netFlowRate) * 3600 : null;\nconst seconds = (c.timeleft != null && Number.isFinite(Number(c.timeleft))) ? Number(c.timeleft) : null;\nconst timeStr = seconds != null ? (seconds > 60 ? Math.round(seconds/60) + ' min' : Math.round(seconds) + ' s') : 'n/a';\nmsg.payload = {\n direction: c.direction || 'steady',\n level: lvl != null ? Number(lvl).toFixed(2) + ' m' : 'n/a',\n volume: vol != null ? Number(vol).toFixed(1) + ' m\u00b3' : 'n/a',\n fillPct: fillPct != null ? fillPct + '%' : 'n/a',\n netFlow: netM3h != null ? netM3h.toFixed(0) + ' m\u00b3/h' : 'n/a',\n timeLeft: timeStr,\n qIn: qIn != null ? (Number(qIn) * 3600).toFixed(0) + ' m\u00b3/h' : 'n/a',\n qOut: qOut != null ? (Number(qOut) * 3600).toFixed(0) + ' m\u00b3/h' : 'n/a',\n // Numerics for trends\n levelNum: lvl != null ? Number(lvl) : null,\n volumeNum: vol != null ? Number(vol) : null,\n fillPctNum: fillPct,\n netFlowNum: netM3h,\n percControl: c.percControl != null ? Number(c.percControl) : null,\n qInNum: qIn != null ? Number(qIn) * 3600 : null,\n qOutNum: qOut != null ? Number(qOut) * 3600 : null,\n};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
@@ -1896,8 +1895,8 @@
"type": "function",
"z": "tab_ui",
"name": "dispatch PS",
"func": "const p = msg.payload || {};\nconst ts = Date.now();\nreturn [\n {payload: String(p.direction || 'steady')},\n {payload: String(p.level || 'n/a')},\n {payload: String(p.volume || 'n/a')},\n {payload: String(p.fillPct || 'n/a')},\n {payload: String(p.netFlow || 'n/a')},\n {payload: String(p.timeLeft || 'n/a')},\n {payload: String(p.qIn || 'n/a')},\n // Trend numerics\n p.fillPctNum != null ? {topic: 'Basin fill', payload: p.fillPctNum, timestamp: ts} : null,\n p.levelNum != null ? {topic: 'Basin level', payload: p.levelNum, timestamp: ts} : null,\n p.netFlowNum != null ? {topic: 'Net flow', payload: p.netFlowNum,timestamp: ts} : null,\n];",
"outputs": 10,
"func": "const p = msg.payload || {};\nconst ts = Date.now();\nreturn [\n {payload: String(p.direction || 'steady')},\n {payload: String(p.level || 'n/a')},\n {payload: String(p.volume || 'n/a')},\n {payload: String(p.fillPct || 'n/a')},\n {payload: String(p.netFlow || 'n/a')},\n {payload: String(p.timeLeft || 'n/a')},\n {payload: String(p.qIn || 'n/a')},\n // Trend numerics\n p.fillPctNum != null ? {topic: 'Basin fill', payload: p.fillPctNum, timestamp: ts} : null,\n p.levelNum != null ? {topic: 'Basin level', payload: p.levelNum, timestamp: ts} : null,\n p.netFlowNum != null ? {topic: 'Net flow', payload: p.netFlowNum,timestamp: ts} : null,\n p.percControl != null ? {topic: 'PS demand', payload: p.percControl, timestamp: ts} : null,\n p.qInNum != null ? {topic: 'Inflow', payload: p.qInNum, timestamp: ts} : null,\n p.qOutNum != null ? {topic: 'Outflow', payload: p.qOutNum, timestamp: ts} : null,\n];",
"outputs": 13,
"noerr": 0,
"initialize": "",
"finalize": "",
@@ -1939,8 +1938,20 @@
"gauge_ps_level_long"
],
[
"trend_short_level",
"trend_long_level"
"trend_short_flow",
"trend_long_flow"
],
[
"trend_short_fill",
"trend_long_fill"
],
[
"trend_short_flow",
"trend_long_flow"
],
[
"trend_short_flow",
"trend_long_flow"
]
]
},
@@ -4101,49 +4112,5 @@
"x": 380,
"y": 250,
"wires": []
},
{
"id": "setup_pumps_startup",
"type": "inject",
"z": "tab_setup",
"name": "auto-startup all pumps",
"props": [
{
"p": "topic",
"vt": "str"
},
{
"p": "payload",
"v": "{\"source\":\"GUI\",\"action\":\"execSequence\",\"parameter\":\"startup\"}",
"vt": "json"
}
],
"topic": "execSequence",
"payload": "{\"source\":\"GUI\",\"action\":\"execSequence\",\"parameter\":\"startup\"}",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "4",
"x": 120,
"y": 350,
"wires": [
[
"lout_setup_station_start"
]
]
},
{
"id": "lout_setup_station_start",
"type": "link out",
"z": "tab_setup",
"name": "cmd:station-startup",
"mode": "link",
"links": [
"lin_station_start"
],
"x": 380,
"y": 350,
"wires": []
}
]