de|en

Temperaturmessung mit dem Raspberry Pi und dem 1-wire Temperatursensor DS1820 (USB-seriell)

Martin Kompf

Raspberry Pi mit angesteckten USB nach Seriell und Seriell nach 1-wire Wandlern

Der Raspberry Pi ist ein vollwertiger, kleiner und stromsparender Computer. Er eignet sich hervorragend zur Realisierung von Mess-, Steuer- und Regelungsaufgaben im Heimbereich. Der Artikel beschreibt den Aufbau einer Temperaturmessstation auf Basis des Raspberry Pi und des 1-wire Temperatursensor DS1820. Dank der reichhaltigen Softwareausstattung des Betriebssystems Raspbian ist die Präsentation der grafisch aufbereiteten Messwerte im Netz mittels eines Webservers einfach einzurichten.

1-wire Temperatursensor DS1820

1-wire Temperatursensor DS18S20 im Schrumpfschlauch
1-wire Temperatursensor DS18S20 im Schrumpfschlauch

Die Temperaturmessung erfolgt mit mehreren Sensoren vom Typ DS18S20, DS18B20 oder DS1822. Die unterschiedlichen Typen sind Anschluss- und Softwarekompatibel, sie unterscheiden sich im Wesentlichen in der erzielbaren Messgenauigkeit und im Preis. Er liegt bei Einzelabnahme bei etwa 3 €. Der integrierte Schaltkreis im TO-92 Gehäuse enthält neben dem eigentlichen Temperatursensor einen Analog-Digitalwandler und ein 1-wire Interface. Es ist eine parasitäre Stromversorgung möglich, welche die Verwendung eines einzigen Anschlusses DQ für Datenübertragung und Stromversorgung erlaubt. Daher kommt die Bezeichnung 1-wire. Neben diesem einen Draht wird noch ein zweiter als Bezugspotential (Masse, GND) benötigt. Man kann daher den DS1820 mit einer einfachen zweipoligen verdrillten Leitung anschließen.

Außerdem hat der DS1820 noch einen dedizierten Anschluss VDD für die Betriebsspannung von 3 bis 5 Volt. Bei Benutzung benötigt man dann jedoch eine dreiadrige Leitung. Eine derartige aktive Speisung ist nötig, wenn man zuverlässig Temperaturen oberhalb von circa 70° Celsius messen will. Für den 1-wire Betrieb mit parasitärer Stromversorgung sind VDD und GND zu verbinden.

Es lassen sich mehrere DS1820 an einem 1-wire Bus ohne weitere Bauteile parallel betreiben. Jeder Sensor besitzt einen während der Herstellung eingebrannten eindeutigen Code zur Identifikation.

Raspberry Pi und 1-wire

Der Raspberry Pi ist ein von der Raspberry Pi Foundation entwickelter kleiner und preiswerter Computer. Er übernimmt die Ansteuerung der Temperatursensoren, die Speicherung der Messwerte in einer Datenbank und die Ausgabe der aktuellen und historischen Daten. Da die Bereitstellung der Ergebnisse später über einen Webservice erfolgen soll, empfiehlt es sich, gleich das Modell B mit eingebauter Netzwerkschnittstelle anzuschaffen.

Als Betriebssystem kommt die Linux-Distribution Raspbian "wheezy" zum Einsatz. Sie erlaubt die einfache Installation der für das Projekt erforderlichen Software.

