source ~/devel/projects/course_env/bin/activate
pip install fastapi uvicorn
course_web/
└── src/
├── app.py
├── core/
│ |── __init__.py # kann leer sein!
│ └── hardware.py
└── html/
├── led.html
└── temp.html
==== 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.
sudo mv /var/www/html/index.html /var/www/html/index_course_backup.html
Projekt Auswahl
Projekt Auswahl
==== 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.
===== 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.
==== API ====
import RPi.GPIO as GPIO
import glob
import time
# -----------------------------
# API-Funktionen GPIO LED Ampel
# -----------------------------
PIN_R = 17
PIN_Y = 27
PIN_G = 22
_initialized = False
def init():
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 setLED(pin, value):
GPIO.output(pin, GPIO.HIGH if value == 1 else GPIO.LOW)
def setRedLED(value):
setLED(PIN_R, value)
def setYellowLED(value):
setLED(PIN_Y, value)
def setGreenLED(value):
setLED(PIN_G, value)
def status():
return (
int(GPIO.input(PIN_R)),
int(GPIO.input(PIN_Y)),
int(GPIO.input(PIN_G)),
)
# -----------------------------
# API-Funktionen ds18b20
# -----------------------------
SENSOR_TIMEOUT = 1
def get_sensor():
sensors = glob.glob("/sys/bus/w1/devices/28-*")
if not sensors:
return None
return sensors[0] + "/w1_slave"
def get_temperature():
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
==== HTML ====
=== LED ===
LED Ampel
LED Ampel
Rot
Status: {{R}}
ON
OFF
Gelb
Status: {{Y}}
ON
OFF
Grün
Status: {{G}}
ON
OFF
Zurück
=== Temperature ===
Temperatur
Temperatur
Temperatur: {{T}} °C
Zurück
==== FASTAPI APP ====
from fastapi import FastAPI, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from core import hardware
app = FastAPI()
@app.on_event("startup")
def startup():
hardware.init()
def load_template(name, replacements):
try:
with open(f"html/{name}", "r") as f:
html = f.read()
except FileNotFoundError:
raise HTTPException(status_code=500, detail="Template nicht gefunden")
for key, value in replacements.items():
html = html.replace(key, str(value))
return html
@app.get("/led", response_class=HTMLResponse)
def led_page():
r, y, g = hardware.status()
return HTMLResponse(
load_template("led.html", {
"{{R}}": r,
"{{Y}}": y,
"{{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}")
def set_led(color: str, value: int):
if value not in (0, 1):
raise HTTPException(status_code=400)
if color == "r":
hardware.setRedLED(value)
elif color == "y":
hardware.setYellowLED(value)
elif color == "g":
hardware.setGreenLED(value)
else:
raise HTTPException(status_code=400)
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
})
)
===== 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 ''
cd /etc/apache2/sites-available/
sudo cp 000-default.conf 000-default.conf.course_backup
ProxyPreserveHost On
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
=== Aktivieren ===
Damit die Weiterleitung an die FastAPI-Anwendung funktioniert, müssen die benötigten Apache-Module aktiviert und der Webserver neu gestartet werden.
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2
==== Systemd ====
Die Service-Datei muss unter ''/etc/systemd/system/course_web.service'' neu erstellt und anschließend bei ''systemd'' registriert werden.
=== Service ===
[Unit]
Description=Python Web FastAPI
After=network-online.target
Wants=network-online.target
[Service]
User=pi
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
Restart=always
[Install]
WantedBy=multi-user.target
=== 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.
sudo systemctl daemon-reload
sudo systemctl enable course_web
sudo systemctl start course_web # starten
Nützlich:
sudo systemctl restart course_web # neu starten
sudo systemctl status course_web # prüfen!!!