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/20 18:50] torsten.roehlprojekt:python_fastapi [2026/02/23 07:26] (aktuell) – [Systemd] torsten.roehl
Zeile 1: Zeile 1:
-====== GPIO mit FastAPI (Websteuerung) ======+====== Python FASTAPI ======
  
 [[raspberry_pi:einstiegskurs_raspberry_pi|☚ zurück - Einstiegskurs Raspberry Pi]] [[raspberry_pi:einstiegskurs_raspberry_pi|☚ zurück - Einstiegskurs Raspberry Pi]]
  
-===== Ziel ===== 
  
-  * Klare Trennung: Hardware Web HTML +//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.//
-  * Keine Template-Engine +
-  * HTML als eigene Datei +
-  * LED + DS18B20 Temperatur +
-  * Apache bleibt Hauptserver +
-  * Reboot-fest über systemd +
-  * VENV: ~/devel/projects/course_env+
  
 +|{{ :raspberry_pi:web_1.png?300 |}}|
 +|Die LED-Ampel kann nun über den Webbrowser gesteuert und die Temperatur ausgelesen werden.|
 +====== Überblick ======
 +  * Voraussetzungen
 +  * Software
 +  * Konfiguration
  
-===== 1. Projektordner =====+====== Details ====== 
 + 
 +===== Voraussetzungen ===== 
 + 
 +==== ENV ==== 
 + 
 +<note important> 
 +**Aktivierung der Python-Environment: ''course_env''** 
 + 
 +Alle weiteren Schritte erfolgen mit der aktivierten Python-Umgebung. 
 + 
 +<code> 
 +source ~/devel/projects/course_env/bin/activate 
 +</code> 
 + 
 +</note> 
 +Anschließend werden FastAPI und Uvicorn installiert:
  
 <code bash> <code bash>
-cd /home/pi/devel/projects +pip install fastapi uvicorn       
-mkdir -p hardware_web/src/core +
-mkdir -p hardware_web/src/static +
-cd hardware_web/src/core +
-touch __init__.py+
 </code> </code>
 +<note>
 +**FastAPI / Uvicorn**
  
 +  * **FastAPI**
 +    * stellt das Web-Framework bereit, mit dem die Webseiten und Routen programmiert werden.
 +  * **Uvicorn**
 +    * startet die Anwendung und sorgt dafür, dass sie im Browser erreichbar ist.
 +</note>
  
-===== 2. VENV =====+==== Projektstruktur ====
  
 +'' cd ~/devel/projects/''
 +<code>
 +course_web/
 +└── src/
 +    ├── app.py
 +    ├── core/
 +    │   |── __init__.py    # kann leer sein!    
 +    │   └── hardware.py
 +    └── html/
 +        ├── led.html
 +        └── temp.html
 +
 +</code>
 +==== Apache2 Startseite ====
 +Im Verzeichnis des Apache2-Webservers (''/var/www/html'') wird eine ''index.html'' bereitgestellt. 
 +Beim Aufruf der **IP-Adresse des Raspberry Pi im Browser** wird diese Startseite geladen, über die anschließend das gewünschte Projekt ausgewählt werden kann.
 +
 +<note tip> **Tip**
 +
 +Bevor die neue ''index.html'' im Verzeichnis ''/var/www/html'' erstellt wird, sollte die vorhandene Apache-Standardseite ''index.html'' gesichert werden.
 <code bash> <code bash>
-source ~/devel/projects/course_env/bin/activate +sudo mv /var/www/html/index.html /var/www/html/index_course_backup.html
-pip install fastapi uvicorn RPi.GPIO +
-which uvicorn+
 </code> </code>
 +</note>
  
-Erwartet: +<code html /var/www/html/index.html> 
-  /home/pi/devel/projects/course_env/bin/uvicorn+<!DOCTYPE html> 
 +<html> 
 +<head> 
 +    <title>Projekt Auswahl</title> 
 +</head> 
 +<body>
  
 +<h1>Projekt Auswahl</h1>
  
