Kategorien
Linux Steuerungen

Temperatursensor DS18B20 unter Linux per Pythonscript abfragen

Vor ein paar Tagen habe ich eine kurze Übersicht über die Benutzung der OneWire-Schnittstelle in CODESYS 3.5 auf dem Raspberry Pi veröffentlicht. Inzwischen habe ich per Mail von mehreren Lesern die Frage nach einer funktionierenden Lösung mit Python bekommen, daher möchte ich das noch schnell hinterher schieben.

Aufbau

Um das ganze noch ein kleines Bisschen spannender zu machen, sind dieses Mal drei Sensoren gleichzeitig angeschlossen. Auf dem Breadboard sieht das so aus:

Drei Temperatursensoren DS18B20 parallel an einer "Sensorleitung"
Drei Temperatursensoren DS18B20 parallel an einer „Sensorleitung“

Schnell in gEDA abgezeichnet sieht es so aus:

Drei DS18B20 parallel als Schaltbild
Drei DS18B20 parallel als Schaltbild

Man sieht also, die Sensoren können parallel geschaltet werden, der Widerstand wird nur ein Mal benötigt.

Wenn, wie im oben bereits verlinkten Artikel die Kernelmodule über den Device Tree geladen sind (/boot/config.txt), sollten die drei Sensoren danach im Verzeichnis /sys/bus/w1/devices/ sichtbar sein, hier gibt es wieder für jeden Sensor einen Ordner, der mit seiner eindeutigen ID benannt ist:

Die Ordner der drei Sensoren, benannt nach der jeweiligen ID
Die Ordner der drei Sensoren, benannt nach der jeweiligen ID

Wie schon im ersten Artikel können auch hier die Werte mit der Datei w1_slave ausgegeben werden:

root@raspberrypi:/sys/bus/w1/devices/28-0216009b68ff# cat w1_slave 
2f 01 4b 46 7f ff 0c 10 a7 : crc=a7 YES
2f 01 4b 46 7f ff 0c 10 a7 t=18937

So weit waren wir beim letzten Mal auch schon, jetzt gehts ans Python-Script.

Programm erstellen

Zuerst müssen wir die bis dahin ja noch nicht existente Datei mit dem Editor unserer Wahl öffnen. Ich mag nano, öffne die Datei also mit

nano temp.py

Um das Programm später mit dem richtigen Interpreter direkt ausführen zu können, müssen wir jetzt im Shebang python als ebendiesen nennen, danach legen wir fest, welche Bibliotheken geladen werden sollen:

#!/usr/bin/env python
import os, time, sys

Um Fehlern aus dem Wege zu gehen, laden wir nun noch die Kernelmodule, die wir nutzen möchten:

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

Am Anfang des Programmes legen wir nun noch ein paar Werte als Variablen fest, die wir später benutzen können. Ich habe als sensorcount die Anzahl des Sensoren angegeben, unter sensors die Kennung der drei Sensoren als Array, unter sensorpath den Pfad zu den Geräteverzeichnissen als String und unter sensorfile den Namen der Datei ebenfalls als String:

sensorcount = 3
sensors = ['28-0216009b68ff', '28-021600b769ff', '28-021600bb4dff'];

sensorpath = '/sys/bus/w1/devices/'
sensorfile = '/w1_slave'

Nun erstellen wir die Funktion, die die Sensordaten abfragt und verarbeitet:

def callsensor(sensor):
  f = open(sensorpath + sensor + sensorfile, 'r')
  lines = f.readlines()
  f.close()
  if lines[0].strip() [-3:] != 'YES':
    sys.exit('Fehler bei Sensor ' + sensor)
  temp_line = lines[1].find('t=')
  if temp_line != -1:
    temp_output = lines[1].strip() [temp_line+2:]
    temp_celsius = float(temp_output) / 1000
    return temp_celsius

Die Funktion öffnet die Gerätedatei im Lesemodus, schreibt den Inhalt auf lines und schließt sie dann wieder. Die Variable sensor wird dabei später als Parameter beim Funktionsaufruf mitgegeben.
Zeile 1 wird nun auf die letzten drei Zeichen gekürzt und geprüft, ob diese „YES“ sind, also ob die Prüfsumme des Sensors okay ist. Wenn nicht, wird das Programm mit einer Fehlermeldung abgebrochen.
Nun wird der Index (also die Position) des Strings t= in der zweiten Zeile ermittelt. Ist diese nicht -1 (das gibt find zurück, wenn nichts gefunden wurde), wird Zeile 2 auf die Zeichen nach t= gekürzt (das ist der fünfstellige Temperaturwert des Sensors), der Wert wird durch 1000 geteilt und wir erhalten so den Wert in °C. Die Funktion wird dann beendet und der Temperaturwert zurückgegeben.

Nun fehlt nur noch der Teil, der die Funktion beim Aufruf des Programms ausführt und die Werte an stdout (also momentan die Konsole) zurückgibt:

for i in range(0, sensorcount):
  s = sensors[i]
  print('Sensor ' + str(i) + ': ' + str(callsensor(s)))
sys.exit()

Hier haben wir eine for-Schleife, die die Funktion callsensor für jeden Sensor einmal aufruft und die Sensor-ID aus dem Array als Parameter an callsensor übergibt. Das Ergebnis wird ausgegeben und das Programm wird beendet.

Das Programm müssen wir nun nur noch speichern. Um es ausführen zu können, müssen wir es noch ausführbar machen:

chmod +x temp.py

Wenn wir es nun in der Konsole ausführen, bekommen wir drei Ausgaben für unsere Sensoren:

root@raspberrypi:~/tutorials/temperatur# ./temp.py
Sensor 0: 18.437
Sensor 1: 19.937
Sensor 2: 20.062

Zum Schluss hänge ich die Programmdatei (übrigens kommentiert) hier an: Python-Programm temp.py

5 Antworten auf „Temperatursensor DS18B20 unter Linux per Pythonscript abfragen“

Hallo Raider,

die einfachste Lösung wäre vermutlich, die Daten zyklisch abzufragen und den Output statt in die Konsole in eine Textdatei zu pipen. Das ganze kannst du mit einem kurzen Shellscript als Daemon ausführen lassen. Allerdings solltest du darauf achten, in der zyklischen Schleife eine Pause einzubauen, damit du den Raspi nicht überlastest, die Abfrage der Datei dauert immer etwas und blockiert die CPU. Da reichen ja vermutlich Daten alle 15s oder so.
Für die Anzeige auf der Seite parst du die Textdatei dann einfach in PHP und gibst sie als HTML aus.

Wenn es komplizierter werden soll, schau dir doch mal Bottle und Cork oder Flask an, das sind Python-Frameworks, die den Aufbau ganzer Websites in Python ermöglichen und einen eigenen Webserver mitbringen.

Wenn du dazu fragen hast, kann ich dir gerne mehr Tipps geben 😉

Entweder das (dann müsstest du quasi nichts weiter beachten), oder eben die Funktion in einer Schleife mit while True:

Komfortabler wäre es noch, ein initscript zu schreiben (in /etc/init.d/ ablegen) und das zyklische Programm darüber beim Systemstart ebenfalls zu starten.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert