Projektbeskrivning

När det här projektet är klart så har vi en Raspberry Pi som övervakar temperaturen via en DS18B20 temperaturprob (finns att köpa för runt 40-80 kr till varstans). För att larma användaren om att temperaturen har överstigit ett visst gradtal tänds en lysiod. Under tiden programmet körs kan man också se temperaturen direkt på skärmen.

Förberedelser

Vi behöver en Raspberry Pi av valfri version med Raspbian installerat. Raspbian version Jessie eller högre är att rekommendera. Sen behöver vi entrådig kopplingstråd av valfri längd, en lysdiod, två resistorer (en på 4,7 kOhm och en på 220 Ohm), en temperaturprob av modell DS18B20. En kopplingsplatta, eller experimentplatta som det också kallas, är att rekommendera för att koppla upp allting på.

Hårdvaran

Vi börjar med att koppla upp allting innan vi börjar på mjukvara. När vi väl kopplat in hårdvaran är det dags att leta upp temperaturproben i systemet. Så första steget blir att koppla in allting enligt kopplingsschemat här nedan. Här följer också en kort förklaring.

  1. Börja med temperaturproben. Koppla ihop VDD och databenet (DQ) med en 4.7 kOhms resistor. Om du köper en färdig mätprob med kabel, så brukar datakabeln vara antingen gul eller vit. VDD är röd och GND är svart.

  2. Koppla därefter mätprobens VDD (inspänningen) till första pinnen (P1) på Raspberry Pi:en. P1 på Raspberry Pi:en levererar 3.3V, vilket vår mätprob kräver för att fungera.

  3. Koppla nu in GND (minus/jord) från mätproben till pinne 9 på Raspberry Pi:en.

  4. Koppla in databenet (DQ) från mätproben till pinne 7 på Raspberry Pi:en. Nu är du klar med inkopplingen av mätproben.

  5. Koppla pinne 11 (GPIO7) från Raspberry Pi:en till anoden (det längsta benet) på lysdioden. Koppla det andra benet på lysdioden till en resistor på 220 Ohm.

  6. Koppla nu andra änden av resistorn (som är kopplad till lysdioden) till pinne 25 (GND) på Raspberry Pi:en.

Det var allt, nu är allting inkopplat! Kontrollera gärna med kopplingsschemat nedan.

Kopplingsschema

Mjukvaran

Jag använder själv uteslutande Python version 3, därför rekommendarar jag dig att installera de bibliotek vi behöver för Python 3 och vår Raspberry Pi. Gör detta med sudo apt-get install python3-rpi.gpio. Svara ja på frågan om du vill installera alla beroenden. Detta installerar även Python 3 om du inte redan har gjort det.

Läsa av temperaturen

Därefter behöver vi aktivera stödet för 1-Wire i Raspberry Pi:en så att vi kan läsa av temperaturen från proben. Detta gör vi genom att lägga till följande rad i filen /boot/config.txt.

dtoverlay=w1-gpio

Det går också bra att aktivera 1-Wire via antingen sudo raspi-config eller via det grafiska verktyget i Raspbian.

Därefter måste du starta om Pi:en för att stödet för 1-Wire ska aktiveras. Efter att du startat om Pi:en är det dags att leta upp ID-numret för just din temperaturprob. 1-Wire fungerar som så att man kan koppla in i princip hur många mätprobar som helst till samma ingång. De olika mätprobarna skiljs sedan åt med ett unikt ID-nummer. För att hitta ID-numret till din mätprob skriv cd /sys/bus/w1/devices. Skriv därefter ls för att lista alla filerna i katalogen. Den fil som ser ut enligt 28-xxxxx är din mätprob. Du kan faktiskt redan nu titta på temperaturen. Skriv cd 28-xxxx där xxxx är resten av namnet på mätproben. Skriv sedan cat w1_slave. Nu ser du temperaturen från mätproben. Observera att du måste dela temperaturen du ser med 1000 för att få den i grader. Nu har vi kommit en bra bit på vägen!

Pythonprogrammet för att övervaka och larma

Nu har det blivit dags att göra Pythonprogrammet som övervakar och larmar vid för hög temperatur. Jag visar först hela programmet här och förklarar sedan rad för rad vad som händer i programmet och vad allting är för något.

