# 04 Fortgeschrittene Variablen

In diesem Tutorial baust du ein Dashboard, das OEE-Kennzahlen und Aufträge pro Maschine anzeigt. Panels wiederholen sich automatisch für jede ausgewählte Maschine:

<figure><img src="https://3556205377-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn6Jn6Re8NNPSKD1jGZyL%2Fuploads%2Fgit-blob-1d02cb6435c4484ea403b77ede8746ea9a41e15a%2Fgrafana-var-adv-hero-01.png?alt=media" alt=""><figcaption></figcaption></figure>

## Was du lernst

* Multi-Select und "Include All" für Variablen
* Panels automatisch wiederholen (Repeat)
* Versteckte Variablen für Zeitrundung (OEE-API)
* OEE per Machine mit POST-Queries
* Kurzüberblick: Zeitreihendaten über die API

## Voraussetzungen

* [Mit Variablen arbeiten](https://docs.enlyze.com/integrations/grafana/advanced-api/03-variables) abgeschlossen
* Verständnis von Dashboard-Variablen, JSONata und API-Queries

***

## Multi-Select und Include All

In [Teil 1](https://docs.enlyze.com/integrations/grafana/advanced-api/03-variables) hatte die `machine`-Variable einen einzelnen Wert. Für ein Dashboard, das mehrere Maschinen gleichzeitig anzeigt, brauchst du Multi-Select.

1. Erstelle ein neues Dashboard mit einer `site`-Variable wie in Teil 1
2. Erstelle eine Variable `machines` (Plural) mit diesen Einstellungen:

| Einstellung   | Wert       |
| ------------- | ---------- |
| Variable type | Query      |
| Name          | `machines` |
| Label         | Machine    |
| URL           | `machines` |
| Root selector | `$.data`   |

3. Füge unter **URL Query Params** hinzu:

| Key    | Value     |
| ------ | --------- |
| `site` | `${site}` |

4. Columns: `name` (Name), `uuid` (UUID)
5. Unter **Selection options**:
   * Aktiviere **Multi-value**
   * Aktiviere **Include All option**
   * **Sort**: Alphabetical (asc)
   * **Refresh**: On dashboard load

Im Dropdown kannst du jetzt einzelne Maschinen auswählen oder **All** für alle Maschinen am Standort.

{% hint style="info" %}
Beachte den Variablennamen `machines` (Plural). Das signalisiert, dass die Variable mehrere Werte enthalten kann, und vermeidet Verwechslung mit der Einzel-Variable `machine` aus Teil 1.
{% endhint %}

***

## Panels wiederholen (Repeat)

Statt für jede Maschine eigene Panels zu erstellen, lässt du Grafana Panels automatisch wiederholen.

### Row mit Repeat konfigurieren

1. Erstelle eine **Row** (Klicke **Add** > **Row**)
2. Klicke auf das Zahnrad-Symbol der Row
3. Setze **Title** auf `${machines:text}`
4. Unter **Repeat for**: Wähle die Variable `machines`

Grafana erstellt jetzt für jeden Wert der `machines`-Variable eine eigene Row. Innerhalb jeder Row wird `${machines}` durch die UUID der jeweiligen Maschine ersetzt.

<figure><img src="https://3556205377-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn6Jn6Re8NNPSKD1jGZyL%2Fuploads%2Fgit-blob-1d02cb6435c4484ea403b77ede8746ea9a41e15a%2Fgrafana-var-adv-repeat-result-01.png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Panels innerhalb einer Repeat-Row verwenden automatisch den aktuellen Iterationswert. Wenn `${machines}` normalerweise mehrere UUIDs enthält, wird es innerhalb einer Repeat-Row zu genau einer UUID pro Iteration.
{% endhint %}

{% hint style="warning" %}
Änderungen kannst du nur am **ersten** wiederholten Element vornehmen — egal ob Row oder Panel. Die übrigen Kopien werden bei jeder Aktualisierung automatisch aus dem ersten Element neu generiert.
{% endhint %}

***

## Versteckte Variablen: Zeitrundung für OEE

Der `productivity-metrics`-Endpunkt erwartet Zeitstempel, die auf 10-Minuten-Intervalle gerundet sind. Grafanas eingebaute Zeitvariablen (`${__from}`, `${__to}`) liefern beliebige Zeitpunkte. Die Lösung: Eigene Variablen, die den gewählten Zeitbereich auf 10-Minuten-Intervalle runden. Da diese Variablen nur für Queries relevant sind, werden sie als **versteckte Variablen** implementiert — sie erscheinen nicht als Dropdown im Dashboard. Bei Bedarf kannst du ihren Wert mit `${start}` oder `${end}` im Panel-Titel einbauen, um mehr Transparenz zu schaffen.

### Start-Variable erstellen

1. Öffne **Dashboard Settings** > **Variables** > **+ New variable**
2. Konfiguriere:

| Einstellung   | Wert                                    |
| ------------- | --------------------------------------- |
| Variable type | Query                                   |
| Name          | `start`                                 |
| Hide          | **Variable** (vollständig ausgeblendet) |
| Source        | Inline                                  |
| Data          | `{"time": ${__from}}`                   |
| Root selector | siehe unten                             |
| Refresh       | **On time range change**                |

3. Root selector (JSONata-Ausdruck):

```
(
  $time_millis := $number($.time);
  $time_rounded := $time_millis - $time_millis % 600000;
  $fromMillis($time_rounded)
)
```

`600000` Millisekunden = 10 Minuten. Die Formel rundet den Zeitstempel auf das nächste 10-Minuten-Intervall ab.

### End-Variable erstellen

Erstelle eine zweite versteckte Variable `end` mit den gleichen Einstellungen, aber:

| Einstellung | Wert                |
| ----------- | ------------------- |
| Name        | `end`               |
| Data        | `{"time": ${__to}}` |

{% hint style="info" %}
**Refresh: On time range change** ist hier entscheidend. Ohne diese Einstellung würden `start` und `end` nur beim Laden des Dashboards berechnet und sich nicht aktualisieren, wenn du den Zeitbereich änderst.
{% endhint %}

***

## OEE per Machine mit Repeat

Jetzt kombinierst du Repeat-Rows mit dem `productivity-metrics`-Endpunkt.

### OEE Stat-Panel

Erstelle innerhalb der Repeat-Row ein **Stat**-Panel:

| Einstellung   | Wert                                        |
| ------------- | ------------------------------------------- |
| Method        | POST                                        |
| URL           | `machines/${machines}/productivity-metrics` |
| Root selector | `$.data`                                    |

Klappe **Parsing options & Result fields** auf und füge eine **Column** hinzu:

| Selector             | Title        | Type   |
| -------------------- | ------------ | ------ |
| `productivity.score` | productivity | Number |

Klappe **URL options** auf und konfiguriere den Request Body:

| Einstellung       | Wert                                                            |
| ----------------- | --------------------------------------------------------------- |
| Body Type         | Raw                                                             |
| Body Content Type | **JSON**                                                        |
| Body Content      | `{"datetime_ranges": [{"start": "${start}", "end": "${end}"}]}` |

{% hint style="warning" %}
Stelle sicher, dass **Body Content Type** auf **JSON** steht (nicht Text). Die ENLYZE API lehnt Anfragen mit `Content-Type: text/plain` ab (HTTP 422).
{% endhint %}

Konfiguriere das Panel:

* **Unit**: Percent (0.0-1.0)
* **Color mode**: Background
* **Thresholds**: Rot (Basis), Gelb (0.6), Grün (0.8)
* **Value Mapping**: `null` → "NO DATA" (Grau)

### Warum Columns statt Root Selector?

Es wäre naheliegend, den Score direkt im Root Selector zu extrahieren, z.B. `$.data[0].productivity.score`. Das funktioniert, solange die API Daten zurückliefert. Läuft eine Maschine im gewählten Zeitraum jedoch nicht, ist `$.data` ein leeres Array. Der Zugriff auf `[0]` schlägt dann fehl und Grafana zeigt einen Fehler statt eines leeren Panels.

Die Lösung: Setze den Root Selector auf `$.data` und extrahiere den Wert über eine **Column** (`productivity.score`). Gibt es keine Daten, liefert die Column `null` zurück. Diesen `null`-Wert kannst du dann mit einem **Value Mapping** als "NO DATA" anzeigen.

### Weitere OEE-Panels

Erstelle nach dem gleichen Muster Panels für:

| Panel        | Root selector | Column Selector      |
| ------------ | ------------- | -------------------- |
| Availability | `$.data`      | `availability.score` |
| Performance  | `$.data`      | `performance.score`  |
| Quality      | `$.data`      | `quality.score`      |

Konfiguriere für alle Panels ein Value Mapping für `null` → "NO DATA" in Grau. Nicht alle Maschinen liefern Qualitätsdaten, und Maschinen ohne Produktion im gewählten Zeitraum zeigen für alle Kennzahlen "NO DATA".

<figure><img src="https://3556205377-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn6Jn6Re8NNPSKD1jGZyL%2Fuploads%2Fgit-blob-bec7f086ee21655ee70645029b1aa6c545d482ad%2Fgrafana-var-adv-oee-row-01.png?alt=media" alt=""><figcaption></figcaption></figure>

### Production Runs Tabelle

Ergänze die Row um eine **Table** mit den Aufträgen der jeweiligen Maschine:

| Einstellung   | Wert                                                                      |
| ------------- | ------------------------------------------------------------------------- |
| Method        | GET                                                                       |
| URL           | `production-runs`                                                         |
| Query Params  | `machine=${machines}`, `start=${__from:date:iso}`, `end=${__to:date:iso}` |
| Root selector | `$.data`                                                                  |

Füge Columns hinzu: `start` (Start, Timestamp), `end` (End, Timestamp), `production_order` (Order, String), `productivity.score` (OEE, Number).

***

## Exkurs: Zeitreihendaten über die API

Für Zeitreihendaten (z.B. Temperaturverläufe, Durchsatz) bietet die ENLYZE API den `timeseries`-Endpunkt:

```json
POST /timeseries
{
  "machine": "uuid",
  "start": "2025-12-08T00:00:00Z",
  "end": "2025-12-09T00:00:00Z",
  "variables": ["variable-uuid-1", "variable-uuid-2"],
  "resampling_interval": 60
}
```

Der Parameter `resampling_interval` (in Sekunden) reduziert die Datenmenge. Ohne Resampling können Abfragen sehr große Datenmengen zurückgeben.

**Einschränkungen:**

* Die API paginiert Antworten (max. 100 Einträge pro Seite). Das Infinity-Plugin unterstützt automatische Pagination nur experimentell.
* Für Zeitreihen-Visualisierungen ist die ENLYZE Data Source (das dedizierte Grafana-Plugin) die bessere Wahl, da sie Pagination und Resampling automatisch handhabt.

***

## Tipps

* **Variable Refresh**: "On dashboard load" für Stammdaten (Standorte, Maschinen). "On time range change" für zeitabhängige Berechnungen wie die gerundeten Zeitstempel.
* **Variablen-Reihenfolge**: Die Reihenfolge in den Settings bestimmt die Auswertungsreihenfolge: `site` → `machines` → `start` → `end`.
* **Repeat debuggen**: Wenn Repeat-Panels nicht erscheinen, prüfe ob die Variable unter **Repeat options** der Row korrekt ausgewählt ist und ob sie mehrere Werte enthält.
* **POST Body**: Der Body wird als String angegeben. Variablen wie `${start}` werden vor dem Senden ersetzt. Achte auf korrekte JSON-Syntax mit Anführungszeichen.

***

## Nächste Schritte

* [**Produktionsstatus-Dashboard**](https://docs.enlyze.com/integrations/grafana/production-dashboards/04-production-status) — Konstante Variablen und Live-Status-Anzeigen für mehrere Maschinen
