Aus Raspberry Pi Geek 05/2013

Mit dem Raspberry Pi eine Wetterstation anzapfen (Seite 2)

Eine neue Datenbankdatei db.sqlite3, die zum Beispiel die Temperaturwerte zu den jeweiligen Zeitpunkten aufnimmt, erstellen Sie mit dem Befehl

$ sqlite3 db.sqlite3 'create table temperatures(zeit integer, t real)

Das Ruby-Programm in Listing 3 greift mit Hilfe von ActiveRecord auf diese Datenbank zu und füllt sie mit den Werten, die es aus einer CSV-Datei wetter.csv einliest. Die Zeilen in der CSV-Datei wiederum enthalten die Daten der Wetterstation im Format aus Listing 1.

Das Schöne an ActiveRecord: Es kümmert sich automatisch um alles, was man für das Lesen und Schreiben von Datenbanken braucht. So erkennt es in Listing 3 an den Namen der Klasse Temperature, dass es in der Datenbank die Tabelle temperatures verwenden muss, und am Namen der Variablen (zeit und t), in welche Spalten der Datenbanktabelle es schreiben muss.

Listing 3

 

require 'csv'
require 'active_record'
data = CSV.read('weather.csv', { col_sep: ':' })
ActiveRecord::Base.establish_connection({"adapter"=>"sqlite3", "database"=>"db.sqlite3"})
class Temperature < ActiveRecord::Base
  validates_uniqueness_of :zeit
end
data.each do |d|
  werte = { zeit: d[0], t: d[11] }
  Temperature.create werte
end

Messwerte lesen

Die Daten lassen sich dank ActiveRecord auch komfortabel wieder aus der Datenbank auslesen. Der Code in Listing 4 liest alle Einträge in einem Schwung in die Variable werte ein und multipliziert dabei die Zeitwerte mit 1000. Das Array enthält Wertepaare aus Zeit und Messwert, damit die Diagrammbibliothek diese später als Datenpunkte interpretieren kann. Die Methode inspect generiert aus dem Array eine entsprechende Zeichenkette der Form: @LI: “[[1363465023000, -1.3],[1363468623000, -1.9],…]”.

Im Listing wird diese Zeichenkette im Terminal ausgegeben, später bauen wir sie in die Webseite an der entsprechenden Stelle im Javascript-Code ein.

Listing 4

 

require 'active_record'
ActiveRecord::Base.establish_connection({"adapter"=>"sqlite3", "database"=>"db.sqlite3"})
class Temperature < ActiveRecord::Base
end
werte = Temperature.all.map {|m| [m.zeit * 1000, m.t]}
data = werte.inspect
puts data

Webseiten darstellen

Es gibt verschiedene Wege, die Daten zu Diagrammen zu verarbeiten und diese in einer Webseite einzubetten. So ließe sich per Skript mit Gnuplot eine Grafikdatei erzeugen und dann als Bild einbauen. Google Charts liefert eine Möglichkeit, die Daten an eine Webschnittstelle zu übermitteln und liefert eine Bilddatei zurück. Dann braucht man keine Grafikanwendungen auf dem eigenen Webserver.

Ich habe mich für eine dritte Variante entschieden und die Javascript-Bibliothek Highcharts [4] zum Erzeugen der Diagramme genutzt. Highcharts liefert sehr ansprechende Ergebnisse. Zwar kostet die Nutzung für den kommerziellen Einsatz nicht gerade wenig, die private Nutzung räumt der Anbieter Highsoft Solutions AS unter der “Creative Commons Attribution-NonCommercial 3.0 License” aber kostenfrei ein.

Listing 5 zeigt ein Diagramm für den Temperaturverlauf über 24 Stunden. Um es zu erzeugen, gilt es lediglich die beiden Javascript-Bibliotheken jQuery und Highcharts einzubetten. Das eigentliche Diagramm wird als Javascript-Funktion definiert. Das einzig Besondere stellt das Kennzeichnen der X-Achse als Datumswerte und das Einbetten der Datenwerte dar. Ein Datenwert setzt sich aus der Zeitangabe und dem Temperaturwert zusammen. Die Zeitangaben aus der Wetterstation haben wir vorher mit 1000 multipliziert, da Javascript die Werte in Millisekunden erwartet, die Angaben in den Messdaten jedoch in Sekunden vorliegen.

Listing 5

 

<html>
 <head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  <script src="http://code.highcharts.com/highcharts.js"></script>
  <script>
   $(function () {
    var chart = new Highcharts.Chart({
     chart: { renderTo: 'container' },
     title: { text: 'Messdaten'},
     xAxis: { type: 'datetime' },
     yAxis: { title: { text: 'Temperatur (C)' } },
     series: [{
      name: "Temperatur",
      data: [[1363465023000, -1.3], [1363468623000, -1.9], [1363472223000, -2.5],
      [1363475823000, -2.5], [1363479423000, -2.8], [1363483023000, -3.1],
      [1363486623000, -3.4], [1363490223000, -3.7], [1363493823000, -3.9],
      [1363497423000, -3.9], [1363501023000, -3.3], [1363504622000, 2.0],
      [1363508223000, 1.1], [1363511822000, 7.8], [1363515422000, 5.4],
      [1363519022000, 4.3], [1363522623000, 5.9], [1363526223000, 6.3],
      [1363529823000, 5.2], [1363533423000, 3.8], [1363537023000, 3.1],
      [1363540623000, 2.0], [1363544223000, 1.6], [1363547823000, 1.3],
      [1363551422000, 1.1]],
      pointStart: 1363465023000,
      pointInterval: 3600 * 1000 // one hour
     }]
    });
   });
  </script>
 </head>
 <body>
  <div id="container" style="height: 400px"></div>
 </body>
</html>

Alles zusammen

Die bisher beschriebenen Zutaten machen den Kern der Anwendung aus. Was noch fehlt, ist im Wesentlichen die regelmäßige Aktualisierung der Daten und das Zusammenspiel der bisher beschriebenen Komponenten. Eine einfache Webanwendung, die Daten aus der Datenbank ausliest und das entsprechende Diagramm generiert, sehen Sie in Listing 6.

Listing 6

 

require 'active_record'
require 'sinatra'
ActiveRecord::Base.establish_connection({"adapter"=>"sqlite3", "database"=>"db.sqlite3"})
class Temperature < ActiveRecord::Base
end
get '/' do
  werte = Temperature.all(order: "zeit desc", limit: 24)
  @data = werte.map {|m| [m.zeit * 1000, m.t]}.inspect
  @start_time = werte.first.zeit
  erb :index
end
__END__
@@ index
<html>
 <head>
 [ ... wie in Listing 5, bis 'series' ...]
      series: [{
        name: "Temperatur",
        data: <%= @data %>,
        pointStart: <%= @start_time * 1000 %>,
        pointInterval: 3600 * 1000 // one hour
      }]
 [ ... weiter wie in Listing 5 ...]
DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben