ESP8266 & NodeMCU (LUA) Tutorial – Temperatursensor DS18B20 abfragen

Dies ist Teil zwei meiner Tutorialserie zum ESP8266.
Teil eins ist hier zu finden: „ESP8266 & NodeMCU (LUA) Einstiegstutorial

Inhalt

  1. Einleitung
  2. Voraussetzungen
  3. Hardware-Vorbereitung
  4. Firmware flashen
  5. Das Programm

Einleitung

Im ersten Teil der Reihe habe ich beschrieben, was der ESP8266 ist, wie man die Firmware auf den Controller läd und sich in der Programmierumgebung ESPlorer mit dem Chip verbindet und die Verbindung überprüft.

Hier soll es nun darum gehen, ein einfaches Programm zu erstellen, um mehrere Temperatursensoren DS18B20 einzubinden und Daten wie Chip-Adresse und die Temperatur anzuzeigen.

Voraussetzungen

Als Hardware wird der ESP8266 in Form des ESP-01 genutzt, grundsätzlich funktioniert natürlich jedes andere Modul mit mindestens einem GPIO-Pin. Dieses Tutorial ist aber ausdrücklich für den ESP-01 geschrieben und auch nur auf diesem getestet.

Ansonsten gehe ich davon aus, dass sowohl das ESPTool zum flashen der Firmware, als auch der ESPlorer bereits installiert sind und funktionieren.

Praktisch wäre es natürlich auch, wenn zwei Temperatursensoren DS18B20 vorhanden sind, diese sind auf ebay sehr günstig aus China, oder etwas teurer aus Deutschland erhältlich. Außerdem wird ein 4,7 Kiloohm-Widerstand benötigt.

Hardware-Vorbereitung

Zuerst sollten wir die Hardware entsprechend zusammen stecken. Grundsätzlich ist der Aufbau sehr ähnlich der bereits aus dem ersten Teil bekannten Konfiguration, hinzu kommen nur ein 4k7Ω Widerstand, sowie die beiden DS18B20. Die Grafik sieht der Übersicht halber ein wenig anders aus, ist aber tatsächlich nur in den genannten Details unterschiedlich zur Grafik aus dem ersten Teil.

Der ESP8266 auf einem Breadboard mit dem zwei Temperatursensoren DS18B20
ESP8266 mit DS18B20

Auf dem Breadboard sieht das in etwas komprimierter Form bei mir so aus:

Der ESP8266 mit zwei DS18B20 zusammengesteckt auf einem Breadboard
ESP8266 mit DS18B20 auf Breadboard

Wie man sieht, habe ich die Sensoren direkt auf das Breadboard gesteckt, ebenso den Widerstand.

Firmware flashen

Hier soll es nicht darum gehen, wie die Firmware auf den Chip kommt, sondern darum, dass die korrekte Firmware auf den Chip kommt. Im weiteren Verlauf des Tutorials wird eine Bibliothek genutzt, die verschiedene Module in der Firmware des ESP8266 benötigt.

Die von mir genutzte Firmware enthält die Module

  • file
  • gpio
  • net
  • node
  • ow
  • tmr
  • uart
  • wifi

geflasht ist die float-Version, da dies für die genutzte Bibliothek des DS18B20 notwendig ist.

Wer mag, kann auch die von mir genutzte Firmware hier herunterladen, dann ist alles genau gleich.

Wie die Firmware auf den ESP8266 kommt, habe ich ja bereits geschrieben, dies sollte nun geschehen.

Das Programm

Nun sollte alles bereit sein: Die Hardware ist zusammengesteckt, die Firmware ist auf den ESP8266 geflasht und die Programmieroberfläche ESPlorer ist installiert und einsatzbereit.