#!/usr/bin/env python3
import RPi.GPIO as GPIO
import time

# ID-numret på temperaturproben
id = "28-0000066f2e4a"

# Temperaturlarm, förinställt värde
larmtemp = 25.0

# GPIO-inställningar
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)

# Variabel för om lysdioden redan har tänts
alarmset = 0
# Släck lysioden om den redan är tänd
GPIO.output(11, False)

# Vi lägger allt i en try, så om vi avslutar programmet (except) så släcks
# lysdioden igen (se längst ner)
try: 
    # Vi loopar allting oändligt
    while True:
        f = open("/sys/bus/w1/devices/" + id + "/w1_slave")
        content = f.readlines()

        line = content[1]
        words = line.split()
        tempstr = (words[9])
        temp = "%.1f" %(int(tempstr[2:])/1000)
        temp = float(temp)

        print (temp)


        # Här börjar koden för att själva "larmet".
        # Om temperaturen är över, eller lika med, förinställt larmvärde,
        # OCH lysioden redan tänts.
        if (temp >= larmtemp and alarmset == 0):
            # Tänd lysdioden
            GPIO.output(11, True)
            alarmset = 1 # Tala om lysdioden redan har tänts
        # Om temperaturen är under förinställt värde OCH lysdioden har tänts
        elif (temp < larmtemp and alarmset == 1):
            GPIO.output(11, False)
            alarmset = 0

        # Vänta 3 sekunder mellan varje körning
        time.sleep(3)
# Om vi avslutar programmet, vill vi släcka lysdioden
except:
    GPIO.output(11, False)

Den första raden, import RPi.GPIO as GPIO, importerar Python-biblioteket för Raspberry Pi:ens GPIO portar. Detta gör att vi får en hel del fördefinierade funktioner för GPIO-portarna, direkt i Python. Rad nummer två, import time importerar diverse tidsfunktioer i Python. I vårt program använder vi en funktion som heter sleep() för att pausa exekveringen av programmet mellan läsningarna av temperaturen. Den femte raden är en mycket viktig rad, här sätter vi ID-numret för just din temperaturprob. Ändra detta värde till namnet på den katalog du såg i /sys/bus/w1/devices/ som började på 28-xxxx.

Därefter följer tre rader som alla börjar med GPIO. Den första, setwarnings(False) stänger av diverse varningar från GPIO-funktionerna i Python. Den andra setmode(GPIO.BOARD) talar om för Python att vi vill hänvisa till GPIO-pinnarna enligt den layout som de fysiska pinnarna sitter i. Här kan man välja mellan BCM eller BOARD. BCM hänvisar till GPIO-pinnarnas namn. Om du tittar på kopplingsschemat ovan så ser du att vissa pinnar har ett namn i tukos färg, t.ex. GPIO11, GPIO17, GPIO22 osv. Det andra systemet, BOARD, som vi använder i detta projekt, hänvisar istället till de fysiska pinnarnas plats (i mörkröd färg på kopplingsschemat). Personligen föredrar jag att använda BOARD, då BCM/GPIO ändrar sig lite från version till version av Raspberry Pi:en. Men med BOARD kan man inte göra fel, det är alltid samma nummer på pinnarna. Det enda som skiljer sig mellan version till version i BOARD är att antalet pinnar blir fler i de nyare versionerna. Dessutom kan man enkelt kontrollera om man kopplat rätt bara genom att räkna pinnarna på Pi:en.

Den tredje GPIO-raden i koden, setup(11, GPIO.OUT) talar om att vi vill använda den elfte pinnen på Pi:en och att denna ska vara i output-mode, det vill säga vi vill kontrollera något med hjälp av Pi:en, inte tvärtom.

Därefter sätter vi en variabel alarmset till 0. Denna använder vi sen för att vi ska veta om lysdioden redan har tänts eller inte. Vi passar också på att släcka lysdioden ifall den redan är tänd med GPIO.output(11, False).

