Als ich die Verschaltung der bash Ampel testen wollte, musste ich feststellen, dass die Pythonprogramme aus dem 15. Teil des Tutorials nicht mehr funktionierten. Grund dafür ist, dass das RPi.GPIO
Modul den RP2 Chip des Raspberry Pi 5 nicht unterstützt. Zeit für mich, eine Alternative zu suchen und die Programme zu updaten.
Hardwareaufbau
Da ich die Ampelschaltung mit dem Button bereits am Raspi 5 angeschlossen habe, benutze ich die der Einfachheit halber für diesen Blogpost weiter.

Den detaillierten Aufbau habe ich bereits im verlinkten Post beschrieben und möchte ihn hier nicht wiederholen.
Projekt einrichten
Softwareseitig kopiere ich einfach das gesamte teil15 Verzeichnis des Pythonkurs nach gpio-rpi5 und initialisiere das Projekt mit uv. Danach installiere ich das lgpio Modul.
cp -a teil15 gpio-rpi5
cd gpio-rpio5
uv init .
uv add lgpio
lgpio
Das lgpio Modul ist eine moderne Bibliothek zur Ansteuerung der GPIO Leiste. Der Projektseite entnehme ich, dass es auch I²C und SPI unterstützt und nicht nur auf den Raspberry Pi 5 festgelegt ist.
Updates
Um die bestehenden Scripts zu aktualisieren,müssen wir in erster Linie statt RPi.GPIO das lgpio Package benutzen.
Importiert wird es einfach mit
import lgpio
Danach muss ein handle für GPIO geöffnet werden.
handle = lgpio.gpiochip_open(0)
Das der Raspi nur einen GPIO Chip besitzt, öffnen wir immer 0
.
Der letzte Initialisierungsschritt, ist die Konfiguration von Pin 17 zur Ausgabe
lgpio.gpio_claim_output(handle, __PIN__, 0)
Damit wird Pin 17 des handle
als Output geschaltet und der initiale Zustand auf „aus“ gesetzt.
Um die rote LED der Ampel ein- oder auszuschalten, benutzen wir
lgpio.gpio_write(handle, __PIN__, state)
In state wird dabei der aktive Zustand mit 0 oder 1 an die setLED() Methode übergeben.
Wenn du die verschiedenen Versionen vergleichst stellst du fest, dass sie sich nicht sehr stark unterscheiden.
Hier das gesamte led.py Programm.
# led.py mit lgpio für den Raspberry Pi 5
#! /usr/bin/python3
import lgpio
from time import sleep
__PIN__ = 17 # GPIO Pin, den wir nutzen (BCM Nummerierung)
__WAIT__ = 0.5 # Warten für 0,5 Sekunden
# Handle auf den GPIO-Chip (meist 0 für /dev/gpiochip0)
handle = lgpio.gpiochip_open(0)
# Pin als Output setzen
lgpio.gpio_claim_output(handle, __PIN__, 0)
#Zustand der LED setzen
def setLED(state):
lgpio.gpio_write(handle, __PIN__, state)
# Dauerschleife, die die LED im Wechsel ein- und ausschaltet.
# Wird gestoppt mit CTRL-C
def blinkloop():
try:
while True:
# Pin auf HIGH setzen schaltet die LED ein
setLED(1)
print('LED ein')
sleep(__WAIT__)
# Pin auf LOW setzen schaltet die LED aus
setLED(0)
print('LED aus')
sleep(__WAIT__)
except KeyboardInterrupt:
pass
finally:
# Zum schluss immer die LED ausschalten.
setLED(0)
if __name__ =='__main__':
blinkloop()
lgpio.gpiochip_close(handle) # Handle schließen
Button auslesen
Um den Button an Pin 23 auszulesen, gehst ähnlich wie oben vor, du musst lediglich den Pin zur Eingabe konfigurieren. Außerdem wird auch sofort der Pull-Up Widerstand des Pins aktiviert.
lgpio.gpio_claim_input(handle, __PIN__,lgpio.SET_PULL_UP) # Pin ist Input mit Pull-Up
Der Rest des Programms bleibt mehr oder weniger unverändert.
# button.py mit lgpio für den Raspberry Pi 5
#! /usr/bin/python3
import lgpio
from time import sleep
import logging
__PIN__ = 23 # GPIO Pin, für den Taster
__WAIT__ = 0.5 # Warten für 0,5 Sekunden
logging.basicConfig( format='%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s', level=logging.DEBUG)
if __name__ =='__main__':
handle = lgpio.gpiochip_open(0)
lgpio.gpio_claim_input(handle, __PIN__,lgpio.SET_PULL_UP) # Pin ist Input mit PullUp
pressed = False
logging.debug('Start der Schleife.')
try:
while True:
value = lgpio.gpio_read(handle, __PIN__)
pressed = value != 1
if pressed:
logging.info(f'Button wurde gedrückt {value}->{pressed}.')
else:
logging.debug(f'Button nicht gedrückt {value}->{pressed}.')
sleep(__WAIT__)
except KeyboardInterrupt:
logging.debug('Abbruch durch Benutzer.')
finally:
logging.debug('handle wird geschlossen.')
lgpio.gpiochip_close(handle) # Handle schließen
LED-Server
Zum Abschluss habe ich auch noch ledserver.py umgeschrieben, das nur in einem Detail vom Original abweicht. Die setLED() Methode wird nicht mehr aus led.py importiert sondern befindet sich direkt im Quellcode. Grund dafür ist, dass durch den import
auch der Initialisierungscode von led.py durchlaufen wird. Dadurch der handle auch da belegt, was zu einem Fehler führt, wenn der LED-Server ihn aufbauen will.
# ledserver.py mit lgpio für den Raspberry Pi 5
#! /usr/bin/python3
from time import sleep
__PIN__ = 17 # GPIO Pin, den wir nutzen (BCM Nummerierung)
__WAIT__ = 0.5 # Warten für 0,5 Sekunden
from http.server import SimpleHTTPRequestHandler
import socketserver
import lgpio
import logging
# Handle auf den GPIO-Chip (meist 0 für /dev/gpiochip0)
handle = lgpio.gpiochip_open(0)
# Pin als Output setzen
lgpio.gpio_claim_output(handle, __PIN__, 0)
responsehtml = '<html><body> <h3>LED-Server</h3><p> LED ist $ledstate_str</p></body></html>'
logging.basicConfig( format='%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s', level=logging.DEBUG)
# Da http ein stateless Protokoll ist, wird der Handler bei jedem Request neu
def setLED(state):
lgpio.gpio_write(handle, __PIN__, state)
# aufgebaut! Deswegen benutzen wir hier setup() statt __init__()
class LEDHttpRequestHandler(SimpleHTTPRequestHandler):
def setup(self):
logging.debug('setting up Handler')
self.ledstate = False
super().setup()
def do_GET(self):
logging.debug(f'path= {self.path}')
logging.debug('GET: empfangen')
self.send_response(200)
self.send_header('Content-Type:','text/html')
# Ende der Header markieren, dass ist wichtig, sonst kommt der Response nicht zurück!
self.end_headers()
#Wenn im Requestpath 'led='on'enthalten ist, schalten wir die LED ein. Bei off aus
if '?led=' in self.path:
if 'on' in self.path:
logging.debug('schalte LED ein')
self.ledstate = True
setLED(self.ledstate)
elif 'off' in self.path:
logging.debug('schalte LED aus')
self.ledstate = False
setLED(self.ledstate)
logging.debug(f'ledstate={self.ledstate}')
response = responsehtml.replace('$ledstate_str',('aus','an')[self.ledstate])
self.wfile.write(response.encode())
class http_server:
def __init__(self):
def handler(*args):
myHandler(*args)
server = HTTPServer(('', 8080), handler)
if __name__ == '__main__':
logging.debug('MAIN: start')
setLED(False) # Beim Start LED ausschalten
#Request-Handler aufbauen
handler = LEDHttpRequestHandler
handler.ledstate = False
#Socketserver mit unserem Handler starten
with socketserver.TCPServer(('',8080),handler) as httpd:
logging.info('SERVER: start')
try:
#Server läuft bis CTRL-C gedrückt wird.
httpd.serve_forever()
except KeyboardInterrupt:
pass
finally:
setLED(False)
lgpio.gpiochip_close(handle) # Handle schließen
Nach dem Start mit uv run ledserver.py
kannst du über den Browser mit http://uter:8080/?led=on die LED ein- und mit http://uter:8080/?led=off wieder ausschalten.
Raspberry Pi 4
Auf dem Raspberry Pi 4 mit DietPi OS habe ich die Programme mit lgpio genauso zum Laufen gebracht.
Fazit
lgpio ist eine moderne Alternative zum veralteten RPi.GPIO Package und ist zumindest kompatibel zu Raspberry Pi 5 und 4. Wenn das Modul das Versprechen auf der Website hält, auch andere SBC zu unterstützen ist derzeit die beste Möglichkeit, in Python die GPIO Leisten anzusprechen.