Strings und DS18B20

Wir haben schon häufig mit Strings gearbeitet. Diese können wir einfach mit string = "Hello World" erzeugen. Alles was zwischen den " steht, wird gespeichert. Doch jetzt bieten uns Strings noch mehr Möglichkeiten, mit diesen gespeicherten Daten umzugehen. Denn wie bei einer Liste hat jedes Zeichen im String eine Nummerierung, die bei 0 anfängt. print(string[1]) würde in diesem Fall ein „e“ ausgeben. Wir können auch Abschnitte in einem String markieren print(string[5:9]) gibt nur „Wor“ aus. Das heißt, vor dem :schreiben wir den Anfangswert und dahinter den Endwert. Wenn wir den Anfangs- oder Endwert von dem ganzen String haben wollen, können wir auch einfach nichts hinter/vor dem : schreiben. print(string[5:]) gibt „World“ aus.

Eine weitere Funktion, die wir schon kennengelernt haben, ist das Verbinden von zwei Strings mit +print(string[:6]+"Welt") gibt nur noch „Hello Welt“ aus. Das zeigt auch, dass sich die einzelnen Funktionen kombinieren lassen.

Strings haben Funktionen

Bis jetzt haben wir nur Funktionen kennengelernt, die so aufgebaut sind: funktionsName(Parameter1, Parameter2) doch es gibt auch noch eingebaute Funktionen, die so aufgerufen werden objekt.funktionsName(Parameter1, Parameter2). Diese eigebauten Funktionen nennt man Methoden. Ein String gehört zu diesen Objekten, die Methoden haben. Wenn wir diese aufrufen wollen, nehmen wir zuerst das Objekt oder die Variable, in der wir das Objekt gespeichert haben und rufen danach die Methode auf. Weil es recht viele String-Methoden gibt, haben wir eine Liste mit Beispielen:

FunktionBeispiel
.capitalize()print("hello".capitalize()) -> Hello
.count(string)print("hello".count("l")) -> 2
.find(string)print("hello".find("o")) -> 4
len(string)print(len("hello")) -> 5
.lstrip()print(" hello".lstrip()) -> hello
.replace(alt, neu)print("Hello World".replace("World", "Welt")) -> Hello Welt
.upper(alt, neu)print("hello world".upper()) -> HELLO WORLD

DS18B20 – Der Temperatur-Sensor

Puh, ganz schön kalt/lauwarm/heiß hier drinnen. Du möchtest wissen, wie kalt/lauwarm/heiß es genau ist? Mit dieser hoch technologischen Temperaturerkennungsapparatur ist das kein Problem.

Pin 1Pin 2Pin 3
GND GroundDataVCC – 3,3V

[Vorne ist die flache Seite]

Der DS18B20, wie wir unseren kleinen Temperatursensor liebevoll nennen, ist ein recht simpel aufgebauter Sensor. Eine Besonderheit an ihm ist, dass er zur Kommunikation das One-Wire-Protokoll benutzt. Dies ermöglicht uns beliebig viele Sensoren an einen GPIO-Pin des Raspberry Pis anzuschließen. Mehr dazu erfährst du in den nächsten Kapiteln.

Raspberry Pi einrichten

Bevor du diesen Sensor benutzen kannst, musst du an deinem Pi noch ein paar Konfigurationen durchführen. Da der Pi ein ganz schön fauler Computer ist, spart er sich einfach etwas Arbeit und lädt nicht alle für uns wichtigen Pakete nach. Um das zu ändern, müssen wir die configx.txt Datei bearbeiten.

$ sudo nano /boot/config.txt

Füge am Ende dieses Dokumentes einfach folgende Zeile hinzu:

dtoverlay=w1-gpio,gpiopin=4

