From cc4ee670ea2354f9f9fedf05a19267377b24d191 Mon Sep 17 00:00:00 2001 From: znetsixe Date: Tue, 14 Apr 2026 10:46:38 +0200 Subject: [PATCH] fix(dashboard): move basin gauges to trend pages next to basin chart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tank gauge (basin level) and 270° arc gauge (fill %) now live on the trend pages alongside the basin metrics chart — not on the control page. Each trend page (10 min / 1 hour) gets its own pair of gauges. Layout per trend page Basin group: - Chart (width 8): Basin fill % + Level + Net flow series - Tank gauge (width 2): 0–3 m with color zones at stop/start levels - Arc gauge (width 2): 0–100% fill with red/orange/green zones Deployed via partial (nodes-only) deploy so the basin wasn't reset. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../build_flow.py | 129 ++++---- .../pumpingstation-3pumps-dashboard/flow.json | 294 ++++++++++++------ 2 files changed, 261 insertions(+), 162 deletions(-) diff --git a/examples/pumpingstation-3pumps-dashboard/build_flow.py b/examples/pumpingstation-3pumps-dashboard/build_flow.py index e323383..737b1d2 100644 --- a/examples/pumpingstation-3pumps-dashboard/build_flow.py +++ b/examples/pumpingstation-3pumps-dashboard/build_flow.py @@ -905,53 +905,15 @@ def build_ui_tab(): ["ui_ps_netflow"], ["ui_ps_timeleft"], ["ui_ps_qin"], - # Trend + gauge outputs - ["trend_short_basin", "trend_long_basin", "gauge_ps_fill"], # fill % → charts + gauge - ["trend_short_basin", "trend_long_basin", "gauge_ps_level"], # level → charts + tank gauge - ["trend_short_basin", "trend_long_basin"], # net flow → charts only + # Trend + gauge outputs (short + long page gauges) + ["trend_short_basin", "trend_long_basin", "gauge_ps_fill", "gauge_ps_fill_long"], # fill % + ["trend_short_basin", "trend_long_basin", "gauge_ps_level", "gauge_ps_level_long"], # level + ["trend_short_basin", "trend_long_basin"], # net flow ], )) - # 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 0–100% - 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": [], - }) + # (Basin gauges live on the trend pages, not the control page — + # see the trend section below for gauge_ps_level / gauge_ps_fill.) # PS text widgets nodes.append(ui_text("ui_ps_direction", TAB_UI, LANE_X[2], y + 160, g_ps, @@ -1127,25 +1089,66 @@ def build_ui_tab(): order=1, )) - # ===== Basin charts (fill %, level, net flow) ===== - # Short-term - nodes.append(ui_chart( - "trend_short_basin", TAB_UI, LANE_X[3], y_charts + 360, - "ui_grp_trend_short_basin", - "Basin — 10 min", "Basin metrics", - width=12, height=8, - remove_older="10", remove_older_unit="60", remove_older_points="300", - y_axis_label="", order=1, - )) - # Long-term - nodes.append(ui_chart( - "trend_long_basin", TAB_UI, LANE_X[3], y_charts + 440, - "ui_grp_trend_long_basin", - "Basin — 1 hour", "Basin metrics", - width=12, height=8, - remove_older="60", remove_older_unit="60", remove_older_points="1800", - y_axis_label="", order=1, - )) + # ===== Basin charts + gauges (fill %, level, net flow) ===== + # Gauge segment definitions (reused for both pages) + TANK_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 + {"color": "#ff9800", "from": 2.5}, # orange: approaching overflow + {"color": "#f44336", "from": 2.8}, # red: overflow zone + ] + FILL_SEGMENTS = [ + {"color": "#f44336", "from": 0}, + {"color": "#ff9800", "from": 10}, + {"color": "#4caf50", "from": 30}, + {"color": "#ff9800", "from": 80}, + {"color": "#f44336", "from": 95}, + ] + + for suffix, grp, remove_older, remove_points, y_off in [ + ("short", "ui_grp_trend_short_basin", "10", "300", 360), + ("long", "ui_grp_trend_long_basin", "60", "1800", 540), + ]: + # Basin trend chart (width 8 to leave room for gauges) + nodes.append(ui_chart( + f"trend_{suffix}_basin", TAB_UI, LANE_X[3], y_charts + y_off, + grp, + f"Basin — {'10 min' if suffix == 'short' else '1 hour'}", "Basin metrics", + width=8, height=8, + remove_older=remove_older, remove_older_unit="60", + remove_older_points=remove_points, + y_axis_label="", order=1, + )) + # Tank gauge: basin level 0–3 m + gauge_id_suffix = "" if suffix == "short" else "_long" + nodes.append({ + "id": f"gauge_ps_level{gauge_id_suffix}", "type": "ui-gauge", + "z": TAB_UI, "group": grp, + "name": f"Basin level gauge ({suffix})", + "gtype": "gauge-tank", "gstyle": "Rounded", + "title": "Level", "units": "m", + "prefix": "", "suffix": " m", + "min": 0, "max": 3, + "segments": TANK_SEGMENTS, + "width": 2, "height": 5, "order": 2, + "icon": "", "sizeGauge": 20, "sizeGap": 2, "sizeSegments": 10, + "x": LANE_X[4], "y": y_charts + y_off, "wires": [], + }) + # 270° arc: fill % + nodes.append({ + "id": f"gauge_ps_fill{gauge_id_suffix}", "type": "ui-gauge", + "z": TAB_UI, "group": grp, + "name": f"Basin fill gauge ({suffix})", + "gtype": "gauge-34", "gstyle": "Rounded", + "title": "Fill", "units": "%", + "prefix": "", "suffix": "%", + "min": 0, "max": 100, + "segments": FILL_SEGMENTS, + "width": 2, "height": 4, "order": 3, + "icon": "water_drop", "sizeGauge": 20, "sizeGap": 2, "sizeSegments": 10, + "x": LANE_X[5], "y": y_charts + y_off, "wires": [], + }) return nodes diff --git a/examples/pumpingstation-3pumps-dashboard/flow.json b/examples/pumpingstation-3pumps-dashboard/flow.json index 019f2e7..6734e4d 100644 --- a/examples/pumpingstation-3pumps-dashboard/flow.json +++ b/examples/pumpingstation-3pumps-dashboard/flow.json @@ -1890,12 +1890,14 @@ [ "trend_short_basin", "trend_long_basin", - "gauge_ps_fill" + "gauge_ps_fill", + "gauge_ps_fill_long" ], [ "trend_short_basin", "trend_long_basin", - "gauge_ps_level" + "gauge_ps_level", + "gauge_ps_level_long" ], [ "trend_short_basin", @@ -1903,100 +1905,6 @@ ] ] }, - { - "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", "type": "ui-text", @@ -3546,7 +3454,7 @@ "#e5e5e5" ], "gridColorDefault": true, - "width": 12, + "width": 8, "height": 8, "className": "", "x": 900, @@ -3555,6 +3463,100 @@ [] ] }, + { + "id": "gauge_ps_level", + "type": "ui-gauge", + "z": "tab_ui", + "group": "ui_grp_trend_short_basin", + "name": "Basin level gauge (short)", + "gtype": "gauge-tank", + "gstyle": "Rounded", + "title": "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": 2, + "height": 5, + "order": 2, + "icon": "", + "sizeGauge": 20, + "sizeGap": 2, + "sizeSegments": 10, + "x": 1160, + "y": 2640, + "wires": [] + }, + { + "id": "gauge_ps_fill", + "type": "ui-gauge", + "z": "tab_ui", + "group": "ui_grp_trend_short_basin", + "name": "Basin fill gauge (short)", + "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": 2, + "height": 4, + "order": 3, + "icon": "water_drop", + "sizeGauge": 20, + "sizeGap": 2, + "sizeSegments": 10, + "x": 1420, + "y": 2640, + "wires": [] + }, { "id": "trend_long_basin", "type": "ui-chart", @@ -3608,15 +3610,109 @@ "#e5e5e5" ], "gridColorDefault": true, - "width": 12, + "width": 8, "height": 8, "className": "", "x": 900, - "y": 2720, + "y": 2820, "wires": [ [] ] }, + { + "id": "gauge_ps_level_long", + "type": "ui-gauge", + "z": "tab_ui", + "group": "ui_grp_trend_long_basin", + "name": "Basin level gauge (long)", + "gtype": "gauge-tank", + "gstyle": "Rounded", + "title": "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": 2, + "height": 5, + "order": 2, + "icon": "", + "sizeGauge": 20, + "sizeGap": 2, + "sizeSegments": 10, + "x": 1160, + "y": 2820, + "wires": [] + }, + { + "id": "gauge_ps_fill_long", + "type": "ui-gauge", + "z": "tab_ui", + "group": "ui_grp_trend_long_basin", + "name": "Basin fill gauge (long)", + "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": 2, + "height": 4, + "order": 3, + "icon": "water_drop", + "sizeGauge": 20, + "sizeGap": 2, + "sizeSegments": 10, + "x": 1420, + "y": 2820, + "wires": [] + }, { "id": "tab_drivers", "type": "tab",