feat(dashboard): add tank gauge for basin level + 270° arc for fill %
Some checks failed
CI / lint-and-test (push) Has been cancelled

Basin Status group on the Control page now has two visual gauges:

1. gauge-tank (vertical tank with fill gradient) for basin level 0–3 m.
   Color zones: red < 0.6 m (below stopLevel) → orange → blue 1.2–2.5 m
   (normal operating range) → orange → red > 2.8 m (overflow zone).

2. gauge-34 (270° arc) for fill percentage 0–100%.
   Color zones: red < 10% → orange → green 30–80% → orange → red > 95%.

Both gauges are fed from the PS dispatcher's numeric outputs (fillPctNum
and levelNum) which also feed the basin trend charts — same data, two
visual forms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
znetsixe
2026-04-14 10:40:43 +02:00
parent b18c47c07e
commit a51bc46e26
2 changed files with 143 additions and 6 deletions

View File

@@ -905,13 +905,54 @@ def build_ui_tab():
["ui_ps_netflow"], ["ui_ps_netflow"],
["ui_ps_timeleft"], ["ui_ps_timeleft"],
["ui_ps_qin"], ["ui_ps_qin"],
# Trend outputs → both short + long charts # Trend + gauge outputs
["trend_short_basin", "trend_long_basin"], # fill % ["trend_short_basin", "trend_long_basin", "gauge_ps_fill"], # fill % → charts + gauge
["trend_short_basin", "trend_long_basin"], # level ["trend_short_basin", "trend_long_basin", "gauge_ps_level"], # level → charts + tank gauge
["trend_short_basin", "trend_long_basin"], # net flow ["trend_short_basin", "trend_long_basin"], # net flow → charts only
], ],
)) ))
# PS gauges — tank for level, 270° arc for fill %
# Tank gauge: basin level 0 3 m with color zones matching
# startLevel (1.2 m) and stopLevel (0.6 m).
nodes.append({
"id": "gauge_ps_level", "type": "ui-gauge", "z": TAB_UI,
"group": g_ps, "name": "Basin level gauge",
"gtype": "gauge-tank", "gstyle": "Rounded",
"title": "Basin Level", "units": "m",
"prefix": "", "suffix": " m",
"min": 0, "max": 3,
"segments": [
{"color": "#f44336", "from": 0}, # red: below stopLevel
{"color": "#ff9800", "from": 0.6}, # orange: between stop and start
{"color": "#2196f3", "from": 1.2}, # blue: normal operating range
{"color": "#ff9800", "from": 2.5}, # orange: approaching overflow
{"color": "#f44336", "from": 2.8}, # red: overflow zone
],
"width": 3, "height": 5, "order": 1,
"icon": "", "sizeGauge": 20, "sizeGap": 2, "sizeSegments": 10,
"x": LANE_X[3], "y": y + 160, "wires": [],
})
# 270° arc: fill percentage 0100%
nodes.append({
"id": "gauge_ps_fill", "type": "ui-gauge", "z": TAB_UI,
"group": g_ps, "name": "Basin fill gauge",
"gtype": "gauge-34", "gstyle": "Rounded",
"title": "Fill", "units": "%",
"prefix": "", "suffix": "%",
"min": 0, "max": 100,
"segments": [
{"color": "#f44336", "from": 0}, # red: dangerously low
{"color": "#ff9800", "from": 10}, # orange: low
{"color": "#4caf50", "from": 30}, # green: normal
{"color": "#ff9800", "from": 80}, # orange: getting full
{"color": "#f44336", "from": 95}, # red: near overflow
],
"width": 3, "height": 4, "order": 2,
"icon": "water_drop", "sizeGauge": 20, "sizeGap": 2, "sizeSegments": 10,
"x": LANE_X[4], "y": y + 160, "wires": [],
})
# PS text widgets # PS text widgets
nodes.append(ui_text("ui_ps_direction", TAB_UI, LANE_X[2], y + 160, g_ps, nodes.append(ui_text("ui_ps_direction", TAB_UI, LANE_X[2], y + 160, g_ps,
"PS direction", "Direction", "{{msg.payload}}")) "PS direction", "Direction", "{{msg.payload}}"))

View File

@@ -1889,11 +1889,13 @@
], ],
[ [
"trend_short_basin", "trend_short_basin",
"trend_long_basin" "trend_long_basin",
"gauge_ps_fill"
], ],
[ [
"trend_short_basin", "trend_short_basin",
"trend_long_basin" "trend_long_basin",
"gauge_ps_level"
], ],
[ [
"trend_short_basin", "trend_short_basin",
@@ -1901,6 +1903,100 @@
] ]
] ]
}, },
{
"id": "gauge_ps_level",
"type": "ui-gauge",
"z": "tab_ui",
"group": "ui_grp_ps",
"name": "Basin level gauge",
"gtype": "gauge-tank",
"gstyle": "Rounded",
"title": "Basin Level",
"units": "m",
"prefix": "",
"suffix": " m",
"min": 0,
"max": 3,
"segments": [
{
"color": "#f44336",
"from": 0
},
{
"color": "#ff9800",
"from": 0.6
},
{
"color": "#2196f3",
"from": 1.2
},
{
"color": "#ff9800",
"from": 2.5
},
{
"color": "#f44336",
"from": 2.8
}
],
"width": 3,
"height": 5,
"order": 1,
"icon": "",
"sizeGauge": 20,
"sizeGap": 2,
"sizeSegments": 10,
"x": 900,
"y": 760,
"wires": []
},
{
"id": "gauge_ps_fill",
"type": "ui-gauge",
"z": "tab_ui",
"group": "ui_grp_ps",
"name": "Basin fill gauge",
"gtype": "gauge-34",
"gstyle": "Rounded",
"title": "Fill",
"units": "%",
"prefix": "",
"suffix": "%",
"min": 0,
"max": 100,
"segments": [
{
"color": "#f44336",
"from": 0
},
{
"color": "#ff9800",
"from": 10
},
{
"color": "#4caf50",
"from": 30
},
{
"color": "#ff9800",
"from": 80
},
{
"color": "#f44336",
"from": 95
}
],
"width": 3,
"height": 4,
"order": 2,
"icon": "water_drop",
"sizeGauge": 20,
"sizeGap": 2,
"sizeSegments": 10,
"x": 1160,
"y": 760,
"wires": []
},
{ {
"id": "ui_ps_direction", "id": "ui_ps_direction",
"type": "ui-text", "type": "ui-text",