monitoring(power): implement six-panel UPS and climate layout
This commit is contained in:
parent
e199d20a3e
commit
758654c9df
@ -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",
|
||||
|
||||
@ -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"
|
||||
}
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
}
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user