Um einen 1-wire Bus vom Raspberry Pi aus anzusteuern, gibt es prinzipiell mehrere Möglichkeiten:

  1. Direkte Ansteuerung eines GPIO-Pins mit dem 1-wire Protokoll. Das ist die Lösung mit dem geringsten Aufwand an externer Beschaltung. Jedoch sollte man bedenken, dass hier die empfindlichen GPIO-Anschlüsse ohne weitere Pufferung auf dem möglicherweise langen 1-wire Bus anliegen.
  2. Verwendung der I2C Schnittstelle des Raspberry Pi und eines I2C nach 1-wire Adapters, zum Beispiel DS2483. Auf den ersten Blick eine sehr elegante Lösung. Die Beschaffung und Verarbeitung des DS2483 kann unter Umständen aufwendig sein (Löten von SMD Bauteilen). Auch ist unklar, inwieweit Raspbian "wheezy" diese Konfiguration softwareseitig unterstützt.
  3. Benutzung der internen seriellen Schnittstelle des Pi und eines aktiven Seriell zu 1-wire Adapters, zum Beispiel DS2480B. Auch hierbei handelt es sich um ein SMD Bauteil, das darüber hinaus für 5 Volt Betriebsspannung ausgelegt ist, während der Pi mit 3,3 Volt arbeitet. Daher sind hier noch zusätzliche Spannungswandler erforderlich.
  4. Einsatz eines fertigen USB Busmasters. Eine Lösung, die ohne Löten auskommt. Es kann jedoch passieren, dass ein kommerziell verfügbarer 1-wire/USB Busmaster teurer ist als der komplette Raspberry Pi!
  5. Kauf eines billigen USB zu Seriell Wandlers und Selbstbau eines passiven Seriell zu 1-wire Adapters. Diese Variante wird als Optimum aus Kosten, Zeitaufwand und Schwierigkeit eingeschätzt und im folgenden weiter vorgestellt. Insbesondere ist diese Lösung auch nicht auf den Raspberry Pi beschränkt, sondern lässt sich an jedem Computer mit USB oder serieller Schnittstelle betreiben!

Einen USB zu Seriell Adapter bietet zum Beispiel Reichelt schon ab circa 6 € an. Beim Kauf sollte man auf die Unterstützung von Linux achten. In der Regel enthalten diese Adapter den Prolific Chip PL2303. Das für die Ansteuerung zuständige Kernelmodul pl2303 ist bereits Bestandteil von Raspbian "wheezy". Beim Anschluss des USB zu Seriell Adapters an eine USB Schnittstelle des Raspberry Pi sollten daher im Systemlog die entsprechenden Meldungen auftauchen:

$ dmesg
usbcore: registered new interface driver pl2303
USB Serial support registered for pl2303
pl2303 1-1.3:1.0: pl2303 converter detected
usb 1-1.3: pl2303 converter now attached to ttyUSB0

Die letzte Zeile informiert in diesem Fall darüber, dass die Ansteuerung der seriellen Schnittstelle des Adapters über das Devicefile /dev/ttyUSB0 erfolgt. Diesen Pfad benötigt man später bei der Konfiguration der Software. Jetzt ist allerdings erst einmal der Bau des Seriell zu 1-wire Adapters an der Reihe.

Seriell zu 1-wire Adapter

Schaltbild DS9097
Schaltbild des Seriell zu 1-wire Adapter DS9097 nach [OWFS-DS9097]


Für den Selbstbau eines passiven Seriell zu 1-wire Adapter auf Basis des DS9097 nach [OWFS-DS9097] benötigt man folgende Bauteile:

Aufbau DS9097
Mit etwas Geschick gelingt es, den DS9097 in eine D-Sub Steckerkappe einzubauen

Die Abbildung oben zeigt das Schaltbild des Adapters. Mit etwas Geschick und Planung gelingt es, den Adapter auf einer Lochrasterplatte mit in das D-Sub Steckergehäuse einzubauen (Abbildung rechts). Das Schaltbild zeigt exemplarisch auch die Ankopplung zweier Temperatursensoren DS1820. Diese kommen nicht mit in das Gehäuse, sondern werden über ein verdrilltes zweiadriges Kabel angeschlossen. Die Lösung verzichtet hier auf weitere Steckverbinder, die Sensoren sind direkt mit dem Kabel verlötet. Mehrere Sensoren schaltet man einfach parallel. Der Aufbau erfolgt dabei als Bus, das heißt es gibt nur ein einziges Kabel, in welches die Sensoren an der passenden Stelle eingelötet sind. Die mögliche Kabellänge hängt von vielen Faktoren ab, im Muster arbeitet ein 10 Meter langes Kabel mit zwei Sensoren zuverlässig.

Temperaturmessung mit digitemp

