diff --git a/config/machine.json b/config/machine.json index 5e0813c..05c51f5 100644 --- a/config/machine.json +++ b/config/machine.json @@ -3,7 +3,10 @@ "list": [ { "builtIn": 1, - "datasource": { "type": "grafana", "uid": "-- Grafana --" }, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -17,179 +20,835 @@ "id": null, "links": [], "panels": [ - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 1, "title": "Status", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }, "mappings": [{ "type": "value", "options": { "off": { "color": "red", "text": "OFF" }, "idle": { "color": "blue", "text": "IDLE" }, "operational": { "color": "green", "text": "RUNNING" }, "starting": { "color": "yellow", "text": "STARTING" }, "stopping": { "color": "yellow", "text": "STOPPING" } } }] }, "overrides": [] }, - "gridPos": { "h": 4, "w": 5, "x": 0, "y": 1 }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "title": "Status", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "mappings": [ + { + "type": "value", + "options": { + "off": { + "color": "red", + "text": "OFF" + }, + "idle": { + "color": "blue", + "text": "IDLE" + }, + "operational": { + "color": "green", + "text": "RUNNING" + }, + "starting": { + "color": "yellow", + "text": "STARTING" + }, + "stopping": { + "color": "yellow", + "text": "STOPPING" + } + } + } + ] + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 1 + }, "id": 2, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"state\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"state\")\n |> last()", + "refId": "A" + } ], "title": "State", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "state" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "purple", "value": null }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 5, "x": 5, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 1 + }, "id": 3, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"mode\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"mode\")\n |> last()", + "refId": "A" + } ], "title": "Mode", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "mode" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "min": 0, "max": 100, "unit": "percent", "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }, { "color": "green", "value": 20 }, { "color": "yellow", "value": 80 }, { "color": "red", "value": 95 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 5, "x": 10, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "min": 0, + "max": 100, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "green", + "value": 20 + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 95 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 1 + }, "id": 4, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "showThresholdLabels": false, "showThresholdMarkers": true }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"ctrl\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"ctrl\")\n |> last()", + "refId": "A" + } ], "title": "Ctrl %", - "type": "gauge" + "type": "gauge", + "meta": { + "emittedFields": [ + "ctrl" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "unit": "h", "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 5, "x": 15, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "unit": "h", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 15, + "y": 1 + }, "id": 5, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "area" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "area" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"runtime\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"runtime\")\n |> last()", + "refId": "A" + } ], "title": "Runtime", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "runtime" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "min": 0, "max": 100, "unit": "percent", "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }, { "color": "orange", "value": 30 }, { "color": "yellow", "value": 60 }, { "color": "green", "value": 80 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 4, "x": 20, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "min": 0, + "max": 100, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 30 + }, + { + "color": "yellow", + "value": 60 + }, + { + "color": "green", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, "id": 6, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "showThresholdLabels": false, "showThresholdMarkers": true }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"NCogPercent\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"NCogPercent\")\n |> last()", + "refId": "A" + } ], "title": "NCog %", - "type": "gauge" + "type": "gauge", + "meta": { + "emittedFields": [ + "ncog" + ] + } }, - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 }, "id": 7, "title": "Flow & Efficiency", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 6 }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 7, + "title": "Flow & Efficiency", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, "id": 8, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^flow\\.predicted\\.(downstream|atequipment)/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^flow\\.predicted\\.(downstream|atequipment)/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Flow (predicted)", - "type": "timeseries" + "type": "timeseries", + "meta": { + "emittedFields": [ + "flow", + "flow.predicted" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 12, "y": 6 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, "id": 9, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and (r._field==\"cog\" or r._field==\"NCogPercent\"))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and (r._field==\"cog\" or r._field==\"NCogPercent\"))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Efficiency (CoG + NCog%)", - "type": "timeseries" + "type": "timeseries", + "meta": { + "emittedFields": [ + "efficiency", + "cog", + "ncog" + ] + } }, - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 14 }, "id": 10, "title": "Pressure & Temperature", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 15 }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "title": "Pressure & Temperature", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, "id": 11, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^pressure\\.(predicted|measured)\\.(upstream|downstream)/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^pressure\\.(predicted|measured)\\.(upstream|downstream)/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Pressure (upstream / downstream)", - "type": "timeseries" + "type": "timeseries", + "meta": { + "emittedFields": [ + "pressure.upstream", + "pressure.downstream" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 12, "y": 15 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, "id": 12, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^temperature/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /^temperature/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Temperature", - "type": "timeseries" + "type": "timeseries", + "meta": { + "emittedFields": [ + "temperature" + ] + } }, - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 23 }, "id": 13, "title": "Diagnostics", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }, { "color": "yellow", "value": 0.3 }, { "color": "green", "value": 0.7 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 0, "y": 24 }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 13, + "title": "Diagnostics", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.3 + }, + { + "color": "green", + "value": 0.7 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 24 + }, "id": 14, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "area" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "area" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"predictionQuality\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"predictionQuality\")\n |> last()", + "refId": "A" + } ], "title": "Prediction Quality", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "predictionQuality" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }, { "color": "yellow", "value": 0.3 }, { "color": "green", "value": 0.7 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 6, "y": 24 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.3 + }, + { + "color": "green", + "value": 0.7 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 24 + }, "id": 15, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "area" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "area" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"predictionConfidence\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"predictionConfidence\")\n |> last()", + "refId": "A" + } ], "title": "Confidence", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "confidence" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 1 }, { "color": "red", "value": 2 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 12, "y": 24 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 2 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 24 + }, "id": 16, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"pressureDriftLevel\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"pressureDriftLevel\")\n |> last()", + "refId": "A" + } ], "title": "Pressure Drift", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "pressureDrift" + ] + } }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 5 }, { "color": "red", "value": 15 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 18, "y": 24 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "red", + "value": 15 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 24 + }, "id": 17, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and (r._field==\"effDistFromPeak\" or r._field==\"effRelDistFromPeak\"))\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and (r._field==\"effDistFromPeak\" or r._field==\"effRelDistFromPeak\"))\n |> last()", + "refId": "A" + } ], "title": "Distance from Peak", - "type": "stat" + "type": "stat", + "meta": { + "emittedFields": [ + "relDistFromPeak" + ] + } } ], "schemaVersion": 39, - "tags": ["EVOLV", "machine", "template"], + "tags": [ + "EVOLV", + "machine", + "template" + ], "templating": { "list": [ - { "name": "dbase", "type": "custom", "label": "dbase", "query": "cdzg44tv250jkd", "current": { "text": "cdzg44tv250jkd", "value": "cdzg44tv250jkd", "selected": false }, "options": [{ "text": "cdzg44tv250jkd", "value": "cdzg44tv250jkd", "selected": true }], "hide": 2 }, - { "name": "measurement", "type": "custom", "query": "template", "current": { "text": "template", "value": "template", "selected": false }, "options": [{ "text": "template", "value": "template", "selected": true }] }, - { "name": "bucket", "type": "custom", "query": "lvl2", "current": { "text": "lvl2", "value": "lvl2", "selected": false }, "options": [{ "text": "lvl2", "value": "lvl2", "selected": true }] } + { + "name": "dbase", + "type": "custom", + "label": "dbase", + "query": "cdzg44tv250jkd", + "current": { + "text": "cdzg44tv250jkd", + "value": "cdzg44tv250jkd", + "selected": false + }, + "options": [ + { + "text": "cdzg44tv250jkd", + "value": "cdzg44tv250jkd", + "selected": true + } + ], + "hide": 2 + }, + { + "name": "measurement", + "type": "custom", + "query": "template", + "current": { + "text": "template", + "value": "template", + "selected": false + }, + "options": [ + { + "text": "template", + "value": "template", + "selected": true + } + ] + }, + { + "name": "bucket", + "type": "custom", + "query": "lvl2", + "current": { + "text": "lvl2", + "value": "lvl2", + "selected": false + }, + "options": [ + { + "text": "lvl2", + "value": "lvl2", + "selected": true + } + ] + } ] }, - "time": { "from": "now-6h", "to": "now" }, + "time": { + "from": "now-6h", + "to": "now" + }, "timezone": "", "title": "template", "uid": null, "version": 1 -} +} \ No newline at end of file diff --git a/config/machineGroup.json b/config/machineGroup.json index 1a43f5f..69ec2e2 100644 --- a/config/machineGroup.json +++ b/config/machineGroup.json @@ -3,7 +3,10 @@ "list": [ { "builtIn": 1, - "datasource": { "type": "grafana", "uid": "-- Grafana --" }, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -17,93 +20,376 @@ "id": null, "links": [], "panels": [ - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 1, "title": "Status", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "purple", "value": null }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 0, "y": 1 }, - "id": 2, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, - "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"mode\")\n |> last()", "refId": "A" } - ], - "title": "Mode", - "type": "stat" + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "title": "Status", + "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 6, "y": 1 }, - "id": 3, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"scaling\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"mode\")\n |> last()", + "refId": "A" + } + ], + "title": "Mode", + "type": "stat", + "meta": { + "emittedFields": [ + "mode" + ] + } + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 3, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "none" + }, + "targets": [ + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"scaling\")\n |> last()", + "refId": "A" + } ], "title": "Scaling", "type": "stat" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 5 }, { "color": "red", "value": 15 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 12, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "red", + "value": 15 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 1 + }, "id": 4, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "area" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "area" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"absDistFromPeak\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"absDistFromPeak\")\n |> last()", + "refId": "A" + } ], "title": "Abs Dist Peak", "type": "stat" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "unit": "percent", "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 10 }, { "color": "red", "value": 25 }] } }, "overrides": [] }, - "gridPos": { "h": 4, "w": 6, "x": 18, "y": 1 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "red", + "value": 25 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 1 + }, "id": 5, - "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "area" }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "colorMode": "value", + "graphMode": "area" + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"relDistFromPeak\")\n |> last()", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: -7d)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field==\"relDistFromPeak\")\n |> last()", + "refId": "A" + } ], "title": "Rel Dist Peak", "type": "stat" }, - { "gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 }, "id": 6, "title": "Totals", "type": "row" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 6 }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 6, + "title": "Totals", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, "id": 7, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /predicted_flow|flow/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /predicted_flow|flow/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Total Flow", "type": "timeseries" }, { - "datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" }, - "fieldConfig": { "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 12, "y": 6 }, + "datasource": { + "type": "influxdb", + "uid": "cdzg44tv250jkd" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineWidth": 2, + "fillOpacity": 10 + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, "id": 8, - "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, "targets": [ - { "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /predicted_power|power/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", "refId": "A" } + { + "query": "from(bucket: \"${bucket}\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn:(r) => r._measurement==\"${measurement}\" and r._field =~ /predicted_power|power/)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", + "refId": "A" + } ], "title": "Total Power", "type": "timeseries" } ], "schemaVersion": 39, - "tags": ["EVOLV", "machineGroup", "template"], + "tags": [ + "EVOLV", + "machineGroup", + "template" + ], "templating": { "list": [ - { "name": "dbase", "type": "custom", "label": "dbase", "query": "cdzg44tv250jkd", "current": { "text": "cdzg44tv250jkd", "value": "cdzg44tv250jkd", "selected": false }, "options": [{ "text": "cdzg44tv250jkd", "value": "cdzg44tv250jkd", "selected": true }], "hide": 2 }, - { "name": "measurement", "type": "custom", "query": "template", "current": { "text": "template", "value": "template", "selected": false }, "options": [{ "text": "template", "value": "template", "selected": true }] }, - { "name": "bucket", "type": "custom", "query": "lvl2", "current": { "text": "lvl2", "value": "lvl2", "selected": false }, "options": [{ "text": "lvl2", "value": "lvl2", "selected": true }] } + { + "name": "dbase", + "type": "custom", + "label": "dbase", + "query": "cdzg44tv250jkd", + "current": { + "text": "cdzg44tv250jkd", + "value": "cdzg44tv250jkd", + "selected": false + }, + "options": [ + { + "text": "cdzg44tv250jkd", + "value": "cdzg44tv250jkd", + "selected": true + } + ], + "hide": 2 + }, + { + "name": "measurement", + "type": "custom", + "query": "template", + "current": { + "text": "template", + "value": "template", + "selected": false + }, + "options": [ + { + "text": "template", + "value": "template", + "selected": true + } + ] + }, + { + "name": "bucket", + "type": "custom", + "query": "lvl2", + "current": { + "text": "lvl2", + "value": "lvl2", + "selected": false + }, + "options": [ + { + "text": "lvl2", + "value": "lvl2", + "selected": true + } + ] + } ] }, - "time": { "from": "now-6h", "to": "now" }, + "time": { + "from": "now-6h", + "to": "now" + }, "timezone": "", "title": "template", "uid": null, "version": 1 -} +} \ No newline at end of file diff --git a/src/specificClass.js b/src/specificClass.js index 6acbe05..430540b 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -105,6 +105,18 @@ class DashboardApi { return JSON.parse(raw); } + // Collect every `meta.emittedFields` declared by panels in a template. + // Used by #39's parent panel filter — a parent panel whose emittedFields + // are fully covered by its children's panels is removed. + collectEmittedFields(dashboard) { + const out = new Set(); + for (const panel of dashboard?.panels || []) { + const fields = panel?.meta?.emittedFields; + if (Array.isArray(fields)) for (const f of fields) out.add(f); + } + return out; + } + grafanaUpsertUrl() { const { protocol, host, port } = this.config.grafanaConnector; return `${protocol}://${host}:${port}/api/dashboards/db`; diff --git a/test/basic/slice37-emitted-fields.basic.test.js b/test/basic/slice37-emitted-fields.basic.test.js new file mode 100644 index 0000000..78bb75f --- /dev/null +++ b/test/basic/slice37-emitted-fields.basic.test.js @@ -0,0 +1,40 @@ +'use strict'; + +const test = require('node:test'); +const assert = require('node:assert/strict'); + +const DashboardApi = require('../../src/specificClass.js'); + +test('rotatingMachine template panels declare meta.emittedFields', () => { + const api = new DashboardApi({}); + const dash = api.loadTemplate('machine'); + assert.ok(dash, 'template loaded'); + const withFields = dash.panels.filter((p) => p?.meta?.emittedFields); + // 13 non-row panels in machine.json get annotated; row panels are skipped. + assert.ok(withFields.length >= 10, `expected ≥10 annotated panels, got ${withFields.length}`); +}); + +test('collectEmittedFields aggregates fields across panels', () => { + const api = new DashboardApi({}); + const dash = api.loadTemplate('machine'); + const fields = api.collectEmittedFields(dash); + assert.ok(fields.has('ctrl'), 'ctrl field declared by Ctrl % panel'); + assert.ok(fields.has('flow'), 'flow field declared by Flow panel'); + assert.ok(fields.has('efficiency'), 'efficiency field declared by Efficiency panel'); + assert.ok(fields.has('relDistFromPeak'), 'relDistFromPeak declared by Distance from Peak panel'); +}); + +test('collectEmittedFields returns empty Set for template without meta', () => { + const api = new DashboardApi({}); + // measurement.json has no emittedFields metadata yet — its panels predate the annotation. + const dash = api.loadTemplate('measurement'); + const fields = api.collectEmittedFields(dash); + assert.equal(fields.size, 0); +}); + +test('collectEmittedFields handles null/empty dashboard input gracefully', () => { + const api = new DashboardApi({}); + assert.equal(api.collectEmittedFields(null).size, 0); + assert.equal(api.collectEmittedFields({}).size, 0); + assert.equal(api.collectEmittedFields({ panels: [] }).size, 0); +});