From e6785f7db160c8ee67b625e1444a5374fdd194b1 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Mon, 13 Apr 2026 00:17:29 -0300 Subject: [PATCH] monitoring(overview): fix ups/climate 2x2 cards and dynamic climate axes --- scripts/dashboards_render_atlas.py | 192 +++++- .../monitoring/dashboards/atlas-overview.json | 625 ++++++++++++++++-- .../grafana-dashboard-overview.yaml | 625 ++++++++++++++++-- 3 files changed, 1306 insertions(+), 136 deletions(-) diff --git a/scripts/dashboards_render_atlas.py b/scripts/dashboards_render_atlas.py index b5d8d292..2d4860cd 100644 --- a/scripts/dashboards_render_atlas.py +++ b/scripts/dashboards_render_atlas.py @@ -651,6 +651,20 @@ CLIMATE_TEMP_MAX = f"max({CLIMATE_TEMP_SERIES}) or on() vector(0)" CLIMATE_TEMP_FAHRENHEIT_MAX = f"max({CLIMATE_TEMP_FAHRENHEIT_SERIES}) or on() vector(0)" CLIMATE_PRESSURE_CURRENT = f"max({CLIMATE_PRESSURE_SERIES}) or on() vector(0)" CLIMATE_HUMIDITY_MAX = f"max({CLIMATE_HUMIDITY_SERIES}) or on() vector(0)" +CLIMATE_TEMP_MIN_BOUND_SERIES = f"(min_over_time({CLIMATE_TEMP_SERIES}[$__range]) - 0.4)" +CLIMATE_TEMP_MAX_BOUND_SERIES = f"(max_over_time({CLIMATE_TEMP_SERIES}[$__range]) + 0.4)" +CLIMATE_HUMIDITY_MIN_BOUND_SERIES = ( + f"clamp_min((min_over_time({CLIMATE_HUMIDITY_SERIES}[$__range]) - 2), 0)" +) +CLIMATE_HUMIDITY_MAX_BOUND_SERIES = ( + f"clamp_max((max_over_time({CLIMATE_HUMIDITY_SERIES}[$__range]) + 2), 100)" +) +CLIMATE_PRESSURE_MIN_BOUND_SERIES = ( + f"clamp_min((min_over_time({CLIMATE_PRESSURE_SERIES}[$__range]) - 0.15), 0)" +) +CLIMATE_PRESSURE_MAX_BOUND_SERIES = ( + f"(max_over_time({CLIMATE_PRESSURE_SERIES}[$__range]) + 0.15)" +) CLIMATE_FAN_OUTLET_CURRENT = ( f'max(max without ({CLIMATE_DEDUP_LABELS}) (typhon_fan_speed_level{{fan_group="outlet"}})) or on() vector(0)' ) @@ -976,6 +990,93 @@ def timeseries_panel( return panel +def canvas_metric_grid_panel( + panel_id, + title, + grid, + *, + targets, + field_overrides=None, + links=None, + description=None, + metric_size=26, +): + """Return a canvas panel with a deterministic 2x2 metric layout.""" + + def metric_element(name, field, left, top): + return { + "type": "metric-value", + "name": name, + "constraint": {"horizontal": "left", "vertical": "top"}, + "placement": { + "left": left, + "top": top, + "width": 146, + "height": 48, + }, + "background": {"color": {"fixed": "transparent"}}, + "border": {"color": {"fixed": "transparent"}}, + "config": { + "align": "left", + "valign": "middle", + "size": metric_size, + "color": {"field": field, "fixed": "text"}, + "text": { + "mode": "field", + "field": field, + "fixed": "", + }, + }, + "links": [], + } + + panel = { + "id": panel_id, + "type": "canvas", + "title": title, + "datasource": PROM_DS, + "gridPos": grid, + "targets": targets, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + {"color": "rgba(115, 115, 115, 1)", "value": None}, + {"color": "green", "value": 1}, + ], + }, + "color": {"mode": "thresholds"}, + }, + "overrides": field_overrides or [], + }, + "options": { + "inlineEditing": False, + "showAdvancedTypes": True, + "panZoom": False, + "infinitePan": False, + "root": { + "type": "frame", + "name": f"{title} frame", + "elements": [ + metric_element("Cell 1", targets[0]["legendFormat"], 10, 14), + metric_element("Cell 2", targets[1]["legendFormat"], 166, 14), + metric_element("Cell 3", targets[2]["legendFormat"], 10, 72), + metric_element("Cell 4", targets[3]["legendFormat"], 166, 72), + ], + "background": {"color": {"fixed": "transparent"}}, + "border": {"color": {"fixed": "transparent"}}, + }, + }, + } + if links: + panel["links"] = links + if description: + panel["description"] = description + return panel + + def table_panel( panel_id, title, @@ -1475,26 +1576,23 @@ def build_overview(): ] panels.append( - stat_panel( + canvas_metric_grid_panel( 40, "UPS Current Load", - UPS_CURRENT_ROW_EXPR, {"h": 5, "w": 6, "x": 0, "y": 7}, - unit="none", - decimals=1, - text_mode="name_and_value", - legend="{{ups}} {{metric}}", - instant=True, + targets=[ + {"refId": "A", "expr": ANANKE_UPS_DRAW_WATTS_DB, "legendFormat": f"{ANANKE_UPS_DB_NAME} Draw", "instant": True}, + {"refId": "B", "expr": ANANKE_UPS_RUNTIME_DB, "legendFormat": f"{ANANKE_UPS_DB_NAME} Runtime", "instant": True}, + {"refId": "C", "expr": ANANKE_UPS_DRAW_WATTS_TETHYS, "legendFormat": f"{ANANKE_UPS_TETHYS_NAME} Draw", "instant": True}, + {"refId": "D", "expr": ANANKE_UPS_RUNTIME_TETHYS, "legendFormat": f"{ANANKE_UPS_TETHYS_NAME} Runtime", "instant": True}, + ], field_overrides=[ {"matcher": {"id": "byRegexp", "options": ".*Draw$"}, "properties": [{"id": "unit", "value": "watt"}]}, {"matcher": {"id": "byRegexp", "options": ".*Runtime$"}, "properties": [{"id": "unit", "value": "s"}]}, ], links=link_to("atlas-power"), - description="Per-UPS live snapshot: draw, discharge runtime, and status.", - orientation="vertical", - wide_layout=False, - title_size=14, - value_size=24, + description="Per-UPS live snapshot in a fixed 2x2 layout: Pyrphoros draw/runtime, Statera draw/runtime.", + metric_size=26, ) ) panels.append( @@ -1515,16 +1613,16 @@ def build_overview(): ) ) panels.append( - stat_panel( + canvas_metric_grid_panel( 42, "Current Climate", - CLIMATE_CURRENT_ROW_EXPR, {"h": 6, "w": 6, "x": 0, "y": 12}, - unit="none", - decimals=2, - text_mode="name_and_value", - legend="{{metric}}", - instant=True, + targets=[ + {"refId": "A", "expr": CLIMATE_TEMP_MAX, "legendFormat": "Temp °C", "instant": True}, + {"refId": "B", "expr": CLIMATE_TEMP_FAHRENHEIT_MAX, "legendFormat": "Temp °F", "instant": True}, + {"refId": "C", "expr": CLIMATE_HUMIDITY_MAX, "legendFormat": "Humidity", "instant": True}, + {"refId": "D", "expr": CLIMATE_PRESSURE_CURRENT, "legendFormat": "Pressure", "instant": True}, + ], field_overrides=[ {"matcher": {"id": "byName", "options": "Temp °C"}, "properties": [{"id": "unit", "value": "celsius"}]}, {"matcher": {"id": "byName", "options": "Temp °F"}, "properties": [{"id": "unit", "value": "fahrenheit"}]}, @@ -1532,11 +1630,8 @@ def build_overview(): {"matcher": {"id": "byName", "options": "Pressure"}, "properties": [{"id": "unit", "value": "suffix:kPa"}]}, ], links=link_to("atlas-power"), - description="Current tent values: Temp °C, Temp °F, Humidity, Pressure.", - orientation="vertical", - wide_layout=False, - title_size=16, - value_size=28, + description="Current tent values in a fixed 2x2 layout: Temp °C / Temp °F / Humidity / Pressure.", + metric_size=30, ) ) panels.append( @@ -1550,6 +1645,12 @@ def build_overview(): {"refId": "A", "expr": CLIMATE_TEMP_SERIES, "legendFormat": "C"}, {"refId": "B", "expr": CLIMATE_HUMIDITY_SERIES, "legendFormat": "RH"}, {"refId": "C", "expr": CLIMATE_PRESSURE_SERIES, "legendFormat": "P"}, + {"refId": "D", "expr": CLIMATE_TEMP_MIN_BOUND_SERIES, "legendFormat": "C bound min"}, + {"refId": "E", "expr": CLIMATE_TEMP_MAX_BOUND_SERIES, "legendFormat": "C bound max"}, + {"refId": "F", "expr": CLIMATE_HUMIDITY_MIN_BOUND_SERIES, "legendFormat": "RH bound min"}, + {"refId": "G", "expr": CLIMATE_HUMIDITY_MAX_BOUND_SERIES, "legendFormat": "RH bound max"}, + {"refId": "H", "expr": CLIMATE_PRESSURE_MIN_BOUND_SERIES, "legendFormat": "P bound min"}, + {"refId": "I", "expr": CLIMATE_PRESSURE_MAX_BOUND_SERIES, "legendFormat": "P bound max"}, ], field_overrides=[ { @@ -1561,6 +1662,19 @@ def build_overview(): {"id": "custom.axisCenteredZero", "value": False}, ], }, + { + "matcher": {"id": "byRegexp", "options": "C bound .*"}, + "properties": [ + {"id": "unit", "value": "suffix:°C"}, + {"id": "custom.axisPlacement", "value": "left"}, + {"id": "custom.axisCenteredZero", "value": False}, + {"id": "custom.hideFrom", "value": {"legend": True, "tooltip": True, "viz": False}}, + {"id": "custom.lineWidth", "value": 0}, + {"id": "custom.fillOpacity", "value": 0}, + {"id": "custom.showPoints", "value": "never"}, + {"id": "color", "value": {"mode": "fixed", "fixedColor": "transparent"}}, + ], + }, { "matcher": {"id": "byName", "options": "RH"}, "properties": [ @@ -1570,6 +1684,19 @@ def build_overview(): {"id": "custom.axisCenteredZero", "value": False}, ], }, + { + "matcher": {"id": "byRegexp", "options": "RH bound .*"}, + "properties": [ + {"id": "unit", "value": "suffix:%"}, + {"id": "custom.axisPlacement", "value": "right"}, + {"id": "custom.axisCenteredZero", "value": False}, + {"id": "custom.hideFrom", "value": {"legend": True, "tooltip": True, "viz": False}}, + {"id": "custom.lineWidth", "value": 0}, + {"id": "custom.fillOpacity", "value": 0}, + {"id": "custom.showPoints", "value": "never"}, + {"id": "color", "value": {"mode": "fixed", "fixedColor": "transparent"}}, + ], + }, { "matcher": {"id": "byName", "options": "P"}, "properties": [ @@ -1578,12 +1705,25 @@ def build_overview(): {"id": "decimals", "value": 2}, {"id": "custom.axisCenteredZero", "value": False}, ], - } + }, + { + "matcher": {"id": "byRegexp", "options": "P bound .*"}, + "properties": [ + {"id": "unit", "value": "suffix:kPa"}, + {"id": "custom.axisPlacement", "value": "right"}, + {"id": "custom.axisCenteredZero", "value": False}, + {"id": "custom.hideFrom", "value": {"legend": True, "tooltip": True, "viz": False}}, + {"id": "custom.lineWidth", "value": 0}, + {"id": "custom.fillOpacity", "value": 0}, + {"id": "custom.showPoints", "value": "never"}, + {"id": "color", "value": {"mode": "fixed", "fixedColor": "transparent"}}, + ], + }, ], legend_display="list", legend_placement="bottom", links=link_to("atlas-power"), - description="Temperature on left axis, humidity and pressure on right axis.", + description="Temperature on left axis, humidity and pressure on right axis with dynamic bound series so small swings remain visible.", ) ) panels.append( diff --git a/services/monitoring/dashboards/atlas-overview.json b/services/monitoring/dashboards/atlas-overview.json index 6968a449..799d46dc 100644 --- a/services/monitoring/dashboards/atlas-overview.json +++ b/services/monitoring/dashboards/atlas-overview.json @@ -1072,7 +1072,7 @@ }, { "id": 40, - "type": "stat", + "type": "canvas", "title": "UPS Current Load", "datasource": { "type": "prometheus", @@ -1086,17 +1086,32 @@ }, "targets": [ { - "expr": "label_replace(label_replace((max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Pyrphoros\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Pyrphoros\"}) / 100) or on() vector(0)), \"ups\", \"Pyrphoros\", \"__name__\", \".*\"), \"metric\", \"Draw\", \"__name__\", \".*\") or label_replace(label_replace((max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Pyrphoros\"}) or on() vector(0)), \"ups\", \"Pyrphoros\", \"__name__\", \".*\"), \"metric\", \"Runtime\", \"__name__\", \".*\") or label_replace(label_replace((max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Statera\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Statera\"}) / 100) or on() vector(0)), \"ups\", \"Statera\", \"__name__\", \".*\"), \"metric\", \"Draw\", \"__name__\", \".*\") or label_replace(label_replace((max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Statera\"}) or on() vector(0)), \"ups\", \"Statera\", \"__name__\", \".*\"), \"metric\", \"Runtime\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "{{ups}} {{metric}}", + "expr": "max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Pyrphoros\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Pyrphoros\"}) / 100) or on() vector(0)", + "legendFormat": "Pyrphoros Draw", + "instant": true + }, + { + "refId": "B", + "expr": "max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Pyrphoros\"}) or on() vector(0)", + "legendFormat": "Pyrphoros Runtime", + "instant": true + }, + { + "refId": "C", + "expr": "max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Statera\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Statera\"}) / 100) or on() vector(0)", + "legendFormat": "Statera Draw", + "instant": true + }, + { + "refId": "D", + "expr": "max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Statera\"}) or on() vector(0)", + "legendFormat": "Statera Runtime", "instant": true } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, "mappings": [], "thresholds": { "mode": "absolute", @@ -1111,11 +1126,9 @@ } ] }, - "unit": "none", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 + "color": { + "mode": "thresholds" + } }, "overrides": [ { @@ -1145,22 +1158,181 @@ ] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" + "inlineEditing": false, + "showAdvancedTypes": true, + "panZoom": false, + "infinitePan": false, + "root": { + "type": "frame", + "name": "UPS Current Load frame", + "elements": [ + { + "type": "metric-value", + "name": "Cell 1", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Pyrphoros Draw", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pyrphoros Draw", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 2", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Pyrphoros Runtime", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pyrphoros Runtime", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 3", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Statera Draw", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Statera Draw", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 4", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Statera Runtime", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Statera Runtime", + "fixed": "" + } + }, + "links": [] + } ], - "fields": "", - "values": false - }, - "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, - "text": { - "titleSize": 14, - "valueSize": 24 + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + } } }, "links": [ @@ -1170,7 +1342,7 @@ "targetBlank": true } ], - "description": "Per-UPS live snapshot: draw, discharge runtime, and status." + "description": "Per-UPS live snapshot in a fixed 2x2 layout: Pyrphoros draw/runtime, Statera draw/runtime." }, { "id": 41, @@ -1228,7 +1400,7 @@ }, { "id": 42, - "type": "stat", + "type": "canvas", "title": "Current Climate", "datasource": { "type": "prometheus", @@ -1242,17 +1414,32 @@ }, "targets": [ { - "expr": "label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) or on() vector(0)), \"metric\", \"Temp \u00b0C\", \"__name__\", \".*\") or label_replace((max((max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) * 9 / 5 + 32) or on() vector(0)), \"metric\", \"Temp \u00b0F\", \"__name__\", \".*\") or label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)) or on() vector(0)), \"metric\", \"Humidity\", \"__name__\", \".*\") or label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)) or on() vector(0)), \"metric\", \"Pressure\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "{{metric}}", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) or on() vector(0)", + "legendFormat": "Temp \u00b0C", + "instant": true + }, + { + "refId": "B", + "expr": "max((max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) * 9 / 5 + 32) or on() vector(0)", + "legendFormat": "Temp \u00b0F", + "instant": true + }, + { + "refId": "C", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)) or on() vector(0)", + "legendFormat": "Humidity", + "instant": true + }, + { + "refId": "D", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)) or on() vector(0)", + "legendFormat": "Pressure", "instant": true } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, "mappings": [], "thresholds": { "mode": "absolute", @@ -1267,11 +1454,9 @@ } ] }, - "unit": "none", - "custom": { - "displayMode": "auto" - }, - "decimals": 2 + "color": { + "mode": "thresholds" + } }, "overrides": [ { @@ -1325,22 +1510,181 @@ ] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" + "inlineEditing": false, + "showAdvancedTypes": true, + "panZoom": false, + "infinitePan": false, + "root": { + "type": "frame", + "name": "Current Climate frame", + "elements": [ + { + "type": "metric-value", + "name": "Cell 1", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Temp \u00b0C", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Temp \u00b0C", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 2", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Temp \u00b0F", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Temp \u00b0F", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 3", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Humidity", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Humidity", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 4", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Pressure", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pressure", + "fixed": "" + } + }, + "links": [] + } ], - "fields": "", - "values": false - }, - "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, - "text": { - "titleSize": 16, - "valueSize": 28 + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + } } }, "links": [ @@ -1350,7 +1694,7 @@ "targetBlank": true } ], - "description": "Current tent values: Temp \u00b0C, Temp \u00b0F, Humidity, Pressure." + "description": "Current tent values in a fixed 2x2 layout: Temp \u00b0C / Temp \u00b0F / Humidity / Pressure." }, { "id": 43, @@ -1381,6 +1725,36 @@ "refId": "C", "expr": "max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)", "legendFormat": "P" + }, + { + "refId": "D", + "expr": "(min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)[$__range]) - 0.4)", + "legendFormat": "C bound min" + }, + { + "refId": "E", + "expr": "(max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)[$__range]) + 0.4)", + "legendFormat": "C bound max" + }, + { + "refId": "F", + "expr": "clamp_min((min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)[$__range]) - 2), 0)", + "legendFormat": "RH bound min" + }, + { + "refId": "G", + "expr": "clamp_max((max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)[$__range]) + 2), 100)", + "legendFormat": "RH bound max" + }, + { + "refId": "H", + "expr": "clamp_min((min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)[$__range]) - 0.15), 0)", + "legendFormat": "P bound min" + }, + { + "refId": "I", + "expr": "(max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)[$__range]) + 0.15)", + "legendFormat": "P bound max" } ], "fieldConfig": { @@ -1412,6 +1786,53 @@ } ] }, + { + "matcher": { + "id": "byRegexp", + "options": "C bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:\u00b0C" + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] + }, { "matcher": { "id": "byName", @@ -1436,6 +1857,53 @@ } ] }, + { + "matcher": { + "id": "byRegexp", + "options": "RH bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:%" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] + }, { "matcher": { "id": "byName", @@ -1459,6 +1927,53 @@ "value": false } ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "P bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:kPa" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] } ] }, @@ -1478,7 +1993,7 @@ "targetBlank": true } ], - "description": "Temperature on left axis, humidity and pressure on right axis." + "description": "Temperature on left axis, humidity and pressure on right axis with dynamic bound series so small swings remain visible." }, { "id": 140, diff --git a/services/monitoring/grafana-dashboard-overview.yaml b/services/monitoring/grafana-dashboard-overview.yaml index 17a151a3..345443d6 100644 --- a/services/monitoring/grafana-dashboard-overview.yaml +++ b/services/monitoring/grafana-dashboard-overview.yaml @@ -1081,7 +1081,7 @@ data: }, { "id": 40, - "type": "stat", + "type": "canvas", "title": "UPS Current Load", "datasource": { "type": "prometheus", @@ -1095,17 +1095,32 @@ data: }, "targets": [ { - "expr": "label_replace(label_replace((max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Pyrphoros\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Pyrphoros\"}) / 100) or on() vector(0)), \"ups\", \"Pyrphoros\", \"__name__\", \".*\"), \"metric\", \"Draw\", \"__name__\", \".*\") or label_replace(label_replace((max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Pyrphoros\"}) or on() vector(0)), \"ups\", \"Pyrphoros\", \"__name__\", \".*\"), \"metric\", \"Runtime\", \"__name__\", \".*\") or label_replace(label_replace((max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Statera\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Statera\"}) / 100) or on() vector(0)), \"ups\", \"Statera\", \"__name__\", \".*\"), \"metric\", \"Draw\", \"__name__\", \".*\") or label_replace(label_replace((max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Statera\"}) or on() vector(0)), \"ups\", \"Statera\", \"__name__\", \".*\"), \"metric\", \"Runtime\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "{{ups}} {{metric}}", + "expr": "max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Pyrphoros\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Pyrphoros\"}) / 100) or on() vector(0)", + "legendFormat": "Pyrphoros Draw", + "instant": true + }, + { + "refId": "B", + "expr": "max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Pyrphoros\"}) or on() vector(0)", + "legendFormat": "Pyrphoros Runtime", + "instant": true + }, + { + "refId": "C", + "expr": "max((ananke_ups_load_percent{job=\"ananke-power\",source=\"Statera\"} * ananke_ups_power_nominal_watts{job=\"ananke-power\",source=\"Statera\"}) / 100) or on() vector(0)", + "legendFormat": "Statera Draw", + "instant": true + }, + { + "refId": "D", + "expr": "max(ananke_ups_runtime_seconds{job=\"ananke-power\",source=\"Statera\"}) or on() vector(0)", + "legendFormat": "Statera Runtime", "instant": true } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, "mappings": [], "thresholds": { "mode": "absolute", @@ -1120,11 +1135,9 @@ data: } ] }, - "unit": "none", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 + "color": { + "mode": "thresholds" + } }, "overrides": [ { @@ -1154,22 +1167,181 @@ data: ] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" + "inlineEditing": false, + "showAdvancedTypes": true, + "panZoom": false, + "infinitePan": false, + "root": { + "type": "frame", + "name": "UPS Current Load frame", + "elements": [ + { + "type": "metric-value", + "name": "Cell 1", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Pyrphoros Draw", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pyrphoros Draw", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 2", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Pyrphoros Runtime", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pyrphoros Runtime", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 3", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Statera Draw", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Statera Draw", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 4", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 26, + "color": { + "field": "Statera Runtime", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Statera Runtime", + "fixed": "" + } + }, + "links": [] + } ], - "fields": "", - "values": false - }, - "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, - "text": { - "titleSize": 14, - "valueSize": 24 + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + } } }, "links": [ @@ -1179,7 +1351,7 @@ data: "targetBlank": true } ], - "description": "Per-UPS live snapshot: draw, discharge runtime, and status." + "description": "Per-UPS live snapshot in a fixed 2x2 layout: Pyrphoros draw/runtime, Statera draw/runtime." }, { "id": 41, @@ -1237,7 +1409,7 @@ data: }, { "id": 42, - "type": "stat", + "type": "canvas", "title": "Current Climate", "datasource": { "type": "prometheus", @@ -1251,17 +1423,32 @@ data: }, "targets": [ { - "expr": "label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) or on() vector(0)), \"metric\", \"Temp \u00b0C\", \"__name__\", \".*\") or label_replace((max((max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) * 9 / 5 + 32) or on() vector(0)), \"metric\", \"Temp \u00b0F\", \"__name__\", \".*\") or label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)) or on() vector(0)), \"metric\", \"Humidity\", \"__name__\", \".*\") or label_replace((max(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)) or on() vector(0)), \"metric\", \"Pressure\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "{{metric}}", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) or on() vector(0)", + "legendFormat": "Temp \u00b0C", + "instant": true + }, + { + "refId": "B", + "expr": "max((max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)) * 9 / 5 + 32) or on() vector(0)", + "legendFormat": "Temp \u00b0F", + "instant": true + }, + { + "refId": "C", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)) or on() vector(0)", + "legendFormat": "Humidity", + "instant": true + }, + { + "refId": "D", + "expr": "max(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)) or on() vector(0)", + "legendFormat": "Pressure", "instant": true } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, "mappings": [], "thresholds": { "mode": "absolute", @@ -1276,11 +1463,9 @@ data: } ] }, - "unit": "none", - "custom": { - "displayMode": "auto" - }, - "decimals": 2 + "color": { + "mode": "thresholds" + } }, "overrides": [ { @@ -1334,22 +1519,181 @@ data: ] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" + "inlineEditing": false, + "showAdvancedTypes": true, + "panZoom": false, + "infinitePan": false, + "root": { + "type": "frame", + "name": "Current Climate frame", + "elements": [ + { + "type": "metric-value", + "name": "Cell 1", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Temp \u00b0C", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Temp \u00b0C", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 2", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 14, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Temp \u00b0F", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Temp \u00b0F", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 3", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 10, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Humidity", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Humidity", + "fixed": "" + } + }, + "links": [] + }, + { + "type": "metric-value", + "name": "Cell 4", + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "placement": { + "left": 166, + "top": 72, + "width": 146, + "height": 48 + }, + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + }, + "config": { + "align": "left", + "valign": "middle", + "size": 30, + "color": { + "field": "Pressure", + "fixed": "text" + }, + "text": { + "mode": "field", + "field": "Pressure", + "fixed": "" + } + }, + "links": [] + } ], - "fields": "", - "values": false - }, - "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, - "text": { - "titleSize": 16, - "valueSize": 28 + "background": { + "color": { + "fixed": "transparent" + } + }, + "border": { + "color": { + "fixed": "transparent" + } + } } }, "links": [ @@ -1359,7 +1703,7 @@ data: "targetBlank": true } ], - "description": "Current tent values: Temp \u00b0C, Temp \u00b0F, Humidity, Pressure." + "description": "Current tent values in a fixed 2x2 layout: Temp \u00b0C / Temp \u00b0F / Humidity / Pressure." }, { "id": 43, @@ -1390,6 +1734,36 @@ data: "refId": "C", "expr": "max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)", "legendFormat": "P" + }, + { + "refId": "D", + "expr": "(min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)[$__range]) - 0.4)", + "legendFormat": "C bound min" + }, + { + "refId": "E", + "expr": "(max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_temperature_celsius != 0)[$__range]) + 0.4)", + "legendFormat": "C bound max" + }, + { + "refId": "F", + "expr": "clamp_min((min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)[$__range]) - 2), 0)", + "legendFormat": "RH bound min" + }, + { + "refId": "G", + "expr": "clamp_max((max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_relative_humidity_percent != 0)[$__range]) + 2), 100)", + "legendFormat": "RH bound max" + }, + { + "refId": "H", + "expr": "clamp_min((min_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)[$__range]) - 0.15), 0)", + "legendFormat": "P bound min" + }, + { + "refId": "I", + "expr": "(max_over_time(max without (job,instance,pod,service,endpoint,namespace) (typhon_vpd_kpa != 0)[$__range]) + 0.15)", + "legendFormat": "P bound max" } ], "fieldConfig": { @@ -1421,6 +1795,53 @@ data: } ] }, + { + "matcher": { + "id": "byRegexp", + "options": "C bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:\u00b0C" + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] + }, { "matcher": { "id": "byName", @@ -1445,6 +1866,53 @@ data: } ] }, + { + "matcher": { + "id": "byRegexp", + "options": "RH bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:%" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] + }, { "matcher": { "id": "byName", @@ -1468,6 +1936,53 @@ data: "value": false } ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "P bound .*" + }, + "properties": [ + { + "id": "unit", + "value": "suffix:kPa" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisCenteredZero", + "value": false + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.showPoints", + "value": "never" + }, + { + "id": "color", + "value": { + "mode": "fixed", + "fixedColor": "transparent" + } + } + ] } ] }, @@ -1487,7 +2002,7 @@ data: "targetBlank": true } ], - "description": "Temperature on left axis, humidity and pressure on right axis." + "description": "Temperature on left axis, humidity and pressure on right axis with dynamic bound series so small swings remain visible." }, { "id": 140,