Benutzer-Werkzeuge

Webseiten-Werkzeuge


projekt:python_fastapi

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
projekt:python_fastapi [2026/02/21 11:30] – [Temperaturverlauf: Daten anlegen] torsten.roehlprojekt:python_fastapi [2026/02/23 07:26] (aktuell) – [Systemd] torsten.roehl
Zeile 5: Zeile 5:
  
 //In diesem Projekt wird auf dem Raspberry Pi eine Weboberfläche mit FastAPI erstellt, über die eine LED-Ampel geschaltet und die Temperatur eines DS18B20 angezeigt werden kann. Die Anwendung ist im lokalen Netzwerk erreichbar, sodass LEDs und Temperatursensor bequem über einen Webbrowser im LAN gesteuert und überwacht werden können.// //In diesem Projekt wird auf dem Raspberry Pi eine Weboberfläche mit FastAPI erstellt, über die eine LED-Ampel geschaltet und die Temperatur eines DS18B20 angezeigt werden kann. Die Anwendung ist im lokalen Netzwerk erreichbar, sodass LEDs und Temperatursensor bequem über einen Webbrowser im LAN gesteuert und überwacht werden können.//
 +
 +|{{ :raspberry_pi:web_1.png?300 |}}|
 +|Die LED-Ampel kann nun über den Webbrowser gesteuert und die Temperatur ausgelesen werden.|
 ====== Überblick ====== ====== Überblick ======
   * Voraussetzungen   * Voraussetzungen
Zeile 22: Zeile 25:
  
 <code> <code>
-source ~/devel/projects/course_env/bin/activate  #ndre nichts ohne nachfrage+source ~/devel/projects/course_env/bin/activate
 </code> </code>
  
Zeile 45: Zeile 48:
 <code> <code>
 course_web/ course_web/
-|── data/ 
-|   └── temperature.txt 
 └── src/ └── src/
     ├── app.py     ├── app.py
Zeile 54: Zeile 55:
     └── html/     └── html/
         ├── led.html         ├── led.html
-        ├── history.html 
         └── temp.html         └── temp.html
  
 </code> </code>
- 
-==== Temperaturverlauf: Daten anlegen ==== 
-Die Messwerte werden in einer Textdatei (''temperature.txt'') gespeichert, damit der Verlauf nachvollziehbar bleibt (auch wenn gerade kein Browser geöffnet ist). 
- 
- 
-<note> 
-**Format der Datei ''temperature.txt''** 
- 
-Jede Zeile enthält Zeitstempel und Temperatur, getrennt durch ein Semikolon: 
- 
-''YYYY-MM-DD HH:MM:SS;TEMPERATUR'' 
- 
-Beispiel: 
-''2026-02-21 12:00:00;21.437'' 
-</note> 
- 
 ==== Apache2 Startseite ==== ==== Apache2 Startseite ====
 Im Verzeichnis des Apache2-Webservers (''/var/www/html'') wird eine ''index.html'' bereitgestellt.  Im Verzeichnis des Apache2-Webservers (''/var/www/html'') wird eine ''index.html'' bereitgestellt. 
Zeile 100: Zeile 84:
     <li><a href="/led">LED Ampel</a></li>     <li><a href="/led">LED Ampel</a></li>
     <li><a href="/temp">Temperatur</a></li>     <li><a href="/temp">Temperatur</a></li>
-    <li><a href="/history">Temperaturverlauf</a></li> 
 </ul> </ul>
  
Zeile 106: Zeile 89:
 </html> </html>
 </code> </code>
- 
 ==== Hardware ==== ==== Hardware ====
 Die Hardware, also die LED-Ampel und der Temperatursensor, wurden in den vorausgegangenen Projekten ausführlich behandelt und werden exakt so verwendet wie dort beschrieben. Die Hardware, also die LED-Ampel und der Temperatursensor, wurden in den vorausgegangenen Projekten ausführlich behandelt und werden exakt so verwendet wie dort beschrieben.
