Raspberry Pi Tutorial 2

Temperatursensor und D2C Nachrichten Senden

Einleitung

In diesem Tutorial geht es darum, einen Raspberry Pi 3 mit dem Clouddienst Microsoft Azure zu verbinden. Im ersten Teil des Tutorials haben wir einen Client auf dem Raspberry Pi programmiert, diesen mit einem Azure IoT Hub verbunden und Cloud-To-Device Nachrichten empfangen. Jetzt erweitern wir das ganze um einen Temperatursensor, dessen Daten wir dann an Azure senden.

Verwendete Hardware: Raspberry Pi

Voraussetzungen:

Dieses Tutorial geht davon aus, das Erfahrung mit Programmierung vorhanden sind, setzt aber keine Erfahrungen mit Raspbian, GPIO Mikroprozessoren (Pi, Arduino etc.) oder Python voraus. Da das Tutorial auf dem Code des ersten Teils aufbaut empfiehlt es sich diesen zuerst durch zuarbeiten, oder den fertigen Code herunterzuladen.

Ziel:

Ziel ist es device-to-cloud Nachrichten an Microsoft Azure IoT Hub zu versenden, die Daten vom Raspberry Pi in die Cloud senden. Um dem ganzen Funktion zu geben schließen wir außerdem einen Temperatursensor an.

Beispiel Nutzungen:

– Außen Temperatursensor

– Bewegungsmelder für eine Hundeklappe

– Verkehrszähler an einer stark befahrenen Straße

Vorbereitung:

Raspberry Pi vorbereiten (Um den Temperatursensor nutzen zu können)

Der in diesem Tutorial verwendete Temperatursensor DS18B20 verwendet das 1-Wire Bus Interface, bevor wir dieses an unserem Raspberry Pi nutzen können, müssen wir dieses dafür vorbereiten. Dafür nutzen wir folgenden Konsolenbefehl um die Konfiguration des Raspberries zu verändern

sudo nano /boot/config.txt  

Dies öffnet die Datei im nano Editor und erlaubt uns diese zu verändern. Wir suchen nun innerhalb dieser Datei nach der Zeile, die dtoverlay=w1-gpio enthält, existiert sie nicht fügen wir sie ganz am Ende der Datei hinzu und speichern das ganze. Damit die Änderungen in Kraft treten müssen wir den Pi neu starten.

Wir bauen jetzt noch einen Schaltkreis mit dem Temperatursensor auf, dafür nutzen wir neben diesem einen GND Pol, einen 3.3V Pol des Pis, sowie den GPIO Pin 4. zwischen dem Kontakt mit dem 3.3V pol und dem Mittleren Füßchen des Sensors wird ein 4.7 Kohm Widerstand eingesetzt. An dem Ende, das nicht mit den 3.3V verbunden ist legen wir das Kable an, das zum GPIO Pin 4 führt.

Schaltplan Temperatursenso

Nachdem wir diesen Schaltkreis aufgebaut haben können wir mittels einiger Befehle testen, ob unsere Einstellungen korrekt sind.

sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices
ls

Dies wird alle Geräte, die über den 1-Wire Bus angeschlossen sind anzeigen. Der Temperatursensor wird eine ID haben, die mit einer 28 anfängt, der viele Nummern folgen. Nun können wir testen ob der Sensor arbeitet, indem wir das Folgende eintippen, dabei wird XXXX durch die Zahlen, die der 28 folgen ersetzt.

cd 28-xxxx
cat w1_slave

Nun sollte man das folgende erhalten. Geschieht das, arbeitet der Sensor

a3 01 4b 46 7f ff 0e 10 d8 : crc=d8 YES
a3 01 4b 46 7f ff 0e 10 d8 t=32768

Den Temperatursensor in den Bisherigen Code einbinden:

Wir öffnen nun wieder unseren Code vom ersten Tutorial und ergänzen diesen um einige imports, da diese für die Verwendung des Temperatursensors von Nöten sind.

 # Import Libraries
 import os
 import glob
 import time

Nun müssen wir noch die folgenden Funktionen in unseren Code einfügen, damit wir die Temperatur auslesen können

# Initialize the GPIO Pins 
os.system('modprobe w1-gpio')  # Turns on the GPIO module 
os.system('modprobe w1-therm') # Turns on the Temperature module   

# Finds the correct device file that holds the temperature data 
base_dir = '/sys/bus/w1/devices/' 
device_folder = glob.glob(base_dir + '28*')[0] 
device_file = device_folder + '/w1_slave'   

# A function that reads the sensors data 
def read_temp_raw():   
  f = open(device_file, 'r') # Opens the temperature device file   
  lines = f.readlines() # Returns the text   
  f.close()          
  return lines   