Nachdem die Lötarbeiten beendet sind, verbindet man den Seriell zu 1-wire Adapter mit dem USB/Seriell Adapter. Nun kann ein erster Funktionstest der kompletten Elektronik erfolgen. Dazu benötigt man die Software DigiTemp. Zur Installation des kompletten Softwarepakets unter Raspbian "wheezy" dient der Befehl:

sudo apt-get install digitemp

Das Paket enthält verschiedene ausführbare Programme für diverse 1-wire Busmaster. Für den DS9097 ist digitemp_DS9097 zuständig. Der Befehl

digitemp_DS9097 -i -s /dev/ttyUSB0

scannt den 1-wire Bus und gibt alle gefunden Sensoren aus:

DigiTemp v3.5.0 Copyright 1996-2007 by Brian C. Lane
..
Searching the 1-Wire LAN
10XXXXXXXXXXX0AC : DS1820/DS18S20/DS1920 Temperature Sensor
10XXXXXXXXXXX04F : DS1820/DS18S20/DS1920 Temperature Sensor
..
Wrote .digitemprc

Der nach dem Parameter -s übergebene Pfad bezeichnet die serielle Schnittstelle. Sein Wert lässt sich wie weiter oben gezeigt durch Analyse der Ausgabe von dmesg ermitteln. In den meisten Fällen sollte er aber identisch sein.

DigiTemp hat beim Aufruf mit dem Parameter -i eine Datei .digitemprc im aktuellen Arbeitsverzeichnis angelegt, welche die ermittelten IDs der Sensoren enthält. Damit brauchen weitere Programmaufrufe kein erneutes Scannen des kompletten Busses durchführen. Das funktioniert aber nur, wenn sie wieder im gleichen Verzeichnis stattfinden. Daher legt man sich am besten schon jetzt auf ein Arbeitsverzeichnis fest, zum Beispiel /home/pi/temperature. Die Ausgabe der Messwerte aller Sensoren kann jetzt mittels

digitemp_DS9097 -a

erfolgen. Wenn alles wie gewünscht funktioniert, überzieht man nun die Sensoren und ihre Lötverbindungen mit Schrumpfschlauch, um Kurzschlüsse zu vermeiden.

Datenerfassung mit RRDtool

Mit dem aktuellen Stand des Projektes ist es möglich, sich auf dem Raspberry Pi einzuloggen und die aktuellen Temperaturmesswerte auf der Kommandozeile auszugeben. Für eine langfristige Wetterdatenaufzeichnung sollen nun die Messwerte in eine Datenbank geschrieben werden. Der Artikel Wetterdatenerfassung mit dem USB-WDE1 befasst sich bereits mit dem Problem der dabei anfallenden Datenmengen und setzt daher die Round Robin Datenbank RRDtool zur Datenspeicherung ein. Diese Lösung bietet sich auch hier an.

RRDtool lässt sich ebenfalls komfortabel mit dem Paketmanager installieren:

sudo apt-get install rrdtool

Am Beginn der Arbeit mit RRDtool steht die Definition der Datenbank. Hierbei muss man sich zunächst Gedanken über zeitliche Auflösung und Umfang der zu speichernden Daten machen. Eine mögliche Festlegung ist:

Daraus ergibt sich dann der folgende Aufruf von rrdtool zum Anlegen der Datenbank.

rrdtool create temperature.rrd --step 900 \
DS:temp0:GAUGE:1200:-40:80 \
DS:temp1:GAUGE:1200:-40:80 \
DS:temp2:GAUGE:1200:-40:80 \
DS:temp3:GAUGE:1200:-40:80 \
RRA:AVERAGE:0.5:1:960 \
RRA:MIN:0.5:96:3600 \
RRA:MAX:0.5:96:3600 \
RRA:AVERAGE:0.5:96:3600

Der Parameter --step 900 legt das grundlegende Datenerfassungsintervall auf 900 Sekunden (15 Minuten) fest.

Anschließend folgt die Definition der Data Sources (DS) - für jeden Sensor eine. Die Namen der Data Sources folgen dabei dem Schema tempn für den Temperatursensor n. Der Temperaturbereich ist auf -40..80 °C eingeschränkt.