Zeile 112: Zeile 94:
 ===== Software ===== ===== Software =====
 Im folgenden Abschnitt werden die für die Webanwendung benötigten Python- und HTML-Dateien vorgestellt. Dazu gehören die Hardware-Anbindung über GPIO und den Temperatursensor, die HTML-Seiten zur Darstellung im Browser sowie die FastAPI-Anwendung, welche die Routen bereitstellt und die einzelnen Komponenten miteinander verbindet. Im folgenden Abschnitt werden die für die Webanwendung benötigten Python- und HTML-Dateien vorgestellt. Dazu gehören die Hardware-Anbindung über GPIO und den Temperatursensor, die HTML-Seiten zur Darstellung im Browser sowie die FastAPI-Anwendung, welche die Routen bereitstellt und die einzelnen Komponenten miteinander verbindet.
- 
-<note> 
-**Temperaturverlauf (History)** 
- 
-Der Temperaturverlauf wird nicht nur beim Aufruf im Browser erzeugt, sondern durch einen Hintergrund-Thread im laufenden FastAPI-Programm. 
-Damit können Messwerte automatisch im Intervall gesammelt, gestoppt und zurückgesetzt werden. 
-</note> 
- 
 ==== API ==== ==== API ====
  
Zeile 212: Zeile 186:
     return float(temp_str) / 1000.0     return float(temp_str) / 1000.0
 </code> </code>
 +
  
 ====  HTML ==== ====  HTML ====
  
 === LED === === LED ===
 +
  
 <code html /home/pi/devel/projects/course_web/src/html/led.html> <code html /home/pi/devel/projects/course_web/src/html/led.html>
Zeile 248: Zeile 224:
 </html> </html>
 </code> </code>
 +
  
 === Temperature === === Temperature ===
 +
  
 <code html /home/pi/devel/projects/course_web/src/html/temp.html> <code html /home/pi/devel/projects/course_web/src/html/temp.html>
Zeile 270: Zeile 248:
 </code> </code>
  
-=== History === 
  
-<code html /home/pi/devel/projects/course_web/src/html/history.html> +==== FASTAPI APP ====
-<!DOCTYPE html> +
-<html> +
-<head> +
-    <title>Temperaturverlauf</title> +
-    <meta charset="utf-8" /> +
-    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> +
-</head> +
-<body>+
  
-<h1>Temperaturverlauf</h1> 
  
-<h2>Aufzeichnung</h2> +<code python /home/pi/devel/projects/course_web/src/app.py>
-<a href="/history/start">Start</a> +
-<a href="/history/stop">Stop</a> +
-<a href="/history/reset">Reset</a>+
  
-<h2>Intervall (Minuten)</h2> 
-<a href="/history/interval/1">1</a> 
-<a href="/history/interval/5">5</a> 
-<a href="/history/interval/10">10</a> 
- 
-<h2>Diagramm</h2> 
-<canvas id="chart" width="900" height="300"></canvas> 
- 
-<script> 
-let chart = null; 
- 
-async function loadData() { 
-    const res = await fetch("/history/data"); 
-    return await res.json(); 
-} 
- 
-async function plot() { 
-    const data = await loadData(); 
- 
-    const ctx = document.getElementById("chart").getContext("2d"); 
-    if (chart) chart.destroy(); 
- 
-    chart = new Chart(ctx, { 
-        type: "line", 
-        data: { 
-            labels: data.labels, 
-            datasets: [{ 
-                label: "Temperatur (°C)", 
-                data: data.values 
-            }] 
-        }, 
-        options: { 
-            animation: false 
-        } 
-    }); 
-} 
- 
-plot(); 
-setInterval(plot, 5000); 
-</script> 
- 
-<br><br> 
-<a href="/">Zurück</a> 
- 
-</body> 
-</html> 
-</code> 
- 
-==== FASTAPI APP ==== 
- 
-<code python /home/pi/devel/projects/course_web/src/app.py> 
  
 from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException
-from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse+from fastapi.responses import HTMLResponse, RedirectResponse
 from core import hardware from core import hardware
- 
-import threading 
-import time 
-from datetime import datetime 
  
 app = FastAPI() app = FastAPI()