# Convert the value of the sensor into a temperature 
def read_temp():   
  lines = read_temp_raw() # Read the temperature 'device file'    
 
  # While the first line does not contain 'YES', wait for 0.2s   
  # and then read the device file again.   
  while lines[0].strip()[-3:] != 'YES':     
    time.sleep(0.2)     
    lines = read_temp_raw()     
  # Look for the position of the '=' in the second line of the   
  # device file.   
  equals_pos = lines[1].find('t=')     

  # If the '=' is found, convert the rest of the line after the   
  # '=' into degrees Celsius, then degrees Fahrenheit   
  if equals_pos != -1:     
    temp_string = lines[1][equals_pos+2:]     
    temp_c = float(temp_string) / 1000.0     
    #temp_f = temp_c * 9.0 / 5.0 + 32.0     
    return temp_c #, temp_f

Sobald diese Funktionen Teil des Codes sind ist es uns möglich die Temperatur auszulesen. Man kann dies nun einfach testen, indem man in der While-Schleife, die die bisher nur ein Delay enthält folgendes einfügt:

s = str(read_temp()) 
print(s) 

Jetzt wird nach jeder Wartezeit die aktuelle Temperatur ausgegeben. Dabei sollte man die Wartezeit auf 15 Sekunden erhöhen.

Nachrichten vom Pi senden

Einfache Nachrichten:

Um nun die Temperatur auch in die Cloud zu bekommen müssen wir unserem Client ein paar neue Methoden zur Verfügung stellen, dazu gehört eine sendText(str) und eine sendKeyValuePair(key, value) methode. Zuerst wollen wir die einfachere sendText Methode erstellen. Diese wandelt den übergebenen String in eine IoTHubMessage und schickt diese dann mittels CLIENT.send_event_async an den Server. Da wir in dieser send methode eine Callback Methode angeben müssen erstellen wir auch diese

#Gibt aus, ob die nachricht erfolgreich gesendet wurde 
def send_confirm_callback(message, result, context):   
  print("Nachricht ID %s Status %s" %(message.message_id, result)) 

# Funktion um einen String an den verbundenen IoT Hub zu schicken 
def sendText(str):   
  global CLIENT, send_confirm_callback   
  #aus der Bibliothek passende funktioählen, um ein objekt vom richtigen
  typen zu   
  msg = IoTHubMessage(str)   
  # es gibt weitere optionale parameter, diese könnten mit dem folgenden 
  code gesetzt werden   
  # msg.message_id = "id"   
  # msg.correlation_id = "cid"      
  print("schicke die Nachricht [%s]..." % (str))     
  CLIENT.send_event_async(msg, send_confirm_callback, 0)

Key Value Pair als Nachricht verschicken

Außer einfachen Nachrichten können wir diesen auch noch ein Key, Value Paar anhängen um das Handlen der Nachrichten im Hub später einfacher zu haben. Auch in dieser wird zuerst eine IoTHubMessage erzeugt, dieser werden dann Attribute hinzugefügt bevor sie verschickt wird.

# Methode um Key, Valu paare an den IoT Hub zu schicken 
def sendKeyValuePair(key, value):   
  global CLIENT, send_confirm_callback, MSGID   
  msg_txt = ("%s, %s" %(key, value))   
  msg = IoTHubMessage(msg_txt)   
  msg.message_id = str(MSGID)      
  propmap = msg.properties()   propmap.add(key,value)     
  CLIENT.send_event_async(msg, send_confirm_callback,0)

Um nun die Temperatur als Key Value Paar an den Server zu schicken erzeugen wir uns noch eine weitere Funktion, die den Aufruf der Sendefunktion und das umwandeln der Temperatur in einen String übernimmt. Außerdem kümmert sie sich darum, dass aufsteigende Nachrichten IDs vergeben werden.

def sendTemp():     
  global MSGID      
  s = str(read_temp())     
  sendKeyValuePair("Temperatur",s)     
  MSGID += 1

Jetzt muss nur noch die Schleife nach angepasst werden und wir senden regelmäßig die Aktuelle Temperatur an die Cloud. Mittels dem was wir im letzten Tutorial gelernt haben können wir das senden sogar ferngesteuert machen. Dafür ändern wir nur die gotMail Methode wie folgt und schreiben dies hier in die While-Schleife

while True:   
  if SENDING:     
    sendTemp()     
    time.sleep(15)   
  else:     
    time.sleep(1)  

In der Funktion gotMail müssen wir folgendes ergänzen:

  global SENDING         
  if msg == "temperature" or msg == "temp":         
    print(read_temp())         
    s = str(read_temp())         
    sendText(s)     
  elif msg == "start" or msg == "start sending":       
    SENDING = True     
  elif msg == "stop" or msg == "stop sending":       
    SENDING = False   

Weitere Tutorials

Schnellstart Tutorial
Tutorial 1: C2D Nachrichten empfangen
Tutorial 3: Daten per Mail versenden