Szenarien für den Einsatz von IoT und BigData: Visualisierung von Sensordaten mit D3.js (Teil 5)

von Matthias Joachimsthaler

Nachdem in den vorgehenden Teilen dieser Blog-Post Serie die Sensordaten erfasst und abgelegt wurden, möchte ich in diesem Blog-Post auf die Visualisierung der abgelegten Daten eingehen. Die Daten werden mit Hilfe der Aggregationen in Elasticsearch aufbereitet und anschließend über JavaScript entsprechend visualisiert.

Für die Visualisierung kommt die JavaScript Bibliothek D3.js zum Einsatz. Dabei handelt es sich um eine freie Javascript Bibliothek, die von Mike Bostock speziell zur Manipulation von datenbasierten Dokumenten entwickelt wurde. Des Weiteren wird die auf D3.js aufbauende Bibliothek Rickshaw verwendet, die ein flotteres Erstellen von Graphen ermöglicht.
Mit Hilfe der Visualisierung wird ein Dashboard erstellt, in dem Wetterdaten, beispielsweise die Temperatur oder Luftfeuchtigkeit der jeweiligen Sensoren, grafisch aufbereitet werden. Hierbei soll sowohl eine momentane Anzeige als auch eine Realtimegrafik die Daten anschaulich repräsentieren. 
Als Beispiel für ein solches Dashboard wird hier die Visualisierung der Indoor Sensordaten gezeigt.

Für die Momentenanzeige werden Gauges, also Messgeräte verwendet. Diese zeigen den aktuellen Wert an und werden automatisch aktualisiert, wenn ein neuer Messwert eines Sensors vorhanden ist.
Die Realtimegrafik stellt die Messwerte der letzen 24 Stunden dar. Sobald ein aktuellerer Messwert verfügbar ist, wird dieser ebenfalls hinzugefügt. Die Realtime Grafik ist wie ein Sliding Window zu verstehen. Es zeigt stets nur die letzen 24h an. Daten, die älter als 24h sind, werden aus der Grafik entfernt, rutschen also aus dem Fenster heraus. Des Weiteren ist es möglich über eine Scrollbar unterhalb der Grafik in beliebige Bereiche hineinzuzoomen. Diese Funktion wird bereits durch Rickshaw selbst geliefert und benötigt keinen weiteren Programmieraufwand.

Queries

Zunächst müssen die erforderlichen Daten durch eine Query über Elasticsearch abgerufen werden. Um den prinzipiellen Aufbau einer solchen Query zu erläutern wird das Beispiel eines Gauge verwendet.

