fix(dashboard): resolve [object Object] in ui-text widgets + use dispatcher pattern
Some checks failed
CI / lint-and-test (push) Has been cancelled
Some checks failed
CI / lint-and-test (push) Has been cancelled
FlowFuse ui-text only supports {{msg.payload}} — not nested paths
like {{msg.payload.state}}. Every ui-text was showing [object Object]
because the formatter sent a fat object as msg.payload and the format
template tried to access sub-fields.
Fix: per-pump (and per-MGC, per-PS) "dispatcher" function on the
Dashboard UI tab. The dispatcher receives the fat object via one
link-in, then returns 7-9 plain-string outputs — one per ui-text
widget — each with msg.payload set to the formatted string value.
Outputs 8+9 carry numeric values (flowNum/powerNum) tagged with
msg.topic for the trend charts, wired directly to both short-term
and long-term chart nodes.
Pattern documented as the recommended approach in the rule set:
"FlowFuse ui-text receives plain strings only — use a dispatcher
function to split a fat object into per-widget outputs."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -402,8 +402,9 @@ def build_process_tab():
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
# Per-pump output formatter: builds the structured event used by the
|
# Per-pump output formatter: builds a fat object with all fields.
|
||||||
# dashboard widgets and trend feeders.
|
# The dashboard dispatcher (on the UI tab) then splits it into
|
||||||
|
# plain-string payloads per ui-text widget. One link-out per pump.
|
||||||
nodes.append(function_node(
|
nodes.append(function_node(
|
||||||
f"format_{pump}", TAB_PROCESS, LANE_X[4], y_section + 80,
|
f"format_{pump}", TAB_PROCESS, LANE_X[4], y_section + 80,
|
||||||
f"format {label} port 0",
|
f"format {label} port 0",
|
||||||
@@ -425,8 +426,8 @@ def build_process_tab():
|
|||||||
" ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n"
|
" ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n"
|
||||||
" flow: flow != null ? Number(flow).toFixed(1) + ' m³/h' : 'n/a',\n"
|
" flow: flow != null ? Number(flow).toFixed(1) + ' m³/h' : 'n/a',\n"
|
||||||
" power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n"
|
" power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n"
|
||||||
" pUp: pU != null ? Number(pU).toFixed(0) : 'n/a',\n"
|
" pUp: pU != null ? Number(pU).toFixed(0) + ' mbar' : 'n/a',\n"
|
||||||
" pDn: pD != null ? Number(pD).toFixed(0) : 'n/a',\n"
|
" pDn: pD != null ? Number(pD).toFixed(0) + ' mbar' : 'n/a',\n"
|
||||||
" flowNum: flow != null ? Number(flow) : null,\n"
|
" flowNum: flow != null ? Number(flow) : null,\n"
|
||||||
" powerNum: power != null ? Number(power) : null,\n"
|
" powerNum: power != null ? Number(power) : null,\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
@@ -434,7 +435,7 @@ def build_process_tab():
|
|||||||
outputs=1, wires=[[f"lout_evt_{pump}"]],
|
outputs=1, wires=[[f"lout_evt_{pump}"]],
|
||||||
))
|
))
|
||||||
|
|
||||||
# link-out: per-pump event stream → dashboard
|
# link-out: one per pump → dashboard dispatcher
|
||||||
nodes.append(link_out(
|
nodes.append(link_out(
|
||||||
f"lout_evt_{pump}", TAB_PROCESS, LANE_X[5], y_section + 80,
|
f"lout_evt_{pump}", TAB_PROCESS, LANE_X[5], y_section + 80,
|
||||||
CH_PUMP_EVT[pump],
|
CH_PUMP_EVT[pump],
|
||||||
@@ -797,30 +798,56 @@ def build_ui_tab():
|
|||||||
nodes.append(link_in(
|
nodes.append(link_in(
|
||||||
"lin_evt_mgc_dash", TAB_UI, LANE_X[0], y + 40,
|
"lin_evt_mgc_dash", TAB_UI, LANE_X[0], y + 40,
|
||||||
CH_MGC_EVT, source_out_ids=["lout_evt_mgc"],
|
CH_MGC_EVT, source_out_ids=["lout_evt_mgc"],
|
||||||
downstream=["ui_mgc_total_flow", "ui_mgc_total_power", "ui_mgc_eff"]
|
downstream=["dispatch_mgc"]
|
||||||
|
))
|
||||||
|
nodes.append(function_node(
|
||||||
|
"dispatch_mgc", TAB_UI, LANE_X[1], y + 40,
|
||||||
|
"dispatch MGC",
|
||||||
|
"const p = msg.payload || {};\n"
|
||||||
|
"return [\n"
|
||||||
|
" {payload: String(p.totalFlow || 'n/a')},\n"
|
||||||
|
" {payload: String(p.totalPower || 'n/a')},\n"
|
||||||
|
" {payload: String(p.efficiency || 'n/a')},\n"
|
||||||
|
"];",
|
||||||
|
outputs=3,
|
||||||
|
wires=[["ui_mgc_total_flow"], ["ui_mgc_total_power"], ["ui_mgc_eff"]],
|
||||||
))
|
))
|
||||||
nodes.append(ui_text("ui_mgc_total_flow", TAB_UI, LANE_X[2], y + 40, g_mgc,
|
nodes.append(ui_text("ui_mgc_total_flow", TAB_UI, LANE_X[2], y + 40, g_mgc,
|
||||||
"MGC total flow", "Total flow", "{{msg.payload.totalFlow}}"))
|
"MGC total flow", "Total flow", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_mgc_total_power", TAB_UI, LANE_X[2], y + 70, g_mgc,
|
nodes.append(ui_text("ui_mgc_total_power", TAB_UI, LANE_X[2], y + 70, g_mgc,
|
||||||
"MGC total power", "Total power", "{{msg.payload.totalPower}}"))
|
"MGC total power", "Total power", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_mgc_eff", TAB_UI, LANE_X[2], y + 100, g_mgc,
|
nodes.append(ui_text("ui_mgc_eff", TAB_UI, LANE_X[2], y + 100, g_mgc,
|
||||||
"MGC efficiency", "Group efficiency", "{{msg.payload.efficiency}}"))
|
"MGC efficiency", "Group efficiency", "{{msg.payload}}"))
|
||||||
|
|
||||||
nodes.append(link_in(
|
nodes.append(link_in(
|
||||||
"lin_evt_ps_dash", TAB_UI, LANE_X[0], y + 160,
|
"lin_evt_ps_dash", TAB_UI, LANE_X[0], y + 160,
|
||||||
CH_PS_EVT, source_out_ids=["lout_evt_ps"],
|
CH_PS_EVT, source_out_ids=["lout_evt_ps"],
|
||||||
downstream=["ui_ps_state", "ui_ps_level", "ui_ps_volume", "ui_ps_qin", "ui_ps_qout"]
|
downstream=["dispatch_ps"]
|
||||||
|
))
|
||||||
|
nodes.append(function_node(
|
||||||
|
"dispatch_ps", TAB_UI, LANE_X[1], y + 160,
|
||||||
|
"dispatch PS",
|
||||||
|
"const p = msg.payload || {};\n"
|
||||||
|
"return [\n"
|
||||||
|
" {payload: String(p.state || 'idle')},\n"
|
||||||
|
" {payload: String(p.level || 'n/a')},\n"
|
||||||
|
" {payload: String(p.volume || 'n/a')},\n"
|
||||||
|
" {payload: String(p.qIn || 'n/a')},\n"
|
||||||
|
" {payload: String(p.qOut || 'n/a')},\n"
|
||||||
|
"];",
|
||||||
|
outputs=5,
|
||||||
|
wires=[["ui_ps_state"], ["ui_ps_level"], ["ui_ps_volume"], ["ui_ps_qin"], ["ui_ps_qout"]],
|
||||||
))
|
))
|
||||||
nodes.append(ui_text("ui_ps_state", TAB_UI, LANE_X[2], y + 160, g_ps,
|
nodes.append(ui_text("ui_ps_state", TAB_UI, LANE_X[2], y + 160, g_ps,
|
||||||
"PS state", "Basin state", "{{msg.payload.state}}"))
|
"PS state", "Basin state", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_ps_level", TAB_UI, LANE_X[2], y + 190, g_ps,
|
nodes.append(ui_text("ui_ps_level", TAB_UI, LANE_X[2], y + 200, g_ps,
|
||||||
"PS level", "Basin level", "{{msg.payload.level}}"))
|
"PS level", "Basin level", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_ps_volume", TAB_UI, LANE_X[2], y + 220, g_ps,
|
nodes.append(ui_text("ui_ps_volume", TAB_UI, LANE_X[2], y + 240, g_ps,
|
||||||
"PS volume","Basin volume", "{{msg.payload.volume}}"))
|
"PS volume","Basin volume", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_ps_qin", TAB_UI, LANE_X[2], y + 250, g_ps,
|
nodes.append(ui_text("ui_ps_qin", TAB_UI, LANE_X[2], y + 280, g_ps,
|
||||||
"PS Qin", "Inflow", "{{msg.payload.qIn}}"))
|
"PS Qin", "Inflow", "{{msg.payload}}"))
|
||||||
nodes.append(ui_text("ui_ps_qout", TAB_UI, LANE_X[2], y + 280, g_ps,
|
nodes.append(ui_text("ui_ps_qout", TAB_UI, LANE_X[2], y + 320, g_ps,
|
||||||
"PS Qout", "Pumped out", "{{msg.payload.qOut}}"))
|
"PS Qout", "Pumped out", "{{msg.payload}}"))
|
||||||
|
|
||||||
# ===== SECTION: Per-pump panels =====
|
# ===== SECTION: Per-pump panels =====
|
||||||
y_pumps_start = 1000
|
y_pumps_start = 1000
|
||||||
@@ -832,24 +859,10 @@ def build_ui_tab():
|
|||||||
nodes.append(comment(f"c_ui_{pump}", TAB_UI, LANE_X[2], y_p,
|
nodes.append(comment(f"c_ui_{pump}", TAB_UI, LANE_X[2], y_p,
|
||||||
f"── {label} ──", ""))
|
f"── {label} ──", ""))
|
||||||
|
|
||||||
# link-in for this pump's events
|
# link-in: one fat object per pump → dispatcher splits into
|
||||||
nodes.append(link_in(
|
# plain-string payloads per ui-text widget + numeric payloads
|
||||||
f"lin_evt_{pump}_dash", TAB_UI, LANE_X[0], y_p + 40,
|
# for trend charts. 9 outputs total.
|
||||||
CH_PUMP_EVT[pump], source_out_ids=[f"lout_evt_{pump}"],
|
DISPLAY_FIELDS = [
|
||||||
downstream=[
|
|
||||||
f"ui_{pump}_state",
|
|
||||||
f"ui_{pump}_mode",
|
|
||||||
f"ui_{pump}_ctrl",
|
|
||||||
f"ui_{pump}_flow",
|
|
||||||
f"ui_{pump}_power",
|
|
||||||
f"ui_{pump}_pUp",
|
|
||||||
f"ui_{pump}_pDn",
|
|
||||||
f"trend_split_{pump}",
|
|
||||||
],
|
|
||||||
))
|
|
||||||
|
|
||||||
# Status text widgets — text-only, fed by the link-in
|
|
||||||
for k, (label_txt, fmt_field) in enumerate([
|
|
||||||
("State", "state"),
|
("State", "state"),
|
||||||
("Mode", "mode"),
|
("Mode", "mode"),
|
||||||
("Controller %", "ctrl"),
|
("Controller %", "ctrl"),
|
||||||
@@ -857,11 +870,43 @@ def build_ui_tab():
|
|||||||
("Power", "power"),
|
("Power", "power"),
|
||||||
("p Upstream", "pUp"),
|
("p Upstream", "pUp"),
|
||||||
("p Downstream", "pDn"),
|
("p Downstream", "pDn"),
|
||||||
]):
|
]
|
||||||
|
nodes.append(link_in(
|
||||||
|
f"lin_evt_{pump}_dash", TAB_UI, LANE_X[0], y_p + 40,
|
||||||
|
CH_PUMP_EVT[pump], source_out_ids=[f"lout_evt_{pump}"],
|
||||||
|
downstream=[f"dispatch_{pump}"],
|
||||||
|
))
|
||||||
|
# Dispatcher: takes the fat object and returns 9 outputs, each
|
||||||
|
# with a plain payload ready for a ui-text or trend chart.
|
||||||
|
nodes.append(function_node(
|
||||||
|
f"dispatch_{pump}", TAB_UI, LANE_X[1], y_p + 40,
|
||||||
|
f"dispatch {label}",
|
||||||
|
"const p = msg.payload || {};\n"
|
||||||
|
"return [\n"
|
||||||
|
" {payload: String(p.state || 'idle')},\n"
|
||||||
|
" {payload: String(p.mode || 'auto')},\n"
|
||||||
|
" {payload: String(p.ctrl || 'n/a')},\n"
|
||||||
|
" {payload: String(p.flow || 'n/a')},\n"
|
||||||
|
" {payload: String(p.power || 'n/a')},\n"
|
||||||
|
" {payload: String(p.pUp || 'n/a')},\n"
|
||||||
|
" {payload: String(p.pDn || 'n/a')},\n"
|
||||||
|
" p.flowNum != null ? {topic: '" + label + "', payload: p.flowNum} : null,\n"
|
||||||
|
" p.powerNum != null ? {topic: '" + label + "', payload: p.powerNum} : null,\n"
|
||||||
|
"];",
|
||||||
|
outputs=9,
|
||||||
|
wires=[
|
||||||
|
[f"ui_{pump}_{f}"] for _, f in DISPLAY_FIELDS
|
||||||
|
] + [
|
||||||
|
["trend_short_flow", "trend_long_flow"], # output 7: flowNum → both flow charts
|
||||||
|
["trend_short_power", "trend_long_power"], # output 8: powerNum → both power charts
|
||||||
|
],
|
||||||
|
))
|
||||||
|
# ui-text widgets
|
||||||
|
for k, (label_txt, field) in enumerate(DISPLAY_FIELDS):
|
||||||
nodes.append(ui_text(
|
nodes.append(ui_text(
|
||||||
f"ui_{pump}_{fmt_field}", TAB_UI, LANE_X[2], y_p + 40 + k * 30, g,
|
f"ui_{pump}_{field}", TAB_UI, LANE_X[2], y_p + 40 + k * 40, g,
|
||||||
f"{label} {label_txt}", label_txt,
|
f"{label} {label_txt}", label_txt,
|
||||||
"{{msg.payload." + fmt_field + "}}"
|
"{{msg.payload}}" # plain string — FlowFuse-safe
|
||||||
))
|
))
|
||||||
|
|
||||||
# Setpoint slider → wrapper → link-out → process pump (cmd:setpoint-X)
|
# Setpoint slider → wrapper → link-out → process pump (cmd:setpoint-X)
|
||||||
@@ -914,23 +959,8 @@ def build_ui_tab():
|
|||||||
target_in_ids=[f"lin_seq_{pump}"]
|
target_in_ids=[f"lin_seq_{pump}"]
|
||||||
))
|
))
|
||||||
|
|
||||||
# Trend feeder — 2 outputs (flow / power), each wired to BOTH
|
# (Trend feed is handled by dispatcher outputs 7+8 above — no separate
|
||||||
# the short-term and long-term chart on their respective pages.
|
# trend_split function needed.)
|
||||||
nodes.append(function_node(
|
|
||||||
f"trend_split_{pump}", TAB_UI, LANE_X[3], y_p + 80,
|
|
||||||
f"trend split ({label})",
|
|
||||||
"const p = msg.payload || {};\n"
|
|
||||||
"const flowMsg = p.flowNum != null ? "
|
|
||||||
"{ topic: '" + label + "', payload: Number(p.flowNum) } : null;\n"
|
|
||||||
"const powerMsg = p.powerNum != null ? "
|
|
||||||
"{ topic: '" + label + "', payload: Number(p.powerNum) } : null;\n"
|
|
||||||
"return [flowMsg, powerMsg];",
|
|
||||||
outputs=2,
|
|
||||||
wires=[
|
|
||||||
["trend_short_flow", "trend_long_flow"],
|
|
||||||
["trend_short_power", "trend_long_power"],
|
|
||||||
]
|
|
||||||
))
|
|
||||||
|
|
||||||
# ===== Trend charts — two pages, two charts per page =====
|
# ===== Trend charts — two pages, two charts per page =====
|
||||||
# Short-term (10 min rolling window) and long-term (1 hour).
|
# Short-term (10 min rolling window) and long-term (1 hour).
|
||||||
|
|||||||
@@ -210,7 +210,7 @@
|
|||||||
"type": "function",
|
"type": "function",
|
||||||
"z": "tab_process",
|
"z": "tab_process",
|
||||||
"name": "format Pump A port 0",
|
"name": "format Pump A 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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) + ' mbar' : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) + ' mbar' : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\n};\nreturn msg;",
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
"initialize": "",
|
"initialize": "",
|
||||||
@@ -431,7 +431,7 @@
|
|||||||
"type": "function",
|
"type": "function",
|
||||||
"z": "tab_process",
|
"z": "tab_process",
|
||||||
"name": "format Pump B port 0",
|
"name": "format Pump B 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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) + ' mbar' : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) + ' mbar' : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\n};\nreturn msg;",
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
"initialize": "",
|
"initialize": "",
|
||||||
@@ -652,7 +652,7 @@
|
|||||||
"type": "function",
|
"type": "function",
|
||||||
"z": "tab_process",
|
"z": "tab_process",
|
||||||
"name": "format Pump C port 0",
|
"name": "format Pump C 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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\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 flow = find('flow.predicted.downstream.');\nconst power = find('power.predicted.atequipment.');\nconst pU = find('pressure.measured.upstream.');\nconst pD = find('pressure.measured.downstream.');\nmsg.payload = {\n state: c.state || 'idle',\n mode: c.mode || 'auto',\n ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + '%' : 'n/a',\n flow: flow != null ? Number(flow).toFixed(1) + ' m\u00b3/h' : 'n/a',\n power: power != null ? Number(power).toFixed(2) + ' kW' : 'n/a',\n pUp: pU != null ? Number(pU).toFixed(0) + ' mbar' : 'n/a',\n pDn: pD != null ? Number(pD).toFixed(0) + ' mbar' : 'n/a',\n flowNum: flow != null ? Number(flow) : null,\n powerNum: power != null ? Number(power) : null,\n};\nreturn msg;",
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
"initialize": "",
|
"initialize": "",
|
||||||
@@ -1749,8 +1749,31 @@
|
|||||||
"y": 640,
|
"y": 640,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"ui_mgc_total_flow",
|
"dispatch_mgc"
|
||||||
"ui_mgc_total_power",
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dispatch_mgc",
|
||||||
|
"type": "function",
|
||||||
|
"z": "tab_ui",
|
||||||
|
"name": "dispatch MGC",
|
||||||
|
"func": "const p = msg.payload || {};\nreturn [\n {payload: String(p.totalFlow || 'n/a')},\n {payload: String(p.totalPower || 'n/a')},\n {payload: String(p.efficiency || 'n/a')},\n];",
|
||||||
|
"outputs": 3,
|
||||||
|
"noerr": 0,
|
||||||
|
"initialize": "",
|
||||||
|
"finalize": "",
|
||||||
|
"libs": [],
|
||||||
|
"x": 380,
|
||||||
|
"y": 640,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"ui_mgc_total_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_mgc_total_power"
|
||||||
|
],
|
||||||
|
[
|
||||||
"ui_mgc_eff"
|
"ui_mgc_eff"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -1765,7 +1788,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "MGC total flow",
|
"name": "MGC total flow",
|
||||||
"label": "Total flow",
|
"label": "Total flow",
|
||||||
"format": "{{msg.payload.totalFlow}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -1785,7 +1808,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "MGC total power",
|
"name": "MGC total power",
|
||||||
"label": "Total power",
|
"label": "Total power",
|
||||||
"format": "{{msg.payload.totalPower}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -1805,7 +1828,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "MGC efficiency",
|
"name": "MGC efficiency",
|
||||||
"label": "Group efficiency",
|
"label": "Group efficiency",
|
||||||
"format": "{{msg.payload.efficiency}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -1827,10 +1850,37 @@
|
|||||||
"y": 760,
|
"y": 760,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"ui_ps_state",
|
"dispatch_ps"
|
||||||
"ui_ps_level",
|
]
|
||||||
"ui_ps_volume",
|
]
|
||||||
"ui_ps_qin",
|
},
|
||||||
|
{
|
||||||
|
"id": "dispatch_ps",
|
||||||
|
"type": "function",
|
||||||
|
"z": "tab_ui",
|
||||||
|
"name": "dispatch PS",
|
||||||
|
"func": "const p = msg.payload || {};\nreturn [\n {payload: String(p.state || 'idle')},\n {payload: String(p.level || 'n/a')},\n {payload: String(p.volume || 'n/a')},\n {payload: String(p.qIn || 'n/a')},\n {payload: String(p.qOut || 'n/a')},\n];",
|
||||||
|
"outputs": 5,
|
||||||
|
"noerr": 0,
|
||||||
|
"initialize": "",
|
||||||
|
"finalize": "",
|
||||||
|
"libs": [],
|
||||||
|
"x": 380,
|
||||||
|
"y": 760,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"ui_ps_state"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_ps_level"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_ps_volume"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_ps_qin"
|
||||||
|
],
|
||||||
|
[
|
||||||
"ui_ps_qout"
|
"ui_ps_qout"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -1845,7 +1895,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "PS state",
|
"name": "PS state",
|
||||||
"label": "Basin state",
|
"label": "Basin state",
|
||||||
"format": "{{msg.payload.state}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -1865,14 +1915,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "PS level",
|
"name": "PS level",
|
||||||
"label": "Basin level",
|
"label": "Basin level",
|
||||||
"format": "{{msg.payload.level}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 790,
|
"y": 800,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1885,14 +1935,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "PS volume",
|
"name": "PS volume",
|
||||||
"label": "Basin volume",
|
"label": "Basin volume",
|
||||||
"format": "{{msg.payload.volume}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 820,
|
"y": 840,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1905,14 +1955,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "PS Qin",
|
"name": "PS Qin",
|
||||||
"label": "Inflow",
|
"label": "Inflow",
|
||||||
"format": "{{msg.payload.qIn}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 850,
|
"y": 880,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1925,14 +1975,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "PS Qout",
|
"name": "PS Qout",
|
||||||
"label": "Pumped out",
|
"label": "Pumped out",
|
||||||
"format": "{{msg.payload.qOut}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 880,
|
"y": 920,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1957,14 +2007,52 @@
|
|||||||
"y": 1040,
|
"y": 1040,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"ui_pump_a_state",
|
"dispatch_pump_a"
|
||||||
"ui_pump_a_mode",
|
]
|
||||||
"ui_pump_a_ctrl",
|
]
|
||||||
"ui_pump_a_flow",
|
},
|
||||||
"ui_pump_a_power",
|
{
|
||||||
"ui_pump_a_pUp",
|
"id": "dispatch_pump_a",
|
||||||
"ui_pump_a_pDn",
|
"type": "function",
|
||||||
"trend_split_pump_a"
|
"z": "tab_ui",
|
||||||
|
"name": "dispatch Pump A",
|
||||||
|
"func": "const p = msg.payload || {};\nreturn [\n {payload: String(p.state || 'idle')},\n {payload: String(p.mode || 'auto')},\n {payload: String(p.ctrl || 'n/a')},\n {payload: String(p.flow || 'n/a')},\n {payload: String(p.power || 'n/a')},\n {payload: String(p.pUp || 'n/a')},\n {payload: String(p.pDn || 'n/a')},\n p.flowNum != null ? {topic: 'Pump A', payload: p.flowNum} : null,\n p.powerNum != null ? {topic: 'Pump A', payload: p.powerNum} : null,\n];",
|
||||||
|
"outputs": 9,
|
||||||
|
"noerr": 0,
|
||||||
|
"initialize": "",
|
||||||
|
"finalize": "",
|
||||||
|
"libs": [],
|
||||||
|
"x": 380,
|
||||||
|
"y": 1040,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"ui_pump_a_state"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_mode"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_ctrl"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_power"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_pUp"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_a_pDn"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_flow",
|
||||||
|
"trend_long_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_power",
|
||||||
|
"trend_long_power"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -1978,7 +2066,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A State",
|
"name": "Pump A State",
|
||||||
"label": "State",
|
"label": "State",
|
||||||
"format": "{{msg.payload.state}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -1998,14 +2086,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A Mode",
|
"name": "Pump A Mode",
|
||||||
"label": "Mode",
|
"label": "Mode",
|
||||||
"format": "{{msg.payload.mode}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1070,
|
"y": 1080,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2018,14 +2106,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A Controller %",
|
"name": "Pump A Controller %",
|
||||||
"label": "Controller %",
|
"label": "Controller %",
|
||||||
"format": "{{msg.payload.ctrl}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1100,
|
"y": 1120,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2038,14 +2126,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A Flow",
|
"name": "Pump A Flow",
|
||||||
"label": "Flow",
|
"label": "Flow",
|
||||||
"format": "{{msg.payload.flow}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1130,
|
"y": 1160,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2058,14 +2146,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A Power",
|
"name": "Pump A Power",
|
||||||
"label": "Power",
|
"label": "Power",
|
||||||
"format": "{{msg.payload.power}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1160,
|
"y": 1200,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2078,14 +2166,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A p Upstream",
|
"name": "Pump A p Upstream",
|
||||||
"label": "p Upstream",
|
"label": "p Upstream",
|
||||||
"format": "{{msg.payload.pUp}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1190,
|
"y": 1240,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2098,14 +2186,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump A p Downstream",
|
"name": "Pump A p Downstream",
|
||||||
"label": "p Downstream",
|
"label": "p Downstream",
|
||||||
"format": "{{msg.payload.pDn}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1220,
|
"y": 1280,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2263,30 +2351,6 @@
|
|||||||
"y": 1355,
|
"y": 1355,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "trend_split_pump_a",
|
|
||||||
"type": "function",
|
|
||||||
"z": "tab_ui",
|
|
||||||
"name": "trend split (Pump A)",
|
|
||||||
"func": "const p = msg.payload || {};\nconst flowMsg = p.flowNum != null ? { topic: 'Pump A', payload: Number(p.flowNum) } : null;\nconst powerMsg = p.powerNum != null ? { topic: 'Pump A', payload: Number(p.powerNum) } : null;\nreturn [flowMsg, powerMsg];",
|
|
||||||
"outputs": 2,
|
|
||||||
"noerr": 0,
|
|
||||||
"initialize": "",
|
|
||||||
"finalize": "",
|
|
||||||
"libs": [],
|
|
||||||
"x": 900,
|
|
||||||
"y": 1080,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"trend_short_flow",
|
|
||||||
"trend_long_flow"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"trend_short_power",
|
|
||||||
"trend_long_power"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "c_ui_pump_b",
|
"id": "c_ui_pump_b",
|
||||||
"type": "comment",
|
"type": "comment",
|
||||||
@@ -2309,14 +2373,52 @@
|
|||||||
"y": 1440,
|
"y": 1440,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"ui_pump_b_state",
|
"dispatch_pump_b"
|
||||||
"ui_pump_b_mode",
|
]
|
||||||
"ui_pump_b_ctrl",
|
]
|
||||||
"ui_pump_b_flow",
|
},
|
||||||
"ui_pump_b_power",
|
{
|
||||||
"ui_pump_b_pUp",
|
"id": "dispatch_pump_b",
|
||||||
"ui_pump_b_pDn",
|
"type": "function",
|
||||||
"trend_split_pump_b"
|
"z": "tab_ui",
|
||||||
|
"name": "dispatch Pump B",
|
||||||
|
"func": "const p = msg.payload || {};\nreturn [\n {payload: String(p.state || 'idle')},\n {payload: String(p.mode || 'auto')},\n {payload: String(p.ctrl || 'n/a')},\n {payload: String(p.flow || 'n/a')},\n {payload: String(p.power || 'n/a')},\n {payload: String(p.pUp || 'n/a')},\n {payload: String(p.pDn || 'n/a')},\n p.flowNum != null ? {topic: 'Pump B', payload: p.flowNum} : null,\n p.powerNum != null ? {topic: 'Pump B', payload: p.powerNum} : null,\n];",
|
||||||
|
"outputs": 9,
|
||||||
|
"noerr": 0,
|
||||||
|
"initialize": "",
|
||||||
|
"finalize": "",
|
||||||
|
"libs": [],
|
||||||
|
"x": 380,
|
||||||
|
"y": 1440,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"ui_pump_b_state"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_mode"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_ctrl"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_power"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_pUp"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_b_pDn"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_flow",
|
||||||
|
"trend_long_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_power",
|
||||||
|
"trend_long_power"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -2330,7 +2432,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B State",
|
"name": "Pump B State",
|
||||||
"label": "State",
|
"label": "State",
|
||||||
"format": "{{msg.payload.state}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -2350,14 +2452,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B Mode",
|
"name": "Pump B Mode",
|
||||||
"label": "Mode",
|
"label": "Mode",
|
||||||
"format": "{{msg.payload.mode}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1470,
|
"y": 1480,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2370,14 +2472,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B Controller %",
|
"name": "Pump B Controller %",
|
||||||
"label": "Controller %",
|
"label": "Controller %",
|
||||||
"format": "{{msg.payload.ctrl}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1500,
|
"y": 1520,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2390,14 +2492,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B Flow",
|
"name": "Pump B Flow",
|
||||||
"label": "Flow",
|
"label": "Flow",
|
||||||
"format": "{{msg.payload.flow}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1530,
|
"y": 1560,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2410,14 +2512,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B Power",
|
"name": "Pump B Power",
|
||||||
"label": "Power",
|
"label": "Power",
|
||||||
"format": "{{msg.payload.power}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1560,
|
"y": 1600,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2430,14 +2532,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B p Upstream",
|
"name": "Pump B p Upstream",
|
||||||
"label": "p Upstream",
|
"label": "p Upstream",
|
||||||
"format": "{{msg.payload.pUp}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1590,
|
"y": 1640,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2450,14 +2552,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump B p Downstream",
|
"name": "Pump B p Downstream",
|
||||||
"label": "p Downstream",
|
"label": "p Downstream",
|
||||||
"format": "{{msg.payload.pDn}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1620,
|
"y": 1680,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2615,30 +2717,6 @@
|
|||||||
"y": 1755,
|
"y": 1755,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "trend_split_pump_b",
|
|
||||||
"type": "function",
|
|
||||||
"z": "tab_ui",
|
|
||||||
"name": "trend split (Pump B)",
|
|
||||||
"func": "const p = msg.payload || {};\nconst flowMsg = p.flowNum != null ? { topic: 'Pump B', payload: Number(p.flowNum) } : null;\nconst powerMsg = p.powerNum != null ? { topic: 'Pump B', payload: Number(p.powerNum) } : null;\nreturn [flowMsg, powerMsg];",
|
|
||||||
"outputs": 2,
|
|
||||||
"noerr": 0,
|
|
||||||
"initialize": "",
|
|
||||||
"finalize": "",
|
|
||||||
"libs": [],
|
|
||||||
"x": 900,
|
|
||||||
"y": 1480,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"trend_short_flow",
|
|
||||||
"trend_long_flow"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"trend_short_power",
|
|
||||||
"trend_long_power"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "c_ui_pump_c",
|
"id": "c_ui_pump_c",
|
||||||
"type": "comment",
|
"type": "comment",
|
||||||
@@ -2661,14 +2739,52 @@
|
|||||||
"y": 1840,
|
"y": 1840,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"ui_pump_c_state",
|
"dispatch_pump_c"
|
||||||
"ui_pump_c_mode",
|
]
|
||||||
"ui_pump_c_ctrl",
|
]
|
||||||
"ui_pump_c_flow",
|
},
|
||||||
"ui_pump_c_power",
|
{
|
||||||
"ui_pump_c_pUp",
|
"id": "dispatch_pump_c",
|
||||||
"ui_pump_c_pDn",
|
"type": "function",
|
||||||
"trend_split_pump_c"
|
"z": "tab_ui",
|
||||||
|
"name": "dispatch Pump C",
|
||||||
|
"func": "const p = msg.payload || {};\nreturn [\n {payload: String(p.state || 'idle')},\n {payload: String(p.mode || 'auto')},\n {payload: String(p.ctrl || 'n/a')},\n {payload: String(p.flow || 'n/a')},\n {payload: String(p.power || 'n/a')},\n {payload: String(p.pUp || 'n/a')},\n {payload: String(p.pDn || 'n/a')},\n p.flowNum != null ? {topic: 'Pump C', payload: p.flowNum} : null,\n p.powerNum != null ? {topic: 'Pump C', payload: p.powerNum} : null,\n];",
|
||||||
|
"outputs": 9,
|
||||||
|
"noerr": 0,
|
||||||
|
"initialize": "",
|
||||||
|
"finalize": "",
|
||||||
|
"libs": [],
|
||||||
|
"x": 380,
|
||||||
|
"y": 1840,
|
||||||
|
"wires": [
|
||||||
|
[
|
||||||
|
"ui_pump_c_state"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_mode"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_ctrl"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_power"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_pUp"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ui_pump_c_pDn"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_flow",
|
||||||
|
"trend_long_flow"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"trend_short_power",
|
||||||
|
"trend_long_power"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -2682,7 +2798,7 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C State",
|
"name": "Pump C State",
|
||||||
"label": "State",
|
"label": "State",
|
||||||
"format": "{{msg.payload.state}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
@@ -2702,14 +2818,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C Mode",
|
"name": "Pump C Mode",
|
||||||
"label": "Mode",
|
"label": "Mode",
|
||||||
"format": "{{msg.payload.mode}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1870,
|
"y": 1880,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2722,14 +2838,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C Controller %",
|
"name": "Pump C Controller %",
|
||||||
"label": "Controller %",
|
"label": "Controller %",
|
||||||
"format": "{{msg.payload.ctrl}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1900,
|
"y": 1920,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2742,14 +2858,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C Flow",
|
"name": "Pump C Flow",
|
||||||
"label": "Flow",
|
"label": "Flow",
|
||||||
"format": "{{msg.payload.flow}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1930,
|
"y": 1960,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2762,14 +2878,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C Power",
|
"name": "Pump C Power",
|
||||||
"label": "Power",
|
"label": "Power",
|
||||||
"format": "{{msg.payload.power}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1960,
|
"y": 2000,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2782,14 +2898,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C p Upstream",
|
"name": "Pump C p Upstream",
|
||||||
"label": "p Upstream",
|
"label": "p Upstream",
|
||||||
"format": "{{msg.payload.pUp}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 1990,
|
"y": 2040,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2802,14 +2918,14 @@
|
|||||||
"height": "0",
|
"height": "0",
|
||||||
"name": "Pump C p Downstream",
|
"name": "Pump C p Downstream",
|
||||||
"label": "p Downstream",
|
"label": "p Downstream",
|
||||||
"format": "{{msg.payload.pDn}}",
|
"format": "{{msg.payload}}",
|
||||||
"layout": "row-left",
|
"layout": "row-left",
|
||||||
"style": false,
|
"style": false,
|
||||||
"font": "",
|
"font": "",
|
||||||
"fontSize": 14,
|
"fontSize": 14,
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"x": 640,
|
"x": 640,
|
||||||
"y": 2020,
|
"y": 2080,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2967,30 +3083,6 @@
|
|||||||
"y": 2155,
|
"y": 2155,
|
||||||
"wires": []
|
"wires": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "trend_split_pump_c",
|
|
||||||
"type": "function",
|
|
||||||
"z": "tab_ui",
|
|
||||||
"name": "trend split (Pump C)",
|
|
||||||
"func": "const p = msg.payload || {};\nconst flowMsg = p.flowNum != null ? { topic: 'Pump C', payload: Number(p.flowNum) } : null;\nconst powerMsg = p.powerNum != null ? { topic: 'Pump C', payload: Number(p.powerNum) } : null;\nreturn [flowMsg, powerMsg];",
|
|
||||||
"outputs": 2,
|
|
||||||
"noerr": 0,
|
|
||||||
"initialize": "",
|
|
||||||
"finalize": "",
|
|
||||||
"libs": [],
|
|
||||||
"x": 900,
|
|
||||||
"y": 1880,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"trend_short_flow",
|
|
||||||
"trend_long_flow"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"trend_short_power",
|
|
||||||
"trend_long_power"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "c_ui_trends",
|
"id": "c_ui_trends",
|
||||||
"type": "comment",
|
"type": "comment",
|
||||||
|
|||||||
Reference in New Issue
Block a user