Am Ende steht die Festlegung der Round Robin Archives (RRA), die für die eigentliche Datenspeicherung verantwortlich sind. Die erste Definition legt fest, dass die Datenbank 960 Samples unverdünnt, das heißt mit mit einer Schrittweite von 1, speichert (siehe dazu die oben getroffenen Festlegungen). Die folgenden drei RRAs bewirken die Speicherung von 3600 Minimal-, Maximal- und Durchschnittswerten. Die Berechnung dieser drei Größen erfolgt dabei für jeweils 96 Samples, das ist genau ein Tag (96 * 900 Sekunden).

Das Ausführen des Befehls legt die knapp 400 Kilobyte große Datei temperature.rrd im aktuellen Arbeitsverzeichnis an. Die Dateigröße ändert sich nicht mehr, egal wieviele Datensätze eingefügt werden - schließlich handelt es sich um eine Round Robin Datenbank!

Aufnahme läuft...

Das Einfügen der Daten in die Datenbank erfolgt mit dem Kommando rrdtool update. Dabei ist eine Umformung der von digitemp gelieferten Ausgabe in eine von rrdtool akzeptierte Form. Die dafür notwendigen Operationen packt man in das Shellscript gettemp.s:

#!/bin/bash
# Hole Temperaturwerte von den Sensoren und speichere sie in RR Datenbank
#
# Pfad zu digitemp
DIGITEMP=/usr/bin/digitemp_DS9097
# DS Namen der vorhandenen Sensoren
SENSORS=temp0:temp1
# Wechsle ins Verzeichnis mit Datenbank und .digitemprc
cd /home/pi/temperature

data=`$DIGITEMP -a -q -o 2 | awk 'NF>1 {OFS=":"; $1="N"; print}'`
if [ -n "$data" ] ; then
        rrdtool update temperature.rrd -t $SENSORS $data
fi

Das erfolgreiche Ausführen des Scripts (Setzen der Ausführungsrechte mit chmod +x gettemp.s nicht vergessen!) bewirkt zunächst nur eine Aktualisierung des Änderungsdatum der Round-Robin-Datenbank. Man kann den Erfolg auch mit rrdtool lastupdate temperature.rrd testen, welches den letzten geschriebenen Datensatz ausgibt.

Für den Dauereinsatz lässt man das Script regelmäßig aller fünf Minuten durch den Zeitplandienst cron ausführen. Da die Datenbank als kleinstes Messintervall 15 Minuten konfiguriert hat, erfolgt eine Durchschnittsbildung über jeweils drei Messwerte. Zum Anlegen eines entsprechenden crontab Eintrags dient der Befehl:

echo '*/5 * * * * $HOME/temperature/gettemp.s >> $HOME/temperature/gettemp.log 2>&1' | crontab -

Die Ausgabeumleitung bewirkt, dass eventuelle Fehlermeldungen in die Datei gettemp.log gelangen, deren Inhalt man also regelmäßig kontrollieren sollte.

Grafik

Eine hervorragende Eigenschaft von rrdtool ist die eingebaute Grafikengine, mit der sich anprechende Grafiken komfortabel erstellen lassen. Eine Grafik mit dem Temperaturverlauf der letzten 24 Stunden erstellt man zum Beispiel durch:

rrdtool graph tempday.png \
  -s 'now - 1 day' -e 'now' \
  DEF:temp0=temperature.rrd:temp0:AVERAGE \
  LINE2:temp0#00FF00:Innen \
  VDEF:temp0last=temp0,LAST \
  "GPRINT:temp0last:%.1lf °C" \
  DEF:temp1=temperature.rrd:temp1:AVERAGE \
  LINE2:temp1#0000FF:Außen \
  VDEF:temp1last=temp1,LAST \
  "GPRINT:temp1last:%.1lf °C"
Temperatur in den vergangenen 24 Stunden
Nach einem heißen Sommertag und einer tropischen Nacht erzeugt der Code im obigen Listing diese Grafik. Die Höchsttemperatur von fast 40 °C kommt allerdings dadurch zustande, dass die Sonne nachmittags direkt auf den Sensor scheint.


Für weitere Grafikbeispiele siehe Wetterdatenerfassung mit dem USB-WDE1 und rrdgraph_examples.

Ab ins Web!

