monitoring(power): implement six-panel UPS and climate layout
This commit is contained in:
parent
4167f0f988
commit
69a02a3352
@ -464,15 +464,75 @@ HECATE_UPS_LOAD_DB = (
|
|||||||
HECATE_UPS_LOAD_TETHYS = (
|
HECATE_UPS_LOAD_TETHYS = (
|
||||||
f'max(hecate_ups_load_percent{{{HECATE_SELECTOR},instance="titan-24"}}) or on() vector(0)'
|
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_RUNTIME_BY_SOURCE = f"hecate_ups_runtime_seconds{{{HECATE_SELECTOR}}}"
|
||||||
HECATE_UPS_LOAD_BY_SOURCE = f"hecate_ups_load_percent{{{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_CHARGE_BY_SOURCE = f"hecate_ups_battery_charge_percent{{{HECATE_SELECTOR}}}"
|
||||||
HECATE_UPS_TRIGGER_BY_SOURCE = f"hecate_ups_trigger_active{{{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_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_HUMIDITY_MAX = "max(atlas_climate_humidity_percent) or on() vector(0)"
|
||||||
CLIMATE_TEMP_SERIES = "atlas_climate_temperature_celsius"
|
CLIMATE_TEMP_SERIES = "(atlas_climate_tent_temperature_celsius or atlas_climate_temperature_celsius)"
|
||||||
CLIMATE_FAN_SERIES = "atlas_climate_fan_rpm"
|
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 = (
|
POSTGRES_CONN_USED = (
|
||||||
'label_replace(sum(pg_stat_activity_count), "conn", "used", "__name__", ".*") '
|
'label_replace(sum(pg_stat_activity_count), "conn", "used", "__name__", ".*") '
|
||||||
'or label_replace(max(pg_settings_max_connections), "conn", "max", "__name__", ".*")'
|
'or label_replace(max(pg_settings_max_connections), "conn", "max", "__name__", ".*")'
|
||||||
@ -572,6 +632,9 @@ def stat_panel(
|
|||||||
instant=False,
|
instant=False,
|
||||||
value_suffix=None,
|
value_suffix=None,
|
||||||
links=None,
|
links=None,
|
||||||
|
targets=None,
|
||||||
|
field_overrides=None,
|
||||||
|
description=None,
|
||||||
):
|
):
|
||||||
"""Return a Grafana stat panel definition."""
|
"""Return a Grafana stat panel definition."""
|
||||||
defaults = {
|
defaults = {
|
||||||
@ -592,14 +655,16 @@ def stat_panel(
|
|||||||
defaults["custom"]["valueSuffix"] = value_suffix
|
defaults["custom"]["valueSuffix"] = value_suffix
|
||||||
if decimals is not None:
|
if decimals is not None:
|
||||||
defaults["decimals"] = decimals
|
defaults["decimals"] = decimals
|
||||||
|
target_list = targets if targets is not None else [{"expr": expr, "refId": "A"}]
|
||||||
|
|
||||||
panel = {
|
panel = {
|
||||||
"id": panel_id,
|
"id": panel_id,
|
||||||
"type": "stat",
|
"type": "stat",
|
||||||
"title": title,
|
"title": title,
|
||||||
"datasource": PROM_DS,
|
"datasource": PROM_DS,
|
||||||
"gridPos": grid,
|
"gridPos": grid,
|
||||||
"targets": [{"expr": expr, "refId": "A"}],
|
"targets": target_list,
|
||||||
"fieldConfig": {"defaults": defaults, "overrides": []},
|
"fieldConfig": {"defaults": defaults, "overrides": field_overrides or []},
|
||||||
"options": {
|
"options": {
|
||||||
"colorMode": "value",
|
"colorMode": "value",
|
||||||
"graphMode": "area",
|
"graphMode": "area",
|
||||||
@ -608,12 +673,15 @@ def stat_panel(
|
|||||||
"textMode": text_mode,
|
"textMode": text_mode,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if legend:
|
if legend and len(panel["targets"]) == 1:
|
||||||
panel["targets"][0]["legendFormat"] = legend
|
panel["targets"][0]["legendFormat"] = legend
|
||||||
if instant:
|
if instant:
|
||||||
panel["targets"][0]["instant"] = True
|
for t in panel["targets"]:
|
||||||
|
t.setdefault("instant", True)
|
||||||
if links:
|
if links:
|
||||||
panel["links"] = links
|
panel["links"] = links
|
||||||
|
if description:
|
||||||
|
panel["description"] = description
|
||||||
return panel
|
return panel
|
||||||
|
|
||||||
|
|
||||||
@ -674,16 +742,20 @@ def timeseries_panel(
|
|||||||
legend_calcs=None,
|
legend_calcs=None,
|
||||||
time_from=None,
|
time_from=None,
|
||||||
links=None,
|
links=None,
|
||||||
|
targets=None,
|
||||||
|
field_overrides=None,
|
||||||
|
description=None,
|
||||||
):
|
):
|
||||||
"""Return a Grafana time-series panel definition."""
|
"""Return a Grafana time-series panel definition."""
|
||||||
|
target_list = targets if targets is not None else [{"expr": expr, "refId": "A"}]
|
||||||
panel = {
|
panel = {
|
||||||
"id": panel_id,
|
"id": panel_id,
|
||||||
"type": "timeseries",
|
"type": "timeseries",
|
||||||
"title": title,
|
"title": title,
|
||||||
"datasource": PROM_DS,
|
"datasource": PROM_DS,
|
||||||
"gridPos": grid,
|
"gridPos": grid,
|
||||||
"targets": [{"expr": expr, "refId": "A"}],
|
"targets": target_list,
|
||||||
"fieldConfig": {"defaults": {"unit": unit}, "overrides": []},
|
"fieldConfig": {"defaults": {"unit": unit}, "overrides": field_overrides or []},
|
||||||
"options": {
|
"options": {
|
||||||
"legend": {
|
"legend": {
|
||||||
"displayMode": legend_display,
|
"displayMode": legend_display,
|
||||||
@ -694,7 +766,7 @@ def timeseries_panel(
|
|||||||
}
|
}
|
||||||
if max_value is not None:
|
if max_value is not None:
|
||||||
panel["fieldConfig"]["defaults"]["max"] = max_value
|
panel["fieldConfig"]["defaults"]["max"] = max_value
|
||||||
if legend:
|
if legend and len(panel["targets"]) == 1:
|
||||||
panel["targets"][0]["legendFormat"] = legend
|
panel["targets"][0]["legendFormat"] = legend
|
||||||
if legend_calcs:
|
if legend_calcs:
|
||||||
panel["options"]["legend"]["calcs"] = legend_calcs
|
panel["options"]["legend"]["calcs"] = legend_calcs
|
||||||
@ -702,6 +774,8 @@ def timeseries_panel(
|
|||||||
panel["timeFrom"] = time_from
|
panel["timeFrom"] = time_from
|
||||||
if links:
|
if links:
|
||||||
panel["links"] = links
|
panel["links"] = links
|
||||||
|
if description:
|
||||||
|
panel["description"] = description
|
||||||
return panel
|
return panel
|
||||||
|
|
||||||
|
|
||||||
@ -2777,222 +2851,161 @@ def build_jobs_dashboard():
|
|||||||
|
|
||||||
def build_power_dashboard():
|
def build_power_dashboard():
|
||||||
panels = []
|
panels = []
|
||||||
on_battery_thresholds = {
|
status_mapping = [
|
||||||
"mode": "absolute",
|
{
|
||||||
"steps": [
|
"type": "value",
|
||||||
{"color": "green", "value": None},
|
"options": {
|
||||||
{"color": "red", "value": 1},
|
"0": {"text": "⚡ Charging"},
|
||||||
],
|
"1": {"text": "🔋 Discharging"},
|
||||||
}
|
},
|
||||||
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},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
panels.append(
|
panels.append(
|
||||||
stat_panel(
|
stat_panel(
|
||||||
1,
|
1,
|
||||||
"titan-db UPS Status (On Battery)",
|
"UPS Current Load",
|
||||||
HECATE_UPS_ON_BATTERY_DB,
|
None,
|
||||||
{"h": 4, "w": 6, "x": 0, "y": 0},
|
{"h": 8, "w": 12, "x": 0, "y": 0},
|
||||||
unit="none",
|
unit="none",
|
||||||
instant=True,
|
decimals=1,
|
||||||
thresholds=on_battery_thresholds,
|
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(
|
panels.append(
|
||||||
stat_panel(
|
timeseries_panel(
|
||||||
2,
|
2,
|
||||||
"tethys UPS Status (On Battery)",
|
"UPS History (Power Draw)",
|
||||||
HECATE_UPS_ON_BATTERY_TETHYS,
|
None,
|
||||||
{"h": 4, "w": 6, "x": 6, "y": 0},
|
{"h": 8, "w": 12, "x": 12, "y": 0},
|
||||||
unit="none",
|
unit="watt",
|
||||||
instant=True,
|
targets=[
|
||||||
thresholds=on_battery_thresholds,
|
{"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(
|
panels.append(
|
||||||
stat_panel(
|
stat_panel(
|
||||||
3,
|
3,
|
||||||
"titan-db Runtime Remaining",
|
"Current Climate",
|
||||||
HECATE_UPS_RUNTIME_DB,
|
None,
|
||||||
{"h": 4, "w": 6, "x": 12, "y": 0},
|
{"h": 8, "w": 12, "x": 0, "y": 8},
|
||||||
unit="s",
|
unit="none",
|
||||||
decimals=0,
|
decimals=2,
|
||||||
instant=True,
|
text_mode="name_and_value",
|
||||||
thresholds=runtime_thresholds,
|
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(
|
panels.append(
|
||||||
stat_panel(
|
timeseries_panel(
|
||||||
4,
|
4,
|
||||||
"tethys Runtime Remaining",
|
"Climate History",
|
||||||
HECATE_UPS_RUNTIME_TETHYS,
|
None,
|
||||||
{"h": 4, "w": 6, "x": 18, "y": 0},
|
{"h": 8, "w": 12, "x": 12, "y": 8},
|
||||||
unit="s",
|
unit="celsius",
|
||||||
decimals=0,
|
targets=[
|
||||||
instant=True,
|
{"refId": "A", "expr": CLIMATE_TEMP_SERIES, "legendFormat": "Temperature (°C)"},
|
||||||
thresholds=runtime_thresholds,
|
{"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(
|
panels.append(
|
||||||
stat_panel(
|
stat_panel(
|
||||||
5,
|
5,
|
||||||
"titan-db Battery Charge",
|
"Fan Activity",
|
||||||
HECATE_UPS_BATTERY_CHARGE_DB,
|
None,
|
||||||
{"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,
|
|
||||||
{"h": 8, "w": 12, "x": 0, "y": 16},
|
{"h": 8, "w": 12, "x": 0, "y": 16},
|
||||||
unit="percent",
|
unit="none",
|
||||||
legend="{{instance}}/{{source}}",
|
decimals=1,
|
||||||
legend_display="table",
|
text_mode="name_and_value",
|
||||||
legend_placement="right",
|
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(
|
panels.append(
|
||||||
timeseries_panel(
|
timeseries_panel(
|
||||||
12,
|
6,
|
||||||
"UPS Trigger Activity by Source",
|
"Fan History (0-10)",
|
||||||
HECATE_UPS_TRIGGER_BY_SOURCE,
|
None,
|
||||||
{"h": 8, "w": 12, "x": 12, "y": 16},
|
{"h": 8, "w": 12, "x": 12, "y": 16},
|
||||||
unit="none",
|
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_display="table",
|
||||||
legend_placement="right",
|
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 {
|
return {
|
||||||
"uid": "atlas-power",
|
"uid": "atlas-power",
|
||||||
|
|||||||
@ -1311,7 +1311,7 @@
|
|||||||
},
|
},
|
||||||
"targets": [
|
"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"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1320,7 +1320,7 @@ data:
|
|||||||
},
|
},
|
||||||
"targets": [
|
"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"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user