Um die Sensoren über unser einfaches Programm abfragen zu können, benötigen wir die Bibliothek ds18b20.lua, die ich vor längerer Zeit mal im Git-Repo von NodeMCU heruntergeladen habe. Ich weiß leider nicht mehr genau, welche der Bibliotheken es war, daher stelle ich auch diese hier zum Download zur Verfügung. Die Bibliothek kann an beliebiger Stelle entpackt werden und dann im ESPlorer geöffnet werden. Hierzu einfach im Reiter „NodeMCU & MicroPython“ auf „Open“ klicken, zu der Datei navigieren, auswählen und öffnen:

Bibliothek ds18b20.lua in ESPlorer öffnen
Bibliothek ds18b20.lua in ESPlorer öffnen

Die geöffnete Datei muss nicht weiter angepasst werden, sie wird nun per Klick auf „Save to ESP“ in den Speicher des ESP8266 geladen und ist ab diesem Zeitpunkt auf dem Gerät nutzbar.

Nun schreiben wir das eigentliche Programm, welches die eben gespeicherte Bibliothek nutzt, um Daten von angeschlossenen DS18B20-Sensoren zu empfangen und auszugeben. Der Dateiname ist hier ds18b20-test.lua.

-- Testprogramm um mehrere DS18B20 zu lesen

-- GPIO-Pin festlegen
pin = 3

-- DS18B20-Modul und GPIO initialisieren
t=require("ds18b20")
t.setup(pin)
addrs=t.addrs()

-- Anzahl der DS18B20 ausgeben
print('Anzahl Sensoren: ' .. table.getn(addrs))

-- Adresse(n) der DS18B20 ausgeben
for k, v in pairs(addrs) do print('Adresse Sensor ' .. k .. ':', v:byte(1,8)) end

for k, v in pairs(addrs) do
print('Temperatur Sensor ' .. k .. ': ' .. t.read(v,C) .. ' Grad Celsius')
end

-- Alle Ressourcen wieder freigeben
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil

Die Kommentare sagen eigentlich schon so ziemlich alles: Der nutzbare GPIO-Pin heißt in der Firmware Pin 3 und wird am Anfang des Programms festgelegt. Die eben auf das Gerät geladene Bibliothek wird geladen und der Pin übergeben. Nun wird gezählt, wieviele Sensoren gefunden wurden, die Zahl wird ausgegeben, danach die Adressen der Sensoren, sowie der Temperaturwert.
Zum Schluss werdend die Ressourcen wieder freigegeben.

Auch dieses Programm kann hier heruntergeladen werden, da vermutlich Hochkommata etc. hier falsch dargestellt sein dürften.

Diese Datei muss nun wie schon die Bibliothek per Klick auf „Save to ESP“ in den Speicher des ESP8266 geladen werden. Ist dies geschehen, wird das Programm bereits ausgeführt. Es sollte also in etwa so aussehen:

Das Programm wird im ESPlorer in den Speicher geladen und danach automatisch ausgeführt.
Das Programm wird gespeichert und ausgeführt

Wir sehen also, dass die beiden Sensoren funktionieren und uns neben ihrer Adresse auch die Temperatur melden.

Um das Programm nun über den ESPlorer ausführen zu lassen, müssen wir nur den Befehl

dofile("ds18b20-test.lua");

in der Befehlszeile unten im ESPlorer ausführen und bekommen schon unser gewünschtes Ergebnis zurück:

Das Programm wird im ESPlorer mit dem Befehl dofile("ds18b20-test.lua"); ausgeführt.
DS18B20 abfragen über ESPlorer

Damit geht dieses Tutorial auch wieder zuende, im (hoffentlich bald folgenden) nächsten Teil steigen wir dann etwas tiefer ein und lassen das Programm zyklisch auf dem Controller laufen und die Werte über eine einfache Webseite im LAN/WLAN ausgeben.

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

Raspberry Pi: 1-Wire Temperatursensor 18B20 auslesen unter Linux und CODESYS

Wer sich mal etwas mit dem kostengünstigen verdrahten moderner Häuser oder Wohnungen auseinander gesetzt hat, wird schon auf den 1-Wire oder OneWire Bus gestoßen sein. Dieser Bus ermöglicht es, mit einem geringen Verdrahtungsaufwand zum Beispiel Sensoren an ein Gerät anzuschließen. Es werden mindestens zwei Adern benötigt, besser drei oder vier, es können jedoch mehrere Sensoren parallel angeschlossen werden.

Ein sehr beliebter Sensor ist der Temperatursensor 18B20 bzw. DS18B20, er misst die Temperatur auf 0,5°C genau und gibt diese als tausendstel aus, 21,5°C zeigt der Sensor also als 21500 an. Die Messung wird über eine Prüfsumme validiert.

1-Wire am Raspberry Pi aktivieren

Der Raspberry Pi bringt einen 1-Wire-Bus mit, der über die GPIO-Pins läuft. Der Bus mus jedoch zuerst eingeschaltet werden, dies geschieht über die Datei /boot/config.txt, hier muss eine Zeile mit folgendem Inhalt eingetragen werden:

dtoverlay=w1-gpio

Dies aktiviert im Device Tree die 1-Wire-Schnittstelle auf dem Standard-GPIO-Pin, also Pin 7. Nach dieser Änderung muss ein Neustart durchgeführt werden, der Bus ist nun aktiv.

DS18B20 an den Raspberry Pi anschließen

Der Sensor hat drei Beinchen. Schaut man auf die abgeflachte Seite mit der Beschriftung, ist das linke Beinchen die Nummer 1 und damit GND (also 0V), das mittlere die Nummer 2 und damit DQ (die Datenleitung) und das rechte Beinchen ist die Nummer 3 und stellt die Versorgungsleitung VCC (3,3V) dar.

Belegung der Pins des DS18B20
Belegung der Pins des DS18B20

In diesem Beispiel schließen wir den DS18B20 mit drei Adern an die 3,3V Versorgungsspannung des Raspberry Pi an. Bei größeren Leitungslängen empfiehlt es sich, für die Versorgungsspannung 5V zu nehmen und den Widerstand von DQ auf eine separate Ader mit 3,3V zu ziehen. Zum Testen reicht dieser Aufbau aber allemal.

So wird der Sensor DS18B20 an die GPIO-Pins des Raspberry Pi angeschlossen
So wird der Sensor DS18B20 an die GPIO-Pins des Raspberry Pi angeschlossen

Die Verkabelung kann entweder fliegend verlötet werden, oder aber (etwas eleganter und einfacher) auf einem Breadboard aufgesteckt werden. Ich tat letzteres, wenn auch wegen akuten Jumperwire-Mangels nicht besonders ordentlich:

Der DS18B20 auf dem Breadboard, verbunden mit dem Rsspberry Pi
Der DS18B20 auf dem Breadboard, verbunden mit dem Rsspberry Pi

Sensordaten abfragen im Linux-Terminal

Jeder Sensor hat eine einmalige Kennung, unter dieser Kennung wird auch ein Geräteordner unter /sys/bus/w1/devices angelegt. In meinem Falle hat der Sensor die Kennung 28-021600bb4dff, daher ist der Geräteordner /sys/bus/w1/devices/28-021600bb4dff. In diesem Ordner befindet sich die Gerätedatei w1_slave. Lässt man sich diese Datei beispielsweise mit cat ausgeben, wird der Sensor abgefragt und die Checksumme, sowie die Temperatur ausgegeben:

Die Ausgabe der Gerätedatei des DS18B20
Die Ausgabe der Gerätedatei des DS18B20

Stimmen beide Checksummen überein, ist das Ergebnis plausibel und hinter der crc steht „YES“. Im Fehlerfall würde dort „NO“ stehen. In der zweiten Zeile wird die Temperatur angezeigt, teilt man diesen Wert durch 1000 kommt man auf die Temperatur in °C, bei mir also 20,125°C.

Das ist eigentlich schon alles. Diese Datei kann man natürlich über Scripte oder Programme auslesen und weiter verwenden.

Sensordaten abfragen unter CODESYS

