Benutzer-Werkzeuge

Webseiten-Werkzeuge


projekt:python_fastapi

Dies ist eine alte Version des Dokuments!


GPIO mit FastAPI (Websteuerung)

GPIO Web – didaktisch sauber (FastAPI + Apache + systemd)

Ziel:

  • Klare Trennung: Hardware / Web / HTML
  • Keine Template-Engine
  • HTML als eigene Datei
  • Einmalige Initialisierung
  • Reboot-fest über systemd
  • VENV: ~/devel/projects/course_env

1. PROJEKTORDNER

cd /home/pi/devel/projects
mkdir -p gpio_web/src/core
mkdir -p gpio_web/src/static
cd gpio_web/src/core
touch __init__.py

2. VENV

source ~/devel/projects/course_env/bin/activate
pip install fastapi uvicorn RPi.GPIO
which uvicorn

Erwartet:

/home/pi/devel/projects/course_env/bin/uvicorn

3. HARDWARE-SCHICHT

Datei:

/home/pi/devel/projects/gpio_web/src/core/hardware.py
"""
Hardware-Schicht.
Kapselt alle GPIO-Zugriffe.
"""
 
import RPi.GPIO as GPIO
 
PIN_R = 17
PIN_Y = 27
PIN_G = 22
 
_initialized = False
 
 
def init():
    """
    Wird genau einmal beim Start des Servers aufgerufen.
    """
    global _initialized
    if _initialized:
        return
 
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
 
    GPIO.setup(PIN_R, GPIO.OUT)
    GPIO.setup(PIN_Y, GPIO.OUT)
    GPIO.setup(PIN_G, GPIO.OUT)
 
    _initialized = True
 
 
def setRedLED(value: int):
    GPIO.output(PIN_R, GPIO.HIGH if value == 1 else GPIO.LOW)
 
 
def setYellowLED(value: int):
    GPIO.output(PIN_Y, GPIO.HIGH if value == 1 else GPIO.LOW)
 
 
def setGreenLED(value: int):
    GPIO.output(PIN_G, GPIO.HIGH if value == 1 else GPIO.LOW)
 
 
def status():
    """
    Liefert aktuellen Hardware-Zustand.
    """
    return (
        int(GPIO.input(PIN_R)),
        int(GPIO.input(PIN_Y)),
        int(GPIO.input(PIN_G)),
    )

4. HTML (GETRENNT, KEIN TEMPLATE-FRAMEWORK)

Datei:

/home/pi/devel/projects/gpio_web/src/static/index.html
<!DOCTYPE html>
<html>
<head>
    <title>GPIO Web</title>
</head>
<body>
 
<h1>LED Steuerung</h1>
 
<h2>Rot (Status: {{R}})</h2>
<a href="/web/led/r/1">ON</a>
<a href="/web/led/r/0">OFF</a>
 
<h2>Gelb (Status: {{Y}})</h2>
<a href="/web/led/y/1">ON</a>
<a href="/web/led/y/0">OFF</a>
 
<h2>Grün (Status: {{G}})</h2>
<a href="/web/led/g/1">ON</a>
<a href="/web/led/g/0">OFF</a>
 
</body>
</html>

5. WEB-SCHICHT

Datei:

/home/pi/devel/projects/gpio_web/src/app.py
"""
Web-Schicht.
Verantwortlich für HTTP.
Keine GPIO-Logik hier.
"""
 
from fastapi import FastAPI, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from core import hardware
 
app = FastAPI(root_path="/web")
 
 
@app.on_event("startup")
def startup():
    hardware.init()
 
 
def load_html(r, y, g):
    with open("static/index.html", "r") as f:
        html = f.read()
 
    html = html.replace("{{R}}", str(r))
    html = html.replace("{{Y}}", str(y))
    html = html.replace("{{G}}", str(g))
 
    return html
 
 
@app.get("/", response_class=HTMLResponse)
def index():
    r, y, g = hardware.status()
    return HTMLResponse(load_html(r, y, g))
 
 
@app.get("/led/{color}/{value}")
def set_led(color: str, value: int):
 
    if value not in (0, 1):
        raise HTTPException(status_code=400, detail="Value must be 0 or 1")
 
    if color == "r":
        hardware.setRedLED(value)
    elif color == "y":
        hardware.setYellowLED(value)
    elif color == "g":
        hardware.setGreenLED(value)
    else:
        raise HTTPException(status_code=400, detail="Invalid color")
 
    return RedirectResponse(url="/web", status_code=303)

6. APACHE

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2

In:

/etc/apache2/sites-available/000-default.conf

Einfügen:

ProxyPreserveHost On
ProxyPass        /web  http://127.0.0.1:8000/
ProxyPassReverse /web  http://127.0.0.1:8000/
sudo systemctl reload apache2

7. SYSTEMD

Datei:

/etc/systemd/system/gpio_web.service
[Unit]
Description=GPIO Web FastAPI
After=network-online.target
Wants=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/devel/projects/gpio_web/src
ExecStart=/home/pi/devel/projects/course_env/bin/uvicorn app:app --host 127.0.0.1 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable gpio_web
sudo systemctl start gpio_web

8. TEST

9. REBOOT

sudo reboot

Nach Neustart erneut aufrufen.

Eigenschaften:

  • HTML sauber getrennt
  • Hardware sauber getrennt
  • Keine versteckte Reinitialisierung
  • Für Anfänger klar strukturiert
  • Reboot-fest über systemd
projekt/python_fastapi.1771613303.txt.gz · Zuletzt geändert: von torsten.roehl