Grafana SQL cookbook —

BACnet

  • Dashboard Variables (Required for Dropdowns)

Before creating the panels below, you must set up the dashboard variables so the drop-down menus work.

In Grafana, go to Dashboard Settings (gear icon) > Variables > Add variable. Set the Type to Query, select your TimescaleDB datasource, and use the following queries:

1. Site Variable

  • Name: site
  • Query:
SELECT s.name AS __text, s.id::text AS __value 
FROM sites s 
ORDER BY s.name;

2. Device Variable

  • Name: device
  • Query:
SELECT DISTINCT p.bacnet_device_id::text AS __text, p.bacnet_device_id::text AS __value 
FROM points p 
WHERE p.site_id::text = '$site' 
  AND p.bacnet_device_id IS NOT NULL 
ORDER BY 1;

3. Point Variable

  • Name: point
  • Query:
SELECT p.external_id AS __text, p.external_id AS __value 
FROM points p 
WHERE p.site_id::text = '$site' 
  AND p.bacnet_device_id::text = '$device' 
ORDER BY 1;

BACnet only data

Insert Snip here

  • This dashboard uses point, device, and site variables.
{
  "id": 1,
  "type": "timeseries",
  "title": "BACnet",
  "gridPos": {
    "x": 0,
    "y": 0,
    "h": 16,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 1,
        "fillOpacity": 0,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "auto",
        "showValues": false,
        "pointSize": 5,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "auto",
        "axisLabel": "",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      }
    },
    "overrides": []
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "editorMode": "code",
      "format": "time_series",
      "rawQuery": true,
      "rawSql": "SELECT\n  time_bucket(\n    make_interval(secs => ($__interval_ms / 1000)::int),\n    tr.ts\n  ) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.bacnet_device_id::text IN (${device:sqlstring})\n  AND p.external_id IN (${point:sqlstring})\nGROUP BY 1, 3\nORDER BY 1, 3;",
      "refId": "A",
      "sql": {
        "columns": [
          {
            "parameters": [],
            "type": "function"
          }
        ],
        "groupBy": [
          {
            "property": {
              "type": "string"
            },
            "type": "groupBy"
          }
        ],
        "limit": 50
      }
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

BACnet Plus Fault Data

{
  "id": null,
  "type": "timeseries",
  "title": "BACnet Telemetry w/ Fault Overlays",
  "gridPos": {
    "x": 0,
    "y": 16,
    "h": 12,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 10,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 5,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "value": null,
            "color": "green"
          },
          {
            "value": 80,
            "color": "red"
          }
        ]
      }
    },
    "overrides": [
      {
        "matcher": {
          "id": "byFrameRefID",
          "options": "B"
        },
        "properties": [
          {
            "id": "custom.axisPlacement",
            "value": "right"
          },
          {
            "id": "custom.drawStyle",
            "value": "bars"
          },
          {
            "id": "custom.fillOpacity",
            "value": 30
          },
          {
            "id": "min",
            "value": 0
          },
          {
            "id": "max",
            "value": 1.2
          },
          {
            "id": "custom.axisLabel",
            "value": "Fault Active (1 = Yes)"
          }
        ]
      }
    ]
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.bacnet_device_id::text IN (${device:sqlstring})\n  AND p.external_id IN (${point:sqlstring})\nGROUP BY 1, 3\nORDER BY 1, 3;"
    },
    {
      "refId": "B",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), fr.ts) AS \"time\",\n  max(fr.flag_value) AS \"value\",\n  fd.name AS \"metric\"\nFROM fault_results fr\nJOIN fault_definitions fd ON fd.fault_id = fr.fault_id\nWHERE $__timeFilter(fr.ts)\n  AND (fr.site_id IN (${site:sqlstring}) OR fr.site_id IN (SELECT name FROM sites WHERE id::text IN (${site:sqlstring})))\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "multi",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Host stats (stack-host-stats)

The stack-host-stats container scrapes host memory, load, swap, disk usage, and Docker container stats into host_metrics, disk_metrics, and container_metrics. Use the same TimescaleDB datasource (openfdd_timescale).

Dashboard variable (Host)

  • Name: hostname
  • Type: Query
  • Datasource: openfdd_timescale
  • Query:
SELECT DISTINCT hostname AS __text, hostname AS __value
FROM host_metrics
WHERE $__timeFilter(ts)
ORDER BY 1;

Host — Memory (used / available / total)

