diff options
-rw-r--r-- | README.txt | 5 | ||||
-rwxr-xr-x | create_backup | 2 | ||||
-rwxr-xr-x | deploy.sh | 4 | ||||
-rw-r--r-- | history.html | 152 | ||||
-rw-r--r-- | index.html | 2 | ||||
-rwxr-xr-x | make_photo | 8 | ||||
-rwxr-xr-x | plot.py | 65 | ||||
-rwxr-xr-x | read_temperature.py | 61 | ||||
-rwxr-xr-x | water_the_plant | 22 |
9 files changed, 309 insertions, 12 deletions
diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..9e7834e --- /dev/null +++ b/README.txt @@ -0,0 +1,5 @@ +#> sudo crontab -e + +*/15 * * * * /usr/local/bin/make_photo +02 12 * * * /usr/local/bin/create_backup +29 08 * * * /usr/local/bin/water_the_plant diff --git a/create_backup b/create_backup new file mode 100755 index 0000000..a166395 --- /dev/null +++ b/create_backup @@ -0,0 +1,2 @@ +#!/bin/bash +cp /mnt/ramdisk/12_00.jpg /var/www/html/waterpi_12h_images/$(date +'%Y-%m-%d')_12_00.jpg @@ -1,4 +1,4 @@ #!/bin/bash set -e -scp index.html *.png robert@waterpi: -ssh robert@waterpi -C 'sudo cp index.html *.png /var/www/html; sudo chown www-data:www-data /var/www/html/index.html' +scp water_the_plant create_backup make_photo *.py 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 create_backup make_photo plot.py read_temperature.py water_the_plant /usr/local/bin' diff --git a/history.html b/history.html new file mode 100644 index 0000000..f48e9fe --- /dev/null +++ b/history.html @@ -0,0 +1,152 @@ +<!DOCTYPE html> +<html> + <head> + <title> waterpi </title> + <meta http-equiv="refresh" content="60"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <style> +.gallery { + max-width: 800px; + margin: 0 auto; + text-align: center; +} + +.main-image { + margin-bottom: 20px; +} + +.main-image img { + width: 100%; + height: auto; + display: block; + margin: 0 auto; + object-fit: contain; +} + +.controls { + display: flex; + justify-content: center; + gap: 20px; + align-items: center; +} + +.nav-button { + padding: 10px 20px; + font-size: 24px; + cursor: pointer; + border: none; + background-color: #f0f0f0; + border-radius: 5px; + transition: background-color 0.3s; +} + +.now-button { + padding: 12px 24px; + font-size: 16px; + font-weight: bold; + cursor: pointer; + border: none; + background-color: #4CAF50; + color: white; + border-radius: 5px; + transition: background-color 0.3s; +} + +.now-button:hover { + background-color: #45a049; +} + +.nav-button:hover { + background-color: #e0e0e0; +} + +.nav-button:disabled, .now-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} +</style> + </head> + + <body> +<div class="gallery"> + <div class="main-image"> + <img id="featured" src="" alt="Hauptbild" onerror="this.src='error.png'"> + </div> + <div class="controls"> + <button onclick="jumpDays(-7)" class="nav-button"><img src="fbck.png"></button> + <button onclick="jumpDays(-1)" class="nav-button"><img src="bck.png"></button> + <button onclick="jumpToCurrent()" class="now-button"><img src="stop.png"></button> + <button onclick="jumpDays(1)" class="nav-button"><img src="fwd.png"></button> + <button onclick="jumpDays(7)" class="nav-button"><img src="ffwd.png"></button> + </div> +</div> +<a href="index.html">go to current day</a> + </body> +</html> + +<script> +let currentDate = new Date(); + +function formatDateString(date) { + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + return `${year}-${month}-${day}_12_00`; +} + +function updateGallery() { + // Setze die Uhrzeit auf 12:00 + currentDate.setHours(12, 0, 0, 0); + updateImage(); + updateButtons(); +} + +function jumpDays(days) { + const newDate = new Date(currentDate); + newDate.setDate(newDate.getDate() + days); + const today = new Date(); + today.setHours(12, 0, 0, 0); + + // Prüfe ob das neue Datum nicht in der Zukunft liegt + if (newDate <= today) { + currentDate = newDate; + updateImage(); + updateButtons(); + } +} + +function jumpToCurrent() { + const today = new Date(); + today.setHours(12, 0, 0, 0); + currentDate = today; + updateImage(); + updateButtons(); +} + +function updateImage() { + const dateString = formatDateString(currentDate); + const img = document.getElementById('featured'); + img.src = `waterpi_12h_images/${dateString}.jpg`; +} + +function updateButtons() { + const today = new Date(); + today.setHours(12, 0, 0, 0); + + const buttons = document.querySelectorAll('.nav-button'); + + // Deaktiviere Vorwärts-Buttons wenn aktueller Tag erreicht + buttons[2].disabled = currentDate.getTime() + 24 * 60 * 60 * 1000 > today.getTime(); + buttons[3].disabled = currentDate.getTime() + 7 * 24 * 60 * 60 * 1000 > today.getTime(); + + // Deaktiviere den Heute-Button wenn bereits der aktuelle Tag angezeigt wird + document.querySelector('.now-button').disabled = + currentDate.getTime() === today.getTime(); +} + +// Initial gallery setup +updateGallery(); + +// Aktualisiere die Galerie jede Sekunde +//setInterval(updateGallery, 1000); +</script> @@ -80,7 +80,7 @@ <button onclick="jumpTime(60)" class="nav-button"><img src="ffwd.png"></button> </div> </div> - +<a href="history.html">go to 12:00 images</a> </body> </html> @@ -1,10 +1,12 @@ #!/bin/bash export LC_TIME=de_DE.utf-8 image=/mnt/ramdisk/$(date +'%H_%M').jpg -#image_small=/mnt/ramdisk/$(date +'%H_%M')_thumb.jpg - +#take photo 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 -#convert $image -resize 200x150 $image_small +#read cpu temp +read_temperature.py +#plot cpu temp +plot.py $image $image @@ -3,11 +3,63 @@ 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 + +import sqlite3 + +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 + 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): - times = np.arange(0, 24, 0.5) # Zeitpunkte (alle halbe Stunde) - temperatures = 20 + 10 * np.sin(times / 24 * 2 * np.pi) # Beispielhafte Sinuskurve für Temperaturen + 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: + print("Keine Daten gefunden.") + + # 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) + for timestamp, temperature 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 @@ -15,13 +67,14 @@ def create_temperature_plot_with_labels(output_filename): # Temperaturdiagramm zeichnen plt.figure(figsize=(8, 2), dpi=100) # Größe des Diagramms: 800x100 Pixel - plt.plot(times, temperatures, color='yellow', linewidth=5, label='Temperatur') + 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('Temperatur in °C', color='white') # Y-Achsenbeschriftung - plt.xticks(np.arange(0, 25, 4), color='white') # X-Achse in 4-Stunden-Schritten beschriften + 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='gray', linestyle='--', linewidth=0.5, alpha=0.7) + 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 diff --git a/read_temperature.py b/read_temperature.py new file mode 100755 index 0000000..0d9249e --- /dev/null +++ b/read_temperature.py @@ -0,0 +1,61 @@ +#!/usr/bin/python3 +import sqlite3 +import subprocess +from datetime import datetime + +# Funktion zur Messung der CPU-Temperatur +def get_cpu_temperature(): + try: + # Führt den Befehl vcgencmd aus, um die CPU-Temperatur zu messen + output = subprocess.run(['vcgencmd', 'measure_temp'], stdout=subprocess.PIPE) + temp_str = output.stdout.decode('utf-8') + # Extrahiert die Temperatur als Float-Wert + temp = float(temp_str.split('=')[1].split("'")[0]) + return temp + except Exception as e: + print(f"Fehler beim Abrufen der CPU-Temperatur: {e}") + return None + +# 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 cpu_temperature ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT NOT NULL, + temperature REAL NOT NULL + ) + """) + conn.commit() + return conn + +# Funktion zum Einfügen von Daten in die Datenbank +def insert_data(conn, timestamp, temperature): + cursor = conn.cursor() + cursor.execute(""" + INSERT INTO cpu_temperature (timestamp, temperature) + VALUES (?, ?) + """, (timestamp, temperature)) + conn.commit() + +# Hauptfunktion +def main(): + db_name = "/var/www/html/cpu_temperature.db" + conn = init_db(db_name) + + # Ruft die aktuelle CPU-Temperatur ab + temperature = get_cpu_temperature() + if temperature 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) + print(f"Gespeichert: {timestamp} - {temperature}°C") + + conn.close() + +if __name__ == "__main__": + main() + diff --git a/water_the_plant b/water_the_plant new file mode 100755 index 0000000..bdfed4d --- /dev/null +++ b/water_the_plant @@ -0,0 +1,22 @@ +#!/usr/bin/python3 +import RPi.GPIO as GPIO +import time + +# GPIO-Modus auf BCM setzen +GPIO.setmode(GPIO.BCM) + +# GPIO4 als Ausgang konfigurieren +GPIO.setup(4, GPIO.OUT) + +try: + # GPIO4 einschalten + GPIO.output(4, GPIO.LOW) + # 1 Sekunde warten + time.sleep(4) + # GPIO4 ausschalten + GPIO.output(4, GPIO.HIGH) +finally: + # Ressourcen freigeben + GPIO.cleanup() + + |