Seit längerem gibt es ja von 3S die CODESYS Laufzeit für den Raspberry Pi, eine meiner Meinung nach für Privatanwender und Bastler schöne Lösung in die Automatisierung einzusteigen, ohne hohe Ausgaben für „echte“ SPS-Hardware zu haben.

Über CODESYS auf dem Raspberry Pi habe ich schon zwei Artikel verfasst. Im ersten Artikel wird unter anderem erklärt, wie die Laufzeit auf dem Gerät installiert wird und wie eine Verbindung zum Raspberry Pi hergestellt wird, im zweiten geht es eher um die Python-Bibliothek Pymodbus, die die Modbus-Kommunikation zum Beispiel zwischen einem Raspberry Pi und einem Controller mit CODESYS ermöglicht.

Wir benötigen also einen Raspberry Pi mit installierter CODESYS Laufzeit, sowie dem angeschlossenen und funktionierenden Sensor wie oben beschrieben.

Im CODESYS legen wir ein neues Projekt an und wählen als Zielsystem den Raspberry Pi.

CODESYS Projekt anlegen für DS18B20 auf Raspberry Pi
CODESYS Projekt anlegen für DS18B20 auf Raspberry Pi

Nachdem das Programm angelegt ist, baut sich automatisch die Struktur auf und man sieht auch schon den Punkt für 1-Wire (bzw. Onewire).

Zunächst muss eine Verbindung zum Raspberry Pi hergestellt werden, dafür werden per Doppelklick auf den Raspberry die Geräteeinstellungen geöffnet und die IP des Gerätes eingetragen (und die Zugangsdaten, falls nicht zuvor schon einmal geschehen). Wenn die Verbindung grün angezeigt wird, ist alles in Ordnung.

CODESYS verbinden mit dem Raspberry Pi im Device Manager
CODESYS verbinden mit dem Raspberry Pi im Device Manager

Nun kann mit der Konfiguration des 1-Wire Sensors begonnen werden. Per Rechtsklick auf den Eintrag „Onewire“ öffnet sich das Kontextmenü, hier wird über den Menüpunkt „Gerät anhängen“ das Gerät „Onewire_master“ angehängt.

Das Gerät Onewire_master anhängen
Das Gerät Onewire_master anhängen

Auf die selbe Art wird nun noch der Sensor DS18B20 angehängt: Rechtsklick auf Onewire_master, Gerät anhängen, DS18B20 auswählen.

Nun sind alle Geräte vorhanden, die benötigt werden. Der Sensor muss nun noch Parametriert werden, die Gerätekennung muss eingetragen werden. Hierzu öffnet man das Device per Doppelklick und trägt im Reiter „1-wire bus Parameter“ in der Spalte „Wert“ die Kennung ein, die eben schon in der Konsole angezeigt wurde, bei mir also 28-021600bb4dff. Das ganze als String, also in Hochkommata ‚.

Der Sensor DS18B20 wird parametriert, die Gerätekennung wird eingetragen.
Der Sensor DS18B20 wird parametriert, die Gerätekennung wird eingetragen.

Das war eigentlich schon alles, der Sensor sollte nun im Programm benutzbar sein. Den Temperaturwert kann man recht einfach nutzen, indem man den String rTemp des Sensors ausliest und beispielsweise auf eine Variable schreibt. Der Wert rTemp ist ein REAL, die Variable muss also auch den Typ REAL haben.

Der Temperaturwert wird über rTemp ausgelesen.
Der Temperaturwert wird über rTemp ausgelesen.

Im laufenden Programm sieht das ganze dann so aus:

Die Livedaten des DS18B20 werden im laufenden Programm angezeigt.
Die Livedaten des DS18B20 werden im laufenden Programm angezeigt.

Eigentlich recht simpel. Da mehrere Sensoren parallel angeschlossen werden können, kann man so einfach die Temperatur in einem ganzen Haus messen und dank der HTML5-WebVisu von CODESYS 3.5 auch optisch ansprechend im Netzwerk abrufbar machen. Eine Heizungssteuerung wäre natürlich auch ein guter Anwendungszweck.