====== DS18B20 – Temperaturdaten loggen und visualisieren ====== [[python| ☚ zurück]] // In diesem Projekt wird ein Temperatur-Logger mit dem digitalen 1-Wire-Sensor DS18B20 am Raspberry Pi realisiert. Ergänzend zur reinen Temperaturauslese werden Messwerte kontinuierlich in einer Textdatei protokolliert und aus diesen Daten automatisch ein Temperaturverlauf als Grafik erzeugt. Der Logger lässt sich über ein Kommandozeilen-Interface steuern und speichert Messdaten sowie das Diagramm lokal oder zur Anzeige im Webserver-Verzeichnis.// |{{ :raspberry_pi:temp_logger_0.png?400 |}}| |Der Temperaturverlauf im Browser wird nur angezeigt, wenn zuvor das Programm ''temp_logger.py'' im Terminal gestartet und die Messung mit ''start'' begonnen wurde. In diesem Beispiel wurde die Messung noch nicht gestartet.| ====== Überblick ====== * Voraussetzungen * Hardware * Environment * Programmstruktur anlegen * Software * Quellcode * Testen * Terminal * Webseite ---- ====== Details ====== ===== Voraussetzungen ===== Das Projekt [[python_projekt_ds18b20_digitaler_temperatursensor|DS18B20 digitaler Temperatursensor]] muss vollständig durchgeführt sowie erfolgreich getestet worden sein, da derselbe Aufbau (Verkabelung und Hardware) weiterverwendet wird. **Nutzung lokal:** Für die reine lokale Verwendung des Loggers sind keine weiteren Projekte erforderlich. **Nutzung mit Webausgabe:** Hierfür muss zuvor das [[dokuwiki|DokuWiki-Projekt]] zur Einrichtung des Webservers abgeschlossen worden sein. Idealerweise wurde auch das [[python_fastapi|FastAPI-Projekt]] bereits durchgeführt. ==== Environment ==== **Aktiviere die Python-Environment** Die Programmierung erfolgt nun immer mit der gewählten Umgebung! source ~/devel/projects/course_env/bin/activate ==== Pakete & Bibliotheken installieren ==== Jetzt die **ENV** aktivieren (falls noch nicht geschehen) und dann erst installieren: pip install matplotlib ==== Programmstruktur ==== (course_env) pi@raspi88:~/devel/projects/course_temp_logger $ tree . ├── data │   ├── temperature.png # wird automatisch erstellt │   └── temperature.txt # wird automatisch erstellt └── src ├── core │   ├── hardware.py # aus dem vorherigen Projekt! │   ├── __init__.py │   └── temperature_logger.py └── temp_logger.py # Hauptprogramm ===== Software ===== Im folgenden Abschnitt wird die vollständige Software zur Datenerfassung, Speicherung und grafischen Darstellung der Temperaturwerte beschrieben. ==== Quellcode ==== === hardware.py === Die Datei ''hardware.py'' (API) bleibt unverändert und wird hier der Vollständigkeit halber erneut vollständig aufgeführt. ++++ Quellcode: ''hardware.py'' | import glob import time # ----------------------------- # API-Funktionen ds18b20 # ----------------------------- SENSOR_TIMEOUT = 1 # Sekunden def is_sensor(): """Prüft, ob mindestens ein DS18B20 Sensor angeschlossen ist""" sensors = glob.glob("/sys/bus/w1/devices/28-*") return len(sensors) > 0 def get_sensor(): """Gibt den ersten DS18B20 Sensor zurück oder None""" if not is_sensor(): return None sensors = glob.glob("/sys/bus/w1/devices/28-*") return sensors[0] + "/w1_slave" def get_temperature(): """Liest Temperatur vom ersten Sensor aus, None bei Fehler oder Timeout""" sensor_file = get_sensor() if sensor_file is None: return None start_time = time.time() while True: with open(sensor_file, "r") as f: lines = f.readlines() if lines[0].strip().endswith("YES"): break if time.time() - start_time > SENSOR_TIMEOUT: return None time.sleep(0.1) temp_line = lines[1] temp_str = temp_line.split("t=")[1] return float(temp_str) / 1000.0 ++++ === temperature_logger.py === In der Datei ''temperature_logger.py'' kann die Variable ''MODE'' die Werte ''local'' oder ''web'' annehmen. * **local** Das erzeugte Bild wird im lokalen Projektverzeichnis gespeichert. * **web** Das erzeugte Bild wird im Webverzeichnis gespeichert und kann über den Webserver angezeigt werden. **Hinweis** Die dafür notwendigen Voraussetzungen wurden bereits in einem vorherigen Projekt (DokuWiki) geschaffen: Der Benutzer pi ist Mitglied der Gruppe **www-data**. Dadurch besitzt er die erforderlichen Schreibrechte, um die Datei in das angegebene Webverzeichnis zu speichern. ++++ Quellcode: ''temperature_logger.py'' | import time import threading from datetime import datetime from pathlib import Path import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from core.hardware import get_temperature # MODE = "local" oder "web" MODE = "local" if MODE == "local": DATA_DIR = Path("~/devel/projects/course_temp_logger/data").expanduser() elif MODE == "web": DATA_DIR = Path("/var/www/html/temp_curve").expanduser() else: raise ValueError("MODE muss 'local' oder 'web' sein") DATA_DIR.mkdir(parents=True, exist_ok=True) DATA_FILE = DATA_DIR / "temperature.txt" PLOT_FILE = DATA_DIR / "temperature.png" INTERVAL = 5 # Sekunden (Auflösung / Messintervall) running = False thread_started = False lock = threading.Lock() def set_interval(seconds: int): global INTERVAL if seconds < 1: seconds = 1 INTERVAL = seconds def generate_plot(): times = [] temps = [] if DATA_FILE.exists(): with open(DATA_FILE, "r") as f: for line in f: parts = line.strip().split() if len(parts) == 2: times.append(parts[0]) temps.append(float(parts[1])) plt.figure() plt.title("Temperaturverlauf") plt.xlabel("Zeit") plt.ylabel("Temperatur (°C)") if temps: plt.plot(temps) step = max(1, len(times) // 10) plt.xticks(range(0, len(times), step), times[::step], rotation=45) else: plt.text( 0.5, 0.5, "Keine Messdaten", ha="center", va="center", transform=plt.gca().transAxes, ) plt.tight_layout() plt.savefig(PLOT_FILE) plt.close() def worker(): global running while True: with lock: active = running interval = INTERVAL if active: temp = get_temperature() if temp is not None: now = datetime.now().strftime("%H:%M:%S") with open(DATA_FILE, "a") as f: f.write(f"{now} {temp}\n") generate_plot() time.sleep(interval) else: time.sleep(0.2) def ensure_thread(): global thread_started if not thread_started: t = threading.Thread(target=worker, daemon=True) t.start() thread_started = True def start(): ensure_thread() global running with lock: running = True def stop(): global running with lock: running = False def reset(): stop() DATA_FILE.write_text("") generate_plot() ++++ === Hauptprogramm === Das eigenständige Programm ''temp_logger.py'' dient als Kommandozeilen-Interface zur Steuerung des //Temperatur-Loggers//. Es ermöglicht das Starten und Stoppen der Messung, das Setzen des Messintervalls sowie das Zurücksetzen der gespeicherten Daten. Die eigentliche Messung läuft in einem //Hintergrund-Thread//. Dadurch bleibt die Kommandozeile reaktionsfähig und kann weiterhin Befehle entgegennehmen, während im Hintergrund kontinuierlich Temperaturwerte erfasst, gespeichert und grafisch ausgewertet werden. Während der Laufzeit werden die erfassten Messwerte in die Datei ''data/temperature.txt'' geschrieben. Zusätzlich wird nach jeder Messung **automatisch eine Grafik** (''data/temperature.png'') **erzeugt bzw. aktualisiert**, die den Temperaturverlauf darstellt. ++++ Quellcode ''temp_logger.py'' | #!/usr/bin/env python3 from core import temperature_logger as temp PROMPT = "> " SHORT_HINT = "h = Hilfe" VERSION = "v1.0.0" def print_short_banner(): print("Temperatur-Logger " + VERSION) print("Mit 'h' Hilfe anzeigen.\n") def print_help(): print(""" VERFÜGBARE BEFEHLE ------------------ start | s Logger starten stop | p Logger stoppen reset | r Messwerte zurücksetzen interval | i Messintervall setzen status | t Status anzeigen help | h Diese Hilfe anzeigen exit | x Programm beenden """) def handle_interval(cmd: str): parts = cmd.split() if len(parts) == 2 and parts[1].isdigit(): temp.set_interval(int(parts[1])) print("OK") else: print("Verwendung: interval ") def handle_status(): state = "RUNNING" if temp.running else "STOPPED" print(f"STATUS : {state}") print(f"INTERVALL: {temp.INTERVAL}") def main(): print_short_banner() while True: try: cmd = input(PROMPT).strip().lower() except (EOFError, KeyboardInterrupt): print() temp.stop() break if not cmd: continue if cmd in ("start", "s"): temp.start() elif cmd in ("stop", "p"): temp.stop() elif cmd in ("reset", "r"): temp.reset() elif cmd.startswith("interval") or cmd.startswith("i "): handle_interval(cmd) elif cmd in ("status", "t"): handle_status() elif cmd in ("help", "h"): print_help() elif cmd in ("exit", "x"): temp.stop() break else: print(f"Unbekannter Befehl ({SHORT_HINT})") if __name__ == "__main__": main() ++++ ===== Testen ===== Das Programm kann sowohl **lokal im Terminal** als auch über den **Webbrowser getestet werden**. Für die Webausgabe gelten die im Abschnitt „Voraussetzungen“ beschriebenen Bedingungen. **Hinweis** Wird die Messung mit ''start'' begonnen, werden in regelmäßigen Abständen Temperaturwerte erfasst, die in der Datei (''temperature.txt'') gespeichert werden. Zusätzlich wird nach jeder Messung automatisch eine aktualisierte Grafik des Temperaturverlaufs erzeugt. Die Erfassung erfolgt entsprechend dem eingestellten Messintervall, sodass neue Messwerte erst nach einigen Sekunden sichtbar werden. Das Programm führt die Messung kontinuierlich im Hintergrund aus, bis sie mit ''stop'' beendet oder das Programm mit ''exit'' geschlossen wird. Vor dem Testen prüfen, welcher ''MODE'' in ''temperature_logger.py'' gesetzt ist: * ''local'' → Dateien werden im Projektordner ''data'' gespeichert. * ''web'' → Dateien werden im Webverzeichnis ''/var/www/html/temp_curve'' gespeichert und können im Browser angezeigt werden. Für die Webausgabe muss ''MODE = "web"'' gesetzt sein. ==== Terminal ==== Zur Überprüfung wird das Programm im Verzeichnis ''src'' gestartet: chmod 755 temp_logger.py ./temp_logger.py Temperatur-Logger v1.0.0 Mit 'h' Hilfe anzeigen. > h VERFÜGBARE BEFEHLE ------------------ start | s Logger starten stop | p Logger stoppen reset | r Messwerte zurücksetzen interval | i Messintervall setzen status | t Status anzeigen help | h Diese Hilfe anzeigen exit | x Programm beenden > start (Programm misst im Hintergrund …) > stop > Nach dem Start erscheint die Kommandozeilen-Oberfläche des Temperatur-Loggers. Im obigen Beispiel wurde mit dem Befehl ''h'' die Hilfe angezeigt. Die Befehle können entweder vollständig ausgeschrieben (z. B. ''start'') oder in der angegebenen Kurzform (z. B. ''s'') verwendet werden, um das Programm zu starten. Die erzeugten Dateien befinden sich im Verzeichnis ''data'': ls temperature.png # erzeugte Grafik temperature.txt # Messdaten Die Grafik kann anschließend mit folgendem Befehl betrachtet werden: feh temperature.png |{{ :raspberry_pi:temp_feh.png?400 |}}| |Bildausgabe mit dem Befehl ''feh''| ==== Webseite ==== In diesem Abschnitt wird die einfache HTML-Struktur beschrieben, mit der das Projekt über den Webbrowser erreichbar ist und der automatisch erzeugte Temperaturverlauf grafisch dargestellt wird. Zum Testen im Browser genügt es, die **IP-Adresse** des //Raspberry Pi// in die Adresszeile einzugeben. Der Apache-Webserver liefert automatisch die Datei ''index.html'' aus, die als Startseite angezeigt wird. |{{ :raspberry_pi:temp_logger_1.png?400 |}}| |Bildausgabe über den Webbrowser| === index.html === Die Datei ''index.html'' dient als Startseite und enthält eine Übersicht der verfügbaren Projekte sowie einen Link zur Anzeige des Temperaturverlaufs. Projekt Auswahl

Projekt Auswahl

=== temperature.html === Die Datei ''temperature.html'' zeigt das vom Logger erzeugte Bild temperature.png an und ermöglicht so die grafische Darstellung des aktuellen Temperaturverlaufs im Browser. Temperatur Verlauf

Temperatur Verlauf

Aktueller Temperaturverlauf:

Temperaturverlauf

Zurück
Die Dateien ''index.html'' und ''temperature.html'' müssen sich im Webverzeichnis ''/var/www/html/'' bzw. im Unterordner ''/var/www/html/temp_curve/'' befinden, damit sie vom Webserver korrekt ausgeliefert werden können.