> For the complete documentation index, see [llms.txt](https://docs.enlyze.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.enlyze.com/integrations/grafana/advanced-api/03b-advanced-variables.md).

# 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="/files/hwsXsJyxsMI8UrKKQ7Jl" 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](/integrations/grafana/advanced-api/03-variables.md) abgeschlossen
* Verständnis von Dashboard-Variablen, JSONata und API-Queries

***

## Multi-Select und Include All

In [Teil 1](/integrations/grafana/advanced-api/03-variables.md) 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="/files/hwsXsJyxsMI8UrKKQ7Jl" 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="/files/X33IAhQkHfrGm7nGw26r" 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**](/integrations/grafana/production-dashboards/04-production-status.md) — Konstante Variablen und Live-Status-Anzeigen für mehrere Maschinen


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.enlyze.com/integrations/grafana/advanced-api/03b-advanced-variables.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
