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:
Schnell in gEDA abgezeichnet sieht es so aus:
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:
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 zu “Temperatursensor DS18B20 unter Linux per Pythonscript abfragen”
Hey, danke für das How-To…
Ich würde die Infos gerne auf einer internen Website im Heimnetz verfügbar machen. HÄttest du da Tipps?
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 😉
Danke!
Wie würdest du denn das zyklisch machen? Per Cron?
Das andere ist mir zu kompliziert, das verstehe ich nicht so recht…
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.
Superscript für 1 und mehrere Sensoren einfach anzupassen und gut verständlich.