Nu när vi är klara med själva inställningarna för GPIO-pinnarna börjar vi koda själva programmet. Vi vill i det här programmet läsa in temperaturen vart tredje sekund, därför börjar vi med while True:, vilket betyder att vi vill repetera all koden som är indenterad nedan så länge som True är sant, vilket kommer vara för evigt. Men innan vi omsluter hela programmet i en while True:-slinga så omsluter vi hela programmet i en try / except för att fånga om programmet avslutas i förväg på grund av något fel. Detta gör så att programmet kan släcka lysdioden efter sig, oavsett vilken sorts fel som än avbryter programmet. Det är alltid god att städa upp efter sig och stänga GPIO-portarna.

Därefter läser vi in filen som innehåller temperaturen. Detta gör vi med f = open("/sys/bus/w1/devices/" + id + "/w1_slave"). I mitten har vi id vilket är variabeln som vi satte i början av programmet till ID-numret på temperaturproben. På nästa rad läser vi in temperaturen, rad för rad, i variabeln content med content = f.readlines(). Texten vi vill åt i denna fil, det vill säga temperaturen, står på andra raden. Därför läser vi rad nummer två till en variabel som heter line med line = content[1] (kom ihåg att vi i programmerings värld börjar räkna från 0, och inte 1). Därefter vill vi komma åt de enskilda orden på raden, och delar därför upp hela raden i enskilda ord i variabeln words med words = line.split(). Nästa steg blir att extrahera endast temperaturen, vilket är det tioende ordet (9 i programmerings värld). Detta gör vi med tempstr = (words[9]).

Nu har vi temperaturen som en sträng i tempstr, inklusive texten “t=”. Nu ska vi skala bort “t=” samt dela summan med 1000 så att temperaturen blir i grader Celsius. Vi vill också bara ha temperaturen med en decimal, inte tre. Allt detta gör vi med raden temp = "%.1f" %(int(tempstr[2:])/1000). Det som händer här är att vi först talar om att vi vill ha resultatet med en decimal ("%.1f"). Därefter talar vi om att tempstr ska tolkas som ett heltal, och inte en sträng. I samma sats säger vi också att vi ska börja läsa från det andra tecknet ([2:]) fram tills raden är slut. Därefter ska det vi får fram delas med 1000 så att vi får ett korrekt decimaltal för våra grader. Nu innehåller variabeln temp ett gradtal i Celcius, t.ex. 23.5. Däremot är temp just nu en sträng. Vi måste således göra om strängen till ett flyttal så att vi kan göra aritmetiska jämförelser längre fram. Detta gör vi med temp = float(temp).

För att se temperaturen live när vi kör vårt program skriver vi ut temperaturen med print(temp). Nu börjar vi på själva temperaturövervakningen. Detta görs med stycket nedan.

if (temp >= larmtemp and alarmset == 0):
     # Tänd lysdioden
     GPIO.output(11, True)
     alarmset = 1 # Tala om larmet redan har skickats
# Om temperaturen är under förinställt värde OCH larmet har lösts ut
elif (temp < larmtemp and alarmset == 1):
     GPIO.output(11, False)
     alarmset = 0

Det som sker här är att vi först jämför om temperaturen är högre än larmtemp, i vårt fall 25 grader och alarmset är satt till noll, det vill säga att inget larm har skickats ännu. Om så är fallet, så körs koden GPIO.output(11, True) vilket tänder lysdioden.

Om temperatren är under (elif-raden) 25 grader och alarmset är satt till 1, det vill säga att lysdioden har tänts, så körs istället GPIO.output(11, False) som stänger av lysdioden.

Den allra sista raden, time.sleep(3) gör att programmet väntar i tre sekunder innan det körs igen. Hade vi inte haft med denna rad hade programet körts flera hundra gånger i sekunden och överbelastat vår Raspberry Pi.

Testkör programmet

Testkör nu programmet för att se så att lysdioden tänds när temperaturen överstiger 25 grader. För att testa så brukar jag använda två glas med vatten, ett glas med kallt vatten, och ett med varmt vatten. När du väl vet att allting fungerar kan du gå vidare till nästa steg, att köra programmet i bakgrunden på Pi:en som en tjänst. Mer om detta kommer lite senare i annan artikel.

Om du vill lära dig mer om Python så köp gärna vår bok, Grunderna i programmering, från antingen Bokus, Adlibris, Faktaböcker eller direkt via CyberInfo Sverige.