Raspberry Pi Zero 2 W – BME68x – DS18B20 – ILI9341 TFT

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.

Teil 4: Jetzt können Sie zum Anzeigebereich weitergehen, wo Sie den Code abrufen können, um tatsächlich schöne Grafiken aus den Datenbankwerten zu erstellen und sie auf einem kleinen TFT-LCD mit 2,8 Zoll anzuzeigen.