Nun will man vielleicht die Wetterdaten einem größeren Kreis von Benutzern zugänglich machen. Dazu bietet sich die Einrichtung eines Webservers auf dem Raspberry Pi an. Ein relativ leichtgewichtiger Vertreter ist lighttpd. Die Installation erfolgt durch:

sudo apt-get install libcgi-pm-perl librrds-perl lighttpd

Das zweite installierte Paket librrds-perl ist ein Perlmodul zur Ansteuerung von rrdtool. Man benötigt es später in einem mittels Perl programmierten CGI-Script. Das Script dient zur dynamischen Erzeugung der Temperaturverlaufsgrafik. Diese ändert sich ja alle Viertelstunden, sodass statische HTML-Seiten und Grafiken allein nicht ausreichend sind.

Allerdings muss man lighttpd erst einmal dazu bringen, Perl-CGI-Scripte auszuführen. Dazu sind Rootrechte erforderlich, die per sudo -s zu erlangen sind. Dann schaltet man die Module cgi und userdir (dazu später mehr) an:

sudo -s
lighty-enable-mod cgi
lighty-enable-mod userdir

Damit lighttpd Perl-Scripte mit der Extension .pl auch wirklich ausführt, ist jetzt noch die Datei /etc/lighttpd/conf-enabled/10-cgi.conf zu editieren. Im Block cgi.assign muss man das Kommentarzeichen vor der entsprechende Zeile entfernen:

cgi.assign      = (
        ".pl"  => "/usr/bin/perl"
)

Danach startet man den Server neu und verlässt den Superuser Modus wieder:

/etc/init.d/lighttpd restart
exit

Die vorgenommene Anschaltung des Moduls userdir bewirkt, dass lighttpd auch die HTML-Dateien und CGI-Scripte bereitsellt, die sich in den Home Directories der User unterhalb des Verzeichnisses public_html befinden. Somit können normale Benutzer wie pi Webseiten erstellen und editieren, Rootrechte sind dafür nicht erforderlich. Man sollte das jetzt einmal durch Anlegen der HTML-Datei index.html im Verzeichnis /home/pi/public_html ausprobieren. Eine minimale index.html könnte beispielsweise so aussehen:

<html>
<body>
<h1>Temperatur</h1>
</body>
</html>

Ein Aufruf der Adresse http://localhost/~pi/ sollte nun die HTML-Seite im Browser anzeigen - sofern Sie diesen Artikel auf dem Raspberry Pi lesen! Andernfalls ist natürlich localhost durch seinen Hostnamen oder seine IP-Adresse zu ersetzen.

Als nächstes geht es an die Erstellung des Perl-CGI-Scripts, welches die Grafik erzeugt. Den folgenden Scriptcode speichert man in der Datei graph.pl im gleichen Verzeichnis wie index.html

#!/usr/bin/perl
#
# CGI script to create image using RRD graph
use CGI qw(:all);
use RRDs;
use strict;

# path to database
my $rrd='/home/pi/temperature/temperature.rrd';

# size
my $width=400;
my $height=100;

# read and check query params
my $query=new CGI;
my $type=$query->param('type');
$type='day' unless $type =~ /day|week|month|year/;

# write image into temp file
my $tmpfile="/tmp/graphx_$$.png";
my @opts=("-v", "°C",
"-w", $width,
"-h", $height,
"-s", "now - 1 $type",
"-e", "now",
"-D");
RRDs::graph($tmpfile,
  @opts,
  "DEF:temp0=$rrd:temp0:AVERAGE",
  "LINE2:temp0#00FF00:Innen",
  "DEF:temp1=$rrd:temp1:AVERAGE",
  "LINE2:temp1#0000FF:Außen"
);
# check error
my $err=RRDs::error;
die "$err\n" if $err;

# feed tmpfile to stdout
open(IMG, $tmpfile) or die "can't open $tmpfile\n";
print header(-type=>'image/png', -expires=>'+1m');
print <IMG>;
close IMG;
unlink $tmpfile;

