From 69a02a335257751c65d1662d554fc42f2ba50b50 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Fri, 3 Apr 2026 20:45:40 -0300 Subject: [PATCH] monitoring(power): implement six-panel UPS and climate layout --- scripts/dashboards_render_atlas.py | 397 +++---- .../monitoring/dashboards/atlas-overview.json | 2 +- .../monitoring/dashboards/atlas-power.json | 983 +++++++----------- .../grafana-dashboard-overview.yaml | 2 +- .../monitoring/grafana-dashboard-power.yaml | 983 +++++++----------- 5 files changed, 915 insertions(+), 1452 deletions(-) diff --git a/scripts/dashboards_render_atlas.py b/scripts/dashboards_render_atlas.py index 0f51403a..4167d576 100644 --- a/scripts/dashboards_render_atlas.py +++ b/scripts/dashboards_render_atlas.py @@ -464,15 +464,75 @@ HECATE_UPS_LOAD_DB = ( HECATE_UPS_LOAD_TETHYS = ( f'max(hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-24"}}) or on() vector(0)' ) +HECATE_UPS_DRAW_WATTS_DB = ( + f'max((hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-db"}} ' + f'* hecate_ups_power_nominal_watts{{{HECATE_SELECTOR},instance="titan-db"}}) / 100) or on() vector(0)' +) +HECATE_UPS_DRAW_WATTS_TETHYS = ( + f'max((hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-24"}} ' + f'* hecate_ups_power_nominal_watts{{{HECATE_SELECTOR},instance="titan-24"}}) / 100) or on() vector(0)' +) +HECATE_UPS_DRAW_WATTS_TOTAL = ( + f'sum((hecate_ups_load_percent{{{HECATE_SELECTOR}}} * hecate_ups_power_nominal_watts{{{HECATE_SELECTOR}}}) / 100) ' + "or on() vector(0)" +) +HECATE_UPS_DRAW_WATTS_DB_SERIES = ( + f'((hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-db"}} ' + f'* hecate_ups_power_nominal_watts{{{HECATE_SELECTOR},instance="titan-db"}}) / 100)' +) +HECATE_UPS_DRAW_WATTS_TETHYS_SERIES = ( + f'((hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-24"}} ' + f'* hecate_ups_power_nominal_watts{{{HECATE_SELECTOR},instance="titan-24"}}) / 100)' +) +HECATE_UPS_DRAW_WATTS_TOTAL_SERIES = ( + f'sum((hecate_ups_load_percent{{{HECATE_SELECTOR}}} * hecate_ups_power_nominal_watts{{{HECATE_SELECTOR}}}) / 100)' +) HECATE_UPS_RUNTIME_BY_SOURCE = f"hecate_ups_runtime_seconds{{{HECATE_SELECTOR}}}" HECATE_UPS_LOAD_BY_SOURCE = f"hecate_ups_load_percent{{{HECATE_SELECTOR}}}" HECATE_UPS_CHARGE_BY_SOURCE = f"hecate_ups_battery_charge_percent{{{HECATE_SELECTOR}}}" HECATE_UPS_TRIGGER_BY_SOURCE = f"hecate_ups_trigger_active{{{HECATE_SELECTOR}}}" CLIMATE_SENSOR_COUNT = "count(atlas_climate_temperature_celsius) or on() vector(0)" -CLIMATE_TEMP_MAX = "max(atlas_climate_temperature_celsius) or on() vector(0)" +CLIMATE_TEMP_MAX = "max(atlas_climate_tent_temperature_celsius) or max(atlas_climate_temperature_celsius) or on() vector(0)" +CLIMATE_PRESSURE_CURRENT = "max(atlas_climate_tent_pressure_kpa) or max(atlas_climate_pressure_kpa) or on() vector(0)" CLIMATE_HUMIDITY_MAX = "max(atlas_climate_humidity_percent) or on() vector(0)" -CLIMATE_TEMP_SERIES = "atlas_climate_temperature_celsius" -CLIMATE_FAN_SERIES = "atlas_climate_fan_rpm" +CLIMATE_TEMP_SERIES = "(atlas_climate_tent_temperature_celsius or atlas_climate_temperature_celsius)" +CLIMATE_PRESSURE_SERIES = "(atlas_climate_tent_pressure_kpa or atlas_climate_pressure_kpa)" +CLIMATE_FAN_OUTLET_CURRENT = ( + 'max(atlas_climate_fan_activity_level{fan_group="outlet"}) ' + 'or max(atlas_climate_fan_activity_level{position="outlet"}) ' + "or on() vector(0)" +) +CLIMATE_FAN_INSIDE_INLET_CURRENT = ( + 'max(atlas_climate_fan_activity_level{fan_group="inside_inlet"}) ' + 'or max(atlas_climate_fan_activity_level{position="inside_inlet"}) ' + "or on() vector(0)" +) +CLIMATE_FAN_OUTSIDE_INLET_CURRENT = ( + 'max(atlas_climate_fan_activity_level{fan_group="outside_inlet"}) ' + 'or max(atlas_climate_fan_activity_level{position="outside_inlet"}) ' + "or on() vector(0)" +) +CLIMATE_FAN_INTERIOR_CURRENT = ( + 'max(atlas_climate_fan_activity_level{fan_group="interior"}) ' + 'or max(atlas_climate_fan_activity_level{position="interior"}) ' + "or on() vector(0)" +) +CLIMATE_FAN_OUTLET_SERIES = ( + '(atlas_climate_fan_activity_level{fan_group="outlet"} ' + 'or atlas_climate_fan_activity_level{position="outlet"})' +) +CLIMATE_FAN_INSIDE_INLET_SERIES = ( + '(atlas_climate_fan_activity_level{fan_group="inside_inlet"} ' + 'or atlas_climate_fan_activity_level{position="inside_inlet"})' +) +CLIMATE_FAN_OUTSIDE_INLET_SERIES = ( + '(atlas_climate_fan_activity_level{fan_group="outside_inlet"} ' + 'or atlas_climate_fan_activity_level{position="outside_inlet"})' +) +CLIMATE_FAN_INTERIOR_SERIES = ( + '(atlas_climate_fan_activity_level{fan_group="interior"} ' + 'or atlas_climate_fan_activity_level{position="interior"})' +) POSTGRES_CONN_USED = ( 'label_replace(sum(pg_stat_activity_count), "conn", "used", "__name__", ".*") ' 'or label_replace(max(pg_settings_max_connections), "conn", "max", "__name__", ".*")' @@ -572,6 +632,9 @@ def stat_panel( instant=False, value_suffix=None, links=None, + targets=None, + field_overrides=None, + description=None, ): """Return a Grafana stat panel definition.""" defaults = { @@ -592,14 +655,16 @@ def stat_panel( defaults["custom"]["valueSuffix"] = value_suffix if decimals is not None: defaults["decimals"] = decimals + target_list = targets if targets is not None else [{"expr": expr, "refId": "A"}] + panel = { "id": panel_id, "type": "stat", "title": title, "datasource": PROM_DS, "gridPos": grid, - "targets": [{"expr": expr, "refId": "A"}], - "fieldConfig": {"defaults": defaults, "overrides": []}, + "targets": target_list, + "fieldConfig": {"defaults": defaults, "overrides": field_overrides or []}, "options": { "colorMode": "value", "graphMode": "area", @@ -608,12 +673,15 @@ def stat_panel( "textMode": text_mode, }, } - if legend: + if legend and len(panel["targets"]) == 1: panel["targets"][0]["legendFormat"] = legend if instant: - panel["targets"][0]["instant"] = True + for t in panel["targets"]: + t.setdefault("instant", True) if links: panel["links"] = links + if description: + panel["description"] = description return panel @@ -674,16 +742,20 @@ def timeseries_panel( legend_calcs=None, time_from=None, links=None, + targets=None, + field_overrides=None, + description=None, ): """Return a Grafana time-series panel definition.""" + target_list = targets if targets is not None else [{"expr": expr, "refId": "A"}] panel = { "id": panel_id, "type": "timeseries", "title": title, "datasource": PROM_DS, "gridPos": grid, - "targets": [{"expr": expr, "refId": "A"}], - "fieldConfig": {"defaults": {"unit": unit}, "overrides": []}, + "targets": target_list, + "fieldConfig": {"defaults": {"unit": unit}, "overrides": field_overrides or []}, "options": { "legend": { "displayMode": legend_display, @@ -694,7 +766,7 @@ def timeseries_panel( } if max_value is not None: panel["fieldConfig"]["defaults"]["max"] = max_value - if legend: + if legend and len(panel["targets"]) == 1: panel["targets"][0]["legendFormat"] = legend if legend_calcs: panel["options"]["legend"]["calcs"] = legend_calcs @@ -702,6 +774,8 @@ def timeseries_panel( panel["timeFrom"] = time_from if links: panel["links"] = links + if description: + panel["description"] = description return panel @@ -2777,222 +2851,161 @@ def build_jobs_dashboard(): def build_power_dashboard(): panels = [] - on_battery_thresholds = { - "mode": "absolute", - "steps": [ - {"color": "green", "value": None}, - {"color": "red", "value": 1}, - ], - } - runtime_thresholds = { - "mode": "absolute", - "steps": [ - {"color": "red", "value": None}, - {"color": "orange", "value": 600}, - {"color": "yellow", "value": 1200}, - {"color": "green", "value": 1800}, - ], - } - charge_thresholds = { - "mode": "absolute", - "steps": [ - {"color": "red", "value": None}, - {"color": "orange", "value": 25}, - {"color": "yellow", "value": 45}, - {"color": "green", "value": 65}, - ], - } - load_thresholds = { - "mode": "absolute", - "steps": [ - {"color": "green", "value": None}, - {"color": "yellow", "value": 55}, - {"color": "orange", "value": 75}, - {"color": "red", "value": 90}, - ], - } + status_mapping = [ + { + "type": "value", + "options": { + "0": {"text": "⚡ Charging"}, + "1": {"text": "🔋 Discharging"}, + }, + } + ] panels.append( stat_panel( 1, - "titan-db UPS Status (On Battery)", - HECATE_UPS_ON_BATTERY_DB, - {"h": 4, "w": 6, "x": 0, "y": 0}, + "UPS Current Load", + None, + {"h": 8, "w": 12, "x": 0, "y": 0}, unit="none", - instant=True, - thresholds=on_battery_thresholds, + decimals=1, + text_mode="name_and_value", + targets=[ + {"refId": "A", "expr": HECATE_UPS_DRAW_WATTS_DB, "legendFormat": "titan-db Draw (W)", "instant": True}, + {"refId": "B", "expr": HECATE_UPS_RUNTIME_DB, "legendFormat": "titan-db Discharge ETA", "instant": True}, + {"refId": "C", "expr": HECATE_UPS_ON_BATTERY_DB, "legendFormat": "titan-db Status", "instant": True}, + {"refId": "D", "expr": HECATE_UPS_DRAW_WATTS_TETHYS, "legendFormat": "tethys Draw (W)", "instant": True}, + {"refId": "E", "expr": HECATE_UPS_RUNTIME_TETHYS, "legendFormat": "tethys Discharge ETA", "instant": True}, + {"refId": "F", "expr": HECATE_UPS_ON_BATTERY_TETHYS, "legendFormat": "tethys Status", "instant": True}, + ], + field_overrides=[ + {"matcher": {"id": "byName", "options": "titan-db Draw (W)"}, "properties": [{"id": "unit", "value": "watt"}]}, + {"matcher": {"id": "byName", "options": "tethys Draw (W)"}, "properties": [{"id": "unit", "value": "watt"}]}, + {"matcher": {"id": "byName", "options": "titan-db Discharge ETA"}, "properties": [{"id": "unit", "value": "s"}]}, + {"matcher": {"id": "byName", "options": "tethys Discharge ETA"}, "properties": [{"id": "unit", "value": "s"}]}, + { + "matcher": {"id": "byName", "options": "titan-db Status"}, + "properties": [{"id": "mappings", "value": status_mapping}], + }, + { + "matcher": {"id": "byName", "options": "tethys Status"}, + "properties": [{"id": "mappings", "value": status_mapping}], + }, + ], + description=( + "Per-UPS live snapshot: current draw in watts, estimated battery runtime if discharge started now, and charging/discharging status." + ), ) ) panels.append( - stat_panel( + timeseries_panel( 2, - "tethys UPS Status (On Battery)", - HECATE_UPS_ON_BATTERY_TETHYS, - {"h": 4, "w": 6, "x": 6, "y": 0}, - unit="none", - instant=True, - thresholds=on_battery_thresholds, + "UPS History (Power Draw)", + None, + {"h": 8, "w": 12, "x": 12, "y": 0}, + unit="watt", + targets=[ + {"refId": "A", "expr": HECATE_UPS_DRAW_WATTS_DB_SERIES, "legendFormat": "titan-db"}, + {"refId": "B", "expr": HECATE_UPS_DRAW_WATTS_TETHYS_SERIES, "legendFormat": "tethys"}, + {"refId": "C", "expr": HECATE_UPS_DRAW_WATTS_TOTAL_SERIES, "legendFormat": "combined"}, + ], + legend_display="table", + legend_placement="right", + description="Historical UPS power consumption in watts for titan-db, tethys, and combined load.", ) ) panels.append( stat_panel( 3, - "titan-db Runtime Remaining", - HECATE_UPS_RUNTIME_DB, - {"h": 4, "w": 6, "x": 12, "y": 0}, - unit="s", - decimals=0, - instant=True, - thresholds=runtime_thresholds, + "Current Climate", + None, + {"h": 8, "w": 12, "x": 0, "y": 8}, + unit="none", + decimals=2, + text_mode="name_and_value", + targets=[ + {"refId": "A", "expr": CLIMATE_TEMP_MAX, "legendFormat": "Tent Temp (°C)", "instant": True}, + {"refId": "B", "expr": CLIMATE_PRESSURE_CURRENT, "legendFormat": "Tent Pressure (kPa)", "instant": True}, + ], + field_overrides=[ + {"matcher": {"id": "byName", "options": "Tent Temp (°C)"}, "properties": [{"id": "unit", "value": "celsius"}]}, + {"matcher": {"id": "byName", "options": "Tent Pressure (kPa)"}, "properties": [{"id": "unit", "value": "none"}]}, + ], + description="Current tent temperature and air pressure. These render once climate telemetry is online.", ) ) panels.append( - stat_panel( + timeseries_panel( 4, - "tethys Runtime Remaining", - HECATE_UPS_RUNTIME_TETHYS, - {"h": 4, "w": 6, "x": 18, "y": 0}, - unit="s", - decimals=0, - instant=True, - thresholds=runtime_thresholds, + "Climate History", + None, + {"h": 8, "w": 12, "x": 12, "y": 8}, + unit="celsius", + targets=[ + {"refId": "A", "expr": CLIMATE_TEMP_SERIES, "legendFormat": "Temperature (°C)"}, + {"refId": "B", "expr": CLIMATE_PRESSURE_SERIES, "legendFormat": "Pressure (kPa)"}, + ], + field_overrides=[ + { + "matcher": {"id": "byName", "options": "Pressure (kPa)"}, + "properties": [ + {"id": "unit", "value": "none"}, + {"id": "custom.axisPlacement", "value": "right"}, + {"id": "custom.axisLabel", "value": "kPa"}, + {"id": "decimals", "value": 2}, + ], + } + ], + legend_display="table", + legend_placement="right", + description="Two-axis chart: tent temperature (left axis) and tent pressure in kPa (right axis).", ) ) panels.append( stat_panel( 5, - "titan-db Battery Charge", - HECATE_UPS_BATTERY_CHARGE_DB, - {"h": 4, "w": 6, "x": 0, "y": 4}, - unit="percent", - decimals=1, - instant=True, - thresholds=charge_thresholds, - ) - ) - panels.append( - stat_panel( - 6, - "tethys Battery Charge", - HECATE_UPS_BATTERY_CHARGE_TETHYS, - {"h": 4, "w": 6, "x": 6, "y": 4}, - unit="percent", - decimals=1, - instant=True, - thresholds=charge_thresholds, - ) - ) - panels.append( - stat_panel( - 7, - "titan-db UPS Load", - HECATE_UPS_LOAD_DB, - {"h": 4, "w": 6, "x": 12, "y": 4}, - unit="percent", - decimals=1, - instant=True, - thresholds=load_thresholds, - ) - ) - panels.append( - stat_panel( - 8, - "tethys UPS Load", - HECATE_UPS_LOAD_TETHYS, - {"h": 4, "w": 6, "x": 18, "y": 4}, - unit="percent", - decimals=1, - instant=True, - thresholds=load_thresholds, - ) - ) - panels.append( - timeseries_panel( - 9, - "UPS Runtime by Source", - HECATE_UPS_RUNTIME_BY_SOURCE, - {"h": 8, "w": 12, "x": 0, "y": 8}, - unit="s", - legend="{{instance}}/{{source}}", - legend_display="table", - legend_placement="right", - ) - ) - panels.append( - timeseries_panel( - 10, - "UPS Load % by Source", - HECATE_UPS_LOAD_BY_SOURCE, - {"h": 8, "w": 12, "x": 12, "y": 8}, - unit="percent", - legend="{{instance}}/{{source}}", - legend_display="table", - legend_placement="right", - ) - ) - panels.append( - timeseries_panel( - 11, - "UPS Battery Charge % by Source", - HECATE_UPS_CHARGE_BY_SOURCE, + "Fan Activity", + None, {"h": 8, "w": 12, "x": 0, "y": 16}, - unit="percent", - legend="{{instance}}/{{source}}", - legend_display="table", - legend_placement="right", + unit="none", + decimals=1, + text_mode="name_and_value", + targets=[ + {"refId": "A", "expr": CLIMATE_FAN_OUTLET_CURRENT, "legendFormat": "Outlet", "instant": True}, + {"refId": "B", "expr": CLIMATE_FAN_INSIDE_INLET_CURRENT, "legendFormat": "Inside Inlet", "instant": True}, + {"refId": "C", "expr": CLIMATE_FAN_OUTSIDE_INLET_CURRENT, "legendFormat": "Outside Inlet", "instant": True}, + {"refId": "D", "expr": CLIMATE_FAN_INTERIOR_CURRENT, "legendFormat": "Interior", "instant": True}, + ], + thresholds={ + "mode": "absolute", + "steps": [ + {"color": "green", "value": None}, + {"color": "yellow", "value": 7}, + {"color": "red", "value": 9}, + ], + }, + description="Current fan activity levels (0-10): outlet, inside inlet, outside inlet, and interior.", ) ) panels.append( timeseries_panel( - 12, - "UPS Trigger Activity by Source", - HECATE_UPS_TRIGGER_BY_SOURCE, + 6, + "Fan History (0-10)", + None, {"h": 8, "w": 12, "x": 12, "y": 16}, unit="none", - legend="{{instance}}/{{source}}", + max_value=10, + targets=[ + {"refId": "A", "expr": CLIMATE_FAN_OUTLET_SERIES, "legendFormat": "Outlet"}, + {"refId": "B", "expr": CLIMATE_FAN_INSIDE_INLET_SERIES, "legendFormat": "Inside Inlet"}, + {"refId": "C", "expr": CLIMATE_FAN_OUTSIDE_INLET_SERIES, "legendFormat": "Outside Inlet"}, + {"refId": "D", "expr": CLIMATE_FAN_INTERIOR_SERIES, "legendFormat": "Interior"}, + ], legend_display="table", legend_placement="right", + description="Historical fan activity for all four fan groups (0-10 scale).", ) ) - climate_temp_panel = timeseries_panel( - 13, - "Climate Temperature Over Time", - CLIMATE_TEMP_SERIES, - {"h": 8, "w": 12, "x": 0, "y": 24}, - unit="celsius", - legend="{{sensor}}", - legend_display="table", - legend_placement="right", - ) - climate_temp_panel["description"] = ( - "Future climate collector panel: temperature probes (inside inlet, outside inlet, outlet, interior)." - ) - panels.append(climate_temp_panel) - climate_fan_panel = timeseries_panel( - 14, - "Climate Fan Speed Over Time", - CLIMATE_FAN_SERIES, - {"h": 8, "w": 12, "x": 12, "y": 24}, - unit="rpm", - legend="{{position}}", - legend_display="table", - legend_placement="right", - ) - climate_fan_panel["description"] = ( - "Future climate collector panel: fan RPM by position (inside inlet, outside inlet, outlet, interior)." - ) - panels.append(climate_fan_panel) - status_panel = table_panel( - 15, - "UPS Status Snapshot (OL/OB/LB)", - f"max by (instance, source, status, target) ({HECATE_UPS_RUNTIME_BY_SOURCE})", - {"h": 6, "w": 24, "x": 0, "y": 32}, - unit="s", - transformations=[{"id": "labelsToFields", "options": {}}, {"id": "sortBy", "options": {"fields": ["instance"], "order": "asc"}}], - instant=True, - ) - status_panel["description"] = "NUT status flags: OL=on line (utility), OB=on battery, LB=low battery." - panels.append(status_panel) return { "uid": "atlas-power", diff --git a/services/monitoring/dashboards/atlas-overview.json b/services/monitoring/dashboards/atlas-overview.json index 2960bff4..16fa81f6 100644 --- a/services/monitoring/dashboards/atlas-overview.json +++ b/services/monitoring/dashboards/atlas-overview.json @@ -1311,7 +1311,7 @@ }, "targets": [ { - "expr": "max(atlas_climate_temperature_celsius) or on() vector(0)", + "expr": "max(atlas_climate_tent_temperature_celsius) or max(atlas_climate_temperature_celsius) or on() vector(0)", "refId": "A" } ], diff --git a/services/monitoring/dashboards/atlas-power.json b/services/monitoring/dashboards/atlas-power.json index dc02d35c..ac5706ff 100644 --- a/services/monitoring/dashboards/atlas-power.json +++ b/services/monitoring/dashboards/atlas-power.json @@ -7,21 +7,52 @@ { "id": 1, "type": "stat", - "title": "titan-db UPS Status (On Battery)", + "title": "UPS Current Load", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, + "h": 8, + "w": 12, "x": 0, "y": 0 }, "targets": [ { - "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", "refId": "A", + "expr": "max((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-db\"}) / 100) or on() vector(0)", + "legendFormat": "titan-db Draw (W)", + "instant": true + }, + { + "refId": "B", + "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", + "legendFormat": "titan-db Discharge ETA", + "instant": true + }, + { + "refId": "C", + "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", + "legendFormat": "titan-db Status", + "instant": true + }, + { + "refId": "D", + "expr": "max((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-24\"}) / 100) or on() vector(0)", + "legendFormat": "tethys Draw (W)", + "instant": true + }, + { + "refId": "E", + "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", + "legendFormat": "tethys Discharge ETA", + "instant": true + }, + { + "refId": "F", + "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", + "legendFormat": "tethys Status", "instant": true } ], @@ -35,11 +66,11 @@ "mode": "absolute", "steps": [ { - "color": "green", + "color": "rgba(115, 115, 115, 1)", "value": null }, { - "color": "red", + "color": "green", "value": 1 } ] @@ -47,9 +78,107 @@ "unit": "none", "custom": { "displayMode": "auto" - } + }, + "decimals": 1 }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "titan-db Draw (W)" + }, + "properties": [ + { + "id": "unit", + "value": "watt" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Draw (W)" + }, + "properties": [ + { + "id": "unit", + "value": "watt" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "titan-db Discharge ETA" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Discharge ETA" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "titan-db Status" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "0": { + "text": "\u26a1 Charging" + }, + "1": { + "text": "\ud83d\udd0b Discharging" + } + } + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Status" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "0": { + "text": "\u26a1 Charging" + }, + "1": { + "text": "\ud83d\udd0b Discharging" + } + } + } + ] + } + ] + } + ] }, "options": { "colorMode": "value", @@ -62,88 +191,83 @@ "fields": "", "values": false }, - "textMode": "value" - } + "textMode": "name_and_value" + }, + "description": "Per-UPS live snapshot: current draw in watts, estimated battery runtime if discharge started now, and charging/discharging status." }, { "id": 2, - "type": "stat", - "title": "tethys UPS Status (On Battery)", + "type": "timeseries", + "title": "UPS History (Power Draw)", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, - "x": 6, + "h": 8, + "w": 12, + "x": 12, "y": 0 }, "targets": [ { - "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", "refId": "A", - "instant": true + "expr": "((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-db\"}) / 100)", + "legendFormat": "titan-db" + }, + { + "refId": "B", + "expr": "((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-24\"}) / 100)", + "legendFormat": "tethys" + }, + { + "refId": "C", + "expr": "sum((hecate_ups_load_percent{job=\"hecate-power\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\"}) / 100)", + "legendFormat": "combined" } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 1 - } - ] - }, - "unit": "none", - "custom": { - "displayMode": "auto" - } + "unit": "watt" }, "overrides": [] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "legend": { + "displayMode": "table", + "placement": "right" }, - "textMode": "value" - } + "tooltip": { + "mode": "multi" + } + }, + "description": "Historical UPS power consumption in watts for titan-db, tethys, and combined load." }, { "id": 3, "type": "stat", - "title": "titan-db Runtime Remaining", + "title": "Current Climate", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 0 + "h": 8, + "w": 12, + "x": 0, + "y": 8 }, "targets": [ { - "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", "refId": "A", + "expr": "max(atlas_climate_tent_temperature_celsius) or max(atlas_climate_temperature_celsius) or on() vector(0)", + "legendFormat": "Tent Temp (\u00b0C)", + "instant": true + }, + { + "refId": "B", + "expr": "max(atlas_climate_tent_pressure_kpa) or max(atlas_climate_pressure_kpa) or on() vector(0)", + "legendFormat": "Tent Pressure (kPa)", "instant": true } ], @@ -157,30 +281,47 @@ "mode": "absolute", "steps": [ { - "color": "red", + "color": "rgba(115, 115, 115, 1)", "value": null }, - { - "color": "orange", - "value": 600 - }, - { - "color": "yellow", - "value": 1200 - }, { "color": "green", - "value": 1800 + "value": 1 } ] }, - "unit": "s", + "unit": "none", "custom": { "displayMode": "auto" }, - "decimals": 0 + "decimals": 2 }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Tent Temp (\u00b0C)" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Tent Pressure (kPa)" + }, + "properties": [ + { + "id": "unit", + "value": "none" + } + ] + } + ] }, "options": { "colorMode": "value", @@ -193,400 +334,14 @@ "fields": "", "values": false }, - "textMode": "value" - } + "textMode": "name_and_value" + }, + "description": "Current tent temperature and air pressure. These render once climate telemetry is online." }, { "id": 4, - "type": "stat", - "title": "tethys Runtime Remaining", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 0 - }, - "targets": [ - { - "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 600 - }, - { - "color": "yellow", - "value": 1200 - }, - { - "color": "green", - "value": 1800 - } - ] - }, - "unit": "s", - "custom": { - "displayMode": "auto" - }, - "decimals": 0 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 5, - "type": "stat", - "title": "titan-db Battery Charge", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_battery_charge_percent{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 25 - }, - { - "color": "yellow", - "value": 45 - }, - { - "color": "green", - "value": 65 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 6, - "type": "stat", - "title": "tethys Battery Charge", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_battery_charge_percent{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 25 - }, - { - "color": "yellow", - "value": 45 - }, - { - "color": "green", - "value": 65 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 7, - "type": "stat", - "title": "titan-db UPS Load", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 55 - }, - { - "color": "orange", - "value": 75 - }, - { - "color": "red", - "value": 90 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 8, - "type": "stat", - "title": "tethys UPS Load", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 55 - }, - { - "color": "orange", - "value": 75 - }, - { - "color": "red", - "value": 90 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 9, "type": "timeseries", - "title": "UPS Runtime by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 8 - }, - "targets": [ - { - "expr": "hecate_ups_runtime_seconds{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "s" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 10, - "type": "timeseries", - "title": "UPS Load % by Source", + "title": "Climate History", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -599,127 +354,46 @@ }, "targets": [ { - "expr": "hecate_ups_load_percent{job=\"hecate-power\"}", "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "percent" + "expr": "(atlas_climate_tent_temperature_celsius or atlas_climate_temperature_celsius)", + "legendFormat": "Temperature (\u00b0C)" }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 11, - "type": "timeseries", - "title": "UPS Battery Charge % by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 16 - }, - "targets": [ { - "expr": "hecate_ups_battery_charge_percent{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "percent" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 12, - "type": "timeseries", - "title": "UPS Trigger Activity by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 16 - }, - "targets": [ - { - "expr": "hecate_ups_trigger_active{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "none" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 13, - "type": "timeseries", - "title": "Climate Temperature Over Time", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 24 - }, - "targets": [ - { - "expr": "atlas_climate_temperature_celsius", - "refId": "A", - "legendFormat": "{{sensor}}" + "refId": "B", + "expr": "(atlas_climate_tent_pressure_kpa or atlas_climate_pressure_kpa)", + "legendFormat": "Pressure (kPa)" } ], "fieldConfig": { "defaults": { "unit": "celsius" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Pressure (kPa)" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "kPa" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] }, "options": { "legend": { @@ -730,12 +404,98 @@ "mode": "multi" } }, - "description": "Future climate collector panel: temperature probes (inside inlet, outside inlet, outlet, interior)." + "description": "Two-axis chart: tent temperature (left axis) and tent pressure in kPa (right axis)." }, { - "id": 14, + "id": 5, + "type": "stat", + "title": "Fan Activity", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "targets": [ + { + "refId": "A", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"outlet\"}) or max(atlas_climate_fan_activity_level{position=\"outlet\"}) or on() vector(0)", + "legendFormat": "Outlet", + "instant": true + }, + { + "refId": "B", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"inside_inlet\"}) or max(atlas_climate_fan_activity_level{position=\"inside_inlet\"}) or on() vector(0)", + "legendFormat": "Inside Inlet", + "instant": true + }, + { + "refId": "C", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"outside_inlet\"}) or max(atlas_climate_fan_activity_level{position=\"outside_inlet\"}) or on() vector(0)", + "legendFormat": "Outside Inlet", + "instant": true + }, + { + "refId": "D", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"interior\"}) or max(atlas_climate_fan_activity_level{position=\"interior\"}) or on() vector(0)", + "legendFormat": "Interior", + "instant": true + } + ], + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 7 + }, + { + "color": "red", + "value": 9 + } + ] + }, + "unit": "none", + "custom": { + "displayMode": "auto" + }, + "decimals": 1 + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name_and_value" + }, + "description": "Current fan activity levels (0-10): outlet, inside inlet, outside inlet, and interior." + }, + { + "id": 6, "type": "timeseries", - "title": "Climate Fan Speed Over Time", + "title": "Fan History (0-10)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -744,18 +504,34 @@ "h": 8, "w": 12, "x": 12, - "y": 24 + "y": 16 }, "targets": [ { - "expr": "atlas_climate_fan_rpm", "refId": "A", - "legendFormat": "{{position}}" + "expr": "(atlas_climate_fan_activity_level{fan_group=\"outlet\"} or atlas_climate_fan_activity_level{position=\"outlet\"})", + "legendFormat": "Outlet" + }, + { + "refId": "B", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"inside_inlet\"} or atlas_climate_fan_activity_level{position=\"inside_inlet\"})", + "legendFormat": "Inside Inlet" + }, + { + "refId": "C", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"outside_inlet\"} or atlas_climate_fan_activity_level{position=\"outside_inlet\"})", + "legendFormat": "Outside Inlet" + }, + { + "refId": "D", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"interior\"} or atlas_climate_fan_activity_level{position=\"interior\"})", + "legendFormat": "Interior" } ], "fieldConfig": { "defaults": { - "unit": "rpm" + "unit": "none", + "max": 10 }, "overrides": [] }, @@ -768,58 +544,7 @@ "mode": "multi" } }, - "description": "Future climate collector panel: fan RPM by position (inside inlet, outside inlet, outlet, interior)." - }, - { - "id": 15, - "type": "table", - "title": "UPS Status Snapshot (OL/OB/LB)", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 32 - }, - "targets": [ - { - "expr": "max by (instance, source, status, target) (hecate_ups_runtime_seconds{job=\"hecate-power\"})", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "unit": "s", - "custom": { - "filterable": true - } - }, - "overrides": [] - }, - "options": { - "showHeader": true, - "columnFilters": false - }, - "transformations": [ - { - "id": "labelsToFields", - "options": {} - }, - { - "id": "sortBy", - "options": { - "fields": [ - "instance" - ], - "order": "asc" - } - } - ], - "description": "NUT status flags: OL=on line (utility), OB=on battery, LB=low battery." + "description": "Historical fan activity for all four fan groups (0-10 scale)." } ], "time": { diff --git a/services/monitoring/grafana-dashboard-overview.yaml b/services/monitoring/grafana-dashboard-overview.yaml index 7c90947f..7c8e0b2b 100644 --- a/services/monitoring/grafana-dashboard-overview.yaml +++ b/services/monitoring/grafana-dashboard-overview.yaml @@ -1320,7 +1320,7 @@ data: }, "targets": [ { - "expr": "max(atlas_climate_temperature_celsius) or on() vector(0)", + "expr": "max(atlas_climate_tent_temperature_celsius) or max(atlas_climate_temperature_celsius) or on() vector(0)", "refId": "A" } ], diff --git a/services/monitoring/grafana-dashboard-power.yaml b/services/monitoring/grafana-dashboard-power.yaml index c2a770fe..9b025ef0 100644 --- a/services/monitoring/grafana-dashboard-power.yaml +++ b/services/monitoring/grafana-dashboard-power.yaml @@ -16,21 +16,52 @@ data: { "id": 1, "type": "stat", - "title": "titan-db UPS Status (On Battery)", + "title": "UPS Current Load", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, + "h": 8, + "w": 12, "x": 0, "y": 0 }, "targets": [ { - "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", "refId": "A", + "expr": "max((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-db\"}) / 100) or on() vector(0)", + "legendFormat": "titan-db Draw (W)", + "instant": true + }, + { + "refId": "B", + "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", + "legendFormat": "titan-db Discharge ETA", + "instant": true + }, + { + "refId": "C", + "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", + "legendFormat": "titan-db Status", + "instant": true + }, + { + "refId": "D", + "expr": "max((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-24\"}) / 100) or on() vector(0)", + "legendFormat": "tethys Draw (W)", + "instant": true + }, + { + "refId": "E", + "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", + "legendFormat": "tethys Discharge ETA", + "instant": true + }, + { + "refId": "F", + "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", + "legendFormat": "tethys Status", "instant": true } ], @@ -44,11 +75,11 @@ data: "mode": "absolute", "steps": [ { - "color": "green", + "color": "rgba(115, 115, 115, 1)", "value": null }, { - "color": "red", + "color": "green", "value": 1 } ] @@ -56,9 +87,107 @@ data: "unit": "none", "custom": { "displayMode": "auto" - } + }, + "decimals": 1 }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "titan-db Draw (W)" + }, + "properties": [ + { + "id": "unit", + "value": "watt" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Draw (W)" + }, + "properties": [ + { + "id": "unit", + "value": "watt" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "titan-db Discharge ETA" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Discharge ETA" + }, + "properties": [ + { + "id": "unit", + "value": "s" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "titan-db Status" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "0": { + "text": "\u26a1 Charging" + }, + "1": { + "text": "\ud83d\udd0b Discharging" + } + } + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tethys Status" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "0": { + "text": "\u26a1 Charging" + }, + "1": { + "text": "\ud83d\udd0b Discharging" + } + } + } + ] + } + ] + } + ] }, "options": { "colorMode": "value", @@ -71,88 +200,83 @@ data: "fields": "", "values": false }, - "textMode": "value" - } + "textMode": "name_and_value" + }, + "description": "Per-UPS live snapshot: current draw in watts, estimated battery runtime if discharge started now, and charging/discharging status." }, { "id": 2, - "type": "stat", - "title": "tethys UPS Status (On Battery)", + "type": "timeseries", + "title": "UPS History (Power Draw)", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, - "x": 6, + "h": 8, + "w": 12, + "x": 12, "y": 0 }, "targets": [ { - "expr": "max(hecate_ups_on_battery{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", "refId": "A", - "instant": true + "expr": "((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-db\"}) / 100)", + "legendFormat": "titan-db" + }, + { + "refId": "B", + "expr": "((hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\",instance=\"titan-24\"}) / 100)", + "legendFormat": "tethys" + }, + { + "refId": "C", + "expr": "sum((hecate_ups_load_percent{job=\"hecate-power\"} * hecate_ups_power_nominal_watts{job=\"hecate-power\"}) / 100)", + "legendFormat": "combined" } ], "fieldConfig": { "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 1 - } - ] - }, - "unit": "none", - "custom": { - "displayMode": "auto" - } + "unit": "watt" }, "overrides": [] }, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "legend": { + "displayMode": "table", + "placement": "right" }, - "textMode": "value" - } + "tooltip": { + "mode": "multi" + } + }, + "description": "Historical UPS power consumption in watts for titan-db, tethys, and combined load." }, { "id": 3, "type": "stat", - "title": "titan-db Runtime Remaining", + "title": "Current Climate", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 0 + "h": 8, + "w": 12, + "x": 0, + "y": 8 }, "targets": [ { - "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", "refId": "A", + "expr": "max(atlas_climate_tent_temperature_celsius) or max(atlas_climate_temperature_celsius) or on() vector(0)", + "legendFormat": "Tent Temp (\u00b0C)", + "instant": true + }, + { + "refId": "B", + "expr": "max(atlas_climate_tent_pressure_kpa) or max(atlas_climate_pressure_kpa) or on() vector(0)", + "legendFormat": "Tent Pressure (kPa)", "instant": true } ], @@ -166,30 +290,47 @@ data: "mode": "absolute", "steps": [ { - "color": "red", + "color": "rgba(115, 115, 115, 1)", "value": null }, - { - "color": "orange", - "value": 600 - }, - { - "color": "yellow", - "value": 1200 - }, { "color": "green", - "value": 1800 + "value": 1 } ] }, - "unit": "s", + "unit": "none", "custom": { "displayMode": "auto" }, - "decimals": 0 + "decimals": 2 }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Tent Temp (\u00b0C)" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Tent Pressure (kPa)" + }, + "properties": [ + { + "id": "unit", + "value": "none" + } + ] + } + ] }, "options": { "colorMode": "value", @@ -202,400 +343,14 @@ data: "fields": "", "values": false }, - "textMode": "value" - } + "textMode": "name_and_value" + }, + "description": "Current tent temperature and air pressure. These render once climate telemetry is online." }, { "id": 4, - "type": "stat", - "title": "tethys Runtime Remaining", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 0 - }, - "targets": [ - { - "expr": "max(hecate_ups_runtime_seconds{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 600 - }, - { - "color": "yellow", - "value": 1200 - }, - { - "color": "green", - "value": 1800 - } - ] - }, - "unit": "s", - "custom": { - "displayMode": "auto" - }, - "decimals": 0 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 5, - "type": "stat", - "title": "titan-db Battery Charge", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_battery_charge_percent{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 25 - }, - { - "color": "yellow", - "value": 45 - }, - { - "color": "green", - "value": 65 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 6, - "type": "stat", - "title": "tethys Battery Charge", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_battery_charge_percent{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "orange", - "value": 25 - }, - { - "color": "yellow", - "value": 45 - }, - { - "color": "green", - "value": 65 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 7, - "type": "stat", - "title": "titan-db UPS Load", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-db\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 55 - }, - { - "color": "orange", - "value": 75 - }, - { - "color": "red", - "value": 90 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 8, - "type": "stat", - "title": "tethys UPS Load", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 4 - }, - "targets": [ - { - "expr": "max(hecate_ups_load_percent{job=\"hecate-power\",instance=\"titan-24\"}) or on() vector(0)", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 55 - }, - { - "color": "orange", - "value": 75 - }, - { - "color": "red", - "value": 90 - } - ] - }, - "unit": "percent", - "custom": { - "displayMode": "auto" - }, - "decimals": 1 - }, - "overrides": [] - }, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "center", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "value" - } - }, - { - "id": 9, "type": "timeseries", - "title": "UPS Runtime by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 8 - }, - "targets": [ - { - "expr": "hecate_ups_runtime_seconds{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "s" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 10, - "type": "timeseries", - "title": "UPS Load % by Source", + "title": "Climate History", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -608,127 +363,46 @@ data: }, "targets": [ { - "expr": "hecate_ups_load_percent{job=\"hecate-power\"}", "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "percent" + "expr": "(atlas_climate_tent_temperature_celsius or atlas_climate_temperature_celsius)", + "legendFormat": "Temperature (\u00b0C)" }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 11, - "type": "timeseries", - "title": "UPS Battery Charge % by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 16 - }, - "targets": [ { - "expr": "hecate_ups_battery_charge_percent{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "percent" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 12, - "type": "timeseries", - "title": "UPS Trigger Activity by Source", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 16 - }, - "targets": [ - { - "expr": "hecate_ups_trigger_active{job=\"hecate-power\"}", - "refId": "A", - "legendFormat": "{{instance}}/{{source}}" - } - ], - "fieldConfig": { - "defaults": { - "unit": "none" - }, - "overrides": [] - }, - "options": { - "legend": { - "displayMode": "table", - "placement": "right" - }, - "tooltip": { - "mode": "multi" - } - } - }, - { - "id": 13, - "type": "timeseries", - "title": "Climate Temperature Over Time", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 24 - }, - "targets": [ - { - "expr": "atlas_climate_temperature_celsius", - "refId": "A", - "legendFormat": "{{sensor}}" + "refId": "B", + "expr": "(atlas_climate_tent_pressure_kpa or atlas_climate_pressure_kpa)", + "legendFormat": "Pressure (kPa)" } ], "fieldConfig": { "defaults": { "unit": "celsius" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Pressure (kPa)" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "kPa" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] }, "options": { "legend": { @@ -739,12 +413,98 @@ data: "mode": "multi" } }, - "description": "Future climate collector panel: temperature probes (inside inlet, outside inlet, outlet, interior)." + "description": "Two-axis chart: tent temperature (left axis) and tent pressure in kPa (right axis)." }, { - "id": 14, + "id": 5, + "type": "stat", + "title": "Fan Activity", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "targets": [ + { + "refId": "A", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"outlet\"}) or max(atlas_climate_fan_activity_level{position=\"outlet\"}) or on() vector(0)", + "legendFormat": "Outlet", + "instant": true + }, + { + "refId": "B", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"inside_inlet\"}) or max(atlas_climate_fan_activity_level{position=\"inside_inlet\"}) or on() vector(0)", + "legendFormat": "Inside Inlet", + "instant": true + }, + { + "refId": "C", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"outside_inlet\"}) or max(atlas_climate_fan_activity_level{position=\"outside_inlet\"}) or on() vector(0)", + "legendFormat": "Outside Inlet", + "instant": true + }, + { + "refId": "D", + "expr": "max(atlas_climate_fan_activity_level{fan_group=\"interior\"}) or max(atlas_climate_fan_activity_level{position=\"interior\"}) or on() vector(0)", + "legendFormat": "Interior", + "instant": true + } + ], + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 7 + }, + { + "color": "red", + "value": 9 + } + ] + }, + "unit": "none", + "custom": { + "displayMode": "auto" + }, + "decimals": 1 + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name_and_value" + }, + "description": "Current fan activity levels (0-10): outlet, inside inlet, outside inlet, and interior." + }, + { + "id": 6, "type": "timeseries", - "title": "Climate Fan Speed Over Time", + "title": "Fan History (0-10)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -753,18 +513,34 @@ data: "h": 8, "w": 12, "x": 12, - "y": 24 + "y": 16 }, "targets": [ { - "expr": "atlas_climate_fan_rpm", "refId": "A", - "legendFormat": "{{position}}" + "expr": "(atlas_climate_fan_activity_level{fan_group=\"outlet\"} or atlas_climate_fan_activity_level{position=\"outlet\"})", + "legendFormat": "Outlet" + }, + { + "refId": "B", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"inside_inlet\"} or atlas_climate_fan_activity_level{position=\"inside_inlet\"})", + "legendFormat": "Inside Inlet" + }, + { + "refId": "C", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"outside_inlet\"} or atlas_climate_fan_activity_level{position=\"outside_inlet\"})", + "legendFormat": "Outside Inlet" + }, + { + "refId": "D", + "expr": "(atlas_climate_fan_activity_level{fan_group=\"interior\"} or atlas_climate_fan_activity_level{position=\"interior\"})", + "legendFormat": "Interior" } ], "fieldConfig": { "defaults": { - "unit": "rpm" + "unit": "none", + "max": 10 }, "overrides": [] }, @@ -777,58 +553,7 @@ data: "mode": "multi" } }, - "description": "Future climate collector panel: fan RPM by position (inside inlet, outside inlet, outlet, interior)." - }, - { - "id": 15, - "type": "table", - "title": "UPS Status Snapshot (OL/OB/LB)", - "datasource": { - "type": "prometheus", - "uid": "atlas-vm" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 32 - }, - "targets": [ - { - "expr": "max by (instance, source, status, target) (hecate_ups_runtime_seconds{job=\"hecate-power\"})", - "refId": "A", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "unit": "s", - "custom": { - "filterable": true - } - }, - "overrides": [] - }, - "options": { - "showHeader": true, - "columnFilters": false - }, - "transformations": [ - { - "id": "labelsToFields", - "options": {} - }, - { - "id": "sortBy", - "options": { - "fields": [ - "instance" - ], - "order": "asc" - } - } - ], - "description": "NUT status flags: OL=on line (utility), OB=on battery, LB=low battery." + "description": "Historical fan activity for all four fan groups (0-10 scale)." } ], "time": {