diff options
author | Robert Scheibe <rob.scheibe@gmail.com> | 2025-01-04 16:06:05 +0100 |
---|---|---|
committer | Robert Scheibe <rob.scheibe@gmail.com> | 2025-01-04 16:06:05 +0100 |
commit | a07c89c0fb9659c9961f8d9cef7ec49123b2171f (patch) | |
tree | 98818e61cf9a9bf184a5db12ff2e776c10781d09 | |
parent | 047178cc439a68c1366a215f4827b52f6437309b (diff) |
added moisture sensor
-rwxr-xr-x | deploy.sh | 7 | ||||
-rwxr-xr-x | make_photo | 4 | ||||
-rwxr-xr-x | plot.py | 165 | ||||
-rw-r--r-- | plot_new.py | 128 | ||||
-rwxr-xr-x | read_dht11.py | 39 | ||||
-rwxr-xr-x | read_sensors.py | 79 |
6 files changed, 204 insertions, 218 deletions
@@ -1,4 +1,7 @@ #!/bin/bash set -e -scp plot_new.py read_dht11.py water_the_plant create_backup make_photo index.html history.html *.png robert@waterpi: -ssh robert@waterpi -C 'sudo cp index.html history.html *.png /var/www/html; sudo chown www-data:www-data /var/www/html/*.html /var/www/html/*.png; sudo cp plot_new.py read_dht11.py create_backup make_photo plot.py read_temperature.py water_the_plant /usr/local/bin' +scp plot.py read_sensors.py water_the_plant create_backup make_photo index.html history.html *.png robert@waterpi: +ssh robert@waterpi -C '\ + sudo cp index.html history.html *.png /var/www/html; \ + sudo chown www-data:www-data /var/www/html/*.html /var/www/html/*.png; \ + sudo cp plot.py read_sensors.py create_backup make_photo plot.py read_temperature.py water_the_plant /usr/local/bin' @@ -8,6 +8,6 @@ rpicam-still -o $image #add date string convert $image -resize 1024x768 -gravity SouthEast -font DejaVu-Sans -pointsize 50 -stroke black -undercolor black -fill "rgba(255,255,255,0.5)" -annotate +30+30 "$(date +\\'%Y-%m-%d %H:%M\')" $image #read cpu temp -read_dht11.py +read_sensors.py #plot cpu temp -plot_new.py $image $image +plot.py $image $image @@ -1,47 +1,30 @@ #!/usr/bin/python3 +import sys +import sqlite3 import matplotlib.pyplot as plt import numpy as np -from PIL import Image -import argparse from datetime import datetime, timedelta import matplotlib.dates as mdates +from PIL import Image -import sqlite3 - +# Funktion zum Lesen von Temperatur-, Luftfeuchtigkeits- und Zeitstempeldaten aus der SQLite-Datenbank def read_data_from_db(db_name): - """ - Liest alle gespeicherten Temperatur- und Zeitstempeldaten aus der SQLite-Datenbank. - - :param db_name: Name der SQLite-Datenbankdatei - :return: Liste von Tupeln mit (timestamp, temperature) - """ try: - # Verbindung zur Datenbank herstellen conn = sqlite3.connect(db_name) cursor = conn.cursor() - - # Abfrage zum Abrufen aller Daten aus der Tabelle - cursor.execute("SELECT timestamp, temperature FROM cpu_temperature") - data = cursor.fetchall() # Alle Ergebnisse abrufen - - conn.close() # Verbindung schließen + cursor.execute("SELECT timestamp, temperature, humidity, moisture FROM sensor_data") + data = cursor.fetchall() + conn.close() return data except sqlite3.Error as e: print(f"Fehler beim Lesen aus der Datenbank: {e}") return [] - - -# Funktion zum Erstellen des Temperaturdiagramms mit Achsenbeschriftungen und Transparenz -def create_temperature_plot_with_labels(output_filename): - db_name = "/var/www/html/cpu_temperature.db" - records = read_data_from_db(db_name) - - if records: - for timestamp, temperature in records: - print(f"Zeit: {timestamp}, Temperatur: {temperature}°C") - else: +# Funktion zum Erstellen eines Diagramms für Temperatur und Luftfeuchtigkeit (800x200 Pixel) +def create_temperature_humidity_plot(records, output_filename): + if not records: print("Keine Daten gefunden.") + return # Aktuelle Zeit und Filterzeitraum (letzte 24 Stunden) now = datetime.now() @@ -49,55 +32,83 @@ def create_temperature_plot_with_labels(output_filename): # Filtern der Datensätze nach den letzten 24 Stunden filtered_records = [ - (datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S"), temperature) - for timestamp, temperature in records + (datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S"), temperature, humidity, moisture) + for timestamp, temperature, humidity, moisture in records if datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S") >= last_24_hours ] if not filtered_records: print("Keine Daten in den letzten 24 Stunden gefunden.") return - # Extrahieren von Zeitstempeln und Temperaturen aus den gefilterten Datensätzen - times = [timestamp for timestamp, _ in filtered_records] - temperatures = [temperature for _, temperature in filtered_records] - - # Grenzen für die y-Achse basierend auf den Temperaturdaten - min_temp = np.floor(min(temperatures) / 5) * 5 # Abrunden auf das nächste Vielfache von 5 - max_temp = np.ceil(max(temperatures) / 5) * 5 # Aufrunden auf das nächste Vielfache von 5 - - # Temperaturdiagramm zeichnen - plt.figure(figsize=(8, 2), dpi=100) # Größe des Diagramms: 800x100 Pixel - plt.plot(times, temperatures, color='yellow', linewidth=2, label='Temperatur') - plt.ylim(min_temp, max_temp) # Y-Achse auf den Bereich der Daten begrenzen - plt.xlabel('Uhrzeit', color='white') # X-Achsenbeschriftung - plt.ylabel('CPU Temp in °C', color='white') # Y-Achsenbeschriftung - plt.xticks(color='white') # X-Achse beschriften (automatisch), gedreht für bessere Lesbarkeit - plt.yticks(np.arange(min_temp, max_temp + 1, 5), color='white') # Y-Achse in Schritten von 5 beschriften - plt.grid(color='white', linestyle='--', linewidth=0.5, alpha=0.7) - plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) - plt.tight_layout() - - # Diagramm mit transparentem Hintergrund speichern + # Extrahieren von Zeitstempeln, Temperaturen, Luftfeuchtigkeit und Feuchtigkeit + times = [timestamp for timestamp, _, _, _ in filtered_records] + temperatures = [temperature for _, temperature, _, _ in filtered_records] + humidities = [humidity for _, _, humidity, _ in filtered_records] + moistures = [moisture for _, _, _, moisture in filtered_records] + + # Grenzen für die y-Achsen basierend auf den Daten + min_temp = np.floor(min(temperatures) / 5) * 5 + max_temp = np.ceil(max(temperatures) / 5) * 5 + min_humidity = np.floor(min(humidities) / 10) * 10 + max_humidity = np.ceil(max(humidities) / 10) * 10 + min_moisture = np.floor(min(moistures) / 10) * 10 + max_moisture = np.ceil(max(moistures) / 10) * 10 + + # Diagramm zeichnen (800x200 Pixel) + fig, ax1 = plt.subplots(figsize=(8, 2), dpi=100) + + # Temperaturplot (linke Y-Achse) + ax1.set_xlabel('Uhrzeit', color='white') + ax1.set_ylabel('Temperatur (°C)', color='tab:red') + ax1.plot(times, temperatures, color='tab:red', label='Temperatur') + ax1.tick_params(axis='y', labelcolor='tab:red') + ax1.tick_params(axis='x', colors='white') + ax1.set_ylim(min_temp, max_temp) + ax1.spines['top'].set_color('white') + ax1.spines['bottom'].set_color('white') + ax1.spines['left'].set_color('white') + ax1.spines['right'].set_color('white') + + + # Luftfeuchtigkeitsplot (rechte Y-Achse) + ax2 = ax1.twinx() + ax2.set_ylabel('Luftfeuchtigkeit (%)', color='tab:blue') + ax2.plot(times, humidities, color='tab:blue', label='Luftfeuchtigkeit') + ax2.tick_params(axis='y', labelcolor='tab:blue') + ax2.set_ylim(min_humidity, max_humidity) + ax2.tick_params(axis='x', colors='white') + ax2.spines['top'].set_color('white') + ax2.spines['bottom'].set_color('white') + ax2.spines['left'].set_color('white') + ax2.spines['right'].set_color('white') + + # Feuchtigkeitsplot (dritte Y-Achse) + ax3 = ax1.twinx() + ax3.spines['right'].set_position(('outward', 60)) # Platz für die dritte Achse schaffen + ax3.set_ylabel('Feuchtigkeit (16-32k)', color='tab:green') + ax3.plot(times, moistures, color='tab:green', label='Feuchtigkeit') + ax3.tick_params(axis='y', labelcolor='tab:green') + ax3.set_ylim(min_moisture, max_moisture) + ax3.tick_params(axis='x', colors='white') + ax3.spines['top'].set_color('white') + ax3.spines['bottom'].set_color('white') + ax3.spines['left'].set_color('white') + ax3.spines['right'].set_color('white') + + # X-Achse formatieren + ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) + + # Layout anpassen und Diagramm speichern + fig.tight_layout() plt.savefig(output_filename, transparent=True, bbox_inches='tight') plt.close() -# Funktion zum Laden und Überprüfen des Basisbildes -def load_and_check_base_image(image_path): - try: - base_image = Image.open(image_path) - if base_image.size != (1024, 768): - raise ValueError("Das Basisbild muss eine Größe von 1024x768 Pixeln haben.") - return base_image - except Exception as e: - print(f"Fehler beim Laden des Basisbildes: {e}") - return None # Funktion zum Überlagern des Diagramms auf das Basisbild def overlay_plot_on_image(base_image_path, plot_image_path, output_image_path): try: base_image = Image.open(base_image_path) - - plot_image = Image.open(plot_image_path) + plot_image = Image.open(plot_image_path).resize((800, 200)) # Größe des Plots anpassen # Überlagern des Diagramms auf das Basisbild (mit Transparenz) base_image.paste(plot_image, (112, 0), plot_image) # Zentrieren: (1024 - 800) / 2 = 112 @@ -110,21 +121,27 @@ def overlay_plot_on_image(base_image_path, plot_image_path, output_image_path): # Hauptfunktion def main(): - parser = argparse.ArgumentParser(description="Overlay transparentes Temperaturdiagramm auf ein Bild.") - parser.add_argument("image", help="Pfad zum Basisbild (1024x768 Pixel)") - parser.add_argument("output", help="Pfad zum kombinierten Ausgabebild") - args = parser.parse_args() + if len(sys.argv) != 3: + print("Bitte geben Sie den Pfad zum Basisbild und den Pfad zum Ausgabebild an.") + sys.exit(1) - base_image_path = args.image - output_image_path = args.output + base_image_path = sys.argv[1] + output_image_path = sys.argv[2] + + db_name = "/var/www/html/sensor_data.db" + + # Daten aus der Datenbank lesen + records = read_data_from_db(db_name) - # Temporäre Datei für das transparente Temperaturdiagramm - plot_filename = "temperature_plot_with_labels.png" + # Temporäre Datei für das transparente Temperatur- und Feuchtigkeitsdiagramm + plot_filename = "temperature_humidity_plot.png" + + # Diagramm erstellen und speichern + create_temperature_humidity_plot(records, plot_filename) - # Schritte ausführen: Diagramm erstellen und überlagern - create_temperature_plot_with_labels(plot_filename) + # Basisbild laden und Diagramm überlagern overlay_plot_on_image(base_image_path, plot_filename, output_image_path) if __name__ == "__main__": - main() + main() diff --git a/plot_new.py b/plot_new.py deleted file mode 100644 index 4a6ee16..0000000 --- a/plot_new.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/python3 -import sys -import sqlite3 -import matplotlib.pyplot as plt -import numpy as np -from datetime import datetime, timedelta -import matplotlib.dates as mdates -from PIL import Image - -# Funktion zum Lesen von Temperatur-, Luftfeuchtigkeits- und Zeitstempeldaten aus der SQLite-Datenbank -def read_data_from_db(db_name): - try: - conn = sqlite3.connect(db_name) - cursor = conn.cursor() - cursor.execute("SELECT timestamp, temperature, humidity FROM sensor_data") - data = cursor.fetchall() - conn.close() - return data - except sqlite3.Error as e: - print(f"Fehler beim Lesen aus der Datenbank: {e}") - return [] - -# Funktion zum Erstellen eines Diagramms für Temperatur und Luftfeuchtigkeit (800x200 Pixel) -def create_temperature_humidity_plot(records, output_filename): - if not records: - print("Keine Daten gefunden.") - return - - # Aktuelle Zeit und Filterzeitraum (letzte 24 Stunden) - now = datetime.now() - last_24_hours = now - timedelta(hours=24) - - # Filtern der Datensätze nach den letzten 24 Stunden - filtered_records = [ - (datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S"), temperature, humidity) - for timestamp, temperature, humidity in records - if datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S") >= last_24_hours - ] - if not filtered_records: - print("Keine Daten in den letzten 24 Stunden gefunden.") - return - - # Extrahieren von Zeitstempeln, Temperaturen und Luftfeuchtigkeit - times = [timestamp for timestamp, _, _ in filtered_records] - temperatures = [temperature for _, temperature, _ in filtered_records] - humidities = [humidity for _, _, humidity in filtered_records] - - # Grenzen für die y-Achsen basierend auf den Daten - min_temp = np.floor(min(temperatures) / 5) * 5 - max_temp = np.ceil(max(temperatures) / 5) * 5 - min_humidity = np.floor(min(humidities) / 10) * 10 - max_humidity = np.ceil(max(humidities) / 10) * 10 - - # Diagramm zeichnen (800x200 Pixel) - fig, ax1 = plt.subplots(figsize=(8, 2), dpi=100) - - # Temperaturplot (linke Y-Achse) - ax1.set_xlabel('Uhrzeit', color='white') - ax1.set_ylabel('Temperatur (°C)', color='tab:red') - ax1.plot(times, temperatures, color='tab:red', label='Temperatur') - ax1.tick_params(axis='y', labelcolor='tab:red') - ax1.tick_params(axis='x', colors='white') - ax1.set_ylim(min_temp, max_temp) - ax1.spines['top'].set_color('white') - ax1.spines['bottom'].set_color('white') - ax1.spines['left'].set_color('white') - ax1.spines['right'].set_color('white') - - # Luftfeuchtigkeitsplot (rechte Y-Achse) - ax2 = ax1.twinx() - ax2.set_ylabel('Luftfeuchtigkeit (%)', color='tab:blue') - ax2.plot(times, humidities, color='tab:blue', label='Luftfeuchtigkeit') - ax2.tick_params(axis='y', labelcolor='tab:blue') - ax2.set_ylim(min_humidity, max_humidity) - ax2.spines['top'].set_color('white') - ax2.spines['bottom'].set_color('white') - ax2.spines['left'].set_color('white') - ax2.spines['right'].set_color('white') - - # X-Achse formatieren - ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) - fig.tight_layout() - - # Diagramm speichern (transparent) - plt.savefig(output_filename, transparent=True, bbox_inches='tight') - plt.close() - -# Funktion zum Überlagern des Diagramms auf das Basisbild -def overlay_plot_on_image(base_image_path, plot_image_path, output_image_path): - try: - base_image = Image.open(base_image_path) - plot_image = Image.open(plot_image_path).resize((800, 200)) # Größe des Plots anpassen - - # Überlagern des Diagramms auf das Basisbild (mit Transparenz) - base_image.paste(plot_image, (112, 0), plot_image) # Zentrieren: (1024 - 800) / 2 = 112 - - # Kombiniertes Bild speichern - base_image.save(output_image_path) - print(f"Kombiniertes Bild gespeichert als {output_image_path}") - except Exception as e: - print(f"Fehler beim Überlagern des Diagramms: {e}") - -# Hauptfunktion -def main(): - if len(sys.argv) != 3: - print("Bitte geben Sie den Pfad zum Basisbild und den Pfad zum Ausgabebild an.") - sys.exit(1) - - base_image_path = sys.argv[1] - output_image_path = sys.argv[2] - - db_name = "/var/www/html/sensor_data.db" - - # Daten aus der Datenbank lesen - records = read_data_from_db(db_name) - - # Temporäre Datei für das transparente Temperatur- und Feuchtigkeitsdiagramm - plot_filename = "temperature_humidity_plot.png" - - # Diagramm erstellen und speichern - create_temperature_humidity_plot(records, plot_filename) - - # Basisbild laden und Diagramm überlagern - overlay_plot_on_image(base_image_path, plot_filename, output_image_path) - -if __name__ == "__main__": - main() - diff --git a/read_dht11.py b/read_dht11.py index 524fdba..e560a8a 100755 --- a/read_dht11.py +++ b/read_dht11.py @@ -3,10 +3,22 @@ import sqlite3 from datetime import datetime import adafruit_dht import board +import busio +import adafruit_ads1x15.ads1115 as ADS +from adafruit_ads1x15.analog_in import AnalogIn # GPIO-Pin für den DHT11-Sensor DHT_SENSOR = adafruit_dht.DHT11(board.D26) +# Initialize the I2C interface +i2c = busio.I2C(board.SCL, board.SDA) + +# Create an ADS1115 object +ads = ADS.ADS1115(i2c) + +# Define the analog input channel +channel = AnalogIn(ads, ADS.P0) + # Funktion zur Initialisierung der SQLite-Datenbank def init_db(db_name): conn = sqlite3.connect(db_name) @@ -17,30 +29,32 @@ def init_db(db_name): id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, temperature REAL NOT NULL, - humidity REAL NOT NULL + humidity REAL NOT NULL, + moisture REAL NOT NULL ) """) conn.commit() return conn # Funktion zum Einfügen von Daten in die Datenbank -def insert_data(conn, timestamp, temperature, humidity): +def insert_data(conn, timestamp, temperature, humidity, moisture): cursor = conn.cursor() cursor.execute(""" - INSERT INTO sensor_data (timestamp, temperature, humidity) - VALUES (?, ?, ?) - """, (timestamp, temperature, humidity)) + INSERT INTO sensor_data (timestamp, temperature, humidity, moisture) + VALUES (?, ?, ?, ?) + """, (timestamp, temperature, humidity, moisture)) conn.commit() # Funktion zum Lesen von Temperatur und Luftfeuchtigkeit vom DHT11-Sensor def read_dht11(): humidity = DHT_SENSOR.humidity temperature = DHT_SENSOR.temperature + moisture = channel.value if humidity is not None and temperature is not None: - return round(temperature, 1), round(humidity, 1) + return round(temperature, 1), round(humidity, 1), moisture else: - print("Fehler beim Lesen des Sensors. Versuche erneut...") - return None, None + print("Fehler beim Lesen der Sensoren. Versuche erneut...") + return None, None, None # Hauptfunktion def main(): @@ -48,14 +62,15 @@ def main(): conn = init_db(db_name) # Ruft Temperatur und Luftfeuchtigkeit ab - temperature, humidity = read_dht11() + temperature, humidity, moisture = read_dht11() + - if temperature is not None and humidity is not None: + if temperature is not None and humidity is not None and moisture is not None: # Holt das aktuelle Datum und die Uhrzeit timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Speichert die Daten in der Datenbank - insert_data(conn, timestamp, temperature, humidity) - print(f"Gespeichert: {timestamp} - Temperatur: {temperature}°C - Luftfeuchtigkeit: {humidity}%") + insert_data(conn, timestamp, temperature, humidity, moisture) + print(f"Gespeichert: {timestamp} - Temperatur: {temperature}°C - Luftfeuchtigkeit: {humidity}% - Bodenfeutigkeit {moisture}") conn.close() diff --git a/read_sensors.py b/read_sensors.py new file mode 100755 index 0000000..e560a8a --- /dev/null +++ b/read_sensors.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +import sqlite3 +from datetime import datetime +import adafruit_dht +import board +import busio +import adafruit_ads1x15.ads1115 as ADS +from adafruit_ads1x15.analog_in import AnalogIn + +# GPIO-Pin für den DHT11-Sensor +DHT_SENSOR = adafruit_dht.DHT11(board.D26) + +# Initialize the I2C interface +i2c = busio.I2C(board.SCL, board.SDA) + +# Create an ADS1115 object +ads = ADS.ADS1115(i2c) + +# Define the analog input channel +channel = AnalogIn(ads, ADS.P0) + +# Funktion zur Initialisierung der SQLite-Datenbank +def init_db(db_name): + conn = sqlite3.connect(db_name) + cursor = conn.cursor() + # Erstellt eine Tabelle, falls sie noch nicht existiert + cursor.execute(""" + CREATE TABLE IF NOT EXISTS sensor_data ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT NOT NULL, + temperature REAL NOT NULL, + humidity REAL NOT NULL, + moisture REAL NOT NULL + ) + """) + conn.commit() + return conn + +# Funktion zum Einfügen von Daten in die Datenbank +def insert_data(conn, timestamp, temperature, humidity, moisture): + cursor = conn.cursor() + cursor.execute(""" + INSERT INTO sensor_data (timestamp, temperature, humidity, moisture) + VALUES (?, ?, ?, ?) + """, (timestamp, temperature, humidity, moisture)) + conn.commit() + +# Funktion zum Lesen von Temperatur und Luftfeuchtigkeit vom DHT11-Sensor +def read_dht11(): + humidity = DHT_SENSOR.humidity + temperature = DHT_SENSOR.temperature + moisture = channel.value + if humidity is not None and temperature is not None: + return round(temperature, 1), round(humidity, 1), moisture + else: + print("Fehler beim Lesen der Sensoren. Versuche erneut...") + return None, None, None + +# Hauptfunktion +def main(): + db_name = "/var/www/html/sensor_data.db" + conn = init_db(db_name) + + # Ruft Temperatur und Luftfeuchtigkeit ab + temperature, humidity, moisture = read_dht11() + + + if temperature is not None and humidity is not None and moisture is not None: + # Holt das aktuelle Datum und die Uhrzeit + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + # Speichert die Daten in der Datenbank + insert_data(conn, timestamp, temperature, humidity, moisture) + print(f"Gespeichert: {timestamp} - Temperatur: {temperature}°C - Luftfeuchtigkeit: {humidity}% - Bodenfeutigkeit {moisture}") + + conn.close() + +if __name__ == "__main__": + main() + |