-===== 3. Hardware-Schicht =====+<ul> 
 +    <li><a href="/wiki">DokuWiki</a></li> 
 +    <li><a href="/led">LED Ampel</a></li> 
 +    <li><a href="/temp">Temperatur</a></li> 
 +</ul> 
 + 
 +</body> 
 +</html> 
 +</code> 
 +==== 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.
  
-Datei: +===== Software ===== 
-  /home/pi/devel/projects/hardware_web/src/core/hardware.py+Im folgenden Abschnitt werden die für die Webanwendung benötigten Python- und HTML-Dateien vorgestelltDazu 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. 
 +==== API ====
  
-<code python>+<code python /home/pi/devel/projects/course_web/src/core/hardware.py >
 import RPi.GPIO as GPIO import RPi.GPIO as GPIO
 import glob import glob
 import time import time
  
-========================= +----------------------------- 
-# GPIO LED +API-Funktionen GPIO LED Ampel 
-=========================+-----------------------------
  
 PIN_R = 17 PIN_R = 17
Zeile 56: Zeile 110:
  
 _initialized = False _initialized = False
- 
  
 def init(): def init():
Zeile 73: Zeile 126:
  
  
-def setRedLED(v): +def setLED(pin, value): 
-    GPIO.output(PIN_R, GPIO.HIGH if == 1 else GPIO.LOW)+    GPIO.output(pin, GPIO.HIGH if value == 1 else GPIO.LOW
 + 
 + 
 +def setRedLED(value): 
 +    setLED(PIN_R, value)
  
  
-def setYellowLED(v): +def setYellowLED(value): 
-    GPIO.output(PIN_Y, GPIO.HIGH if v == 1 else GPIO.LOW)+    setLED(PIN_Y, value)
  
  
-def setGreenLED(v): +def setGreenLED(value): 
-    GPIO.output(PIN_G, GPIO.HIGH if v == 1 else GPIO.LOW)+    setLED(PIN_G, value)
  
  
-def led_status():+def status():
     return (     return (
         int(GPIO.input(PIN_R)),         int(GPIO.input(PIN_R)),
Zeile 93: Zeile 150:
  
  
-========================= +----------------------------- 
-DS18B20 Temperatur +API-Funktionen ds18b20 
-=========================+-----------------------------
  
 SENSOR_TIMEOUT = 1 SENSOR_TIMEOUT = 1
  
- +def get_sensor():
-def get_sensor_file():+
     sensors = glob.glob("/sys/bus/w1/devices/28-*")     sensors = glob.glob("/sys/bus/w1/devices/28-*")
     if not sensors:     if not sensors:
Zeile 108: Zeile 164:
  
 def get_temperature(): def get_temperature():
-    sensor_file = get_sensor_file()+    sensor_file = get_sensor()
     if sensor_file is None:     if sensor_file is None:
         return None         return None
Zeile 132: Zeile 188:
  
  
-===== 4. HTML-Datei =====+====  HTML ====
  
-Datei: +=== LED ===
-  /home/pi/devel/projects/hardware_web/src/static/index.html+
  
-<code html>+ 
 +<code html /home/pi/devel/projects/course_web/src/html/led.html>
 <!DOCTYPE html> <!DOCTYPE html>
 <html> <html>
 <head> <head>
-    <title>Hardware Web</title>+    <title>LED Ampel</title>
 </head> </head>
 <body> <body>
  
-<h1>LED Steuerung</h1>+<h1>LED Ampel</h1>
  
-<h2>Rot (Status: {{R}})</h2+<h2>Rot</h2> 
-<a href="/web/led/r/1">ON</a> +<p>Status: {{R}}</p
-<a href="/web/led/r/0">OFF</a>+<a href="/led/r/1">ON</a> 
 +<a href="/led/r/0">OFF</a>
  
-<h2>Gelb (Status: {{Y}})</h2+<h2>Gelb</h2> 
-<a href="/web/led/y/1">ON</a> +<p>Status: {{Y}}</p
-<a href="/web/led/y/0">OFF</a>+<a href="/led/y/1">ON</a> 
 +<a href="/led/y/0">OFF</a>
  
-<h2>Grün (Status: {{G}})</h2+<h2>Grün</h2> 
-<a href="/web/led/g/1">ON</a> +<p>Status: {{G}}</p
-<a href="/web/led/g/0">OFF</a>+<a href="/led/g/1">ON</a> 
 +<a href="/led/g/0">OFF</a>
  
-<hr>+<br><br> 
 +<a href="/">Zurück</a> 
 + 
 +</body> 
 +</html> 
 +</code> 
 + 
 + 
 +=== Temperature === 
 + 
 + 
 +<code html /home/pi/devel/projects/course_web/src/html/temp.html> 
 +<!DOCTYPE html> 
 +<html> 
 +<head> 
 +    <title>Temperatur</title> 
 +</head> 
 +<body>
  
 <h1>Temperatur</h1> <h1>Temperatur</h1>
 +
 <p>Temperatur: {{T}} °C</p> <p>Temperatur: {{T}} °C</p>
 +
 +<br>
 +<a href="/">Zurück</a>
  
 </body> </body>
Zeile 169: Zeile 249:
  
  
-===== 5. Web-Schicht =====+==== FASTAPI APP ==== 
 + 
 + 
 +<code python /home/pi/devel/projects/course_web/src/app.py>
  
-Datei: 
-  /home/pi/devel/projects/hardware_web/src/app.py 
  
-<code python> 
 from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException
 from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
 from core import hardware from core import hardware
  
-app = FastAPI(root_path="/web")+app = FastAPI()
  
  
Zeile 187: Zeile 267:
  
  
-def load_html(r, y, gt): +def load_template(namereplacements): 
-    with open("static/index.html", "r") as f: +    try: 
-        html = f.read()+        with open(f"html/{name}", "r") as f: 
 +            html = f.read(
 +    except FileNotFoundError: 
 +        raise HTTPException(status_code=500, detail="Template nicht gefunden")
  
-    html = html.replace("{{R}}"str(r)) +    for keyvalue in replacements.items(): 
-    html = html.replace("{{Y}}", str(y)+        html = html.replace(key, str(value))
-    html = html.replace("{{G}}", str(g)+
- +
-    if t is None: +
-        html = html.replace("{{T}}", "Sensorfehler"+
-    else: +
-        html = html.replace("{{T}}", f"{t:.2f}")+
  
     return html     return html
  
 +@app.get("/led", response_class=HTMLResponse)
 +def led_page():
 +    r, y, g = hardware.status()
  
-@app.get("/", response_class=HTMLResponse) +    return HTMLResponse( 
-def index(): +        load_template("led.html", { 
-    r, y, g = hardware.led_status() +            "{{R}}": r, 
-    t = hardware.get_temperature() +            "{{Y}}": y, 
-    return HTMLResponse(load_html(r, y, g, t)+            "{{G}}": g, 
 +            "{{R_ON}}": "on" if == 1 else "", 
 +            "{{Y_ON}}": "on" if == 1 else "", 
 +            "{{G_ON}}": "on" if == 1 else "", 
 +        }
 +    )
  
 @app.get("/led/{color}/{value}") @app.get("/led/{color}/{value}")
Zeile 225: Zeile 309:
         raise HTTPException(status_code=400)         raise HTTPException(status_code=400)
  
-    return RedirectResponse(url="/web", status_code=303)+    return RedirectResponse(url="/led", status_code=303
 + 
 + 
 +@app.get("/temp", response_class=HTMLResponse) 
 +def temp_page(): 
 +    t = hardware.get_temperature() 
 + 
 +    if t is None: 
 +        value = "Sensorfehler" 
 +    else: 
 +        value = f"{t:.2f}" 
 + 
 +    return HTMLResponse( 
 +        load_template("temp.html",
 +            "{{T}}": value 
 +        }) 
 +    )
 </code> </code>
  
  
-===== 6. Apache ===== 
  
-In: 
-  /etc/apache2/sites-available/000-default.conf 
  
-<code>+===== 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 ==== 
 + 
 +=== Konfiguration === 
 + 
 +In der Datei '' /etc/apache2/sites-available/000-default.conf'', 
 +innerhalb von ''<VirtualHost *:80>'' folgendes einfügen: 
 + 
 + 
 +<note tip> **Tip** 
 + 
 +Bevor die Datei ''/etc/apache2/sites-available/000-default.conf'' geändert wird, 
 +sollte die vorhandene Konfiguration gesichert werden. 
 + 
 +<code bash> 
 +cd  /etc/apache2/sites-available/ 
 +sudo  cp 000-default.conf 000-default.conf.course_backup 
 +</code> 
 + 
 +</note> 
 + 
 + 
 +<code bash /etc/apache2/sites-available/000-default.conf>
 ProxyPreserveHost On ProxyPreserveHost On
-ProxyPass        /web  http://127.0.0.1:8000/ + 
-ProxyPassReverse /web  http://127.0.0.1:8000/+ProxyPass        /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
 </code> </code>
 +
 +=== Aktivieren ===
 +Damit die Weiterleitung an die FastAPI-Anwendung funktioniert, müssen die benötigten Apache-Module aktiviert und der Webserver neu gestartet werden.
  
 <code bash> <code bash>
 sudo a2enmod proxy sudo a2enmod proxy
 sudo a2enmod proxy_http sudo a2enmod proxy_http
-sudo systemctl reload apache2+sudo systemctl restart apache2
 </code> </code>
  
 +==== Systemd ====
  
-===== 7. systemd =====+Die Service-Datei muss unter ''/etc/systemd/system/course_web.service'' neu erstellt und anschließend bei ''systemd'' registriert werden. 
 +=== Service ===
  
-Datei: 
-  /etc/systemd/system/hardware_web.service 
  
-<code>+<code bash /etc/systemd/system/course_web.service>
 [Unit] [Unit]
-Description=Hardware Web FastAPI+Description=Python Web FastAPI
 After=network-online.target After=network-online.target
 Wants=network-online.target Wants=network-online.target
Zeile 260: Zeile 387:
 [Service] [Service]
 User=pi User=pi
-WorkingDirectory=/home/pi/devel/projects/hardware_web/src+WorkingDirectory=/home/pi/devel/projects/course_web/src
 ExecStart=/home/pi/devel/projects/course_env/bin/uvicorn app:app --host 127.0.0.1 --port 8000 ExecStart=/home/pi/devel/projects/course_env/bin/uvicorn app:app --host 127.0.0.1 --port 8000
 Restart=always Restart=always
Zeile 267: Zeile 394:
 WantedBy=multi-user.target WantedBy=multi-user.target
 </code> </code>
 +
 +=== 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 hardware_web +sudo systemctl enable course_web 
-sudo systemctl start hardware_web+sudo systemctl start course_web       # starten 
 </code> </code>
  
- +Nützlich:
-===== 8. Test ===== +
- +
-  * http://raspberrypi/web +
-  * http://raspberrypi/wiki +
- +
-===== 9. Reboot ===== +
 <code bash> <code bash>
-sudo reboot+sudo systemctl restart course_web     # neu starten 
 +sudo systemctl status course_web      # prüfen!!!
 </code> </code>
- 
-System startet automatisch. 
-Hardware wird einmal initialisiert. 
-Reboot-fest. 
- 
- 
projekt/python_fastapi.1771613414.txt.gz · Zuletzt geändert: von torsten.roehl