{
  "id": null,
  "type": "timeseries",
  "title": "Host — Memory (used / available / total)",
  "gridPos": { "x": 0, "y": 0, "h": 10, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "lineWidth": 2,
        "fillOpacity": 12,
        "axisPlacement": "left",
        "scaleDistribution": { "type": "linear" }
      },
      "unit": "bytes",
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    },
    "overrides": [
      {
        "matcher": { "id": "byName", "options": "mem_used_bytes" },
        "properties": [{ "id": "displayName", "value": "Used" }]
      },
      {
        "matcher": { "id": "byName", "options": "mem_available_bytes" },
        "properties": [{ "id": "displayName", "value": "Available" }]
      },
      {
        "matcher": { "id": "byName", "options": "mem_total_bytes" },
        "properties": [{ "id": "displayName", "value": "Total" }]
      }
    ]
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", mem_used_bytes AS \"mem_used_bytes\", mem_available_bytes AS \"mem_available_bytes\", mem_total_bytes AS \"mem_total_bytes\" FROM host_metrics WHERE $__timeFilter(ts) AND hostname IN (${hostname:sqlstring}) ORDER BY ts;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Host — Load (1 / 5 / 15 min)

{
  "id": null,
  "type": "timeseries",
  "title": "Host — Load (1 / 5 / 15 min)",
  "gridPos": { "x": 0, "y": 10, "h": 8, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 8, "axisPlacement": "left" },
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    },
    "overrides": [
      { "matcher": { "id": "byName", "options": "load_1" }, "properties": [{ "id": "displayName", "value": "Load 1m" }] },
      { "matcher": { "id": "byName", "options": "load_5" }, "properties": [{ "id": "displayName", "value": "Load 5m" }] },
      { "matcher": { "id": "byName", "options": "load_15" }, "properties": [{ "id": "displayName", "value": "Load 15m" }] }
    ]
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", load_1 AS \"load_1\", load_5 AS \"load_5\", load_15 AS \"load_15\" FROM host_metrics WHERE $__timeFilter(ts) AND hostname IN (${hostname:sqlstring}) ORDER BY ts;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Host — Swap (used / total)

{
  "id": null,
  "type": "timeseries",
  "title": "Host — Swap (used / total)",
  "gridPos": { "x": 0, "y": 18, "h": 6, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10, "axisPlacement": "left" },
      "unit": "bytes",
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    },
    "overrides": [
      { "matcher": { "id": "byName", "options": "swap_used_bytes" }, "properties": [{ "id": "displayName", "value": "Swap used" }] },
      { "matcher": { "id": "byName", "options": "swap_total_bytes" }, "properties": [{ "id": "displayName", "value": "Swap total" }] }
    ]
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", swap_used_bytes AS \"swap_used_bytes\", swap_total_bytes AS \"swap_total_bytes\" FROM host_metrics WHERE $__timeFilter(ts) AND hostname IN (${hostname:sqlstring}) ORDER BY ts;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Host — Disk space (free / used / total)

Disk metrics come from disk_metrics (mount path from env OFDD_DISK_MOUNT_PATHS, default /). The table is created by the same migration as host_metrics (stack/sql/006_host_metrics.sql); re-run migrations if you added host-stats after an older deploy.

{
  "id": null,
  "type": "timeseries",
  "title": "Host — Disk space (free / used / total)",
  "gridPos": { "x": 0, "y": 24, "h": 10, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 12, "axisPlacement": "left" },
      "unit": "bytes",
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    },
    "overrides": [
      { "matcher": { "id": "byName", "options": "free_bytes" }, "properties": [{ "id": "displayName", "value": "Free" }] },
      { "matcher": { "id": "byName", "options": "used_bytes" }, "properties": [{ "id": "displayName", "value": "Used" }] },
      { "matcher": { "id": "byName", "options": "total_bytes" }, "properties": [{ "id": "displayName", "value": "Total" }] }
    ]
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", free_bytes AS \"free_bytes\", used_bytes AS \"used_bytes\", total_bytes AS \"total_bytes\" FROM disk_metrics WHERE $__timeFilter(ts) AND hostname IN (${hostname:sqlstring}) AND mount_path = '/' ORDER BY ts;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Host — Disk available (gauge, latest)

