In meinen bisherigen Projekten habe ich für die Visualisierung der Daten bisher immer verschiedene lokale Libraries verwendet mit dem Effekt das diese entweder sehr kompliziert waren oder einfach nicht den Umfang anbieten den ich mir gewünscht habe. Diese Problemstellung hatte ich auch in meinem Temperatur Sensor Projekt.
Endlich habe ich eine passende Lösung für mich gefunden und zwar die Google Chart Tools, diese haben folgende Vorteile:
- Wir brauchen am Webserver des Raspberry Pi keine Libraries mehr, es reicht PHP und eine Datenbank als Datenquelle
- Die Formatierung der Daten wird bei den richtigen Datentypen von Google übernommen
- Es gibt etliche Diagramme, Vorlagen und Beispiele
- Die Charts sind interaktiv und fast unbegrenzt anpassbar
- Wir müssen nicht immer einzeln Tages, Wochen, Monats und Jahres Diagramme erstellen
Allerdings sei gesagt das man auch hier Zeit und Entwicklungserfahrung benötigt um die API zu verstehen und das gewünschte Ergebnis zu erzielen. Erwähnt sei natürlich noch die nicht unumstrittene Daten sammelnde Krake Google , es sollte aber jeder für sich selbst entscheiden welche Tools er verwenden. Bei diesen beiden Beispielen werden die Daten NICHT an Google übertragen, die Charts werden in eurem Browser generiert, selbst wenn Daten übertragen werden versichert Google diese direkt nach der Generierung zu löschen und nicht weiter zu verwenden.
Update: Die Methode via Google Charts ist auch recht komplex schaut auch daher am Besten noch das EmonCMS an und entscheidet selbst welche ihr verwenden wollt, alle Methoden benötigen allerdings etwas Wissen rund um die eingesetzten Technologien.
Ausgabe als normales Liniendiagramm |
Ausgabe als Diagram vom Typ AnnotatedTimeLine |
Wie funktioniert das ganze?
Wie ich bereits erwähnt habe basieren die Diagramme auf den Google Charts. Wir sammeln auf unserem Raspberry Pi aus der Datenbank die benötigten Werte zusammen, in meinem Fall ist es eine Sqlite Datenbank, bringen Sie in das in der Google API definierte DataTable Format und generieren mit den passenden JavaScript Libraries im Browser (nicht auf dem Server) die Diagramme. Ich habe mich anstelle von JSON für das Data Table Format entschieden da mit diesem eine automatische Skalierung der X-Achse möglich ist.
Der Code zum generieren der Diagramme
Die passenden Informationen zum Setup des Webservers und zur Einrichtung des Perl Scripts zur Datenübermittlung findet ihr in meinem Raspberry Pi Projekt Funksensoren selbst bauen.
Die Dateien könnt ihr auch direkt herunterladen www-sensor.
index.php
Die index.php enthält neben den notwendigen SQL Abfragen und dem Auswahl Dialog den notwendigen Java Script Code zum generieren des Diagramm. Es wird eine Listbox mit möglichen Sensoren angezeigt für welche wir dann ein Diagramm generieren.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
//------------------- Config und Funktionen einbinden -------------------------- require_once("config.php"); require_once("functions.php"); //------------------------ PHP Settings ---------------------------------------- ini_set('track_errors', 1); ini_set('display_errors', 1); ini_set('log_errors', 1); ini_set("memory_limit","64M"); ini_set("max_execution_time","30"); @ob_implicit_flush(true); @ob_end_flush(); $_SELF=$_SERVER['PHP_SELF']; if (!file_exists($DBfile)) { echo " $SelectedNodes = isset($_POST["nodeID"]) ? $_POST["nodeID"] : ""; //------------------------ Daten für Grafik holen ---------------------------------------- //Aus selektierter Node DataTable für Chart generieren if (!empty($SelectedNodes)) { $SQL="SELECT supplyV,temp,hum,datetime(time,'unixepoch') AS timestamp FROM werte WHERE nodeID='".$SelectedNodes."'"; $db = db_con($DBfile); $q = db_query($SQL); //Zeilen Header definieren, werden im Chart angezeigt $data = "var data = new google.visualization.DataTable();n" ."data.addColumn('datetime', 'Timestamp');n" ."data.addColumn('number', 'Volt');n" ."data.addColumn('number', 'Feuchtigkeit');n" ."data.addColumn('number', 'Temperatur');nn" ."data.addRows([n"; while ($res = $q->fetch(PDO::FETCH_ASSOC)) { $temp = (int)$res['temp'] / 100; $hum = (int)$res['hum'] / 100; $pwr = (int)$res['supplyV'] / 1000; $timestamp = $res['timestamp']; $data = $data." [new Date('".$timestamp."'), ".$pwr.", ".$hum.", ".$temp."],n"; } $data = $data."[new Date('2014-11-22 16:01:29'), 4.434, 59, 19.79]"; $data = $data."]);n"; } ?> google.load("visualization", "1", { packages: ["annotatedtimeline"] }); google.setOnLoadCallback(drawChart); function drawChart() { var options = { title: 'Raspberry.Tips Daten', backgroundColor: {stroke:'black', fill:'#f2f2f2', strokeSize: 0}, displayZoomButtons: true, hAxis: { format: 'dd.MM. HH:mm' } }; var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div')); chart.draw(data, options); } //----------------- Aktuelle Werte Ausgeben ------------------------------------ echo " echo "
echo "n"; //----------------------------------------------------------------------------------- //----------------- Knoten zur Auswahl holen ------------------------------------ echo " echo " n"; echo " n"; echo " Sensordaten anzeigenn";echo " echo " $i=0; $s=" "; $MAXROW=10; $db = db_con($DBfile); $q = db_query("SELECT nodeID,place FROM werte WHERE 1 GROUP BY nodeID ORDER BY nodeID ASC"); while ($res = $q->fetch(PDO::FETCH_ASSOC)) { echo "'"; } unset($FoundChecked); unset($node_id); unset($res); echo "n nn"; echo "n"; ?> |
functions.php
Das Functions Script enthält wiederverwendbare Funktionen, in meinem Fall die Methoden zur Abfrage der SQL-Lite Datenbank
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
function _exit() { echo " |