var client = getESClient();

 setInterval(function () {
  client.search({
   index: 'sensorraspberry',
   body: { 
     "query": {
    "bool": {
      "must": [
     {
       "term": {
      "type": "indoor"
       }
     },
     {
       "range": {
      "created": {
        "gte": "now-1d"
      }
       }
     }
      ]
    }
     },
     "aggs": {
    "devices": {
      "terms": {
     "field": "device",
     "order": {
       "_term": "asc"
     }
      },
      "aggs": {
     "time": {
       "terms": {
      "field": "created",
      "order": {
        "_term": "desc"
      },
      "size": 1
       },
       "aggs": {
      "temp": {
        "avg": {
       "field": "temperature"
        }
      }
       }
     }
      }
    }
     },
     "size": 0
   }
   }

Zunächst wird der Index festgelegt, aus dem die Daten abgefragt werden. Wird kein Index festgelegt, so wird über alle Indizes die Suche gestartet. Die Suche kann über mehrere Suchkriterien eingeschränkt werden. In diesem Beispiel müssen die Suchergebnisse vom Typ „indoor“ sein. Außerdem sollen nur Daten des letzten Tages gefunden werden. Folglich werden alle notwendigen Daten zur späteren Visualisierung gefunden.
Aufgrund der Anzahl der Messergebnisse ist es sinnvoll die Daten zu gruppieren. Hierzu bietet Elasticsearch die Aggregationen an. Diese ermöglichen es Suchergebnisse direkt in verschiedene „Töpfe“ (buckets) einzusortieren. Eine Aggregation kann beliebig verschachtelt sein und über mehrere Optionen frei konfiguriert werden. In diesem Beispiel wird für jeden Sensor (device) ein eigener Topf erstellt. In diesen Töpfen werden die Daten nach dem Erstellungsdatum sortiert und nur der neuste Wert angezeigt. Die maximale Anzahl der zurückzuliefernden Werte lassen sich über „size“ festlegen.

Erstellen des Gauge

Das Gauge für die Temperatur kann über JavaScript erstellt werden. Verschiedene Optionen, wie beispielsweise die Größe oder auch Farbbereiche können festgelegt werden.

google.load('visualization', '1', {packages: ['gauge']});
    google.setOnLoadCallback(function () {
        var data1 = google.visualization.arrayToDataTable([
            ['Label', 'Value'],
            [String.fromCharCode(186) + 'C', 0]
        ]);
 
        // Create and draw the visualization.
        var options1 = {
            width: 200,
            max: 50,
            redFrom: 40,
            redTo: 50,
            yellowFrom: 30,
            yellowTo: 40,
            greenFrom: 20,
            greenTo: 30,
            minorTicks: 10,
            majorTicks: ['0', '10', '20', '30', '40', '50']
        };
        var gaugechart1 = new google.visualization.Gauge(document.getElementById('visual_temp_server'));
        gaugechart1.draw(data1, options1);

Dies reicht aus um einen Gauge zu erstellen. Das Ergebnis ist im folgenden Bild zu sehen.

Query für Realtimegrafiken

Um einen Verlauf von Messpunkten zu visualisieren benötigt man die Daten nach Datum bzw. Uhrzeit sortiert. Für diesen Anwendungsfall bietet Elasticsearch eine spezielle Aggregation, die sogenannte „Date Histogram Aggregation“. Sie unterteilt die Suchergebnisse in frei wählbare Zeitabschnitte (Intervalle).

"aggs": {
 "devices": {
   "terms": {
  "field": "device",
  "order": {
    "_term": "asc"
  }
   },
   "aggs": {
  "time": {
    "terms": {
   "field": "created",
   "order": {
     "_term": "desc"
   },
   "size": 1
    },
    "aggs": {
   "temp": {
     "avg": {
    "field": "temperature"
     }
   }
    }
  }
   }
 }
},

In unserem Beispiel wird von den Sensoren alle 2 Sekunden ein Wert geliefert. Dies führt zu einer großen Anzahl an Daten. Für die Visualisierung genügt es gemittelte Werte, z.B. über Minuten, anzuzeigen. Die Query des Gauge muss nur leicht verändert werden, um die notwendigen Daten zu erhalten. Diese werden  anschließend in einem Array ablegt.

Erstellen der Grafik mit Messpunkteverlauf

Um die nun gewonnenen Messpunkte zu visualisieren, kommt die schon erwähnte Bibliothek Rickshaw zum Einsatz. Es muss lediglich der Graph erstellt und mit den Daten befüllt werden. Optionen welche Art von Graph bzw. auch welche Farben welchen Daten entsprechen sollen, lassen sich beliebig zuweisen.

var graph = new Rickshaw.Graph( {
              element: document.getElementById("chart_temp_indoor"),
              height: 300,
              renderer: 'line',
              stroke: true,
              preserve: true,
              series: [
              {color: 'steelblue', data: dataserver, name: 'Serverroom'},
              {color: 'green', data: dataroom1, name:'Office'},
              {color: 'red', data: dataroom3, name: 'Meeting room'},
              {color: 'brown', data: outside, name: 'Outdoor'},
              ]
              } );

Verschiedene Zusätze wie Legenden oder die Scrollbar können optional hinzugefügt werden. Das Ausführen des JavaScript führt zu folgender Darstellung.

Um nun zu erreichen, dass aus dem statisch aufgebauten Graphen eine Realtime Anzeige der letzen 24h wird, müssen neue Daten hinzugefügt, bzw. ältere Daten aus der Grafik entfernt werden. Hierzu wird die JavaScript Funktion setInterval() verwendet. In dieser wird in definierbaren Zeitabständen eine Query abgesetzt, die lediglich die neusten Werte der Sensoren als Ergebnis zurückbekommt. Die Query ist somit identisch mit der Gauge-Query .
Liegt nun ein neuer Messwert vor wird dieser mit der Arrayfunktion push(neuerMesswert) zu dem jeweiligen Datenarray hinzugefügt. Um den ältesten Messwert zu entfernen wird die Funktion shift() verwendet. 
Sind die neuen Daten im Datenarray eingepflegt, kann die Grafik mittels graph.update() aktualisiert werden. Dies reicht bereits aus damit die Grafik Realtimefähig wird.

Fazit zum gewählten Ansatz

Über Elasticsearch kann man einfach Queries bauen, die nach mehreren Kriterien gefiltert werden können. Die Ergebnisse der Suche lassen sich durch die Aggregation für den jeweiligen Zweck in verschiedene „Töpfe“ (buckets) gruppieren. 
Durch die Verwendung der Bibliotheken D3 und Rickshaw können Daten ohne großen Programmieraufwand visualisiert werden. Da D3 auf Effizienz ausgelegt ist werden die Seiten auch mit mehreren Grafiken schnell aufgebaut.

Die Serie gliedert sich folgendermaßen: 

Kategorien: Big DataD3Internet of ThingsJavaScriptSpring Boot

Zurück