{
  "id": null,
  "type": "gauge",
  "title": "Host — Disk space available (latest)",
  "gridPos": { "x": 0, "y": 34, "h": 6, "w": 8 },
  "fieldConfig": {
    "defaults": {
      "unit": "bytes",
      "min": 0,
      "color": { "mode": "thresholds" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "red", "value": null}, {"color": "yellow", "value": 5368709120}, {"color": "green", "value": 10737418240}] }
    }
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", free_bytes AS \"value\" FROM disk_metrics WHERE hostname IN (${hostname:sqlstring}) AND mount_path = '/' ORDER BY ts DESC LIMIT 1;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "showThresholdLabels": false }
}

Containers — CPU %

{
  "id": null,
  "type": "timeseries",
  "title": "Containers — CPU %",
  "gridPos": { "x": 0, "y": 40, "h": 8, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": { "drawStyle": "line", "lineWidth": 1, "fillOpacity": 5, "axisPlacement": "left" },
      "unit": "percent",
      "min": 0,
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    }
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", cpu_pct AS \"value\", container_name AS \"metric\" FROM container_metrics WHERE $__timeFilter(ts) ORDER BY ts, container_name;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Containers — Memory %

{
  "id": null,
  "type": "timeseries",
  "title": "Containers — Memory %",
  "gridPos": { "x": 0, "y": 48, "h": 8, "w": 24 },
  "fieldConfig": {
    "defaults": {
      "custom": { "drawStyle": "line", "lineWidth": 1, "fillOpacity": 5, "axisPlacement": "left" },
      "unit": "percent",
      "min": 0,
      "max": 100,
      "color": { "mode": "palette-classic" },
      "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] }
    }
  },
  "targets": [
    {
      "refId": "A",
      "format": "time_series",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT ts AS \"time\", COALESCE(mem_pct, 0) AS \"value\", container_name AS \"metric\" FROM container_metrics WHERE $__timeFilter(ts) ORDER BY ts, container_name;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "legend": { "showLegend": true, "placement": "bottom" } }
}

Containers — Table (latest)

{
  "id": null,
  "type": "table",
  "title": "Containers — Latest stats",
  "gridPos": { "x": 0, "y": 56, "h": 12, "w": 24 },
  "fieldConfig": {
    "defaults": { "custom": { "align": "auto", "displayMode": "auto" }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [{"color": "green", "value": null}] } },
    "overrides": [
      { "matcher": { "id": "byName", "options": "cpu_pct" }, "properties": [{ "id": "unit", "value": "percent" }] },
      { "matcher": { "id": "byName", "options": "mem_pct" }, "properties": [{ "id": "unit", "value": "percent" }] },
      { "matcher": { "id": "byName", "options": "mem_usage_bytes" }, "properties": [{ "id": "unit", "value": "bytes" }] }
    ]
  },
  "targets": [
    {
      "refId": "A",
      "format": "table",
      "rawQuery": true,
      "editorMode": "code",
      "rawSql": "SELECT container_name, ts, cpu_pct, mem_pct, mem_usage_bytes, pids FROM (SELECT *, row_number() OVER (PARTITION BY container_name ORDER BY ts DESC) AS rn FROM container_metrics WHERE $__timeFilter(ts)) sub WHERE rn = 1 ORDER BY container_name;"
    }
  ],
  "datasource": { "uid": "openfdd_timescale" },
  "options": { "showHeader": true }
}

Weather

Temp RH Dewpoint

{
  "id": 21,
  "type": "timeseries",
  "title": "Weather — Temp / RH / Dewpoint",
  "gridPos": {
    "x": 0,
    "y": 0,
    "h": 10,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 12,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 4,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "°F",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      }
    },
    "overrides": [
      {
        "matcher": {
          "id": "byName",
          "options": "temp_f"
        },
        "properties": [
          {
            "id": "unit",
            "value": "fahrenheit"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          },
          {
            "id": "custom.axisLabel",
            "value": "°F"
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "dewpoint_f"
        },
        "properties": [
          {
            "id": "unit",
            "value": "fahrenheit"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "rh_pct"
        },
        "properties": [
          {
            "id": "unit",
            "value": "percent"
          },
          {
            "id": "custom.axisPlacement",
            "value": "right"
          },
          {
            "id": "custom.axisLabel",
            "value": "RH (%)"
          },
          {
            "id": "min",
            "value": 0
          },
          {
            "id": "max",
            "value": 100
          }
        ]
      }
    ]
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "editorMode": "code",
      "rawQuery": true,
      "format": "time_series",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.external_id IN ('temp_f','rh_pct','dewpoint_f')\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Wind Speed Gusts Direction


{
  "id": 22,
  "type": "timeseries",
  "title": "Weather — Wind (Speed / Gust / Direction)",
  "gridPos": {
    "x": 0,
    "y": 10,
    "h": 9,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 10,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 4,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "mph",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      }
    },
    "overrides": [
      {
        "matcher": {
          "id": "byName",
          "options": "wind_mph"
        },
        "properties": [
          {
            "id": "unit",
            "value": "mph"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          },
          {
            "id": "custom.axisLabel",
            "value": "mph"
          },
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "gust_mph"
        },
        "properties": [
          {
            "id": "unit",
            "value": "mph"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          },
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "wind_dir_deg"
        },
        "properties": [
          {
            "id": "unit",
            "value": "degrees"
          },
          {
            "id": "custom.axisPlacement",
            "value": "right"
          },
          {
            "id": "custom.axisLabel",
            "value": "°"
          },
          {
            "id": "min",
            "value": 0
          },
          {
            "id": "max",
            "value": 360
          }
        ]
      }
    ]
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "editorMode": "code",
      "rawQuery": true,
      "format": "time_series",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.external_id IN ('wind_mph','gust_mph','wind_dir_deg')\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Wind Speed Gust Direction

{
  "id": 22,
  "type": "timeseries",
  "title": "Weather — Wind (Speed / Gust / Direction)",
  "gridPos": {
    "x": 0,
    "y": 10,
    "h": 9,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 10,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 4,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "mph",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      }
    },
    "overrides": [
      {
        "matcher": {
          "id": "byName",
          "options": "wind_mph"
        },
        "properties": [
          {
            "id": "unit",
            "value": "mph"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          },
          {
            "id": "custom.axisLabel",
            "value": "mph"
          },
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "gust_mph"
        },
        "properties": [
          {
            "id": "unit",
            "value": "mph"
          },
          {
            "id": "custom.axisPlacement",
            "value": "left"
          },
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "wind_dir_deg"
        },
        "properties": [
          {
            "id": "unit",
            "value": "degrees"
          },
          {
            "id": "custom.axisPlacement",
            "value": "right"
          },
          {
            "id": "custom.axisLabel",
            "value": "°"
          },
          {
            "id": "min",
            "value": 0
          },
          {
            "id": "max",
            "value": 360
          }
        ]
      }
    ]
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "editorMode": "code",
      "rawQuery": true,
      "format": "time_series",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.external_id IN ('wind_mph','gust_mph','wind_dir_deg')\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Solar Radiation

{
  "id": 23,
  "type": "timeseries",
  "title": "Weather — Solar / Radiation (W/m²)",
  "gridPos": {
    "x": 0,
    "y": 19,
    "h": 9,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 10,
        "gradientMode": "none",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 4,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "W/m²",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": true,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      },
      "unit": "wattperm2",
      "min": 0
    },
    "overrides": [
      {
        "matcher": {
          "id": "byName",
          "options": "shortwave_wm2"
        },
        "properties": [
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "direct_wm2"
        },
        "properties": [
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "diffuse_wm2"
        },
        "properties": [
          {
            "id": "min",
            "value": 0
          }
        ]
      },
      {
        "matcher": {
          "id": "byName",
          "options": "gti_wm2"
        },
        "properties": [
          {
            "id": "min",
            "value": 0
          }
        ]
      }
    ]
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "editorMode": "code",
      "rawQuery": true,
      "format": "time_series",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.external_id IN ('shortwave_wm2','direct_wm2','diffuse_wm2','gti_wm2')\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Cloud Cover


{
  "id": 24,
  "type": "timeseries",
  "title": "Weather — Cloud Cover (%)",
  "gridPos": {
    "x": 0,
    "y": 28,
    "h": 7,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "drawStyle": "line",
        "lineInterpolation": "linear",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "lineWidth": 2,
        "fillOpacity": 35,
        "gradientMode": "opacity",
        "spanNulls": false,
        "insertNulls": false,
        "showPoints": "never",
        "showValues": false,
        "pointSize": 4,
        "stacking": {
          "mode": "none",
          "group": "A"
        },
        "axisPlacement": "left",
        "axisLabel": "Cloud (%)",
        "axisColorMode": "text",
        "axisBorderShow": false,
        "scaleDistribution": {
          "type": "linear"
        },
        "axisCenteredZero": false,
        "hideFrom": {
          "tooltip": false,
          "viz": false,
          "legend": false
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "color": {
        "mode": "palette-classic"
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      },
      "unit": "percent",
      "min": 0,
      "max": 100
    },
    "overrides": []
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "refId": "A",
      "editorMode": "code",
      "rawQuery": true,
      "format": "time_series",
      "rawSql": "SELECT\n  time_bucket(make_interval(secs => ($__interval_ms / 1000)::int), tr.ts) AS \"time\",\n  avg(tr.value) AS \"value\",\n  p.external_id AS \"metric\"\nFROM timeseries_readings tr\nJOIN points p ON p.id = tr.point_id\nWHERE $__timeFilter(tr.ts)\n  AND p.site_id::text IN (${site:sqlstring})\n  AND p.external_id IN ('cloud_pct')\nGROUP BY 1, 3\nORDER BY 1, 3;"
    }
  ],
  "datasource": {
    "uid": "openfdd_timescale"
  },
  "options": {
    "tooltip": {
      "mode": "single",
      "sort": "none",
      "hideZeros": false
    },
    "legend": {
      "showLegend": true,
      "displayMode": "list",
      "placement": "bottom",
      "calcs": []
    }
  }
}

Faults

Fault Definitions

{
  "id": 1,
  "type": "table",
  "title": "Fault Definitions",
  "gridPos": {
    "x": 0,
    "y": 0,
    "h": 10,
    "w": 14
  },
  "fieldConfig": {
    "defaults": {
      "custom": {
        "align": "auto",
        "footer": {
          "reducers": []
        },
        "cellOptions": {
          "type": "auto"
        },
        "inspect": false,
        "hideFrom": {
          "viz": false
        }
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      },
      "color": {
        "mode": "thresholds"
      }
    },
    "overrides": []
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "dataset": "openfdd",
      "datasource": {
        "type": "grafana-postgresql-datasource",
        "uid": "openfdd_timescale"
      },
      "editorMode": "code",
      "format": "table",
      "rawQuery": true,
      "rawSql": "SELECT \r\n  fault_id, \r\n  name, \r\n  category, \r\n  severity, \r\n  -- Shows what Brick equipment this rule binds to (e.g., AHU, VAV)\r\n  array_to_string(equipment_types, ', ') AS target_equipment,\r\n  -- Shows the raw JSON of the specific Brick points it needs (e.g., sat, mat)\r\n  inputs AS required_points,\r\n  updated_at\r\nFROM fault_definitions\r\nWHERE $__timeFilter(updated_at)\r\nORDER BY updated_at DESC;",
      "refId": "A",
      "sql": {
        "columns": [
          {
            "parameters": [],
            "type": "function"
          }
        ],
        "groupBy": [
          {
            "property": {
              "type": "string"
            },
            "type": "groupBy"
          }
        ],
        "limit": 50
      }
    }
  ],
  "datasource": {
    "type": "grafana-postgresql-datasource",
    "uid": "openfdd_timescale"
  },
  "options": {
    "showHeader": true,
    "cellHeight": "sm"
  }
}

Fault Definition Count


{
  "id": 2,
  "type": "stat",
  "title": "Fault Definition Count",
  "gridPos": {
    "x": 0,
    "y": 15,
    "h": 15,
    "w": 24
  },
  "fieldConfig": {
    "defaults": {
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green",
            "value": null
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      },
      "color": {
        "mode": "thresholds"
      }
    },
    "overrides": []
  },
  "pluginVersion": "12.4.0",
  "targets": [
    {
      "dataset": "openfdd",
      "datasource": {
        "type": "grafana-postgresql-datasource",
        "uid": "openfdd_timescale"
      },
      "editorMode": "code",
      "format": "table",
      "rawQuery": true,
      "rawSql": "SELECT count(*)::int AS \"Fault definitions\"\r\nFROM fault_definitions;",
      "refId": "A",
      "sql": {
        "columns": [
          {
            "parameters": [],
            "type": "function"
          }
        ],
        "groupBy": [
          {
            "property": {
              "type": "string"
            },
            "type": "groupBy"
          }
        ],
        "limit": 50
      }
    }
  ],
  "datasource": {
    "type": "grafana-postgresql-datasource",
    "uid": "openfdd_timescale"
  },
  "options": {
    "reduceOptions": {
      "values": false,
      "calcs": [
        "lastNotNull"
      ],
      "fields": ""
    },
    "orientation": "auto",
    "textMode": "auto",
    "wideLayout": true,
    "colorMode": "value",
    "graphMode": "area",
    "justifyMode": "auto",
    "showPercentChange": false,
    "percentChangeColorMode": "standard"
  }
}