Wetterstation [Update 2]
Updates zum Post sind ganz unten.
Auch dieses Projekt begann wieder mit einer Idee oder einem Wunsch meiner Frau. Sie wünscht sich eine automatische Belüftung des Gewächshauses in unserem Garten.
Der erste Schritt dabei ist die Erfassung der Umgebungstemperatur und -luftfeuchtigkeit. Also bastelte ich eine kleine Wetterstation - oder vielmehr nur ein Raspberry Pi-Thermometer.
Hardware
- Raspberry Pi B+
- Adafruit Pi T-Cobbler Plus
- Adafruit Monochrome 0.96" 128x64 OLED graphic display
- DTH22 Sensor mit Widerstand
- Breadboard
- einige Jumper-Kabel
Software
Ich habe eine ganz normale Raspbian-Installation durchgeführt. Danach natürlich noch die obligatorischen Befehle
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install rpi-update
sudo rpi-update
ausführen.
Damit auch der Sensor korrekt arbeitet und das Display angesprochen werden kann, muss mittels
sudo raspi-config
nochmals die Konfiguration aufgerufen werden. Hier auf der zweiten Seite ("Advanced Settings") müssen SPI und I2C aktiviert werden. Nach einem Neustart des Raspberry Pi sind die Schnittstellen aktiv.
Nun installierst du noch ein paar zusätzliche Pakete:
sudo apt-get install git build-essential python-dev python-pip python-imaging python-smbus
sudo pip install RPi.GPIO
Zum Ansprechen des Sensors und des Displays gibt es von Adafruit bereit gestellte Bibliotheken auf Github, die du nun installierst
cd ~
git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT/
sudo python setup.py install
cd ~
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
cd Adafruit_Python_SSD1306
sudo python setup.py install
Damit die Daten später auch grafisch im Browser angezeigt werden können, musst du noch einen Web- und einen Datenbankserver installieren
sudo apt-get install apache2 php5 mysql-server python-mysqldb
Nach der Installation verbindest du dich mit dem Datenbankserver. Hier musst du das Passwort verwenden, das du bei der Installation angegeben hast. Bitte ersetze in der Zeile CREATE USER weather@localhost IDENTIFIED by 'PASSWORD';
PASSWORD
durch ein von dir gewähltes Passwort.
pi@raspberrypi ~ $ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 43
Server version: 5.5.41-0+wheezy1 (Debian)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> CREATE DATABASE weather;
Query OK, 1 row affected (0.01 sec)
mysql> CREATE USER weather@localhost IDENTIFIED by 'PASSWORD';
Query OK, 0 rows affected (0.01 sec)
mysql> USE weather;
Database changed
mysql> GRANT ALL ON weather.* TO weather@localhost;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE temperatures (id INT PRIMARY KEY AUTO_INCREMENT, sensor INT, date TIMESTAMP NOT NULL, temperature FLOAT, humidity FLOAT);
Query OK, 0 rows affected (0.03 sec)
mysql> quit
Bye
Nun legst du im Homeverzeichnis ein neues Verzeichnis "wetter" an
cd ~
mkdir wetter
cd wetter
und in dem Verzeichnis wiederum legst du einen Datei wetter.py
an, die folgenden Inhalt hat:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import MySQLdb as mdb
import sys
import Adafruit_DHT
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
import Image
import ImageDraw
import ImageFont
# Raspberry Pi pin configuration:
RST = 24
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0
sensor = Adafruit_DHT.DHT22
pin = 18
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))
# Initialize library.
disp.begin()
# Clear display.
disp.clear()
disp.display()
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# initialize temperatures
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
minTemp = temperature
maxTemp = temperature
lastInsert = 0
padding = 2
top = padding
x = padding
font = ImageFont.load_default()
con = mdb.connect('localhost', 'weather', 'PASSWORD', 'weather')
while 1:
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if temperature is not None and humidity is not None:
if temperature > maxTemp:
maxTemp = temperature
if temperature < minTemp:
minTemp = temperature
if lastInsert < time.time() - 900:
with con:
cur = con.cursor()
cur.execute("INSERT INTO temperatures (sensor, date, temperature, humidity) VALUES (1, %s, %s, %s)",
(time.strftime('%Y-%m-%d %H:%M:%S'), "{: f}".format(temperature),
"{: f}".format(humidity)))
lastInsert = time.time()
# Write two lines of text.
draw.text((x, top), time.strftime("%d.%m.%Y %H:%M"), font=font, fill=255)
draw.text((x, top + 20), '{0:.1f} *C {1:.1f} % LF'.format(temperature, humidity), font=font, fill=255)
draw.text((x, top + 40), 'min: {:.1f} *C'.format(minTemp), font=font, fill=255)
draw.text((x, top + 50), 'max: {:.1f} *C'.format(maxTemp), font=font, fill=255)
# Display image.
disp.image(image)
disp.display()
time.sleep(15)
Ersetze hier auch wieder in der Zeile con = mdb.connect('localhost', 'weather', 'PASSWORD', 'weather')
PASSWORD
durch das von dir vergebene Passwort.
Das Skript liest alle 15 Sekunden die aktuelle Luftfeuchtigkeit und Temperatur aus und zeigt die Werte auf dem Display an. Zusätzlich werden die Werte alle 15 Minuten in die Datenbank geschrieben.
Gestartet wird das Skript mittels
sudo python /home/pi/wetter/wetter.py &
So sieht es zur Zeit bei mir aus:
Den Quelltext für die Anzeige habe ich in meiner ownCloud meinem GitHub-Repository abgelegt. Entpacke diesen, ändere in der Datei index.php
in Zeile 3 ebenfalls das Passwort und lade dann die Dateien in den Ordner /var/www
hoch. Nun kannst du unter http://<IP_DEINES_RASPBERRY_PI>/
die gespeicherten Daten deiner Wetterstation ansehen.
Updates
4. Mai 2015
Heute habe ich meinen Code auf einem GitHub-Repository hochgeladen, wo die weiteren Modifikationen zu finden sind.
Es steht jedem frei, den Code zu verwenden und auch Änderungen vorzunehmen.
Fragen und Anmerkungen dazu natürlich gern auch hier.
Ich habe das Verzeichnis bower_components
nicht mit hochgeladen, das bedeutet also, dass du, nachdem du das Repository heruntergeladen hast, ein
bower install
im Verzeichnis web
machen musst, damit Bootstrap heruntergeladen wird.
Zusätzlich habe ich noch kleine Veränderungen vorgenommen und Code-Teile optimiert.
15. Mai 2015
Heute habe ich einige Updates in das Repository gespielt, die sich um kleine Optimierungen kümmern. So ist die Python-Datei aufgeräumter und beide Skripte (Python und PHP) nutzen nun Konfigurationsdateien, in denen die Verbindungsparameter zur Datenbank hinterlegt sind.
Läuft das Display über mehrere Stunden oder Tage, ändern sich auch die minimalen und maximalen Temperaturen. Bisher war es so, wenn man die Werte löschen wollte, musste man das Skript stoppen und neu starten. Also dachte ich, dass es gut wäre, wenn es einen Button gäbe, den man drücken kann und dann werden die Werte zurück gesetzt. Die Umsetzung sieht dann so aus:
Im Code habe ich das auch schon eingefügt (Neuerungen sind hier abgebildet).
...
import RPi.GPIO as GPIO
...
RESET_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(RESET_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
...
if GPIO.input(RESET_PIN):
maxTemp = -9999.99
minTemp = 9999.99
...
Es muss eine neue Bibliothek (RPi.GPIO
) importiert werden. Danach setze ich für die Pin-Nummerierung die BCM-Nummerierung (siehe hier) ein. Der Pin wird als Eingang (GPIO.IN
) deklariert. In der Schleife wird dann über GPIO.input
der Wert abgefragt, der im gedrückten Zustand 1
und im nicht gedrückten Zustand 0
ist. Wird der Taster gedrückt (GPIO.input
liefert 1
), werden die minimalen und maximalen Temperaturen zurück (in meinem Fall auf sehr hohe bzw. sehr niedrige Werte) gesetzt.
Nur in der Realität funktioniert das nicht zuverlässig, da das Auslesen des Sensors ein paar Sekunden benötigt. Deshalb wartet das System an dieser Stelle und kann keine Eingaben von dem Taster annehmen.