Teil 3: Sensor- und Datenbankeinrichtung
An diesem Punkt gehe ich davon aus, dass Sie bereits mit einem Betriebssystem vertraut sind oder es möglicherweise auf Ihrem Raspberry Pi installiert haben.
Falls nicht, finden Sie hier eine gute Anleitung:
https://www.raspberrypi.com/software/
oder hier: https://pibakery.org/
Ich betreibe auch einen der kleinen Zeros mit Debian 12 (Bookworm) und einen anderen mit Ubuntu. Sie können tatsächlich frei eine dieser Derivate installieren, und ich glaube, dass der Beispielcode auf jedem davon ausgeführt werden kann.
Sobald Sie die Installation eines grundlegenden Betriebssystems auf Ihrer kleinen Hardware abgeschlossen haben, können wir mit dem Code zur Steuerung der Sensoren und des Displays fortfahren. Melden Sie sich über Wi-Fi (oder direkt) auf Ihrem Raspberry Pi-Gerät per SSH an.
1. Lassen Sie uns zuerst den BME68x-Sensor vorbereiten.
Wie bei jeder Anleitung für Raspberry Pi oder andere Varianten von Linux-Betriebssystemen empfehle ich die Standardroutine zum Aktualisieren und Aufrüsten Ihres Kernels, der OS-Komponenten und aller installierten Software, indem Sie die folgenden Befehle in Ihrer Shell eingeben:
sudo apt update
sudo apt upgrade
Starten Sie das Gerät neu, wenn Firmware- oder Kernel-Upgrades durchgeführt wurden.
Nun benötigen wir ein Python-Basissystem und einige andere notwendige und nützliche Softwaremodule.
sudo apt install i2c-tools
sudo apt install python pip
pip install bme680
pip install mysql.connector
Dies installiert alle wesentlichen Python-Komponenten und installiert das bme680-Modul, um mit Ihrem Sensor zu kommunizieren, und das mysql.connector-Modul, um die ausgelesenen Sensorwerte in eine MySQL-Datenbank zu schreiben, entweder lokal oder remote.
Sie können überprüfen, ob der Sensor im i2c-Bus vorhanden ist, indem Sie folgenden Befehl eingeben:
i2cdetect -y 1
Es sollte bereits auf dem zweiten Bus mit der Geräteadresse 0x77 erscheinen.
Beginnen Sie, indem Sie eine Python-Skriptdatei öffnen:
sudo nano bme688_ds18b20.py
Dieser Code enthält bereits die Auslese-Routine für den DS18B20-Außentemperatursensor. Entfernen Sie die Routine und die Teile für das Datenbankeinfügen, wenn Sie dies nicht benötigen. Kopieren Sie und fügen Sie den folgenden Code in den Texteditor ein.
#!/usr/bin/env python import bme680 import mysql.connector from datetime import datetime import os import time import logging # Hostnamen auslesen hostname = os.uname()[1] # Teile des Hostnamens aufteilen hostname_parts = hostname.split('.') if len(hostname_parts) >= 1: device = hostname_parts[0] else: device = hostname logging.warning("Hostname doesn't match the expected pattern (device.x.y)") # DS18B20-Sensor-Adresse ds18b20_address = "xx-yyyyyyyyyyy" ds18b20_file = '/sys/bus/w1/devices/{}/w1_slave'.format(ds18b20_address) # Setup des Loggings am Anfang deines Skripts logging.basicConfig(filename='sensor_log.txt', level=logging.DEBUG) # Verbindung zur MySQL-Datenbank herstellen db_host = "192.168.x.y" db_user = "dbuser" db_password = "password" db_name = "sensor_data" db_connection = mysql.connector.connect( host=db_host, user=db_user, password=db_password, database=db_name ) db_cursor = db_connection.cursor() # Beispiel-Schwellenwerte für die Luftqualität sehrGuteLuftSchwelle = 7000 guteLuftSchwelle = 8500 moderateLuftSchwelle = 10000 schlechteLuftSchwelle = 120000 sehrSchlechteLuftSchwelle = 15000 print("bme688_data_read_corr_airqq5.py - Displays temperature, pressure, humidity, and gas.\n") try: sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY) except (RuntimeError, IOError): sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY) # Diese Kalibrierungsdaten können sicher auskommentiert werden, wenn gewünscht. print('Calibration data:') for name in dir(sensor.calibration_data): if not name.startswith('_'): value = getattr(sensor.calibration_data, name) if isinstance(value, int): print('{}: {}'.format(name, value)) # Diese Oversampling-Einstellungen können angepasst werden, um das Gleichgewicht zwischen Genauigkeit und Rauschen in den Daten zu ändern. sensor.set_humidity_oversample(bme680.OS_2X) sensor.set_pressure_oversample(bme680.OS_4X) sensor.set_temperature_oversample(bme680.OS_8X) sensor.set_filter(bme680.FILTER_SIZE_3) sensor.set_gas_status(bme680.ENABLE_GAS_MEAS) # DS18B20-Temperatur auslesen try: with open(ds18b20_file, 'r') as file: ds18b20_temperature_raw = file.read().split("\n")[1].split(" ")[9] ds18b20_temperature_celsius = float(ds18b20_temperature_raw[2:]) / 1000.0 + 0.0 # Temperaturkompensation in Grad Celsius print(f'DS18B20 Temperature: {ds18b20_temperature_celsius} C') logging.info('DS18B20 Temperature: %s C', ds18b20_temperature_celsius) except Exception as e: print(f"Error reading DS18B20 sensor: {e}") logging.info('DS18B20 Temperature: %s C', ds18b20_temperature_celsius) print('\nInitial reading:') for name in dir(sensor.data): value = getattr(sensor.data, name) if not name.startswith('_'): print('{}: {}'.format(name, value)) sensor.set_gas_heater_temperature(320) sensor.set_gas_heater_duration(150) sensor.select_gas_heater_profile(0) print('\nPolling:') while True: if sensor.get_sensor_data(): temperature = sensor.data.temperature - 1.95 # Temperaturkompensation der Sensorheizung pressure = sensor.data.pressure humidity = sensor.data.humidity if sensor.data.heat_stable: gas_resistance = sensor.data.gas_resistance air_quality = 25.0 + 0.3 * gas_resistance + 0.2 * humidity + 0.2 * temperature + 0.3 * pressure print('Temperature: {0:.2f} C, Pressure: {1:.2f} hPa, Humidity: {2:.2f} %RH, Gas Resistance: {3} Ohms, AirQuality: {4}'.format( temperature, pressure, humidity, gas_resistance, air_quality)) # Kategorisierung der Luftqualität basierend auf Schwellenwerten if air_quality < sehrGuteLuftSchwelle: luftqualitaet_kategorie = "Sehr gute Luftqualität" elif air_quality < guteLuftSchwelle: luftqualitaet_kategorie = "Gute Luftqualität" elif air_quality < moderateLuftSchwelle: luftqualitaet_kategorie = "Moderate Luftqualität" elif air_quality < schlechteLuftSchwelle: luftqualitaet_kategorie = "Schlechte Luftqualität" else: luftqualitaet_kategorie = "Sehr schlechte Luftqualität" print(f"Luftqualitätsindex: {air_quality:.2f}, Kategorie: {luftqualitaet_kategorie}") if gas_resistance != 0: current_datetime = datetime.now() date = current_datetime.date() systime = current_datetime.time() # Schreibe Luftqualität und Kategorie in die Datenbank insert_query = "INSERT INTO sensor_data2 (Innentemperatur2, Luftdruck2, Feuchtigkeit2, Gaswiderstand2, AirQuality2, AirQualityScale2, date2, time2, Aussentemperatur2, device, hostname) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" data_values = (temperature, pressure, humidity, gas_resistance, air_quality, luftqualitaet_kategorie, date, systime, ds18b20_temperature_celsius, device, hostname) # insert_query = "INSERT INTO sensor_data2 (Innentemperatur2, Luftdruck2, Feuchtigkeit2, Gaswiderstand2, AirQuality2, AirQualityScale2, date2, time2, Aussentemperatur2) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" # data_values = (temperature, pressure, humidity, gas_resistance, air_quality, luftqualitaet_kategorie, date, systime, ds18b20_temperature_celsius) # insert_query = "INSERT INTO sensor_data2 (Innentemperatur2, Luftdruck2, Feuchtigkeit2, Gaswiderstand2, AirQuality2, AirQualityScale2, date2, time2) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)" # data_values = (temperature, pressure, humidity, gas_resistance, air_quality, luftqualitaet_kategorie, date, systime) db_cursor.execute(insert_query, data_values) db_connection.commit() break # Verbindung zur MySQL-Datenbank schließen db_cursor.close() db_connection.close()
Ändern Sie Ihre Einstellungen für Benutzer, Passwort und Host sowie Ihre ds18b20-Adresse.
Schreiben Sie die Datei mit STRG-O, drücken Sie Enter, um zu speichern, und beenden Sie den Nano-Editor mit STRG-X.
2. Der andere Temperatursensor für draußen – DS18B20
Wir sind noch nicht fertig, da der Code auch die Auslesung des DS18B20-Sensors enthält, den wir noch nicht im System eingerichtet haben. Setzen wir dies fort, indem wir ein Software-Overlay für den Außentemperatursensor verwenden und die Datei /boot/config.txt bearbeiten:
sudo nano /boot/config.txt
und fügen Sie die Zeile
dtoverlay=w1-gpio,gpiopin=24
am Ende hinzu (falls Sie mein Verkabelungsschema verwendet haben. Wenn Sie eine andere Verkabelung haben, ändern Sie gpiopin entsprechend Ihrer Konfiguration). Starten Sie dann Ihren Raspberry neu.
Als nächstes müssen wir die Kernelmodule für den 1-Wire-Bus und das Thermomodul laden.
Geben Sie dies in Ihre Konsole ein:
sudo modprobe w1-gpio
sudo modprobe w1-therm
Das lädt die Kernelmodule entsprechend. Wenn alles gut gegangen ist, sollten Sie die Kernelmodule bereits sehen, indem Sie folgenden Befehl eingeben:
sudo lsmod | grep w1
Finden Sie als nächstes das Gerät im w1-Bus. Wechseln Sie in das Verzeichnis /sys/bus/w1/devices und listen Sie es auf.
Geben Sie ein:
cd /sys/bus/w1/devices/ ls
Ihr DS18B20 sollte mit etwas Ähnlichem aufgeführt sein:
28-3ce1d443d02b
Oder so ähnlich.
Der DS18B20-Sensor schreibt seine Auslesung in eine Datei namens w1_slave. Wenn Sie sie mit “cat” auslesen, sehen Sie etwas wie dies:
ce ff 55 05 7f a5 a5 66 2b : crc=2b YES
ce ff 55 05 7f a5 a5 66 2b t=-3125
Der Wert „-3125“ ist bereits unsere ausgelesene Temperatur vom Sensor, die wir später nur durch 1000 teilen müssen, um den realen Wert in Grad Celsius zu erhalten. Dies geschieht bereits im Python-Code, den Sie oben in Ihre Datei eingefügt haben. Und das sollte bereits lauffähig sein, immer noch ohne etwas in einer Datenbank zu speichern, was vorerst einen Fehler verursachen würde.
Um die Module automatisch zu laden, bearbeiten Sie die Datei „/etc/modules-load.d/modules.conf“, indem Sie eingeben:
sudo nano /etc/modules-load.d/modules.conf
und fügen Sie die folgenden Zeilen hinzu, falls nicht vorhanden. Dies lädt die Kernelmodule (Treiber), die Sie für Ihre Temperatursensor-Kaskade benötigen.
i2c-dev
w1-gpio
w1-therm
Wir müssen dieses Skript immer noch alle 5 Minuten von einem Cronjob aufrufen:
crontab -e
Fügen Sie die folgende Zeile am Ende hinzu:
*/5 * * * * python /home/axel/dev/bme688screen/bme688_ds18b20.py > /dev/null 2>&1
Dies liest nun alle 5 Minuten die Temperaturen aus und speichert sie in einer Datenbank, die wir jetzt einrichten werden.
3. Jetzt ist es an der Zeit, eine Datenbank einzurichten, um unsere Auslesungen zu sammeln und sie später auf Websites, in Apps, für die Heizungssteuerung oder für alle Ideen, die Sie damit haben, zu verwenden.
Wie gesagt, ich verwende einen Raspberry Pi 4 als „zentrale Anlaufstelle“ dafür. Daher betreibe ich auch meinen MySQL-Server dort, da dieses Gerät nicht ausgelastet ist und seit einigen Jahren ohne Fehler oder Unterbrechungen läuft. Aber Sie können Ihre Daten überall speichern, sogar auf externen MySQL-Servern, oder meinen Code für PostgreSQL oder jede andere Datenbank, die Sie bevorzugen, umschreiben.
Da ich immer noch nicht weiß, wie viele Daten gesammelt werden und welche Engpässe ich bereits ohne dieses Wissen schaffe, habe ich mich vorerst dafür entschieden, es einfach zu halten, aber jeden Wert einer temperatursammelnden Himbeere in ihrer Tabelle innerhalb dieser Datenbank zu sammeln. So ist es einfacher, später zu teilen und zu splitten.
Meine Datenbank heißt „sensor_data“, und auch die Tabellen für jede Raspberry heißen „sensor_data“, „sensor_data2“ und so weiter.
Sie können die Namen und Tabellen nach Belieben ändern, je nachdem, was Ihren persönlichen Namenskonventionen entspricht. Wenn Sie noch keine Datenbank haben oder nicht wissen, wie Sie Benutzer oder Berechtigungen hinzufügen sollen, schlage ich vor, Webmin oder ein ähnliches Tool zu installieren, um Ihre Datenbank und die Datenbankbenutzer, die Sie in diesem Tutorial verwenden möchten, zu konfigurieren.
Für meinen Code melden Sie sich einfach in Ihrer MySQL-Konsole auf Ihrem datensammelnden Server an, indem Sie eingeben:
mysql -u root
CREATE DATABASE IF NOT EXISTS sensor_data; USE sensor_data; CREATE TABLE IF NOT EXISTS sensor_data ( Innentemperatur FLOAT, Luftdruck FLOAT, Feuchtigkeit FLOAT, Gaswiderstand FLOAT, date DATE, time TIME, Aussentemperatur FLOAT, AirQuality FLOAT, AirQualityScale VARCHAR(32) );
exit;
Sobald Sie Ihre Datenbank eingerichtet haben, ändern Sie die folgenden Variablen in Ihrem bme688…py-Skript, das wir zuvor erstellt haben. So kann das Skript die Auslesungen der Sensoren in dieser Datenbank speichern. Überprüfen Sie auch die Namen und Felder der Datenbanktabelle in meinem Skript und passen Sie sie an, wenn Sie in Ihrer Datenbank eine andere Benennung gewählt haben.
Ändern Sie:
db_host = "192.168.x.y" db_user = "database-user" db_password = "dbuser-password" db_name = "sensor_data" ds18b20_address
Fürs Erste sollten wir bereit sein, die erste Temperaturwert-Sammlung direkt von Ihrer Hardware durchzuführen und zu sehen, dass die Skripte sie korrekt auslesen und alles in der Datenbank speichern. Sie finden die Innentemperatur, den Luftdruck, die Luftfeuchtigkeit, den Gaswiderstand, das Aufnahmedatum, die Aufnahmezeit, die Außentemperatur, die Luftqualität und eine Luftqualitätsskala darin.