Speichern musst du mit mit Strg + X, dann y und am Ende noch Enter. Was haben wir jetzt eigentlich verändert? Ganz einfach, beim Start deines Pi wird jetzt immer das One-Wire-Interface geladen. Außerdem legen wir mit gpiopin=4 fest, dass der GPIO Pin 4 der zuständige One Wire Pin ist.
Alternativ kannst du das One-Wire-Interface auch in der raspi-config aktivieren: Interface Options->1-Wire

Alle wichtigen Einstellungen sind jetzt gespeichert. Damit alles auch einwandfrei funktioniert, musst du deinen einmal Pi kurz neu starten.

$ sudo reboot

DS18B20 anschließen

GPIO Pins am PiPins am Sensor
3,3VVCC
GPIO4Data+ 4,7kΩ zu VCC
GNDGND

Das Verbinden des Sensors mit deinem Pi ist simpler als einen Kaktus am Leben zu erhalten. Du solltest darauf achten, den Data Pin und den VCC Pin mit einem 4,7kΩ Widerstand zu verbinden UND das er richtig rum ist!

Daten auslesen

Um ganz einfach die ersten Daten auszulesen, musst du, wenn alles richtig angeschlossen ist, erstmal einen großen Berg versetzen. Da dieser Sensor ein One-Wire Sensor ist, kannst du alle Daten auch in dem Verzeichnis von den One-Wire Geräten lesen.

$ cd /sys/bus/w1/devices
$ ls

Alle One-Wire Geräte haben eine spezifische Adresse, die einzigartig ist. Beim DS18B20 fangen diese Adressen gewöhnlich mit 28-xxxxxxxxxxxxx an. Deswegen ersetzt du einfach die xxxxxxxxxxxxx durch deine Nummer in den nachfolgenden Beispielen.

$ cd 28-xxxxxxxxxxx

In diesem Ordner sehen wir verschiedene Dateien. Die einzige Datei, die für uns jetzt interessant ist, ist die w1_slave. In dieser steht auch die gemessene Temperatur, die wir aber zuerst auslesen müssen.

$ cat w1_slave

Mit cat nameDerDatei werden Inhalte von einer Datei im Terminal dargestellt. Damit könnt ihr euch auch die sonstigen Python Dateien anzeigen lassen. In der ersten Zeile ist vor allem das Ende wichtig, weil uns das YES anzeigt, dass alle Daten korrekt gelesen wurden. In der zweite Zeile steht am Ende die Temperatur. In diesem Fall beträgt die Zimmertemperatur gerade 21,5°C. Für mich persönlich eine sehr angenehme Temperatur. Ein Pinguin fände es wahrscheinlich etwas zu warm. So viel zur subjektiven Wahrnehmung einer objektivierten Einheit durch unterschiedliche Individuen.

Auch wenn viele Nachkommastellen angegeben werden, hat der Sensor eine Ungenauigkeit von ± 0,5°C. Das heißt, in diesem Fall liegt die echte Temperatur zwischen 22,0°C und 21,0°C

Jetzt hast du den kleinen DS18B20 schon manuell ausgelesen. Aber ein super praktischer Mini-PC wäre kein super praktischer Mini-PC, wenn er diese Aufgabe nicht auch automatisch erledigen könnte. Und das alles macht er mit den folgenden paar Zeilen Python Code. Das Programm können wir nicht in dem Verzeichnis mit den Sensor Daten erstellen sondern müssen dafür erstmal zurück in unser Homeverzeichnis. Dafür reicht es nur cd ohne etwas anderes einzugeben 😉

import glob
import time

path = "/sys/bus/w1/devices/"
sensor_path = glob.glob(path + "28*")[0]
sensor_data_path = sensor_path + "/w1_slave"

def read_temperature():
  file = open(sensor_data_path, "r")
  rows = file.readlines()
  file.close()
  return rows