- 
-LOG_FILE = "/home/pi/devel/projects/course_web/data/temperature.txt" 
- 
-recording = False 
-interval_seconds = 60 
-_collector_started = False 
-_lock = threading.Lock() 
- 
- 
-def _collector_loop(): 
-    global recording 
- 
-    while True: 
-        if recording: 
-            t = hardware.get_temperature() 
-            if t is not None: 
-                ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 
-                try: 
-                    with open(LOG_FILE, "a") as f: 
-                        f.write(f"{ts};{t:.3f}\n") 
-                except Exception: 
-                    pass 
- 
-        time.sleep(interval_seconds) 
- 
- 
-def _ensure_collector(): 
-    global _collector_started 
- 
-    with _lock: 
-        if _collector_started: 
-            return 
- 
-        th = threading.Thread(target=_collector_loop, daemon=True) 
-        th.start() 
-        _collector_started = True 
  
  
Zeile 391: Zeile 265:
 def startup(): def startup():
     hardware.init()     hardware.init()
-    _ensure_collector() 
  
  
Zeile 405: Zeile 278:
  
     return html     return html
- 
  
 @app.get("/led", response_class=HTMLResponse) @app.get("/led", response_class=HTMLResponse)
 def led_page(): def led_page():
     r, y, g = hardware.status()     r, y, g = hardware.status()
 +
     return HTMLResponse(     return HTMLResponse(
         load_template("led.html", {         load_template("led.html", {
             "{{R}}": r,             "{{R}}": r,
             "{{Y}}": y,             "{{Y}}": y,
-            "{{G}}": g+            "{{G}}": g
 +            "{{R_ON}}": "on" if r == 1 else "", 
 +            "{{Y_ON}}": "on" if y == 1 else "", 
 +            "{{G_ON}}": "on" if g == 1 else "",
         })         })
     )     )
- 
  
 @app.get("/led/{color}/{value}") @app.get("/led/{color}/{value}")
Zeile 451: Zeile 326:
         })         })
     )     )
 +</code>
  
  
-# ----------------------------- 
-# History (Temperaturverlauf) 
-# ----------------------------- 
  
-@app.get("/history", response_class=HTMLResponse) 
-def history_page(): 
-    return HTMLResponse(load_template("history.html", {})) 
  
 +===== Konfiguration =====
 +In diesem Abschnitt wird die Einbindung der **FastAPI-Anwendung** in den Apache-Webserver sowie die Einrichtung als ''systemd-Service'' beschrieben, damit die Anwendung automatisch startet und im lokalen Netzwerk erreichbar ist.
 +==== Apache Proxy ====
  
