Rapsberry Zero 2W – BME68x – DS18B20 – ILI9341 TFT

Part 3: Sensor and database setup

At this point, I assume that you are already familiar with an operating system, or you might have one installed on your Raspberry Pi.

If not, you can find a good guide here:

https://www.raspberrypi.com/software/

or here: https://pibakery.org/


I also operate one of the small Zeros with Debian 12 (Bookworm) and another one with Ubuntu. You are actually quite free to install any of these derivatives, and I believe that the sample code will run on any of these.

Once you have completed the installation of a basic OS on your tiny hardware, we can proceed with the code to operate the sensors and the display. Log in over Wi-Fi (or directly) onto your Raspberry Pi device via SSH.

1. Let us prepare the BME68x sensor first.


As with any guide on Raspberry Pi or other Linux OS variants, I will recommend the standard routine of updating and upgrading your kernel, OS components, and any installed software by advising you to type the following in your shell:

sudo apt update
sudo apt upgrade

Then reboot the device if any firmware or kernel upgrades were happening.

Now we need a Python base system and some other necessary and useful software modules.

sudo apt install i2c-tools
sudo apt install python pip 
pip install bme680 
pip install mysql.connector

This will install all essential Python components and download/install the bme680 module to communicate with your sensor and the mysql.connector module to write the readout sensor values into a MySQL database, either locally or remotely.

You can check if the sensor is present on the i2c bus by typing:

i2cdetect -y 1

It should already show up on the second bus with the device address 0x77.

Start by opening a Python script file with:

sudo nano bme688_ds18b20.py

This code already includes the readout routine for the DS18B20 outside temperature sensor. Remove the routine and the database insert parts if you do not need this. Copy and paste the following code into the text editor.

#!/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()

Change your settings for dbuser, password and host and your ds18b20_address.

Now write the file with CTRL-O, press Enter to save, and exit the nano editor with CTRL-X.

2. The other temperature sensor for the outside – DS18B20

We are not done yet since the code also contains the readout of the DS18B20 sensor, which we still haven’t set up in the system. Let’s continue by using a software Overlay for the outside temperature sensor by editing the file /boot/config.txt

sudo nano /boot/config.txt

and add the line

dtoverlay=w1-gpio,gpiopin=24

at the end of it (if you used my wiring scheme. If you have a different wiring, change the gpiopin to your configuration). Then reboot your Raspberry.

Next, we need to load the kernel modules for the 1-wire bus and the thermal module.

Type this into your console:

sudo modprobe w1-gpio 
sudo modprobe w1-therm

which loads the kernel modules accordingly. If everything went well, you should see the kernel modules already by typing

sudo lsmod | grep w1

Next, find the device register on the w1 bus. Cd into the directory /sys/bus/w1/devices and list it.

Type:

cd /sys/bus/w1/devices/ 
ls

Your DS18B20 should be listed with something like:

28-3ce1d443d02b

Or something similar.

The DS18B20 sensor writes its readout into a file called w1_slave. If you cat it, you can read something like this:

ce ff 55 05 7f a5 a5 66 2b : crc=2b YES 
ce ff 55 05 7f a5 a5 66 2b t=-3125

The value „-3125“ is already our read temperature from the sensor which we later just have to divide by 1000 to get the real value in degrees Celsius. We do this already in the Python code that you pasted into your file above. And this should already be able to run, still without saving something into a database, which will give an error for now.

To automatically load the modules, edit the „/etc/modules-load.d/modules.conf“ file by typing:

sudo nano /etc/modules-load.d/modules.conf

and add the following lines to it:

i2c-dev 
w1-gpio 
w1-therm

if not present. This will load the kernel modules (drivers) that you need to operate your temperature sensor cascade.

We still need to call this script every 5 minutes from a cronjob:

crontab -e

add the follwing line at the end:

*/5 * * * * python /home/axel/dev/bme688screen/bme688_ds18b20.py > /dev/null 2>&1

This will now read out the temperatures every 5 minutes and store those in a database that we will setup now.

3. Now it is time to set up a database to collect our readouts and use them later on websites, apps, for heating control, or whatever ideas you have with it.

As I said, I use a Raspberry Pi 4 as a „central hub“ for this. So I also run my MySQL server there since this device is not busy and has been running for a few years without flaw or interruptions. But you are free to save your data anywhere you like, even on external MySQL servers, or rewrite my code for PostgreSQL or any other database you like.

Since I still do not know how much data will be collected and whatever bottleneck I am already creating without this knowledge, I decided to keep it simple for now but collect every value of a temperature-collecting Raspberry in its table within this database. So it is easier to divide and split at a later point.

My database is called „sensor_data“, and also the tables for each Raspberry are called „sensor_data“, „sensor_data2“, and so on.

You can change the names and tables as you like to whatever fits your personal naming conventions. If you do not have a database yet or do not know how to add users or privileges, I suggest installing Webmin or a similar tool to configure your database and database users that you wish to use in this tutorial.

For my code, simply log in to your MySQL console on your data-collecting server by typing:

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;

Once you have your database up and running, change the following variables in your bme688...py script that we created before. So the script can store the readouts of the sensors within this database. Also, check the database table and field names in my script and adjust them accordingly if you chose different naming in your database.

Change:

db_host = "192.168.x.y" 
db_user = "database-user" 
db_password = "dbuser-password" 
db_name = "sensor_data"
ds18b20_address

For now, we should be ready to go for the first temperature value collection directly from your hardware and see that the scripts read them out correctly and save everything within the database. You will find the inside temperature, air pressure, humidity, gas resistance, date of recording, time of recording, outside temperature, air quality, and an air quality scale in it.


Part 4: Now you can continue to the display section, where you can grab the code to actually create nice little graphics out of the database values and show them on a small TFT LCD 2,8 inch display