def get_temperature_in_degree():
  rows = read_temperature()
  while rows[0].strip()[-3:] != 'YES':
    time.sleep(0.2)
    rows = read_temperature()
  equals_pos = rows[1].find('t=')
  if equals_pos != -1:
      temp_string = rows[1][equals_pos+2:]
      temp_c = float(temp_string) / 1000.0
      return temp_c
while True:
  print(get_temperature_in_degree())
  time.sleep(1)

Wenn du alles richtig angeschlossen hast und das Programm ausführst, wird jede Sekunde die Temperatur ausgelesen und im Terminal ausgegeben.

Was macht das Programm?

Wie in der vorherigen Einheit schreibt der Sensor seine gesamten gemessenen Daten in eine Textdatei, die in /sys/bus/w1/devices/28-xxxxxxxxxxxxxxxxxxxx/w1_slave steht. Das heißt, die einzige Herausforderung ist es, die Textdatei mit dem Pythonprogramm auszulesen und dann die richtige Temperaturwerte aus der gesamten Datei herauszuschneiden.

Schritt für Schritt

In Zeile 1 und 2 importieren wir zuerst die nötigen Bibliotheken. Mit der glob Bibliothek können wir uns im Dateisystem des Raspberry Pi bewegen. In der 4. Zeile geben wir den Pfad an, in dem die One-Wire-Sensoren ihre Daten speichern. Jetzt haben wir nur ein Problem, da wir nicht genau wissen, wie die ID des Sensors lautet. Das können wir aber ganz leicht mit der glob.glob() Funktion herausfinden. Alles, was diese Funktion macht, ist nachzusehen, ob es unter diesem Pfad einen Ordner gibt, der mit 28 anfängt und dann den Pfad des Ordner in der Variable sensor_path speichert.

Wenn du mehrere Sensoren eingebunden hast, wirst du mit dieser Funktion immer nur den ersten Sensor auslesen

In Zeile 6 fügen wir jetzt einfach nur die Datei hinzu und haben damit den kompletten Pfad zu der Datei, in der die Temperaturen stehen.

Damit der Code ein wenig aufgeräumter ist, erzeugen wir in Zeile 8 unsere eigene Funktion und nennen diese read_temperature(). Diese Funktion liest dann in den Zeilen 9 bis 11 die Datei und gibt dann in einer Liste die einzelnen Zeilen in der Liste zurück. Funktionen können einfach Werte wie strings oder integer zurückgeben. Das machen sie zum Beispiel mit return variable oder return "Hallo".

In Zeile 14 erzeugen wir die zweite Funktion mit dem Namen grad_lesen. Der Name ist Programm. Damit wird die Gradzahl der Temperatur ausgelesen. Die ganze Erklärung findest du online, aber kurz gesagt geht das Programm in Zeile 16 die gesamte Liste durch, welche in der Variablen zeilen gespeichert wurde, und sucht nach dem „YES“. Wenn das nicht der Fall ist, wartet das Programm in Zeile 17 für 0,2 Sekunden und liest dann mit dem erneuten Aufrufen der Funktion read_temperature() in Zeile 16 den gesamten Inhalt solange erneut auf, bis es ein „YES“ gefunden hat, was bedeutet, dass der Sensor Daten ausgelesen hat.

In Zeile 19 sucht das Programm nach dem t=, hinter dem die Temperatur steht, um diese dann auszuschneiden und von einem String in ein Float, also eine Kommazahl umzuwandeln. Et voilà!

Diese Funktion rufen wir dann in Zeile 25 auf. Da die while Schleife auf true gesetzt ist, läuft sie solange, bis das Programm beendet wird. Damit aber nicht alles viel zu schnell abläuft, wartet die while Schleife immer für eine Sekunde, bis sie sich wiederholt. Du wirst feststellen, dass sich meistens die Temperatur in deinem Zimmer innerhalb einer Sekunde nicht großartig verändert. Wenn du trotzdem mal den Sensor „testen“ möchtest, kannst du ihn zum Beispiel anhauchen oder einfach mal anfassen.