Kern des Scripts ist der Aufruf von RRDs::graph zur Erzeugung der Grafik mittels rrdtool. Dabei werden einige Parameter als Variable übergeben, zum Beispiel der Pfad zur Datenbank oder die Größe der Grafik. RRDs::graph schreibt die Grafik in eine temporäre Datei, anschließend kopiert das Script sie auf seine Standardausgabe. Diese wiederum transportiert der Webserver direkt zum Browser. Vorher wird allerdings noch der Content-Type image/png ausgegeben, damit der Browser weiß, dass jetzt Imagedaten ankommen.

Eine Besonderheit ist die Möglichkeit, den Zeitraum mittels des Query-Parameters type als Bestandteil der URL beim Aufruf des Scripts zu übergeben. Die URL http://localhost/~pi/graph.pl?type=week generiert zum Beispiel den Temperaturverlauf der letzten Woche. Andere mögliche Werte für type sollte man dem obigen Scriptcode leicht entnehmen können. Die Grafiken lassen sich mittels des img Tags in die HTML-Seite einbinden, zum Beispiel:

<img src="graph.pl?type=month">

Man kann dies natürlich auch mehrmals tun, sodass die Seite dann vier Grafiken für den täglichen, wöchentlichen, monatlichen und jährlichen Temperaturverlauf zeigt, beispielsweise wie auf Wetteraufzeichnung - Feste Zeiträume zu sehen.

Oder man stellt nur eine Grafik dar und überlässt dem Anwender die Auswahl des Zeitraums. Der Schlüssel hierzu ist ein HTML-Formular, welches die möglichen Zeiträume und die korrespondieren Query-Parameter in Form von Radiobuttons definiert. Ein iframe und die Angabe des target Attributs mit dem Namen des iframes sorgen dafür, dass der Browser die Grafik auf der gleichen Seite darstellt. Der folgende Codeschnipsel zeigt dies examplarisch, man fügt ihn auf der oben gezeigten minimalen HTML-Seite unmittelbar nach der Überschrift ein:

<iframe marginwidth="0" marginheight="0" frameborder="0" width="400" height="100" name="graph">
</iframe>
<form action="graph.pl" method="get" target="graph">
  <fieldset>
  <legend>Zeitraum</legend>
  <input type="radio" name="type" value="day" checked="checked"/>Tag
  <input type="radio" name="type" value="week"/>Woche
  <input type="radio" name="type" value="month"/>Monat
  <input type="radio" name="type" value="year"/>Jahr
  </fieldset>
  <input type="submit" value="Anzeigen" />
</form> 
Webseite mit Formular und dynamisch erzeugter Grafik
Der Benutzer kann in seinem Browser den interessierenden Zeitraum selbst auswählen,das Perl-CGI-Script erzeugt dann die Grafik mit dem aktuellen Temperaturverlauf.

Das Ergebnis ist im Bild rechts zu sehen, ein weiter ausgebautes Beispiel ist Wetteraufzeichnung - Beliebiger Zeitraum. Dem Erfindungsreichtum sind also keine Grenzen gesetzt. Als sehr gute Hilfestellung und Referenz für die Webseitenerstellung empiehlt sich Selfhtml.

Der auf dem Raspberry Pi laufende Webserver ist in seiner Leistungsfähigkeit aufgrund der Hardware eingeschränkt. Man darf also nicht erwarten, dass er einem Massenansturm von Seitenanfragen gewachsen ist. Besondere Vorsicht ist geboten, wenn ein öffentlicher Zugriff auf den Webserver über das Internet möglich ist. Fehlerhaft oder nachlässig programmierte CGI-Scripte stellen immer wieder ein Sicherheitsrisko dar. Im Zweifelsfall sollte man einen erfahrenen Programmierer oder Sicherheitsexperten konsultieren. Generell sind die hier beschriebenen Techniken ohne weitere Prüfung nur für den Hobby- und Privatbereich geeignet!

Fazit

Der Artikel stellt keine vollständige Schritt-für-Schritt Bauanleitung dar, sondern soll zur Entwicklung eigener, kreativer D.I.Y. Lösungen anregen. Am Ende eines erfolgreichen Projekts hat man eine Menge über Elektronik, Programmierung, Linux und Wetterstationen gelernt. Zwei nach dem beschriebenen Muster gebaute Prototypen arbeiten seit mehreren Monaten zuverlässig.