-@app.get("/history/start"+=== Konfiguration ===
-def history_start(): +
-    global recording +
-    recording True +
-    return RedirectResponse(url="/history", status_code=303)+
  
 +In der Datei '' /etc/apache2/sites-available/000-default.conf'',
 +innerhalb von ''<VirtualHost *:80>'' folgendes einfügen:
  
-@app.get("/history/stop") 
-def history_stop(): 
-    global recording 
-    recording = False 
-    return RedirectResponse(url="/history", status_code=303) 
  
 +<note tip> **Tip**
  
-@app.get("/history/reset"+Bevor die Datei ''/etc/apache2/sites-available/000-default.conf'' geändert wird
-def history_reset(): +sollte die vorhandene Konfiguration gesichert werden.
-    open(LOG_FILE, "w").close() +
-    return RedirectResponse(url="/history", status_code=303) +
- +
- +
-@app.get("/history/interval/{minutes}"+
-def history_interval(minutes: int): +
-    global interval_seconds +
- +
-    if minutes < 1: +
-        raise HTTPException(status_code=400) +
- +
-    interval_seconds = minutes * 60 +
-    return RedirectResponse(url="/history", status_code=303) +
- +
- +
-@app.get("/history/data"+
-def history_data(): +
-    labels = [] +
-    values = [] +
- +
-    try: +
-        with open(LOG_FILE"r") as f: +
-            for line in f: +
-                line = line.strip() +
-                if not line: +
-                    continue +
-                try: +
-                    ts, val = line.split(";"+
-                    labels.append(ts)          # kompletter Zeitstempel fürs Diagramm +
-                    values.append(float(val)) +
-                except Exception: +
-                    continue +
-    except FileNotFoundError: +
-        pass +
- +
-    return JSONResponse({"labels": labels, "values": values})+
  
 +<code bash>
 +cd  /etc/apache2/sites-available/
 +sudo  cp 000-default.conf 000-default.conf.course_backup
 </code> </code>
  
-===== Konfiguration ===== +</note>
-In diesem Abschnitt wird die Einbindung der **FastAPI-Anwendung** in den Apache-Webserver sowie die Einrichtung als ''systemd-Service'' beschrieben, damit die Anwendung automatisch startet und im lokalen Netzwerk erreichbar ist.+
  
-==== Apache Proxy ==== 
- 
-=== Konfiguration === 
- 
-In der Datei '' /etc/apache2/sites-available/000-default.conf'', innerhalb von ''<VirtualHost *:80>'' folgendes einfügen: 
  
 <code bash /etc/apache2/sites-available/000-default.conf> <code bash /etc/apache2/sites-available/000-default.conf>
 ProxyPreserveHost On ProxyPreserveHost On
  
-ProxyPass        /led      http://127.0.0.1:8000/led +ProxyPass        /led   http://127.0.0.1:8000/led 
-ProxyPassReverse /led      http://127.0.0.1:8000/led +ProxyPassReverse /led   http://127.0.0.1:8000/led
- +
-ProxyPass        /temp     http://127.0.0.1:8000/temp +
-ProxyPassReverse /temp     http://127.0.0.1:8000/temp+
  
-ProxyPass        /history  http://127.0.0.1:8000/history +ProxyPass        /temp  http://127.0.0.1:8000/temp 
-ProxyPassReverse /history  http://127.0.0.1:8000/history+ProxyPassReverse /temp  http://127.0.0.1:8000/temp
 </code> </code>
  
-<note tip> +=== Aktivieren === 
-Falls ''/history/start'' oder ''/history/data'' nicht sauber funktionierenzusätzlich das Prefix weiterleiten:+Damit die Weiterleitung an die FastAPI-Anwendung funktioniertmüssen die benötigten Apache-Module aktiviert und der Webserver neu gestartet werden.
  
-<code> 
-ProxyPass        /history/  http://127.0.0.1:8000/history/ 
-ProxyPassReverse /history/  http://127.0.0.1:8000/history/ 
-</code> 
-</note> 
- 
-=== Aktivieren === 
 <code bash> <code bash>
 sudo a2enmod proxy sudo a2enmod proxy
Zeile 558: Zeile 376:
  
 Die Service-Datei muss unter ''/etc/systemd/system/course_web.service'' neu erstellt und anschließend bei ''systemd'' registriert werden. Die Service-Datei muss unter ''/etc/systemd/system/course_web.service'' neu erstellt und anschließend bei ''systemd'' registriert werden.
- 
 === Service === === Service ===
 +
  
 <code bash /etc/systemd/system/course_web.service> <code bash /etc/systemd/system/course_web.service>
Zeile 578: Zeile 396:
  
 === Registrierung === === Registrierung ===
 +Damit die neu erstellte Service-Datei von ''systemd'' erkannt wird und die Anwendung automatisch beim Systemstart gestartet wird, muss der Dienst neu geladen, aktiviert und gestartet werden.
 +
 <code bash> <code bash>
 sudo systemctl daemon-reload sudo systemctl daemon-reload
 sudo systemctl enable course_web sudo systemctl enable course_web
 sudo systemctl start course_web       # starten sudo systemctl start course_web       # starten
-sudo systemctl status course_web      # prüfen!!!+
 </code> </code>
  
-==== Test Temperaturverlauf ====+Nützlich:
 <code bash> <code bash>
-tail -n 20 /home/pi/devel/projects/course_web/data/temperature.txt+sudo systemctl restart course_web     # neu starten 
 +sudo systemctl status course_web      # prüfen!!!
 </code> </code>
projekt/python_fastapi.1771673459.txt.gz · Zuletzt geändert: von torsten.roehl